summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2019-05-15 08:43:46 -0300
committerRenato Botelho <renato@netgate.com>2019-05-15 08:43:46 -0300
commit4a2bfdce1333812530dc82117658c9fdcdbd5632 (patch)
tree3cfcd3cc8bf04122ea5b0c40c8f03397af2d5b90
parentfed039d3092243b82f8b05665ff26c241f04f948 (diff)
parent03a7fd6cb603ce806894914f45b7c0d0c453ad50 (diff)
downloadFreeBSD-src-4a2bfdce1333812530dc82117658c9fdcdbd5632.zip
FreeBSD-src-4a2bfdce1333812530dc82117658c9fdcdbd5632.tar.gz
Merge remote-tracking branch 'origin/releng/11.2' into RELENG_2_4_4
-rw-r--r--UPDATING23
-rw-r--r--contrib/ntp/COPYRIGHT51
-rw-r--r--contrib/ntp/ChangeLog117
-rw-r--r--contrib/ntp/CommitLog7760
-rw-r--r--contrib/ntp/Makefile.in12
-rw-r--r--contrib/ntp/NEWS127
-rw-r--r--contrib/ntp/aclocal.m4261
-rw-r--r--contrib/ntp/adjtimed/Makefile.in4
-rwxr-xr-xcontrib/ntp/build2
-rw-r--r--contrib/ntp/clockstuff/Makefile.in4
-rw-r--r--contrib/ntp/config.h.in77
-rwxr-xr-xcontrib/ntp/configure299
-rw-r--r--contrib/ntp/configure.ac34
-rw-r--r--contrib/ntp/html/authentic.html306
-rw-r--r--contrib/ntp/html/authopt.html49
-rw-r--r--contrib/ntp/html/confopt.html4
-rw-r--r--contrib/ntp/html/keygen.html4
-rw-r--r--contrib/ntp/html/ntpdate.html4
-rw-r--r--contrib/ntp/include/Makefile.in4
-rw-r--r--contrib/ntp/include/isc/Makefile.in4
-rw-r--r--contrib/ntp/include/ntp.h12
-rw-r--r--contrib/ntp/include/ntp_calendar.h24
-rw-r--r--contrib/ntp/include/ntp_md5.h7
-rw-r--r--contrib/ntp/include/ntp_stdlib.h3
-rw-r--r--contrib/ntp/include/ntpd.h4
-rw-r--r--contrib/ntp/include/parse.h1
-rw-r--r--contrib/ntp/kernel/Makefile.in4
-rw-r--r--contrib/ntp/kernel/sys/Makefile.in4
-rw-r--r--contrib/ntp/libntp/Makefile.am1
-rw-r--r--contrib/ntp/libntp/Makefile.in14
-rw-r--r--contrib/ntp/libntp/a_md5encrypt.c17
-rw-r--r--contrib/ntp/libntp/authreadkeys.c2
-rw-r--r--contrib/ntp/libntp/calyearstart.c2
-rw-r--r--contrib/ntp/libntp/ntp_calendar.c40
-rw-r--r--contrib/ntp/libntp/prettydate.c5
-rw-r--r--contrib/ntp/libntp/ssl_init.c27
-rw-r--r--contrib/ntp/libntp/syssignal.c7
-rw-r--r--contrib/ntp/libntp/work_fork.c8
-rw-r--r--contrib/ntp/libntp/work_thread.c17
-rw-r--r--contrib/ntp/libntp/xsbprintf.c75
-rw-r--r--contrib/ntp/libparse/Makefile.in4
-rw-r--r--contrib/ntp/libparse/clk_trimtsip.c14
-rw-r--r--contrib/ntp/libparse/gpstolfp.c5
-rw-r--r--contrib/ntp/ntpd/Makefile.in4
-rw-r--r--contrib/ntp/ntpd/complete.conf.in2
-rw-r--r--contrib/ntp/ntpd/invoke-ntp.conf.texi12
-rw-r--r--contrib/ntp/ntpd/invoke-ntp.keys.texi6
-rw-r--r--contrib/ntp/ntpd/invoke-ntpd.texi8
-rw-r--r--contrib/ntp/ntpd/ntp.conf.5man16
-rw-r--r--contrib/ntp/ntpd/ntp.conf.5mdoc14
-rw-r--r--contrib/ntp/ntpd/ntp.conf.def10
-rw-r--r--contrib/ntp/ntpd/ntp.conf.html2952
-rw-r--r--contrib/ntp/ntpd/ntp.conf.man.in16
-rw-r--r--contrib/ntp/ntpd/ntp.conf.mdoc.in14
-rw-r--r--contrib/ntp/ntpd/ntp.keys.5man8
-rw-r--r--contrib/ntp/ntpd/ntp.keys.5mdoc10
-rw-r--r--contrib/ntp/ntpd/ntp.keys.def4
-rw-r--r--contrib/ntp/ntpd/ntp.keys.html287
-rw-r--r--contrib/ntp/ntpd/ntp.keys.man.in8
-rw-r--r--contrib/ntp/ntpd/ntp.keys.mdoc.in10
-rw-r--r--contrib/ntp/ntpd/ntp_config.c62
-rw-r--r--contrib/ntp/ntpd/ntp_control.c139
-rw-r--r--contrib/ntp/ntpd/ntp_crypto.c7
-rw-r--r--contrib/ntp/ntpd/ntp_io.c55
-rw-r--r--contrib/ntp/ntpd/ntp_loopfilter.c44
-rw-r--r--contrib/ntp/ntpd/ntp_parser.c677
-rw-r--r--contrib/ntp/ntpd/ntp_parser.h2
-rw-r--r--contrib/ntp/ntpd/ntp_proto.c153
-rw-r--r--contrib/ntp/ntpd/ntp_refclock.c2
-rw-r--r--contrib/ntp/ntpd/ntp_request.c9
-rw-r--r--contrib/ntp/ntpd/ntp_timer.c8
-rw-r--r--contrib/ntp/ntpd/ntpd-opts.c16
-rw-r--r--contrib/ntp/ntpd/ntpd-opts.h10
-rw-r--r--contrib/ntp/ntpd/ntpd.1ntpdman6
-rw-r--r--contrib/ntp/ntpd/ntpd.1ntpdmdoc4
-rw-r--r--contrib/ntp/ntpd/ntpd.c395
-rw-r--r--contrib/ntp/ntpd/ntpd.html1511
-rw-r--r--contrib/ntp/ntpd/ntpd.man.in6
-rw-r--r--contrib/ntp/ntpd/ntpd.mdoc.in4
-rw-r--r--contrib/ntp/ntpd/rc_cmdlength.c2
-rw-r--r--contrib/ntp/ntpd/refclock_bancomm.c119
-rw-r--r--contrib/ntp/ntpd/refclock_datum.c3
-rw-r--r--contrib/ntp/ntpd/refclock_gpsdjson.c4
-rw-r--r--contrib/ntp/ntpd/refclock_jupiter.c60
-rw-r--r--contrib/ntp/ntpd/refclock_parse.c3
-rw-r--r--contrib/ntp/ntpd/refclock_shm.c1
-rw-r--r--contrib/ntp/ntpd/refclock_true.c2
-rw-r--r--contrib/ntp/ntpdate/Makefile.in4
-rw-r--r--contrib/ntp/ntpdate/ntpdate.c198
-rw-r--r--contrib/ntp/ntpdc/Makefile.in4
-rw-r--r--contrib/ntp/ntpdc/invoke-ntpdc.texi4
-rwxr-xr-xcontrib/ntp/ntpdc/nl.pl2
-rw-r--r--contrib/ntp/ntpdc/ntpdc-opts.c16
-rw-r--r--contrib/ntp/ntpdc/ntpdc-opts.h10
-rw-r--r--contrib/ntp/ntpdc/ntpdc.1ntpdcman6
-rw-r--r--contrib/ntp/ntpdc/ntpdc.1ntpdcmdoc4
-rw-r--r--contrib/ntp/ntpdc/ntpdc.c80
-rw-r--r--contrib/ntp/ntpdc/ntpdc.html813
-rw-r--r--contrib/ntp/ntpdc/ntpdc.man.in6
-rw-r--r--contrib/ntp/ntpdc/ntpdc.mdoc.in4
-rw-r--r--contrib/ntp/ntpdc/ntpdc_ops.c23
-rw-r--r--contrib/ntp/ntpq/Makefile.in4
-rw-r--r--contrib/ntp/ntpq/invoke-ntpq.texi4
-rw-r--r--contrib/ntp/ntpq/ntpq-opts.c16
-rw-r--r--contrib/ntp/ntpq/ntpq-opts.h10
-rw-r--r--contrib/ntp/ntpq/ntpq-subs.c59
-rw-r--r--contrib/ntp/ntpq/ntpq.1ntpqman6
-rw-r--r--contrib/ntp/ntpq/ntpq.1ntpqmdoc4
-rw-r--r--contrib/ntp/ntpq/ntpq.c886
-rw-r--r--contrib/ntp/ntpq/ntpq.html2925
-rw-r--r--contrib/ntp/ntpq/ntpq.man.in6
-rw-r--r--contrib/ntp/ntpq/ntpq.mdoc.in4
-rw-r--r--contrib/ntp/ntpq/ntpq.texi2
-rw-r--r--contrib/ntp/ntpsnmpd/Makefile.in4
-rw-r--r--contrib/ntp/ntpsnmpd/invoke-ntpsnmpd.texi21
-rw-r--r--contrib/ntp/ntpsnmpd/ntpsnmpd-opts.c16
-rw-r--r--contrib/ntp/ntpsnmpd/ntpsnmpd-opts.h10
-rw-r--r--contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdman6
-rw-r--r--contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc4
-rw-r--r--contrib/ntp/ntpsnmpd/ntpsnmpd.html153
-rw-r--r--contrib/ntp/ntpsnmpd/ntpsnmpd.man.in6
-rw-r--r--contrib/ntp/ntpsnmpd/ntpsnmpd.mdoc.in4
-rw-r--r--contrib/ntp/packageinfo.sh2
-rw-r--r--contrib/ntp/parseutil/Makefile.in4
-rw-r--r--contrib/ntp/scripts/Makefile.in4
-rw-r--r--contrib/ntp/scripts/build/Makefile.in4
-rwxr-xr-xcontrib/ntp/scripts/build/check--help4
-rw-r--r--contrib/ntp/scripts/calc_tickadj/Makefile.in4
-rw-r--r--contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjman6
-rw-r--r--contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc4
-rw-r--r--contrib/ntp/scripts/calc_tickadj/calc_tickadj.html306
-rw-r--r--contrib/ntp/scripts/calc_tickadj/calc_tickadj.man.in6
-rw-r--r--contrib/ntp/scripts/calc_tickadj/calc_tickadj.mdoc.in4
-rw-r--r--contrib/ntp/scripts/calc_tickadj/invoke-calc_tickadj.texi2
-rw-r--r--contrib/ntp/scripts/invoke-plot_summary.texi4
-rw-r--r--contrib/ntp/scripts/invoke-summary.texi4
-rw-r--r--contrib/ntp/scripts/lib/Makefile.in4
-rw-r--r--contrib/ntp/scripts/ntp-wait/Makefile.in4
-rw-r--r--contrib/ntp/scripts/ntp-wait/invoke-ntp-wait.texi4
-rw-r--r--contrib/ntp/scripts/ntp-wait/ntp-wait-opts4
-rw-r--r--contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitman6
-rw-r--r--contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitmdoc4
-rw-r--r--contrib/ntp/scripts/ntp-wait/ntp-wait.html339
-rw-r--r--contrib/ntp/scripts/ntp-wait/ntp-wait.man.in6
-rw-r--r--contrib/ntp/scripts/ntp-wait/ntp-wait.mdoc.in4
-rw-r--r--contrib/ntp/scripts/ntpsweep/Makefile.in4
-rw-r--r--contrib/ntp/scripts/ntpsweep/invoke-ntpsweep.texi4
-rw-r--r--contrib/ntp/scripts/ntpsweep/ntpsweep-opts4
-rw-r--r--contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepman6
-rw-r--r--contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepmdoc4
-rw-r--r--contrib/ntp/scripts/ntpsweep/ntpsweep.html355
-rw-r--r--contrib/ntp/scripts/ntpsweep/ntpsweep.man.in6
-rw-r--r--contrib/ntp/scripts/ntpsweep/ntpsweep.mdoc.in4
-rw-r--r--contrib/ntp/scripts/ntptrace/Makefile.in4
-rw-r--r--contrib/ntp/scripts/ntptrace/invoke-ntptrace.texi4
-rw-r--r--contrib/ntp/scripts/ntptrace/ntptrace-opts4
-rw-r--r--contrib/ntp/scripts/ntptrace/ntptrace.1ntptraceman6
-rw-r--r--contrib/ntp/scripts/ntptrace/ntptrace.1ntptracemdoc4
-rw-r--r--contrib/ntp/scripts/ntptrace/ntptrace.html323
-rw-r--r--contrib/ntp/scripts/ntptrace/ntptrace.man.in6
-rw-r--r--contrib/ntp/scripts/ntptrace/ntptrace.mdoc.in4
-rw-r--r--contrib/ntp/scripts/plot_summary-opts4
-rw-r--r--contrib/ntp/scripts/plot_summary.1plot_summaryman6
-rw-r--r--contrib/ntp/scripts/plot_summary.1plot_summarymdoc4
-rw-r--r--contrib/ntp/scripts/plot_summary.html372
-rw-r--r--contrib/ntp/scripts/plot_summary.man.in6
-rw-r--r--contrib/ntp/scripts/plot_summary.mdoc.in4
-rw-r--r--contrib/ntp/scripts/summary-opts4
-rw-r--r--contrib/ntp/scripts/summary.1summaryman6
-rw-r--r--contrib/ntp/scripts/summary.1summarymdoc4
-rw-r--r--contrib/ntp/scripts/summary.html330
-rw-r--r--contrib/ntp/scripts/summary.man.in6
-rw-r--r--contrib/ntp/scripts/summary.mdoc.in4
-rw-r--r--contrib/ntp/scripts/update-leap/Makefile.in4
-rw-r--r--contrib/ntp/scripts/update-leap/invoke-update-leap.texi2
-rw-r--r--contrib/ntp/scripts/update-leap/update-leap-opts4
-rw-r--r--contrib/ntp/scripts/update-leap/update-leap.1update-leapman6
-rw-r--r--contrib/ntp/scripts/update-leap/update-leap.1update-leapmdoc4
-rw-r--r--contrib/ntp/scripts/update-leap/update-leap.html526
-rw-r--r--contrib/ntp/scripts/update-leap/update-leap.man.in6
-rw-r--r--contrib/ntp/scripts/update-leap/update-leap.mdoc.in4
-rw-r--r--contrib/ntp/sntp/COPYRIGHT51
-rw-r--r--contrib/ntp/sntp/Makefile.in12
-rw-r--r--contrib/ntp/sntp/aclocal.m4261
-rw-r--r--contrib/ntp/sntp/config.h.in63
-rwxr-xr-xcontrib/ntp/sntp/configure180
-rw-r--r--contrib/ntp/sntp/crypto.c9
-rw-r--r--contrib/ntp/sntp/include/Makefile.in4
-rw-r--r--contrib/ntp/sntp/include/version.def2
-rw-r--r--contrib/ntp/sntp/include/version.texi6
-rw-r--r--contrib/ntp/sntp/invoke-sntp.texi50
-rw-r--r--contrib/ntp/sntp/libevent/Makefile.in12
-rw-r--r--contrib/ntp/sntp/libevent/aclocal.m4163
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/ar-lib2
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/compile9
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/config.guess38
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/config.sub31
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/depcomp6
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/install-sh4
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/missing6
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/test-driver6
-rwxr-xr-xcontrib/ntp/sntp/libevent/build-aux/ylwrap6
-rw-r--r--contrib/ntp/sntp/libevent/config.h.in47
-rwxr-xr-xcontrib/ntp/sntp/libevent/configure166
-rw-r--r--contrib/ntp/sntp/libevent/evconfig-private.h2
-rw-r--r--contrib/ntp/sntp/libevent/test/regress.gen.c1226
-rw-r--r--contrib/ntp/sntp/libevent/test/regress.gen.h208
-rw-r--r--contrib/ntp/sntp/libopts/Makefile.in4
-rw-r--r--contrib/ntp/sntp/libopts/autoopts/options.h2
-rw-r--r--contrib/ntp/sntp/libopts/genshell.h2
-rw-r--r--contrib/ntp/sntp/m4/ntp_libntp.m452
-rw-r--r--contrib/ntp/sntp/m4/ntp_openssl.m41
-rw-r--r--contrib/ntp/sntp/m4/version.m42
-rw-r--r--contrib/ntp/sntp/main.c6
-rw-r--r--contrib/ntp/sntp/networking.c3
-rw-r--r--contrib/ntp/sntp/scm-rev2
-rw-r--r--contrib/ntp/sntp/scripts/Makefile.in4
-rw-r--r--contrib/ntp/sntp/sntp-opts.c16
-rw-r--r--contrib/ntp/sntp/sntp-opts.h10
-rw-r--r--contrib/ntp/sntp/sntp.1sntpman6
-rw-r--r--contrib/ntp/sntp/sntp.1sntpmdoc4
-rw-r--r--contrib/ntp/sntp/sntp.html990
-rw-r--r--contrib/ntp/sntp/sntp.man.in6
-rw-r--r--contrib/ntp/sntp/sntp.mdoc.in4
-rw-r--r--contrib/ntp/sntp/tests/Makefile.in4
-rw-r--r--contrib/ntp/sntp/tests/crypto.c4
-rw-r--r--contrib/ntp/sntp/tests/packetProcessing.c8
-rw-r--r--contrib/ntp/sntp/unity/Makefile.in4
-rw-r--r--contrib/ntp/sntp/version.c2
-rw-r--r--contrib/ntp/util/Makefile.in4
-rw-r--r--contrib/ntp/util/invoke-ntp-keygen.texi40
-rw-r--r--contrib/ntp/util/ntp-keygen-opts.c16
-rw-r--r--contrib/ntp/util/ntp-keygen-opts.def2
-rw-r--r--contrib/ntp/util/ntp-keygen-opts.h10
-rw-r--r--contrib/ntp/util/ntp-keygen.1ntp-keygenman8
-rw-r--r--contrib/ntp/util/ntp-keygen.1ntp-keygenmdoc6
-rw-r--r--contrib/ntp/util/ntp-keygen.html2307
-rw-r--r--contrib/ntp/util/ntp-keygen.man.in8
-rw-r--r--contrib/ntp/util/ntp-keygen.mdoc.in6
-rw-r--r--contrib/ntp/util/ntp-keygen.texi2
-rw-r--r--contrib/ntp/util/ntptime.c4
-rw-r--r--contrib/ntp/util/sht.c8
-rw-r--r--contrib/tzdata/Makefile29
-rw-r--r--contrib/tzdata/NEWS53
-rw-r--r--contrib/tzdata/README4
-rw-r--r--contrib/tzdata/africa10
-rw-r--r--contrib/tzdata/asia42
-rw-r--r--contrib/tzdata/backward3
-rw-r--r--contrib/tzdata/backzone4
-rw-r--r--contrib/tzdata/etcetera1
-rw-r--r--contrib/tzdata/europe4
-rw-r--r--contrib/tzdata/leap-seconds.list8
-rw-r--r--contrib/tzdata/leapseconds6
-rw-r--r--contrib/tzdata/northamerica11
-rw-r--r--contrib/tzdata/theory.html91
-rw-r--r--contrib/tzdata/version2
-rw-r--r--contrib/wpa/CONTRIBUTIONS30
-rw-r--r--contrib/wpa/COPYING2
-rw-r--r--contrib/wpa/README2
-rw-r--r--contrib/wpa/hostapd/ChangeLog183
-rw-r--r--contrib/wpa/hostapd/README30
-rw-r--r--contrib/wpa/hostapd/README-MULTI-AP160
-rw-r--r--contrib/wpa/hostapd/config_file.c1264
-rw-r--r--contrib/wpa/hostapd/config_file.h5
-rw-r--r--contrib/wpa/hostapd/ctrl_iface.c1997
-rw-r--r--contrib/wpa/hostapd/defconfig61
-rw-r--r--contrib/wpa/hostapd/hapd_module_tests.c1
-rw-r--r--contrib/wpa/hostapd/hlr_auc_gw.c136
-rw-r--r--contrib/wpa/hostapd/hostapd.conf769
-rw-r--r--contrib/wpa/hostapd/hostapd.eap_user_sqlite18
-rw-r--r--contrib/wpa/hostapd/hostapd.wpa_psk6
-rw-r--r--contrib/wpa/hostapd/hostapd_cli.c1063
-rw-r--r--contrib/wpa/hostapd/main.c166
-rwxr-xr-xcontrib/wpa/hostapd/wps-ap-nfc.py62
-rw-r--r--contrib/wpa/hs20/client/Android.mk2
-rw-r--r--contrib/wpa/hs20/client/Makefile6
-rw-r--r--contrib/wpa/hs20/client/est.c79
-rw-r--r--contrib/wpa/hs20/client/oma_dm_client.c6
-rw-r--r--contrib/wpa/hs20/client/osu_client.c275
-rw-r--r--contrib/wpa/hs20/client/osu_client.h1
-rw-r--r--contrib/wpa/patches/openssl-0.9.8za-tls-extensions.patch397
-rw-r--r--contrib/wpa/patches/openssl-0.9.8zf-tls-extensions.patch398
-rw-r--r--contrib/wpa/src/ap/accounting.c256
-rw-r--r--contrib/wpa/src/ap/accounting.h7
-rw-r--r--contrib/wpa/src/ap/acs.c144
-rw-r--r--contrib/wpa/src/ap/acs.h5
-rw-r--r--contrib/wpa/src/ap/ap_config.c357
-rw-r--r--contrib/wpa/src/ap/ap_config.h229
-rw-r--r--contrib/wpa/src/ap/ap_drv_ops.c300
-rw-r--r--contrib/wpa/src/ap/ap_drv_ops.h51
-rw-r--r--contrib/wpa/src/ap/ap_mlme.c19
-rw-r--r--contrib/wpa/src/ap/authsrv.c71
-rw-r--r--contrib/wpa/src/ap/beacon.c358
-rw-r--r--contrib/wpa/src/ap/beacon.h5
-rw-r--r--contrib/wpa/src/ap/bss_load.c52
-rw-r--r--contrib/wpa/src/ap/ctrl_iface_ap.c482
-rw-r--r--contrib/wpa/src/ap/ctrl_iface_ap.h12
-rw-r--r--contrib/wpa/src/ap/dfs.c106
-rw-r--r--contrib/wpa/src/ap/dfs.h5
-rw-r--r--contrib/wpa/src/ap/dhcp_snoop.c60
-rw-r--r--contrib/wpa/src/ap/dpp_hostapd.c1646
-rw-r--r--contrib/wpa/src/ap/dpp_hostapd.h37
-rw-r--r--contrib/wpa/src/ap/drv_callbacks.c638
-rw-r--r--contrib/wpa/src/ap/eap_user_db.c14
-rw-r--r--contrib/wpa/src/ap/eth_p_oui.c191
-rw-r--r--contrib/wpa/src/ap/eth_p_oui.h28
-rw-r--r--contrib/wpa/src/ap/fils_hlp.c654
-rw-r--r--contrib/wpa/src/ap/fils_hlp.h27
-rw-r--r--contrib/wpa/src/ap/gas_query_ap.c714
-rw-r--r--contrib/wpa/src/ap/gas_query_ap.h43
-rw-r--r--contrib/wpa/src/ap/gas_serv.c817
-rw-r--r--contrib/wpa/src/ap/gas_serv.h27
-rw-r--r--contrib/wpa/src/ap/hostapd.c714
-rw-r--r--contrib/wpa/src/ap/hostapd.h158
-rw-r--r--contrib/wpa/src/ap/hs20.c88
-rw-r--r--contrib/wpa/src/ap/hs20.h4
-rw-r--r--contrib/wpa/src/ap/hw_features.c169
-rw-r--r--contrib/wpa/src/ap/iapp.c17
-rw-r--r--contrib/wpa/src/ap/ieee802_11.c2981
-rw-r--r--contrib/wpa/src/ap/ieee802_11.h79
-rw-r--r--contrib/wpa/src/ap/ieee802_11_auth.c169
-rw-r--r--contrib/wpa/src/ap/ieee802_11_auth.h8
-rw-r--r--contrib/wpa/src/ap/ieee802_11_he.c119
-rw-r--r--contrib/wpa/src/ap/ieee802_11_ht.c89
-rw-r--r--contrib/wpa/src/ap/ieee802_11_shared.c562
-rw-r--r--contrib/wpa/src/ap/ieee802_11_vht.c227
-rw-r--r--contrib/wpa/src/ap/ieee802_1x.c484
-rw-r--r--contrib/wpa/src/ap/ieee802_1x.h7
-rw-r--r--contrib/wpa/src/ap/mbo_ap.c244
-rw-r--r--contrib/wpa/src/ap/mbo_ap.h51
-rw-r--r--contrib/wpa/src/ap/ndisc_snoop.c2
-rw-r--r--contrib/wpa/src/ap/neighbor_db.c257
-rw-r--r--contrib/wpa/src/ap/neighbor_db.h25
-rw-r--r--contrib/wpa/src/ap/peerkey_auth.c396
-rw-r--r--contrib/wpa/src/ap/pmksa_cache_auth.c245
-rw-r--r--contrib/wpa/src/ap/pmksa_cache_auth.h24
-rw-r--r--contrib/wpa/src/ap/rrm.c674
-rw-r--r--contrib/wpa/src/ap/rrm.h33
-rw-r--r--contrib/wpa/src/ap/sta_info.c514
-rw-r--r--contrib/wpa/src/ap/sta_info.h155
-rw-r--r--contrib/wpa/src/ap/taxonomy.c292
-rw-r--r--contrib/wpa/src/ap/taxonomy.h24
-rw-r--r--contrib/wpa/src/ap/tkip_countermeasures.c5
-rw-r--r--contrib/wpa/src/ap/vlan.c34
-rw-r--r--contrib/wpa/src/ap/vlan.h30
-rw-r--r--contrib/wpa/src/ap/vlan_full.c801
-rw-r--r--contrib/wpa/src/ap/vlan_ifconfig.c69
-rw-r--r--contrib/wpa/src/ap/vlan_init.c995
-rw-r--r--contrib/wpa/src/ap/vlan_init.h17
-rw-r--r--contrib/wpa/src/ap/vlan_ioctl.c155
-rw-r--r--contrib/wpa/src/ap/vlan_util.c44
-rw-r--r--contrib/wpa/src/ap/vlan_util.h18
-rw-r--r--contrib/wpa/src/ap/wmm.c15
-rw-r--r--contrib/wpa/src/ap/wnm_ap.c310
-rw-r--r--contrib/wpa/src/ap/wnm_ap.h6
-rw-r--r--contrib/wpa/src/ap/wpa_auth.c2457
-rw-r--r--contrib/wpa/src/ap/wpa_auth.h308
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ft.c3696
-rw-r--r--contrib/wpa/src/ap/wpa_auth_glue.c820
-rw-r--r--contrib/wpa/src/ap/wpa_auth_i.h121
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ie.c365
-rw-r--r--contrib/wpa/src/ap/wpa_auth_ie.h18
-rw-r--r--contrib/wpa/src/ap/wps_hostapd.c104
-rw-r--r--contrib/wpa/src/common/cli.c267
-rw-r--r--contrib/wpa/src/common/cli.h47
-rw-r--r--contrib/wpa/src/common/common_module_tests.c234
-rw-r--r--contrib/wpa/src/common/ctrl_iface_common.c209
-rw-r--r--contrib/wpa/src/common/ctrl_iface_common.h42
-rw-r--r--contrib/wpa/src/common/defs.h109
-rw-r--r--contrib/wpa/src/common/dhcp.h279
-rw-r--r--contrib/wpa/src/common/dpp.c8721
-rw-r--r--contrib/wpa/src/common/dpp.h505
-rw-r--r--contrib/wpa/src/common/eapol_common.h2
-rw-r--r--contrib/wpa/src/common/gas.c2
-rw-r--r--contrib/wpa/src/common/gas.h3
-rw-r--r--contrib/wpa/src/common/gas_server.c487
-rw-r--r--contrib/wpa/src/common/gas_server.h44
-rw-r--r--contrib/wpa/src/common/hw_features_common.c197
-rw-r--r--contrib/wpa/src/common/hw_features_common.h8
-rw-r--r--contrib/wpa/src/common/ieee802_11_common.c860
-rw-r--r--contrib/wpa/src/common/ieee802_11_common.h148
-rw-r--r--contrib/wpa/src/common/ieee802_11_defs.h901
-rw-r--r--contrib/wpa/src/common/ieee802_1x_defs.h10
-rw-r--r--contrib/wpa/src/common/ocv.c172
-rw-r--r--contrib/wpa/src/common/ocv.h40
-rw-r--r--contrib/wpa/src/common/privsep_commands.h25
-rw-r--r--contrib/wpa/src/common/qca-vendor.h6375
-rw-r--r--contrib/wpa/src/common/sae.c616
-rw-r--r--contrib/wpa/src/common/sae.h18
-rw-r--r--contrib/wpa/src/common/version.h6
-rw-r--r--contrib/wpa/src/common/wpa_common.c1246
-rw-r--r--contrib/wpa/src/common/wpa_common.h163
-rw-r--r--contrib/wpa/src/common/wpa_ctrl.c25
-rw-r--r--contrib/wpa/src/common/wpa_ctrl.h123
-rw-r--r--contrib/wpa/src/common/wpa_helpers.c6
-rw-r--r--contrib/wpa/src/crypto/aes-cbc.c6
-rw-r--r--contrib/wpa/src/crypto/aes-ctr.c28
-rw-r--r--contrib/wpa/src/crypto/aes-internal-dec.c4
-rw-r--r--contrib/wpa/src/crypto/aes-internal-enc.c7
-rw-r--r--contrib/wpa/src/crypto/aes-omac1.c3
-rw-r--r--contrib/wpa/src/crypto/aes-siv.c62
-rw-r--r--contrib/wpa/src/crypto/aes.h4
-rw-r--r--contrib/wpa/src/crypto/aes_siv.h10
-rw-r--r--contrib/wpa/src/crypto/aes_wrap.h4
-rw-r--r--contrib/wpa/src/crypto/crypto.h98
-rw-r--r--contrib/wpa/src/crypto/crypto_gnutls.c255
-rw-r--r--contrib/wpa/src/crypto/crypto_internal-modexp.c73
-rw-r--r--contrib/wpa/src/crypto/crypto_internal.c53
-rw-r--r--contrib/wpa/src/crypto/crypto_libtomcrypt.c54
-rw-r--r--contrib/wpa/src/crypto/crypto_linux.c1009
-rw-r--r--contrib/wpa/src/crypto/crypto_module_tests.c495
-rw-r--r--contrib/wpa/src/crypto/crypto_nettle.c469
-rw-r--r--contrib/wpa/src/crypto/crypto_none.c3
-rw-r--r--contrib/wpa/src/crypto/crypto_openssl.c881
-rw-r--r--contrib/wpa/src/crypto/crypto_wolfssl.c1786
-rw-r--r--contrib/wpa/src/crypto/des-internal.c17
-rw-r--r--contrib/wpa/src/crypto/dh_group5.c1
-rw-r--r--contrib/wpa/src/crypto/dh_groups.c45
-rw-r--r--contrib/wpa/src/crypto/fips_prf_openssl.c25
-rw-r--r--contrib/wpa/src/crypto/fips_prf_wolfssl.c87
-rw-r--r--contrib/wpa/src/crypto/md4-internal.c5
-rw-r--r--contrib/wpa/src/crypto/md5-internal.c3
-rw-r--r--contrib/wpa/src/crypto/ms_funcs.c47
-rw-r--r--contrib/wpa/src/crypto/ms_funcs.h8
-rw-r--r--contrib/wpa/src/crypto/random.c77
-rw-r--r--contrib/wpa/src/crypto/sha1-internal.c12
-rw-r--r--contrib/wpa/src/crypto/sha1-tlsprf.c3
-rw-r--r--contrib/wpa/src/crypto/sha256-internal.c9
-rw-r--r--contrib/wpa/src/crypto/sha256-kdf.c20
-rw-r--r--contrib/wpa/src/crypto/sha256-prf.c26
-rw-r--r--contrib/wpa/src/crypto/sha256.h12
-rw-r--r--contrib/wpa/src/crypto/sha384-internal.c92
-rw-r--r--contrib/wpa/src/crypto/sha384-kdf.c87
-rw-r--r--contrib/wpa/src/crypto/sha384-prf.c28
-rw-r--r--contrib/wpa/src/crypto/sha384.c104
-rw-r--r--contrib/wpa/src/crypto/sha384.h15
-rw-r--r--contrib/wpa/src/crypto/sha384_i.h23
-rw-r--r--contrib/wpa/src/crypto/sha512-internal.c270
-rw-r--r--contrib/wpa/src/crypto/sha512-kdf.c87
-rw-r--r--contrib/wpa/src/crypto/sha512-prf.c108
-rw-r--r--contrib/wpa/src/crypto/sha512.c104
-rw-r--r--contrib/wpa/src/crypto/sha512.h27
-rw-r--r--contrib/wpa/src/crypto/sha512_i.h25
-rw-r--r--contrib/wpa/src/crypto/tls.h98
-rw-r--r--contrib/wpa/src/crypto/tls_gnutls.c307
-rw-r--r--contrib/wpa/src/crypto/tls_internal.c108
-rw-r--r--contrib/wpa/src/crypto/tls_none.c22
-rw-r--r--contrib/wpa/src/crypto/tls_openssl.c1743
-rw-r--r--contrib/wpa/src/crypto/tls_openssl.h19
-rw-r--r--contrib/wpa/src/crypto/tls_openssl_ocsp.c846
-rw-r--r--contrib/wpa/src/crypto/tls_wolfssl.c2201
-rw-r--r--contrib/wpa/src/drivers/driver.h1370
-rw-r--r--contrib/wpa/src/drivers/driver_bsd.c348
-rw-r--r--contrib/wpa/src/drivers/driver_common.c100
-rw-r--r--contrib/wpa/src/drivers/driver_macsec_linux.c1437
-rw-r--r--contrib/wpa/src/drivers/driver_macsec_qca.c669
-rw-r--r--contrib/wpa/src/drivers/driver_ndis.c32
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211.h65
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_capa.c722
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_event.c704
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_monitor.c13
-rw-r--r--contrib/wpa/src/drivers/driver_nl80211_scan.c828
-rw-r--r--contrib/wpa/src/drivers/driver_openbsd.c3
-rw-r--r--contrib/wpa/src/drivers/driver_privsep.c60
-rw-r--r--contrib/wpa/src/drivers/driver_wired.c360
-rw-r--r--contrib/wpa/src/drivers/driver_wired_common.c322
-rw-r--r--contrib/wpa/src/drivers/driver_wired_common.h34
-rw-r--r--contrib/wpa/src/drivers/drivers.c39
-rw-r--r--contrib/wpa/src/eap_common/eap_eke_common.c74
-rw-r--r--contrib/wpa/src/eap_common/eap_fast_common.c27
-rw-r--r--contrib/wpa/src/eap_common/eap_fast_common.h6
-rw-r--r--contrib/wpa/src/eap_common/eap_gpsk_common.c9
-rw-r--r--contrib/wpa/src/eap_common/eap_pax_common.c6
-rw-r--r--contrib/wpa/src/eap_common/eap_pwd_common.c473
-rw-r--r--contrib/wpa/src/eap_common/eap_pwd_common.h25
-rw-r--r--contrib/wpa/src/eap_common/eap_sake_common.c77
-rw-r--r--contrib/wpa/src/eap_common/eap_sake_common.h8
-rw-r--r--contrib/wpa/src/eap_common/eap_sim_common.c9
-rw-r--r--contrib/wpa/src/eap_common/ikev2_common.c15
-rw-r--r--contrib/wpa/src/eap_peer/eap.c448
-rw-r--r--contrib/wpa/src/eap_peer/eap.h35
-rw-r--r--contrib/wpa/src/eap_peer/eap_aka.c136
-rw-r--r--contrib/wpa/src/eap_peer/eap_config.h131
-rw-r--r--contrib/wpa/src/eap_peer/eap_eke.c19
-rw-r--r--contrib/wpa/src/eap_peer/eap_fast.c121
-rw-r--r--contrib/wpa/src/eap_peer/eap_fast_pac.c24
-rw-r--r--contrib/wpa/src/eap_peer/eap_gpsk.c24
-rw-r--r--contrib/wpa/src/eap_peer/eap_gtc.c6
-rw-r--r--contrib/wpa/src/eap_peer/eap_i.h15
-rw-r--r--contrib/wpa/src/eap_peer/eap_ikev2.c12
-rw-r--r--contrib/wpa/src/eap_peer/eap_leap.c23
-rw-r--r--contrib/wpa/src/eap_peer/eap_md5.c6
-rw-r--r--contrib/wpa/src/eap_peer/eap_methods.c17
-rw-r--r--contrib/wpa/src/eap_peer/eap_methods.h1
-rw-r--r--contrib/wpa/src/eap_peer/eap_mschapv2.c34
-rw-r--r--contrib/wpa/src/eap_peer/eap_otp.c6
-rw-r--r--contrib/wpa/src/eap_peer/eap_pax.c52
-rw-r--r--contrib/wpa/src/eap_peer/eap_peap.c167
-rw-r--r--contrib/wpa/src/eap_peer/eap_proxy.h12
-rw-r--r--contrib/wpa/src/eap_peer/eap_proxy_dummy.c23
-rw-r--r--contrib/wpa/src/eap_peer/eap_psk.c18
-rw-r--r--contrib/wpa/src/eap_peer/eap_pwd.c624
-rw-r--r--contrib/wpa/src/eap_peer/eap_sake.c49
-rw-r--r--contrib/wpa/src/eap_peer/eap_sim.c71
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls.c95
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls_common.c138
-rw-r--r--contrib/wpa/src/eap_peer/eap_tls_common.h8
-rw-r--r--contrib/wpa/src/eap_peer/eap_tnc.c18
-rw-r--r--contrib/wpa/src/eap_peer/eap_ttls.c214
-rw-r--r--contrib/wpa/src/eap_peer/eap_vendor_test.c6
-rw-r--r--contrib/wpa/src/eap_peer/eap_wsc.c15
-rw-r--r--contrib/wpa/src/eap_peer/ikev2.c7
-rw-r--r--contrib/wpa/src/eap_peer/tncc.c25
-rw-r--r--contrib/wpa/src/eap_server/eap.h9
-rw-r--r--contrib/wpa/src/eap_server/eap_i.h3
-rw-r--r--contrib/wpa/src/eap_server/eap_methods.h1
-rw-r--r--contrib/wpa/src/eap_server/eap_server.c112
-rw-r--r--contrib/wpa/src/eap_server/eap_server_aka.c23
-rw-r--r--contrib/wpa/src/eap_server/eap_server_eke.c15
-rw-r--r--contrib/wpa/src/eap_server/eap_server_fast.c65
-rw-r--r--contrib/wpa/src/eap_server/eap_server_gpsk.c22
-rw-r--r--contrib/wpa/src/eap_server/eap_server_gtc.c9
-rw-r--r--contrib/wpa/src/eap_server/eap_server_identity.c6
-rw-r--r--contrib/wpa/src/eap_server/eap_server_ikev2.c11
-rw-r--r--contrib/wpa/src/eap_server/eap_server_md5.c6
-rw-r--r--contrib/wpa/src/eap_server/eap_server_methods.c15
-rw-r--r--contrib/wpa/src/eap_server/eap_server_mschapv2.c21
-rw-r--r--contrib/wpa/src/eap_server/eap_server_pax.c74
-rw-r--r--contrib/wpa/src/eap_server/eap_server_peap.c82
-rw-r--r--contrib/wpa/src/eap_server/eap_server_psk.c18
-rw-r--r--contrib/wpa/src/eap_server/eap_server_pwd.c495
-rw-r--r--contrib/wpa/src/eap_server/eap_server_sake.c59
-rw-r--r--contrib/wpa/src/eap_server/eap_server_sim.c15
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tls.c58
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tls_common.c46
-rw-r--r--contrib/wpa/src/eap_server/eap_server_tnc.c6
-rw-r--r--contrib/wpa/src/eap_server/eap_server_ttls.c33
-rw-r--r--contrib/wpa/src/eap_server/eap_server_vendor_test.c6
-rw-r--r--contrib/wpa/src/eap_server/eap_server_wsc.c8
-rw-r--r--contrib/wpa/src/eap_server/eap_sim_db.c88
-rw-r--r--contrib/wpa/src/eap_server/eap_sim_db.h2
-rw-r--r--contrib/wpa/src/eap_server/eap_tls_common.h8
-rw-r--r--contrib/wpa/src/eap_server/ikev2.c12
-rw-r--r--contrib/wpa/src/eap_server/tncs.c20
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm.c38
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm.h1
-rw-r--r--contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h12
-rw-r--r--contrib/wpa/src/eapol_supp/eapol_supp_sm.c136
-rw-r--r--contrib/wpa/src/eapol_supp/eapol_supp_sm.h50
-rw-r--r--contrib/wpa/src/fst/fst.c8
-rw-r--r--contrib/wpa/src/fst/fst.h16
-rw-r--r--contrib/wpa/src/fst/fst_ctrl_aux.c31
-rw-r--r--contrib/wpa/src/fst/fst_ctrl_aux.h22
-rw-r--r--contrib/wpa/src/fst/fst_ctrl_iface.c10
-rw-r--r--contrib/wpa/src/fst/fst_defs.h10
-rw-r--r--contrib/wpa/src/fst/fst_group.c272
-rw-r--r--contrib/wpa/src/fst/fst_group.h12
-rw-r--r--contrib/wpa/src/fst/fst_iface.c7
-rw-r--r--contrib/wpa/src/fst/fst_iface.h5
-rw-r--r--contrib/wpa/src/fst/fst_session.c97
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet.h1
-rw-r--r--contrib/wpa/src/l2_packet/l2_packet_privsep.c4
-rw-r--r--contrib/wpa/src/p2p/p2p.c387
-rw-r--r--contrib/wpa/src/p2p/p2p.h89
-rw-r--r--contrib/wpa/src/p2p/p2p_build.c8
-rw-r--r--contrib/wpa/src/p2p/p2p_go_neg.c141
-rw-r--r--contrib/wpa/src/p2p/p2p_group.c28
-rw-r--r--contrib/wpa/src/p2p/p2p_i.h25
-rw-r--r--contrib/wpa/src/p2p/p2p_invitation.c6
-rw-r--r--contrib/wpa/src/p2p/p2p_parse.c98
-rw-r--r--contrib/wpa/src/p2p/p2p_pd.c893
-rw-r--r--contrib/wpa/src/p2p/p2p_sd.c82
-rw-r--r--contrib/wpa/src/p2p/p2p_utils.c23
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_cp.c96
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_cp.h15
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay.c2302
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay.h157
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_kay_i.h400
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_key.c89
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_key.h26
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_secy_ops.c149
-rw-r--r--contrib/wpa/src/pae/ieee802_1x_secy_ops.h16
-rw-r--r--contrib/wpa/src/radius/radius.c145
-rw-r--r--contrib/wpa/src/radius/radius.h29
-rw-r--r--contrib/wpa/src/radius/radius_client.c230
-rw-r--r--contrib/wpa/src/radius/radius_client.h3
-rw-r--r--contrib/wpa/src/radius/radius_das.c228
-rw-r--r--contrib/wpa/src/radius/radius_das.h6
-rw-r--r--contrib/wpa/src/radius/radius_server.c909
-rw-r--r--contrib/wpa/src/radius/radius_server.h6
-rw-r--r--contrib/wpa/src/rsn_supp/peerkey.c1155
-rw-r--r--contrib/wpa/src/rsn_supp/peerkey.h82
-rw-r--r--contrib/wpa/src/rsn_supp/pmksa_cache.c149
-rw-r--r--contrib/wpa/src/rsn_supp/pmksa_cache.h53
-rw-r--r--contrib/wpa/src/rsn_supp/preauth.c17
-rw-r--r--contrib/wpa/src/rsn_supp/preauth.h6
-rw-r--r--contrib/wpa/src/rsn_supp/tdls.c63
-rw-r--r--contrib/wpa/src/rsn_supp/wpa.c2203
-rw-r--r--contrib/wpa/src/rsn_supp/wpa.h95
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ft.c375
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_i.h100
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ie.c87
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ie.h14
-rw-r--r--contrib/wpa/src/tls/asn1.c8
-rw-r--r--contrib/wpa/src/tls/asn1.h4
-rw-r--r--contrib/wpa/src/tls/bignum.c4
-rw-r--r--contrib/wpa/src/tls/libtommath.c222
-rw-r--r--contrib/wpa/src/tls/pkcs5.c446
-rw-r--r--contrib/wpa/src/tls/rsa.c2
-rw-r--r--contrib/wpa/src/tls/tlsv1_client.c89
-rw-r--r--contrib/wpa/src/tls/tlsv1_client.h13
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_i.h18
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_ocsp.c803
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_read.c496
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_write.c161
-rw-r--r--contrib/wpa/src/tls/tlsv1_common.c43
-rw-r--r--contrib/wpa/src/tls/tlsv1_common.h5
-rw-r--r--contrib/wpa/src/tls/tlsv1_cred.c783
-rw-r--r--contrib/wpa/src/tls/tlsv1_cred.h8
-rw-r--r--contrib/wpa/src/tls/tlsv1_server.c59
-rw-r--r--contrib/wpa/src/tls/tlsv1_server.h7
-rw-r--r--contrib/wpa/src/tls/tlsv1_server_i.h5
-rw-r--r--contrib/wpa/src/tls/tlsv1_server_read.c137
-rw-r--r--contrib/wpa/src/tls/tlsv1_server_write.c173
-rw-r--r--contrib/wpa/src/tls/x509v3.c317
-rw-r--r--contrib/wpa/src/tls/x509v3.h36
-rw-r--r--contrib/wpa/src/utils/base64.c144
-rw-r--r--contrib/wpa/src/utils/base64.h4
-rw-r--r--contrib/wpa/src/utils/browser-android.c6
-rw-r--r--contrib/wpa/src/utils/browser-wpadebug.c7
-rw-r--r--contrib/wpa/src/utils/browser.c3
-rw-r--r--contrib/wpa/src/utils/common.c140
-rw-r--r--contrib/wpa/src/utils/common.h32
-rw-r--r--contrib/wpa/src/utils/const_time.h191
-rw-r--r--contrib/wpa/src/utils/crc32.c85
-rw-r--r--contrib/wpa/src/utils/crc32.h14
-rw-r--r--contrib/wpa/src/utils/edit_simple.c6
-rw-r--r--contrib/wpa/src/utils/eloop.c297
-rw-r--r--contrib/wpa/src/utils/eloop.h16
-rw-r--r--contrib/wpa/src/utils/eloop_win.c6
-rw-r--r--contrib/wpa/src/utils/ext_password.c4
-rw-r--r--contrib/wpa/src/utils/ext_password_i.h6
-rw-r--r--contrib/wpa/src/utils/http_curl.c139
-rw-r--r--contrib/wpa/src/utils/json.c576
-rw-r--r--contrib/wpa/src/utils/json.h42
-rw-r--r--contrib/wpa/src/utils/list.h6
-rw-r--r--contrib/wpa/src/utils/module_tests.h20
-rw-r--r--contrib/wpa/src/utils/os.h16
-rw-r--r--contrib/wpa/src/utils/os_internal.c16
-rw-r--r--contrib/wpa/src/utils/os_none.c12
-rw-r--r--contrib/wpa/src/utils/os_unix.c32
-rw-r--r--contrib/wpa/src/utils/os_win32.c10
-rw-r--r--contrib/wpa/src/utils/pcsc_funcs.c29
-rw-r--r--contrib/wpa/src/utils/platform.h4
-rw-r--r--contrib/wpa/src/utils/radiotap.c2
-rw-r--r--contrib/wpa/src/utils/radiotap.h4
-rw-r--r--contrib/wpa/src/utils/radiotap_iter.h2
-rw-r--r--contrib/wpa/src/utils/trace.c46
-rw-r--r--contrib/wpa/src/utils/trace.h2
-rw-r--r--contrib/wpa/src/utils/utils_module_tests.c372
-rw-r--r--contrib/wpa/src/utils/uuid.c25
-rw-r--r--contrib/wpa/src/utils/uuid.h1
-rw-r--r--contrib/wpa/src/utils/wpa_debug.c58
-rw-r--r--contrib/wpa/src/utils/wpa_debug.h3
-rw-r--r--contrib/wpa/src/utils/wpabuf.c36
-rw-r--r--contrib/wpa/src/utils/wpabuf.h17
-rw-r--r--contrib/wpa/src/utils/xml-utils.c8
-rw-r--r--contrib/wpa/src/utils/xml_libxml2.c2
-rw-r--r--contrib/wpa/src/wps/wps.c28
-rw-r--r--contrib/wpa/src/wps/wps.h52
-rw-r--r--contrib/wpa/src/wps/wps_attr_build.c45
-rw-r--r--contrib/wpa/src/wps/wps_attr_parse.c15
-rw-r--r--contrib/wpa/src/wps/wps_attr_parse.h1
-rw-r--r--contrib/wpa/src/wps/wps_attr_process.c10
-rw-r--r--contrib/wpa/src/wps/wps_common.c64
-rw-r--r--contrib/wpa/src/wps/wps_defs.h7
-rw-r--r--contrib/wpa/src/wps/wps_dev_attr.c8
-rw-r--r--contrib/wpa/src/wps/wps_dev_attr.h1
-rw-r--r--contrib/wpa/src/wps/wps_enrollee.c47
-rw-r--r--contrib/wpa/src/wps/wps_er.c13
-rw-r--r--contrib/wpa/src/wps/wps_i.h9
-rw-r--r--contrib/wpa/src/wps/wps_module_tests.c3
-rw-r--r--contrib/wpa/src/wps/wps_registrar.c176
-rw-r--r--contrib/wpa/src/wps/wps_upnp.c13
-rw-r--r--contrib/wpa/src/wps/wps_upnp.h3
-rw-r--r--contrib/wpa/src/wps/wps_upnp_i.h3
-rw-r--r--contrib/wpa/src/wps/wps_upnp_ssdp.c6
-rw-r--r--contrib/wpa/src/wps/wps_upnp_web.c88
-rw-r--r--contrib/wpa/src/wps/wps_validate.c2
-rw-r--r--contrib/wpa/wpa_supplicant/Android.mk1778
-rw-r--r--contrib/wpa/wpa_supplicant/ChangeLog283
-rw-r--r--contrib/wpa/wpa_supplicant/README63
-rw-r--r--contrib/wpa/wpa_supplicant/README-DPP195
-rw-r--r--contrib/wpa/wpa_supplicant/README-HS2084
-rw-r--r--contrib/wpa/wpa_supplicant/README-P2P28
-rw-r--r--contrib/wpa/wpa_supplicant/README-Windows.txt299
-rw-r--r--contrib/wpa/wpa_supplicant/android.config545
-rw-r--r--contrib/wpa/wpa_supplicant/ap.c448
-rw-r--r--contrib/wpa/wpa_supplicant/ap.h31
-rw-r--r--contrib/wpa/wpa_supplicant/autoscan.c41
-rw-r--r--contrib/wpa/wpa_supplicant/autoscan.h10
-rw-r--r--contrib/wpa/wpa_supplicant/bgscan.c8
-rw-r--r--contrib/wpa/wpa_supplicant/bgscan.h9
-rw-r--r--contrib/wpa/wpa_supplicant/bgscan_learn.c3
-rw-r--r--contrib/wpa/wpa_supplicant/bgscan_simple.c10
-rw-r--r--contrib/wpa/wpa_supplicant/binder/.clang-format9
-rw-r--r--contrib/wpa/wpa_supplicant/binder/binder.cpp104
-rw-r--r--contrib/wpa/wpa_supplicant/binder/binder.h46
-rw-r--r--contrib/wpa/wpa_supplicant/binder/binder_constants.cpp18
-rw-r--r--contrib/wpa/wpa_supplicant/binder/binder_constants.h21
-rw-r--r--contrib/wpa/wpa_supplicant/binder/binder_i.h28
-rw-r--r--contrib/wpa/wpa_supplicant/binder/binder_manager.cpp100
-rw-r--r--contrib/wpa/wpa_supplicant/binder/binder_manager.h58
-rw-r--r--contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl16
-rw-r--r--contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl59
-rw-r--r--contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl20
-rw-r--r--contrib/wpa/wpa_supplicant/binder/iface.cpp16
-rw-r--r--contrib/wpa/wpa_supplicant/binder/iface.h42
-rw-r--r--contrib/wpa/wpa_supplicant/binder/supplicant.cpp127
-rw-r--r--contrib/wpa/wpa_supplicant/binder/supplicant.h55
-rw-r--r--contrib/wpa/wpa_supplicant/bss.c170
-rw-r--r--contrib/wpa/wpa_supplicant/bss.h31
-rw-r--r--contrib/wpa/wpa_supplicant/config.c693
-rw-r--r--contrib/wpa/wpa_supplicant/config.h289
-rw-r--r--contrib/wpa/wpa_supplicant/config_file.c261
-rw-r--r--contrib/wpa/wpa_supplicant/config_ssid.h308
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface.c2600
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c6
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_udp.c174
-rw-r--r--contrib/wpa/wpa_supplicant/ctrl_iface_unix.c370
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/Makefile4
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf10
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_common.c8
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_common_i.h10
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c74
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h15
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new.c955
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new.h72
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c1508
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h313
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c372
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h165
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c390
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c9
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h12
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c4
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old.c745
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old.h142
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c1404
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h101
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c152
-rw-r--r--contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in5
-rw-r--r--contrib/wpa/wpa_supplicant/defconfig176
-rw-r--r--contrib/wpa/wpa_supplicant/dpp_supplicant.c2246
-rw-r--r--contrib/wpa/wpa_supplicant/dpp_supplicant.h29
-rw-r--r--contrib/wpa/wpa_supplicant/driver_i.h304
-rw-r--r--contrib/wpa/wpa_supplicant/eapol_test.c21
-rwxr-xr-xcontrib/wpa/wpa_supplicant/eapol_test.py2
-rw-r--r--contrib/wpa/wpa_supplicant/events.c1715
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py20
-rw-r--r--contrib/wpa/wpa_supplicant/examples/dpp-qrcode.py130
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/p2p-nfc.py168
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py70
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py30
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py34
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py30
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py50
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py44
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py32
-rw-r--r--contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py32
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py29
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py34
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py16
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py20
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wpas-test.py91
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wps-ap-cli6
-rwxr-xr-xcontrib/wpa/wpa_supplicant/examples/wps-nfc.py124
-rw-r--r--contrib/wpa/wpa_supplicant/gas_query.c258
-rw-r--r--contrib/wpa/wpa_supplicant/gas_query.h7
-rw-r--r--contrib/wpa/wpa_supplicant/hs20_supplicant.c450
-rw-r--r--contrib/wpa/wpa_supplicant/hs20_supplicant.h22
-rw-r--r--contrib/wpa/wpa_supplicant/ibss_rsn.c65
-rw-r--r--contrib/wpa/wpa_supplicant/ibss_rsn.h3
-rw-r--r--contrib/wpa/wpa_supplicant/interworking.c393
-rw-r--r--contrib/wpa/wpa_supplicant/interworking.h3
-rw-r--r--contrib/wpa/wpa_supplicant/libwpa_test.c32
-rw-r--r--contrib/wpa/wpa_supplicant/main.c108
-rw-r--r--contrib/wpa/wpa_supplicant/mbo.c635
-rw-r--r--contrib/wpa/wpa_supplicant/mesh.c341
-rw-r--r--contrib/wpa/wpa_supplicant/mesh.h3
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_mpm.c481
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_mpm.h5
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_rsn.c446
-rw-r--r--contrib/wpa/wpa_supplicant/mesh_rsn.h11
-rw-r--r--contrib/wpa/wpa_supplicant/notify.c160
-rw-r--r--contrib/wpa/wpa_supplicant/notify.h20
-rw-r--r--contrib/wpa/wpa_supplicant/offchannel.c57
-rw-r--r--contrib/wpa/wpa_supplicant/op_classes.c387
-rw-r--r--contrib/wpa/wpa_supplicant/p2p_supplicant.c1746
-rw-r--r--contrib/wpa/wpa_supplicant/p2p_supplicant.h27
-rw-r--r--contrib/wpa/wpa_supplicant/p2p_supplicant_sd.c18
-rw-r--r--contrib/wpa/wpa_supplicant/preauth_test.c15
-rw-r--r--contrib/wpa/wpa_supplicant/rrm.c1575
-rw-r--r--contrib/wpa/wpa_supplicant/scan.c814
-rw-r--r--contrib/wpa/wpa_supplicant/scan.h13
-rw-r--r--contrib/wpa/wpa_supplicant/sme.c1124
-rw-r--r--contrib/wpa/wpa_supplicant/sme.h19
-rw-r--r--contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in15
-rw-r--r--contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in15
-rw-r--r--contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in15
-rw-r--r--contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.in13
-rw-r--r--contrib/wpa/wpa_supplicant/tests/link_test.c83
-rw-r--r--contrib/wpa/wpa_supplicant/tests/test_eap_sim_common.c47
-rw-r--r--contrib/wpa/wpa_supplicant/tests/test_wpa.c369
-rwxr-xr-xcontrib/wpa/wpa_supplicant/utils/log2pcap.py2
-rw-r--r--contrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj473
-rw-r--r--contrib/wpa/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj203
-rw-r--r--contrib/wpa/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj215
-rw-r--r--contrib/wpa/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj236
-rw-r--r--contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant.sln52
-rw-r--r--contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj461
-rw-r--r--contrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj461
-rw-r--r--contrib/wpa/wpa_supplicant/wifi_display.c13
-rw-r--r--contrib/wpa/wpa_supplicant/wmm_ac.c16
-rw-r--r--contrib/wpa/wpa_supplicant/wmm_ac.h2
-rw-r--r--contrib/wpa/wpa_supplicant/wnm_sta.c989
-rw-r--r--contrib/wpa/wpa_supplicant/wnm_sta.h18
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_cli.c1105
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_passphrase.c8
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_priv.c324
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant.c2589
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant.conf464
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant_i.h378
-rw-r--r--contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf1
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_glue.c192
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_kay.c178
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_kay.h10
-rw-r--r--contrib/wpa/wpa_supplicant/wpas_module_tests.c33
-rw-r--r--contrib/wpa/wpa_supplicant/wps_supplicant.c84
-rw-r--r--contrib/wpa/wpa_supplicant/wps_supplicant.h9
-rw-r--r--sys/amd64/amd64/exception.S2
-rw-r--r--sys/amd64/amd64/genassym.c3
-rw-r--r--sys/amd64/amd64/initcpu.c1
-rw-r--r--sys/amd64/amd64/machdep.c1
-rw-r--r--sys/amd64/amd64/support.S248
-rw-r--r--sys/amd64/include/pcpu.h6
-rw-r--r--sys/conf/newvers.sh2
-rw-r--r--sys/dev/cpuctl/cpuctl.c1
-rw-r--r--sys/i386/i386/exception.s1
-rw-r--r--sys/i386/i386/genassym.c3
-rw-r--r--sys/i386/i386/initcpu.c1
-rw-r--r--sys/i386/i386/support.s191
-rw-r--r--sys/i386/include/pcpu.h6
-rw-r--r--sys/netpfil/pf/pf.c25
-rw-r--r--sys/x86/include/specialreg.h2
-rw-r--r--sys/x86/include/x86_var.h2
-rw-r--r--sys/x86/x86/cpu_machdep.c195
-rwxr-xr-xusr.bin/xinstall/tests/install_test.sh24
-rw-r--r--usr.bin/xinstall/xinstall.c15
-rw-r--r--usr.sbin/ntp/config.h32
-rw-r--r--usr.sbin/ntp/doc/ntp-keygen.86
-rw-r--r--usr.sbin/ntp/doc/ntp.conf.514
-rw-r--r--usr.sbin/ntp/doc/ntp.keys.58
-rw-r--r--usr.sbin/ntp/doc/ntpd.84
-rw-r--r--usr.sbin/ntp/doc/ntpdc.84
-rw-r--r--usr.sbin/ntp/doc/ntpq.84
-rw-r--r--usr.sbin/ntp/doc/sntp.84
-rw-r--r--usr.sbin/ntp/libntp/Makefile2
-rwxr-xr-xusr.sbin/ntp/scripts/mkver2
-rw-r--r--usr.sbin/wpa/Makefile.crypto6
-rw-r--r--usr.sbin/wpa/Makefile.inc5
-rw-r--r--usr.sbin/wpa/hostapd/Makefile113
-rw-r--r--usr.sbin/wpa/hostapd_cli/Makefile3
-rw-r--r--usr.sbin/wpa/wpa_cli/Makefile27
-rw-r--r--usr.sbin/wpa/wpa_supplicant/Makefile33
875 files changed, 136439 insertions, 32827 deletions
diff --git a/UPDATING b/UPDATING
index 6e159f8..6e3e0e5 100644
--- a/UPDATING
+++ b/UPDATING
@@ -16,6 +16,29 @@ from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to
the tip of head, and then rebuild without this option. The bootstrap process
from older version of current across the gcc/clang cutover is a bit fragile.
+20190514 p10 FreeBSD-EN-19:08.tzdata
+ FreeBSD-EN-19:09.xinstall
+ FreeBSD-SA-19:03.wpa
+ FreeBSD-SA-19:04.ntp
+ FreeBSD-SA-19:05.pf
+ FreeBSD-SA-19:06.pf
+ FreeBSD-SA-19:07.mds
+
+ Import tzdata 2019a. [EN-19:08.tzdata]
+
+ Fix install with partially matching relative paths. [EN-19:09.xinstall]
+
+ Fix multiple vulnerabilities in hostapd/wpa_supplicant. [SA-19:03.wpa]
+
+ Fix authenticated denial of service in ntpd. [SA-19:04.ntp]
+
+ Fix IPv6 fragment reassembly in pf. [SA-19:05.pf]
+
+ Fix ICMP/ICMP6 packet filter bypass in pf. [SA-19:06.pf]
+
+ Add mitigations for Microarchitectural Data Sampling. [SA-19:07.mds]
+
+
20190205 p9 FreeBSD-SA-19:01.syscall
amd64: clear callee-preserved registers on syscall exit
diff --git a/contrib/ntp/COPYRIGHT b/contrib/ntp/COPYRIGHT
index 935d574..f38933c 100644
--- a/contrib/ntp/COPYRIGHT
+++ b/contrib/ntp/COPYRIGHT
@@ -1,16 +1,15 @@
This file is automatically generated from html/copyright.html
-
Copyright Notice
-
+
jpg "Clone me," says Dolly sheepishly.
-
+
Last update: 2-Jan-2017 11:58 UTC
- _________________________________________________________________
-
- The following copyright notice applies to all files collectively
- called the Network Time Protocol Version 4 Distribution. Unless
- specifically declared otherwise in an individual file, this entire
- notice applies as if the text was explicitly included in the file.
+ __________________________________________________________________
+
+ The following copyright notice applies to all files collectively called
+ the Network Time Protocol Version 4 Distribution. Unless specifically
+ declared otherwise in an individual file, this entire notice applies as
+ if the text was explicitly included in the file.
***********************************************************************
* *
* Copyright (c) University of Delaware 1992-2015 *
@@ -62,13 +61,13 @@ This file is automatically generated from html/copyright.html
***********************************************************************
The following individuals contributed in part to the Network Time
- Protocol Distribution Version 4 and are acknowledged as authors of
- this work.
+ Protocol Distribution Version 4 and are acknowledged as authors of this
+ work.
1. [1]Takao Abe <takao_abe@xurb.jp> Clock driver for JJY receivers
2. [2]Mark Andrews <mark_andrews@isc.org> Leitch atomic clock
controller
- 3. [3]Bernd Altmeier <altmeier@atlsoft.de> hopf Elektronik serial
- line and PCI-bus devices
+ 3. [3]Bernd Altmeier <altmeier@atlsoft.de> hopf Elektronik serial line
+ and PCI-bus devices
4. [4]Viraj Bais <vbais@mailman1.intel.com> and [5]Clayton Kirkwood
<kirkwood@striderfm.intel.com> port to WindowsNT 3.5
5. [6]Michael Barone <michael,barone@lmco.com> GPSVME fixes
@@ -84,13 +83,12 @@ This file is automatically generated from html/copyright.html
<Jean-Francois.Boudreault@viagenie.qc.ca> IPv6 support
12. [13]Reg Clemens <reg@dwf.com> Oncore driver (Current maintainer)
13. [14]Steve Clift <clift@ml.csiro.au> OMEGA clock driver
- 14. [15]Casey Crellin <casey@csc.co.za> vxWorks (Tornado) port and
- help with target configuration
+ 14. [15]Casey Crellin <casey@csc.co.za> vxWorks (Tornado) port and help
+ with target configuration
15. [16]Sven Dietrich <sven_dietrich@trimble.com> Palisade reference
clock driver, NT adj. residuals, integrated Greg's Winnt port.
16. [17]John A. Dundas III <dundas@salt.jpl.nasa.gov> Apple A/UX port
- 17. [18]Torsten Duwe <duwe@immd4.informatik.uni-erlangen.de> Linux
- port
+ 17. [18]Torsten Duwe <duwe@immd4.informatik.uni-erlangen.de> Linux port
18. [19]Dennis Ferguson <dennis@mrbill.canet.ca> foundation code for
NTP Version 2 as specified in RFC-1119
19. [20]John Hay <jhay@icomtek.csir.co.za> IPv6 support and testing
@@ -122,9 +120,8 @@ This file is automatically generated from html/copyright.html
code for Version 3 as specified in RFC-1305
36. [39]Danny Mayer <mayer@ntp.org>Network I/O, Windows Port, Code
Maintenance
- 37. [40]David L. Mills <mills@udel.edu> Version 4 foundation,
- precision kernel; clock drivers: 1, 3, 4, 6, 7, 11, 13, 18, 19,
- 22, 36
+ 37. [40]David L. Mills <mills@udel.edu> Version 4 foundation, precision
+ kernel; clock drivers: 1, 3, 4, 6, 7, 11, 13, 18, 19, 22, 36
38. [41]Wolfgang Moeller <moeller@gwdgv1.dnet.gwdg.de> VMS port
39. [42]Jeffrey Mogul <mogul@pa.dec.com> ntptrace utility
40. [43]Tom Moore <tmoore@fievel.daytonoh.ncr.com> i386 svr4 port
@@ -136,22 +133,18 @@ This file is automatically generated from html/copyright.html
44. [48]Rainer Pruy <Rainer.Pruy@informatik.uni-erlangen.de>
monitoring/trap scripts, statistics file handling
45. [49]Dirce Richards <dirce@zk3.dec.com> Digital UNIX V4.0 port
- 46. [50]Wilfredo Sánchez <wsanchez@apple.com> added support for
- NetInfo
+ 46. [50]Wilfredo Sánchez <wsanchez@apple.com> added support for NetInfo
47. [51]Nick Sayer <mrapple@quack.kfu.com> SunOS streams modules
48. [52]Jack Sasportas <jack@innovativeinternet.com> Saved a Lot of
space on the stuff in the html/pic/ subdirectory
49. [53]Ray Schnitzler <schnitz@unipress.com> Unixware1 port
50. [54]Michael Shields <shields@tembel.org> USNO clock driver
- 51. [55]Jeff Steinman <jss@pebbles.jpl.nasa.gov> Datum PTS clock
- driver
+ 51. [55]Jeff Steinman <jss@pebbles.jpl.nasa.gov> Datum PTS clock driver
52. [56]Harlan Stenn <harlan@pfcs.com> GNU automake/autoconfigure
makeover, various other bits (see the ChangeLog)
53. [57]Kenneth Stone <ken@sdd.hp.com> HP-UX port
- 54. [58]Ajit Thyagarajan <ajit@ee.udel.edu>IP multicast/anycast
- support
- 55. [59]Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp>TRAK clock
- driver
+ 54. [58]Ajit Thyagarajan <ajit@ee.udel.edu>IP multicast/anycast support
+ 55. [59]Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp>TRAK clock driver
56. [60]Brian Utterback <brian.utterback@oracle.com> General codebase,
Solaris issues
57. [61]Loganaden Velvindron <loganaden@gmail.com> Sandboxing
@@ -160,7 +153,7 @@ This file is automatically generated from html/copyright.html
TrueTime clock driver
59. [63]Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> corrected and
validated HTML documents according to the HTML DTD
- _________________________________________________________________
+ __________________________________________________________________
References
diff --git a/contrib/ntp/ChangeLog b/contrib/ntp/ChangeLog
index b4ee424..9ff845c 100644
--- a/contrib/ntp/ChangeLog
+++ b/contrib/ntp/ChangeLog
@@ -1,4 +1,113 @@
---
+(4.2.8p13) 2019/03/07 Released by Harlan Stenn <stenn@ntp.org>
+
+* [Sec 3565] Crafted null dereference attack in authenticated
+ mode 6 packet <perlinger@ntp.org>
+ - reported by Magnus Stubman
+* [Bug 3560] Fix build when HAVE_DROPROOT is not defined <perlinger@ntp.org>
+ - applied patch by Ian Lepore
+* [Bug 3558] Crash and integer size bug <perlinger@ntp.org>
+ - isolate and fix linux/windows specific code issue
+* [Bug 3556] ntp_loopfilter.c snprintf compilation warnings <perlinger@ntp.org>
+ - provide better function for incremental string formatting
+* [Bug 3555] Tidy up print alignment of debug output from ntpdate <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3554] config revoke stores incorrect value <perlinger@ntp.org>
+ - original finding by Gerry Garvey, additional cleanup needed
+* [Bug 3549] Spurious initgroups() error message <perlinger@ntp.org>
+ - patch by Christous Zoulas
+* [Bug 3548] Signature not verified on windows system <perlinger@ntp.org>
+ - finding by Chen Jiabin, plus another one by me
+* [Bug 3541] patch to fix STA_NANO struct timex units <perlinger@ntp.org>
+ - applied patch by Maciej Szmigiero
+* [Bug 3540] Cannot set minsane to 0 anymore <perlinger@ntp.org>
+ - applied patch by Andre Charbonneau
+* [Bug 3539] work_fork build fails when droproot is not supported <perlinger@ntp.org>
+ - applied patch by Baruch Siach
+* [Bug 3538] Build fails for no-MMU targets <perlinger@ntp.org>
+ - applied patch by Baruch Siach
+* [Bug 3535] libparse won't handle GPS week rollover <perlinger@ntp.org>
+ - refactored handling of GPS era based on 'tos basedate' for
+ parse (TSIP) and JUPITER clocks
+* [Bug 3529] Build failures on Mac OS X 10.13 (High Sierra) <perlinger@ntp.org>
+ - patch by Daniel J. Luke; this does not fix a potential linker
+ regression issue on MacOS.
+* [Bug 3527 - Backward Incompatible] mode7 clockinfo fudgeval2 packet
+ anomaly <perlinger@ntp.org>, reported by GGarvey.
+ - --enable-bug3527-fix support by HStenn
+* [Bug 3526] Incorrect poll interval in packet <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3471] Check for openssl/[ch]mac.h. <perlinger@ntp.org>
+ - added missing check, reported by Reinhard Max <perlinger@ntp.org>
+* [Bug 1674] runtime crashes and sync problems affecting both x86 and x86_64
+ - this is a variant of [bug 3558] and should be fixed with it
+* Implement --disable-signalled-io
+
+---
+(4.2.8p12) 2018/08/14 Released by Harlan Stenn <stenn@ntp.org>
+
+* [Sec 3505] CVE-2018-12327 - Arbitrary Code Execution Vulnerability
+ - fixed stack buffer overflow in the openhost() command-line call
+ of NTPQ/NTPDC <perlinger@ntp.org>
+* [Sec 3012] noepeer tweaks. <stenn@ntp.org>
+* [Bug 3521] Fix a logic bug in the INVALIDNAK checks. <stenn@ntp.org>
+* [Bug 3509] Add support for running as non-root on FreeBSD, Darwin,
+ other TrustedBSD platforms
+ - applied patch by Ian Lepore <perlinger@ntp.org>
+* [Bug 3506] Service Control Manager interacts poorly with NTPD <perlinger@ntp.org>
+ - changed interaction with SCM to signal pending startup
+* [Bug 3486] Buffer overflow in ntpq/ntpq.c:tstflags() <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3485] Undefined sockaddr used in error messages in ntp_config.c <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3484] ntpq response from ntpd is incorrect when REFID is null <perlinger@ntp.org>
+ - rework of ntpq 'nextvar()' key/value parsing
+* [Bug 3482] Fixes for compilation warnings (ntp_io.c & ntpq-subs.c) <perlinger@ntp.org>
+ - applied patch by Gerry Garvey (with mods)
+* [Bug 3480] Refclock sample filter not cleared on clock STEP <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3479] ctl_putrefid() allows unsafe characters through to ntpq <perlinger@ntp.org>
+ - applied patch by Gerry Garvey (with mods)
+* [Bug 3476]ctl_putstr() sends empty unquoted string [...] <perlinger@ntp.org>
+ - applied patch by Gerry Garvey (with mods); not sure if that's bug or feature, though
+* [Bug 3475] modify prettydate() to suppress output of zero time <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3474] Missing pmode in mode7 peer info response <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3471] Check for openssl/[ch]mac.h. HStenn.
+ - add #define ENABLE_CMAC support in configure. HStenn.
+* [Bug 3470] ntpd4.2.8p11 fails to compile without OpenSSL <perlinger@ntp.org>
+* [Bug 3469] Incomplete string compare [...] in is_refclk_addr <perlinger@ntp.org>
+ - patch by Stephen Friedl
+* [Bug 3467] Potential memory fault in ntpq [...] <perlinger@ntp.org>
+ - fixed IO redirection and CTRL-C handling in ntq and ntpdc
+* [Bug 3465] Default TTL values cannot be used <perlinger@ntp.org>
+* [Bug 3461] refclock_shm.c: clear error status on clock recovery <perlinger@ntp.org>
+ - initial patch by Hal Murray; also fixed refclock_report() trouble
+* [Bug 3460] Fix typo in ntpq.texi, reported by Kenyon Ralph. <stenn@ntp.org>
+* [Bug 3456] Use uintptr_t rather than size_t to store an integer in a pointer
+ - According to Brooks Davis, there was only one location <perlinger@ntp.org>
+* [Bug 3449] ntpq - display "loop" instead of refid [...] <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3445] Symmetric peer won't sync on startup <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3442] Fixes for ntpdate as suggested by Gerry Garvey,
+ with modifications
+ New macro REFID_ISTEXT() which is also used in ntpd/ntp_control.c.
+* [Bug 3434] ntpd clears STA_UNSYNC on start <perlinger@ntp.org>
+ - applied patch by Miroslav Lichvar
+* [Bug 3426] ntpdate.html -t default is 2 seconds. Leonid Evdokimov.
+* [Bug 3121] Drop root privileges for the forked DNS worker <perlinger@ntp.org>
+ - integrated patch by Reinhard Max
+* [Bug 2821] minor build issues <perlinger@ntp.org>
+ - applied patches by Christos Zoulas, including real bug fixes
+* html/authopt.html: cleanup, from <stenn@ntp.org>
+* ntpd/ntpd.c: DROPROOT cleanup. <stenn@ntp.org>
+* Symmetric key range is 1-65535. Update docs. <stenn@ntp.org>
+* html/authentic.html: cleanup, from <stenn@ntp.org>
+
+---
+(4.2.8p11) 2018/02/27 Released by Harlan Stenn <stenn@ntp.org>
* [Sec 3454] Unauthenticated packet can reset authenticated interleave
associations. HStenn.
@@ -14,16 +123,16 @@
- applied patch by Sean Haugh
* [Bug 3452] PARSE driver prints uninitialized memory. <perlinger@ntp.org>
* [Bug 3450] Dubious error messages from plausibility checks in get_systime()
- - removed error log caused by rounding/slew, ensured postcondition <perlinger@ntp.org>
+ - removed error log caused by rounding/slew, ensured postcondition <perlinger@ntp.org>
* [Bug 3447] AES-128-CMAC (fixes) <perlinger@ntp.org>
- refactoring the MAC code, too
* [Bug 3441] Validate the assumption that AF_UNSPEC is 0. stenn@ntp.org
* [Bug 3439] When running multiple commands / hosts in ntpq... <perlinger@ntp.org>
- - applied patch by ggarvey
+ - applied patch by ggarvey
* [Bug 3438] Negative values and values > 999 days in... <perlinger@ntp.org>
- - applied patch by ggarvey (with minor mods)
+ - applied patch by ggarvey (with minor mods)
* [Bug 3437] ntpd tries to open socket with AF_UNSPEC domain
- - applied patch (with mods) by Miroslav Lichvar <perlinger@ntp.org>
+ - applied patch (with mods) by Miroslav Lichvar <perlinger@ntp.org>
* [Bug 3435] anchor NTP era alignment <perlinger@ntp.org>
* [Bug 3433] sntp crashes when run with -a. <stenn@ntp.org>
* [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
diff --git a/contrib/ntp/CommitLog b/contrib/ntp/CommitLog
index cd75940..8883b0c 100644
--- a/contrib/ntp/CommitLog
+++ b/contrib/ntp/CommitLog
@@ -1,363 +1,6898 @@
-ChangeSet@1.3729, 2017-02-01 07:39:35-05:00, stenn@deacon.udel.edu
+ChangeSet@1.3849, 2019-02-20 17:13:36-08:00, harlan@ntp-build.tal1.ntfo.org
+ Update NEWS file
+
+ NEWS@1.200 +3 -0
+ Update NEWS file
+
+ChangeSet@1.3848, 2019-02-20 09:44:58-08:00, harlan@ntp-build.tal1.ntfo.org
+ build system cleanups
+
+ build@1.50 +1 -1
+ build system cleanups
+
+ scripts/build/check--help@1.4 +2 -2
+ build system cleanups
+
+ sntp/libopts/autoopts/options.h@1.31 +1 -1
+ build system cleanups
+
+ sntp/libopts/genshell.h@1.31 +1 -1
+ build system cleanups
+
+ChangeSet@1.3847, 2019-02-18 22:26:26-08:00, harlan@ntp-build.tal1.ntfo.org
+ ChangeLog and NEWS description cleanups
+
+ ChangeLog@1.1971 +4 -4
+ ChangeLog and NEWS description cleanups
+
+ NEWS@1.199 +4 -2
+ ChangeLog and NEWS description cleanups
+
+ChangeSet@1.3844.1.4, 2019-02-18 20:10:25-08:00, harlan@ntp-build.tal1.ntfo.org
+ NEWS file update
+
+ NEWS@1.198 +49 -2
+ NEWS file update
+
+ChangeSet@1.3844.1.3, 2019-02-16 07:36:50+00:00, stenn@stenn.ntp.org
+ Improve messages around signalled IO handling in configure
+
+ sntp/m4/ntp_libntp.m4@1.38 +5 -0
+ Improve messages around signalled IO handling in configure
+
+ChangeSet@1.3844.1.2, 2019-02-15 13:27:05+00:00, stenn@stenn.ntp.org
+ Implement --disable-signalled-io
+
+ ChangeLog@1.1968.1.2 +1 -0
+ Implement --disable-signalled-io
+
+ sntp/m4/ntp_libntp.m4@1.37 +22 -2
+ Implement --disable-signalled-io
+
+ChangeSet@1.3844.1.1, 2019-01-17 04:16:52+00:00, stenn@psp-deb1.ntp.org
+ Cleanup
+
+ ChangeLog@1.1968.1.1 +0 -1
+ Cleanup
+
+ChangeSet@1.3845, 2019-01-16 21:42:59+01:00, perlinger@ntp.org
+ [Sec 3565] null pointer crash by remote attack
+
+ ChangeLog@1.1969 +3 -0
+ [Sec 3565] null pointer crash by remote attack
+
+ ntpd/ntp_control.c@1.233 +17 -9
+ [Sec 3565] null pointer crash by remote attack
+
+ChangeSet@1.3827.1.2, 2018-12-15 13:25:25+00:00, stenn@psp-deb1.ntp.org
+ bug3527 fixes
+
+ ChangeLog@1.1952.1.2 +3 -3
+ bug3527 fixes
+
+ configure.ac@1.614.1.1 +18 -0
+ bug3527 fixes
+
+ ntpd/ntp_request.c@1.129 +7 -4
+ bug3527 fixes
+
+ ntpdc/ntpdc_ops.c@1.85 +8 -3
+ bug3527 fixes
+
+ChangeSet@1.3827.15.1, 2018-12-12 07:37:12+01:00, perlinger@ntp.org
+ [Bug 3560] Fix build when HAVE_DROPROOT is not defined
+
+ ChangeLog@1.1952.15.1 +4 -0
+ [Bug 3560] Fix build when HAVE_DROPROOT is not defined
+
+ libntp/work_fork.c@1.20.2.1 +2 -0
+ [Bug 3560] Fix build when HAVE_DROPROOT is not defined
+
+ChangeSet@1.3827.14.1, 2018-12-11 07:42:01+01:00, perlinger@ntp.org
+ [Bug 3558] Crash and integer size bug
+ [Bug 1674] runtime crashes and sync problems affecting both x86 and x86_64
+ - isolate & fix LP64/LLP64 problem with BANCOMM SDK
+
+ ChangeLog@1.1952.14.1 +6 -0
+ [Bug 3558] Crash and integer size bug
+ [Bug 1674] runtime crashes and sync problems affecting both x86 and x86_64
+ - isolate & fix LP64/LLP64 problem with BANCOMM SDK
+
+ configure.ac@1.615 +1 -0
+ [Bug 3558] Crash and integer size bug
+ [Bug 1674] runtime crashes and sync problems affecting both x86 and x86_64
+ - search for BANCOMM SDK lib
+
+ ntpd/refclock_bancomm.c@1.17 +96 -23
+ [Bug 3558] Crash and integer size bug
+ [Bug 1674] runtime crashes and sync problems affecting both x86 and x86_64
+ - isolate & fix LP64/LLP64 problem with BANCOMM SDK
+
+ChangeSet@1.3827.11.2, 2018-12-05 06:58:13+01:00, perlinger@ntp.org
+ Bug 3556 - ntp_loopfilter.c snprintf compilation warnings
+ - stricter buffer range checks
+
+ libntp/xsbprintf.c@1.2 +11 -13
+ Bug 3556 - ntp_loopfilter.c snprintf compilation warnings
+ - stricter buffer range checks
+
+ tests/libntp/run-sbprintf.c@1.2 +8 -4
+ Bug 3556 - ntp_loopfilter.c snprintf compilation warnings
+ - stricter buffer range checks
+
+ tests/libntp/sbprintf.c@1.2 +28 -0
+ Bug 3556 - ntp_loopfilter.c snprintf compilation warnings
+ - stricter buffer range checks
+
+ChangeSet@1.3827.10.2, 2018-12-03 02:29:24-05:00, stenn@psp-fb1.ntp.org
+ Update Changelog for latest fix for 3471
+
+ ChangeLog@1.1952.10.2 +6 -1
+ Update Changelog for latest fix for 3471
+
+ChangeSet@1.3827.13.1, 2018-12-02 09:05:37+01:00, perlinger@ntp.org
+ [Bug 3555] Tidy up print alignment of debug output from ntpdate
+
+ ChangeLog@1.1952.13.1 +4 -0
+ [Bug 3555] Tidy up print alignment of debug output from ntpdate
+
+ ntpdate/ntpdate.c@1.102 +12 -9
+ [Bug 3555] Tidy up print alignment of debug output from ntpdate
+
+ChangeSet@1.3827.12.1, 2018-12-02 08:17:05+01:00, perlinger@ntp.org
+ [Bug 3554] config revoke stores incorrect value
+ - plus some additional cleanup
+
+ ChangeLog@1.1952.12.1 +4 -0
+ [Bug 3554] config revoke stores incorrect value
+
+ include/ntpd.h@1.204 +2 -2
+ [Bug 3554] config revoke stores incorrect value
+ - sys_{revoke,automax} hold positive log2 value -- unsigned char is enough.
+
+ ntpd/ntp_config.c@1.365.2.1 +12 -3
+ [Bug 3554] config revoke stores incorrect value
+ - sys_{revoke,automax} hold positive log2 value for shift; clamp values
+
+ ntpd/ntp_crypto.c@1.190.1.1 +2 -2
+ [Bug 3554] config revoke stores incorrect value
+ - avoid possible integer truncation
+
+ ntpd/ntp_timer.c@1.97 +4 -4
+ [Bug 3554] config revoke stores incorrect value
+ - sys_{revoke,automax} hold positive log2 value -- unsigned char is enough.
+ - avoid possible integer truncation
+
+ChangeSet@1.3827.11.1, 2018-12-01 12:10:51+01:00, perlinger@ntp.org
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - provide better function for incremental string formatting
+
+ ChangeLog@1.1952.11.1 +4 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - provide better function for incremental string formatting
+
+ include/ntp_stdlib.h@1.87 +3 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - provide better API for incremental string formatting
+
+ libntp/Makefile.am@1.82 +1 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add source of new API for incremental string formatting
+
+ libntp/xsbprintf.c@1.1 +77 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - implement new API for incremental string formatting
+
+ libntp/xsbprintf.c@1.0 +0 -0
+
+ ntpd/ntp_loopfilter.c@1.192 +18 -14
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - use new API for incremental string formatting
+
+ ports/winnt/vs2005/libntp.vcproj@1.27 +4 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add source of new API for incremental string formatting
+
+ ports/winnt/vs2008/libntp/libntp.vcproj@1.58 +4 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add source of new API for incremental string formatting
+
+ ports/winnt/vs2013/libntp/libntp.vcxproj@1.14 +3 -2
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add source of new API for incremental string formatting
+
+ ports/winnt/vs2013/libntp/libntp.vcxproj.filters@1.12 +5 -2
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add source of new API for incremental string formatting
+
+ ports/winnt/vs2015/libntp/libntp.vcxproj@1.4 +3 -2
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add source of new API for incremental string formatting
+
+ ports/winnt/vs2015/libntp/libntp.vcxproj.filters@1.4 +5 -2
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add source of new API for incremental string formatting
+
+ tests/libntp/Makefile.am@1.100 +12 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add string buffer formatting tests
+
+ tests/libntp/run-sbprintf.c@1.1 +72 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add string buffer formatting tests
+
+ tests/libntp/run-sbprintf.c@1.0 +0 -0
+
+ tests/libntp/sbprintf.c@1.1 +67 -0
+ [Bug 3556] ntp_loopfilter.c snprintf compilation warnings
+ - add string buffer formatting tests
+
+ tests/libntp/sbprintf.c@1.0 +0 -0
+
+ChangeSet@1.3827.10.1, 2018-11-30 06:34:35+01:00, perlinger@ntp.org
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - added missing check in code
+
+ ChangeLog@1.1952.10.1 +1 -0
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - added missing check in code
+
+ libntp/authreadkeys.c@1.33 +2 -0
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - added missing check in code
+
+ChangeSet@1.3827.9.1, 2018-11-11 12:03:14+01:00, perlinger@ntp.org
+ [Bug 3549] Spurious initgroups() error message
+
+ ChangeLog@1.1952.9.1 +4 -0
+ [Bug 3549] Spurious initgroups() error message
+
+ ntpd/ntpd.c@1.177.2.1 +33 -17
+ [Bug 3549] Spurious initgroups() error message
+ - make 'set_user_group_ids()' idempotent: If we're already there, don't complain.
+
+ChangeSet@1.3827.8.1, 2018-11-11 11:07:23+01:00, perlinger@ntp.org
+ [Bug 3548] Signature not verified on windows system
+
+ ChangeLog@1.1952.8.1 +4 -0
+ [Bug 3548] Signature not verified on windows system
+
+ ntpd/ntp_crypto.c@1.191 +2 -1
+ [Bug 3548] Signature not verified on windows system
+ - ntohl() can be a macro
+
+ sntp/networking.c@1.70 +2 -1
+ [Bug 3548] Signature not verified on windows system
+ - ntohl() can be a macro
+
+ChangeSet@1.3827.7.1, 2018-11-11 09:56:34+01:00, perlinger@ntp.org
+ [Bug 3541] patch to fix STA_NANO struct timex units
+
+ ChangeLog@1.1952.7.1 +4 -0
+ [Bug 3541] patch to fix STA_NANO struct timex units
+
+ ntpd/ntp_control.c@1.232 +9 -7
+ [Bug 3541] patch to fix STA_NANO struct timex units
+
+ ntpdc/ntpdc_ops.c@1.83.1.1 +7 -7
+ [Bug 3541] patch to fix STA_NANO struct timex units
+
+ util/ntptime.c@1.28 +0 -4
+ [Bug 3541] patch to fix STA_NANO struct timex units
+
+ChangeSet@1.3827.6.1, 2018-10-27 11:00:56+02:00, perlinger@ntp.org
+ [Bug 3540] Cannot set minsane to 0 anymore
+
+ ChangeLog@1.1952.6.1 +4 -0
+ [Bug 3540] Cannot set minsane to 0 anymore
+
+ ntpd/ntp_config.c@1.365.1.1 +2 -2
+ [Bug 3540] Cannot set minsane to 0 anymore
+
+ChangeSet@1.3827.5.1, 2018-10-27 10:33:55+02:00, perlinger@ntp.org
+ [Bug 3539] work_fork build fails when droproot is not supported
+
+ ChangeLog@1.1952.5.1 +4 -0
+ [Bug 3539] work_fork build fails when droproot is not supported
+
+ libntp/work_fork.c@1.20.1.1 +2 -0
+ [Bug 3539] work_fork build fails when droproot is not supported
+
+ChangeSet@1.3827.4.1, 2018-10-27 10:23:05+02:00, perlinger@ntp.org
+ [Bug 3538] Build fails for no-MMU targets
+
+ ChangeLog@1.1952.4.1 +4 -0
+ [Bug 3538] Build fails for no-MMU targets
+
+ ntpd/ntpd.c@1.177.1.1 +2 -0
+ [Bug 3538] Build fails for no-MMU targets
+
+ChangeSet@1.3827.3.1, 2018-10-13 08:03:48+02:00, perlinger@ntp.org
+ [Bug 3535] libparse won't handle GPS week rollover
+
+ ChangeLog@1.1952.3.1 +5 -0
+ [Bug 3535] libparse won't handle GPS week rollover
+
+ include/ntp_calendar.h@1.20 +21 -3
+ [Bug 3535] libparse won't handle GPS week rollover
+ - GPS week era support
+
+ include/parse.h@1.15 +0 -1
+ [Bug 3535] libparse won't handle GPS week rollover
+ - remove GPSWRAP definition to avoid lurking uses
+
+ libntp/calyearstart.c@1.7 +1 -1
+ [Bug 3535] libparse won't handle GPS week rollover
+
+ libntp/ntp_calendar.c@1.21 +38 -0
+ [Bug 3535] libparse won't handle GPS week rollover
+ - set GPS base week as first Sunday on or after base date
+
+ libparse/clk_trimtsip.c@1.15 +5 -9
+ [Bug 3535] libparse won't handle GPS week rollover
+ - use centralized week expansion code
+
+ libparse/gpstolfp.c@1.14 +0 -5
+ [Bug 3535] libparse won't handle GPS week rollover
+ - don't try to expand weeks in the conversion
+
+ ntpd/ntp_config.c@1.366 +4 -0
+ [Bug 3535] libparse won't handle GPS week rollover
+ - set basedate based on build stamp if not set explicitely
+
+ ntpd/refclock_jupiter.c@1.32 +1 -56
+ [Bug 3535] libparse won't handle GPS week rollover
+ - use centralized week expansion code instead of local copy
+
+ ntpd/refclock_parse.c@1.87 +1 -2
+ [Bug 3535] libparse won't handle GPS week rollover
+ - use centralized week expansion code
+
+ChangeSet@1.3827.2.1, 2018-10-02 18:03:33+02:00, perlinger@ntp.org
+ [Bug 3529] Build failures on Mac OS X 10.13 (High Sierra)
+
+ ChangeLog@1.1952.2.1 +5 -0
+ [Bug 3529] Build failures on Mac OS X 10.13 (High Sierra)
+
+ libntp/work_fork.c@1.21 +6 -3
+ [Bug 3529] Build failures on Mac OS X 10.13 (High Sierra)
+ - make existence of 'set_user_group_ids()' depend on HAVE_DROPROOT
+
+ChangeSet@1.3827.1.1, 2018-10-02 17:38:18+02:00, perlinger@ntp.org
+ [Bug 3527] fudgeval2 anomaly in mode7 clock info packet
+
+ ChangeLog@1.1952.1.1 +5 -0
+ [Bug 3527] fudgeval2 anomaly in mode7 clock info packet
+
+ ntpd/ntp_request.c@1.128 +5 -0
+ [Bug 3527] fudgeval2 anomaly in mode7 clock info packet
+
+ ntpdc/ntpdc_ops.c@1.84 +4 -0
+ [Bug 3527] fudgeval2 anomaly in mode7 clock info packet
+
+ChangeSet@1.3828, 2018-09-12 22:52:00+02:00, perlinger@ntp.org
+ [Bug 3526] Incorrect poll interval in packet
+
+ ChangeLog@1.1953 +4 -0
+ [Bug 3526] Incorrect poll interval in packet
+
+ ntpd/ntp_proto.c@1.423 +4 -4
+ [Bug 3526] Incorrect poll interval in packet
+
+ ntpd/ntpd.c@1.178 +4 -4
+ [Bug 3526] Incorrect poll interval in packet
+ (side kick: fix function prototypes. C is not C++.)
+
+ sntp/main.c@1.104 +2 -3
+ [Bug 3526] Incorrect poll interval in packet
+ (side kick: fix function prototypes. C is not C++.)
+
+ChangeSet@1.3827, 2018-08-14 08:31:08-04:00, stenn@deacon.udel.edu
+ NTP_4_2_8P12
+ TAG: NTP_4_2_8P12
+
+ ChangeLog@1.1952 +1 -0
+ NTP_4_2_8P12
+
+ ntpd/invoke-ntp.conf.texi@1.217 +1 -1
+ NTP_4_2_8P12
+
+ ntpd/invoke-ntp.keys.texi@1.202 +1 -1
+ NTP_4_2_8P12
+
+ ntpd/invoke-ntpd.texi@1.516 +2 -2
+ NTP_4_2_8P12
+
+ ntpd/ntp.conf.5man@1.251 +3 -3
+ NTP_4_2_8P12
+
+ ntpd/ntp.conf.5mdoc@1.251 +2 -2
+ NTP_4_2_8P12
+
+ ntpd/ntp.conf.html@1.200 +92 -105
+ NTP_4_2_8P12
+
+ ntpd/ntp.conf.man.in@1.251 +3 -3
+ NTP_4_2_8P12
+
+ ntpd/ntp.conf.mdoc.in@1.251 +2 -2
+ NTP_4_2_8P12
+
+ ntpd/ntp.keys.5man@1.236 +2 -2
+ NTP_4_2_8P12
+
+ ntpd/ntp.keys.5mdoc@1.236 +3 -3
+ NTP_4_2_8P12
+
+ ntpd/ntp.keys.html@1.199 +17 -29
+ NTP_4_2_8P12
+
+ ntpd/ntp.keys.man.in@1.236 +2 -2
+ NTP_4_2_8P12
+
+ ntpd/ntp.keys.mdoc.in@1.236 +3 -3
+ NTP_4_2_8P12
+
+ ntpd/ntpd-opts.c@1.538 +7 -7
+ NTP_4_2_8P12
+
+ ntpd/ntpd-opts.h@1.537 +3 -3
+ NTP_4_2_8P12
+
+ ntpd/ntpd.1ntpdman@1.345 +3 -3
+ NTP_4_2_8P12
+
+ ntpd/ntpd.1ntpdmdoc@1.345 +2 -2
+ NTP_4_2_8P12
+
+ ntpd/ntpd.html@1.191 +101 -145
+ NTP_4_2_8P12
+
+ ntpd/ntpd.man.in@1.345 +3 -3
+ NTP_4_2_8P12
+
+ ntpd/ntpd.mdoc.in@1.345 +2 -2
+ NTP_4_2_8P12
+
+ ntpdc/invoke-ntpdc.texi@1.513 +2 -2
+ NTP_4_2_8P12
+
+ ntpdc/ntpdc-opts.c@1.531 +7 -7
+ NTP_4_2_8P12
+
+ ntpdc/ntpdc-opts.h@1.530 +3 -3
+ NTP_4_2_8P12
+
+ ntpdc/ntpdc.1ntpdcman@1.344 +3 -3
+ NTP_4_2_8P12
+
+ ntpdc/ntpdc.1ntpdcmdoc@1.344 +2 -2
+ NTP_4_2_8P12
+
+ ntpdc/ntpdc.html@1.359 +57 -77
+ NTP_4_2_8P12
+
+ ntpdc/ntpdc.man.in@1.344 +3 -3
+ NTP_4_2_8P12
+
+ ntpdc/ntpdc.mdoc.in@1.344 +2 -2
+ NTP_4_2_8P12
+
+ ntpq/invoke-ntpq.texi@1.523 +2 -2
+ NTP_4_2_8P12
+
+ ntpq/ntpq-opts.c@1.540 +7 -7
+ NTP_4_2_8P12
+
+ ntpq/ntpq-opts.h@1.538 +3 -3
+ NTP_4_2_8P12
+
+ ntpq/ntpq.1ntpqman@1.351 +3 -3
+ NTP_4_2_8P12
+
+ ntpq/ntpq.1ntpqmdoc@1.351 +2 -2
+ NTP_4_2_8P12
+
+ ntpq/ntpq.html@1.190 +105 -129
+ NTP_4_2_8P12
+
+ ntpq/ntpq.man.in@1.351 +3 -3
+ NTP_4_2_8P12
+
+ ntpq/ntpq.mdoc.in@1.351 +2 -2
+ NTP_4_2_8P12
+
+ ntpsnmpd/invoke-ntpsnmpd.texi@1.515 +1 -1
+ NTP_4_2_8P12
+
+ ntpsnmpd/ntpsnmpd-opts.c@1.533 +7 -7
+ NTP_4_2_8P12
+
+ ntpsnmpd/ntpsnmpd-opts.h@1.532 +3 -3
+ NTP_4_2_8P12
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.344 +3 -3
+ NTP_4_2_8P12
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.344 +2 -2
+ NTP_4_2_8P12
+
+ ntpsnmpd/ntpsnmpd.html@1.185 +10 -14
+ NTP_4_2_8P12
+
+ ntpsnmpd/ntpsnmpd.man.in@1.344 +3 -3
+ NTP_4_2_8P12
+
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.344 +2 -2
+ NTP_4_2_8P12
+
+ packageinfo.sh@1.542 +2 -2
+ NTP_4_2_8P12
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.105 +3 -3
+ NTP_4_2_8P12
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.106 +2 -2
+ NTP_4_2_8P12
+
+ scripts/calc_tickadj/calc_tickadj.html@1.106 +1 -1
+ NTP_4_2_8P12
+
+ scripts/calc_tickadj/calc_tickadj.man.in@1.104 +3 -3
+ NTP_4_2_8P12
+
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.106 +2 -2
+ NTP_4_2_8P12
+
+ scripts/calc_tickadj/invoke-calc_tickadj.texi@1.109 +1 -1
+ NTP_4_2_8P12
+
+ scripts/invoke-plot_summary.texi@1.127 +2 -2
+ NTP_4_2_8P12
+
+ scripts/invoke-summary.texi@1.126 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.336 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntp-wait/ntp-wait-opts@1.72 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.333 +3 -3
+ NTP_4_2_8P12
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.334 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntp-wait/ntp-wait.html@1.355 +31 -49
+ NTP_4_2_8P12
+
+ scripts/ntp-wait/ntp-wait.man.in@1.333 +3 -3
+ NTP_4_2_8P12
+
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.334 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.124 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntpsweep/ntpsweep-opts@1.74 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.112 +3 -3
+ NTP_4_2_8P12
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.112 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntpsweep/ntpsweep.html@1.127 +33 -44
+ NTP_4_2_8P12
+
+ scripts/ntpsweep/ntpsweep.man.in@1.112 +3 -3
+ NTP_4_2_8P12
+
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.113 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntptrace/invoke-ntptrace.texi@1.125 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntptrace/ntptrace-opts@1.74 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntptrace/ntptrace.1ntptraceman@1.112 +3 -3
+ NTP_4_2_8P12
+
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.113 +2 -2
+ NTP_4_2_8P12
+
+ scripts/ntptrace/ntptrace.html@1.128 +27 -36
+ NTP_4_2_8P12
+
+ scripts/ntptrace/ntptrace.man.in@1.112 +3 -3
+ NTP_4_2_8P12
+
+ scripts/ntptrace/ntptrace.mdoc.in@1.114 +2 -2
+ NTP_4_2_8P12
+
+ scripts/plot_summary-opts@1.75 +2 -2
+ NTP_4_2_8P12
+
+ scripts/plot_summary.1plot_summaryman@1.125 +3 -3
+ NTP_4_2_8P12
+
+ scripts/plot_summary.1plot_summarymdoc@1.125 +2 -2
+ NTP_4_2_8P12
+
+ scripts/plot_summary.html@1.130 +29 -47
+ NTP_4_2_8P12
+
+ scripts/plot_summary.man.in@1.125 +3 -3
+ NTP_4_2_8P12
+
+ scripts/plot_summary.mdoc.in@1.125 +2 -2
+ NTP_4_2_8P12
+
+ scripts/summary-opts@1.74 +2 -2
+ NTP_4_2_8P12
+
+ scripts/summary.1summaryman@1.124 +3 -3
+ NTP_4_2_8P12
+
+ scripts/summary.1summarymdoc@1.124 +2 -2
+ NTP_4_2_8P12
+
+ scripts/summary.html@1.129 +27 -39
+ NTP_4_2_8P12
+
+ scripts/summary.man.in@1.124 +3 -3
+ NTP_4_2_8P12
+
+ scripts/summary.mdoc.in@1.124 +2 -2
+ NTP_4_2_8P12
+
+ scripts/update-leap/invoke-update-leap.texi@1.25 +1 -1
+ NTP_4_2_8P12
+
+ scripts/update-leap/update-leap-opts@1.25 +2 -2
+ NTP_4_2_8P12
+
+ scripts/update-leap/update-leap.1update-leapman@1.25 +3 -3
+ NTP_4_2_8P12
+
+ scripts/update-leap/update-leap.1update-leapmdoc@1.25 +2 -2
+ NTP_4_2_8P12
+
+ scripts/update-leap/update-leap.html@1.27 +35 -59
+ NTP_4_2_8P12
+
+ scripts/update-leap/update-leap.man.in@1.25 +3 -3
+ NTP_4_2_8P12
+
+ scripts/update-leap/update-leap.mdoc.in@1.25 +2 -2
+ NTP_4_2_8P12
+
+ sntp/invoke-sntp.texi@1.515 +23 -27
+ NTP_4_2_8P12
+
+ sntp/sntp-opts.c@1.534 +7 -7
+ NTP_4_2_8P12
+
+ sntp/sntp-opts.h@1.532 +3 -3
+ NTP_4_2_8P12
+
+ sntp/sntp.1sntpman@1.350 +3 -3
+ NTP_4_2_8P12
+
+ sntp/sntp.1sntpmdoc@1.350 +2 -2
+ NTP_4_2_8P12
+
+ sntp/sntp.html@1.531 +106 -134
+ NTP_4_2_8P12
+
+ sntp/sntp.man.in@1.350 +3 -3
+ NTP_4_2_8P12
+
+ sntp/sntp.mdoc.in@1.350 +2 -2
+ NTP_4_2_8P12
+
+ util/invoke-ntp-keygen.texi@1.518 +2 -2
+ NTP_4_2_8P12
+
+ util/ntp-keygen-opts.c@1.536 +7 -7
+ NTP_4_2_8P12
+
+ util/ntp-keygen-opts.h@1.534 +3 -3
+ NTP_4_2_8P12
+
+ util/ntp-keygen.1ntp-keygenman@1.346 +3 -3
+ NTP_4_2_8P12
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.346 +2 -2
+ NTP_4_2_8P12
+
+ util/ntp-keygen.html@1.191 +148 -206
+ NTP_4_2_8P12
+
+ util/ntp-keygen.man.in@1.346 +3 -3
+ NTP_4_2_8P12
+
+ util/ntp-keygen.mdoc.in@1.346 +2 -2
+ NTP_4_2_8P12
+
+ChangeSet@1.3826, 2018-08-14 07:16:23-04:00, stenn@deacon.udel.edu
+ Trigger the release of ntp-4.2.8p12
+
+ packageinfo.sh@1.541 +1 -1
+ Trigger the release of ntp-4.2.8p12
+
+ChangeSet@1.3825, 2018-08-13 04:31:37+00:00, stenn@psp-deb1.ntp.org
+ NEWS update
+
+ NEWS@1.197 +1 -1
+ NEWS update
+
+ChangeSet@1.3812.1.10, 2018-08-04 10:31:58+00:00, stenn@psp-deb1.ntp.org
+ [Bug 3521] Fix a logic bug in the INVALIDNAK checks
+
+ ChangeLog@1.1942.1.9 +1 -0
+ [Bug 3521] Fix a logic bug in the INVALIDNAK checks
+
+ NEWS@1.192.1.2 +1 -0
+ [Bug 3521] Fix a logic bug in the INVALIDNAK checks
+
+ ntpd/ntp_proto.c@1.422 +46 -35
+ [Bug 3521] Fix a logic bug in the INVALIDNAK checks
+
+ChangeSet@1.3823, 2018-07-28 05:03:57+00:00, stenn@psp-deb1.ntp.org
+ 3505 description updates
+
+ ChangeLog@1.1950 +2 -1
+ 3505 description updates
+
+ NEWS@1.195 +2 -2
+ 3505 description updates
+
+ChangeSet@1.3812.1.9, 2018-07-25 09:56:39+00:00, stenn@psp-deb1.ntp.org
+ updates
+
+ ChangeLog@1.1942.1.8 +1 -0
+ updates
+
+ NEWS@1.192.1.1 +2 -2
+ updates
+
+ html/authentic.html@1.18 +219 -87
+ updates
+
+ChangeSet@1.3821, 2018-07-25 07:41:01+00:00, stenn@psp-deb1.ntp.org
+ updates
+
+ ntpd/ntp.conf.html@1.199 +104 -91
+ updates
+
+ ntpd/ntp.keys.html@1.198 +28 -16
+ updates
+
+ ntpd/ntpd.html@1.190 +145 -101
+ updates
+
+ ntpdc/ntpdc.html@1.358 +75 -55
+ updates
+
+ ntpsnmpd/ntpsnmpd.html@1.184 +13 -9
+ updates
+
+ scripts/ntp-wait/ntp-wait.html@1.354 +47 -29
+ updates
+
+ scripts/ntpsweep/ntpsweep.html@1.126 +42 -31
+ updates
+
+ scripts/ntptrace/ntptrace.html@1.127 +34 -25
+ updates
+
+ scripts/plot_summary.html@1.129 +45 -27
+ updates
+
+ scripts/summary.html@1.128 +37 -25
+ updates
+
+ scripts/update-leap/update-leap.html@1.26 +132 -34
+ updates
+
+ sntp/sntp.html@1.530 +107 -83
+ updates
+
+ChangeSet@1.3820, 2018-07-25 07:38:42+00:00, stenn@psp-deb1.ntp.org
+ Bug 3509 tweaks
+
+ NEWS@1.193 +6 -1
+ Bug 3509 tweaks
+
+ sntp/m4/ntp_libntp.m4@1.36 +1 -1
+ Bug 3509 tweaks
+
+ChangeSet@1.3816.1.1, 2018-07-25 07:08:13+02:00, perlinger@ntp.org
+ [Bug 3509] Add support for running as non-root on FreeBSD, Darwin, other TrustedBSD platforms
+
+ ChangeLog@1.1946.1.1 +3 -0
+ [Bug 3509] Add support for running as non-root on FreeBSD, Darwin, other TrustedBSD platforms
+
+ ntpd/ntpd.c@1.177 +20 -2
+ [Bug 3509] Add support for running as non-root on FreeBSD, Darwin, other TrustedBSD platforms
+
+ sntp/m4/ntp_libntp.m4@1.35 +22 -1
+ [Bug 3509] Add support for running as non-root on FreeBSD, Darwin, other TrustedBSD platforms
+
+ChangeSet@1.3812.1.8, 2018-07-24 09:16:25+00:00, stenn@psp-deb1.ntp.org
+ Symmetric key range is 1-65535. Update docs.
+
+ html/authentic.html@1.17 +3 -3
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/invoke-ntp.conf.texi@1.216 +5 -5
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.5man@1.250 +5 -5
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.5mdoc@1.250 +5 -5
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.def@1.33 +4 -4
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.html@1.198 +4 -4
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.man.in@1.250 +5 -5
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.mdoc.in@1.250 +5 -5
+ Symmetric key range is 1-65535. Update docs.
+
+ChangeSet@1.3812.1.7, 2018-07-24 07:38:08+00:00, stenn@psp-deb1.ntp.org
+ Symmetric key range is 1-65535. Update docs.
+
+ ChangeLog@1.1942.1.7 +1 -0
+ Symmetric key range is 1-65535. Update docs.
+
+ NEWS@1.192 +66 -1
+ Symmetric key range is 1-65535. Update docs.
+
+ html/authopt.html@1.76 +3 -3
+ Symmetric key range is 1-65535. Update docs.
+
+ html/confopt.html@1.64 +2 -2
+ Symmetric key range is 1-65535. Update docs.
+
+ html/keygen.html@1.37 +2 -2
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/complete.conf.in@1.34 +1 -1
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/invoke-ntp.conf.texi@1.215 +2 -2
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/invoke-ntp.keys.texi@1.201 +3 -3
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.5man@1.249 +4 -4
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.5mdoc@1.249 +3 -3
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.def@1.32 +1 -1
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.html@1.197 +1 -1
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.man.in@1.249 +4 -4
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.conf.mdoc.in@1.249 +3 -3
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.keys.5man@1.235 +4 -4
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.keys.5mdoc@1.235 +5 -5
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.keys.def@1.13 +2 -2
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.keys.html@1.197 +2 -2
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.keys.man.in@1.235 +4 -4
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpd/ntp.keys.mdoc.in@1.235 +5 -5
+ Symmetric key range is 1-65535. Update docs.
+
+ ntpq/ntpq.html@1.189 +129 -105
+ Symmetric key range is 1-65535. Update docs.
+
+ util/invoke-ntp-keygen.texi@1.517 +21 -19
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen-opts.c@1.535 +1 -1
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen-opts.def@1.32 +1 -1
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen-opts.h@1.533 +1 -1
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen.1ntp-keygenman@1.345 +4 -4
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.345 +3 -3
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen.html@1.190 +208 -150
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen.man.in@1.345 +4 -4
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen.mdoc.in@1.345 +3 -3
+ Symmetric key range is 1-65535. Update docs.
+
+ util/ntp-keygen.texi@1.3 +1 -1
+ Symmetric key range is 1-65535. Update docs.
+
+ChangeSet@1.3812.1.6, 2018-07-21 07:59:28+00:00, stenn@psp-deb1.ntp.org
+ [Bug 3460] Fix typo in ntpq.texi, reported by Kenyon Ralph. <stenn@ntp.org>
+
+ ChangeLog@1.1942.1.6 +1 -0
+ [Bug 3460] Fix typo in ntpq.texi, reported by Kenyon Ralph. <stenn@ntp.org>
+
+ ntpq/ntpq.texi@1.6 +1 -1
+ [Bug 3460] Fix typo in ntpq.texi, reported by Kenyon Ralph. <stenn@ntp.org>
+
+ChangeSet@1.3812.1.5, 2018-07-21 04:25:55+00:00, stenn@psp-deb1.ntp.org
+ [Bug 3426] ntpdate.html -t default is 2 seconds. Leonid Evdokimov.
+
+ ChangeLog@1.1942.1.5 +2 -1
+ [Bug 3426] ntpdate.html -t default is 2 seconds. Leonid Evdokimov.
+
+ html/ntpdate.html@1.29 +2 -2
+ [Bug 3426] ntpdate.html -t default is 2 seconds. Leonid Evdokimov.
+
+ChangeSet@1.3812.1.3, 2018-07-20 08:57:05+00:00, stenn@psp-deb1.ntp.org
+ Tweak the description of bug 3506
+
+ ChangeLog@1.1942.1.3 +1 -1
+ Tweak the description of bug 3506
+
+ChangeSet@1.3812.1.1, 2018-07-03 22:51:08+02:00, perlinger@ntp.org
+ [Bug 3506] NTPD/SCM interact not well
+
+ ChangeLog@1.1942.1.1 +2 -0
+ [Bug 3506] NTPD/SCM interact not well
+
+ ntpd/ntpd.c@1.176 +14 -1
+ [Bug 3506] NTPD/SCM interact not well
+ - changed interaction with SCM to signal pending startup
+
+ ports/winnt/include/ntservice.h@1.5 +1 -0
+ [Bug 3506] NTPD/SCM interact not well
+ - changed interaction with SCM to signal pending startup
+
+ ports/winnt/ntpd/nt_clockstuff.c@1.67 +0 -6
+ [Bug 3506] NTPD/SCM interact not well
+ - changed interaction with SCM to signal pending startup
+
+ ports/winnt/ntpd/ntservice.c@1.32 +52 -17
+ [Bug 3506] NTPD/SCM interact not well
+ - changed interaction with SCM to signal pending startup
+
+ChangeSet@1.3813, 2018-07-03 18:46:27+02:00, perlinger@ntp.org
+ [Sec 3505] CVE-2018-12327 - Arbitrary Code Execution Vulnerability
+
+ ChangeLog@1.1943 +2 -0
+ [Sec 3505] CVE-2018-12327 - Arbitrary Code Execution Vulnerability
+
+ ntpdc/ntpdc.c@1.112 +11 -14
+ [Sec 3505] CVE-2018-12327 - Arbitrary Code Execution Vulnerability
+
+ ntpq/ntpq.c@1.188 +10 -13
+ [Sec 3505] CVE-2018-12327 - Arbitrary Code Execution Vulnerability
+
+ChangeSet@1.3790.6.3, 2018-06-19 13:00:54+02:00, burnicki@pc-martin4.py.meinberg.de
+ Fixes for ntpdate as discussed in bug #3442.
+
+ ChangeLog@1.1920.6.2 +2 -0
+ Fixes for ntpdate as discussed in bug #3442.
+
+ ntpdate/ntpdate.c@1.101 +96 -73
+ Fixes for ntpdate as discussed in bug #3442.
+
+ChangeSet@1.3790.6.2, 2018-06-19 12:30:58+02:00, burnicki@pc-martin4.py.meinberg.de
+ New macro REFID_IS_TEXT().
+
+ ChangeLog@1.1920.6.1 +3 -1
+ New macro REFID_IS_TEXT().
+
+ include/ntp.h@1.231 +12 -0
+ New macro REFID_IS_TEXT().
+
+ ntpd/ntp_control.c@1.226.1.2 +6 -7
+ Use new macro REFID_IS_TEXT().
+
+ChangeSet@1.3790.6.1, 2018-06-19 11:40:42+02:00, burnicki@pc-martin4.py.meinberg.de
+ Removed trailing spaces in some files.
+
+ ntpd/ntp_config.c@1.360.2.1 +9 -9
+ Removed trailing spaces.
+
+ ntpd/ntp_control.c@1.226.1.1 +26 -26
+ Removed trailing spaces.
+
+ ntpdate/ntpdate.c@1.100 +10 -10
+ Removed trailing spaces.
+
+ChangeSet@1.3812, 2018-06-16 02:42:06-07:00, harlan@max.pfcs.com
+ [Sec 3012] noepeer tweaks
+
+ ChangeLog@1.1942 +1 -0
+ [Sec 3012] noepeer tweaks
+
+ ntpd/ntp_proto.c@1.421 +45 -29
+ [Sec 3012] noepeer tweaks
+
+ChangeSet@1.3808.3.2, 2018-06-13 04:41:27+00:00, stenn@psp-deb1.ntp.org
+ ntpd/ntpd.c: DROPROOT cleanup
+
+ ChangeLog@1.1938.3.2 +1 -0
+ ntpd/ntpd.c: DROPROOT cleanup
+
+ ntpd/ntpd.c@1.175 +2 -0
+ ntpd/ntpd.c: DROPROOT cleanup
+
+ChangeSet@1.3808.3.1, 2018-06-13 04:38:41+00:00, stenn@psp-deb1.ntp.org
+ Cleanup html/authopt.html
+
+ ChangeLog@1.1938.3.1 +1 -0
+ Cleanup html/authopt.html
+
+ html/authopt.html@1.75 +23 -22
+ Cleanup html/authopt.html
+
+ChangeSet@1.3808.2.1, 2018-05-05 09:07:30+02:00, perlinger@ntp.org
+ [Bug 3484] ntpq response from ntpd is incorrect when REFID is null
+ - rework of ntpq 'nextvar()' key/value parsing
+
+ ChangeLog@1.1938.2.1 +1 -0
+ [Bug 3484] ntpq response from ntpd is incorrect when REFID is null
+ - rework of ntpq 'nextvar()' key/value parsing
+
+ ntpq/ntpq-subs.c@1.127 +12 -14
+ [Bug 3484] ntpq response from ntpd is incorrect when REFID is null
+ - rework of ntpq 'nextvar()' key/value parsing
+
+ ntpq/ntpq.c@1.186.1.1 +246 -78
+ [Bug 3484] ntpq response from ntpd is incorrect when REFID is null
+ - rework of ntpq 'nextvar()' key/value parsing
+
+ChangeSet@1.3808.1.1, 2018-04-21 11:48:47+02:00, perlinger@ntp.org
+ [Bug 3486] Buffer overflow in ntpq/ntpq.c:tstflags()
+
+ ChangeLog@1.1938.1.1 +2 -0
+ [Bug 3486] Buffer overflow in ntpq/ntpq.c:tstflags()
+
+ ntpq/ntpq.c@1.187 +39 -22
+ [Bug 3486] Buffer overflow in ntpq/ntpq.c:tstflags()
+
+ChangeSet@1.3809, 2018-04-21 11:30:19+02:00, perlinger@ntp.org
+ [Bug 3445] Symmetric peer won't sync on startup
+
+ ChangeLog@1.1939 +2 -0
+ [Bug 3445] Symmetric peer won't sync on startup
+
+ ntpd/ntp_proto.c@1.420 +8 -2
+ [Bug 3445] Symmetric peer won't sync on startup
+
+ChangeSet@1.3806.2.1, 2018-04-14 08:18:38+02:00, perlinger@ntp.org
+ [Bug 3121] Drop root privileges for the forked DNS worker
+
+ ChangeLog@1.1936.2.1 +2 -0
+ [Bug 3121] Drop root privileges for the forked DNS worker
+
+ libntp/work_fork.c@1.20 +4 -0
+ [Bug 3121] Drop root privileges for the forked DNS worker
+
+ ntpd/ntpd.c@1.174 +218 -145
+ [Bug 3121] Drop root privileges for the forked DNS worker
+
+ sntp/main.c@1.103 +7 -0
+ [Bug 3121] Drop root privileges for the forked DNS worker
+
+ChangeSet@1.3806.1.1, 2018-04-13 22:57:11+02:00, perlinger@ntp.org
+ [Bug 3434] ntpd clears STA_UNSYNC on start
+
+ ChangeLog@1.1936.1.1 +2 -0
+ [Bug 3434] ntpd clears STA_UNSYNC on start
+
+ ntpd/ntp_loopfilter.c@1.191 +8 -4
+ [Bug 3434] ntpd clears STA_UNSYNC on start
+
+ChangeSet@1.3807, 2018-04-13 22:38:02+02:00, perlinger@ntp.org
+ B[ug 3449] ntpq - display "loop" instead of refid for peers which are flagged as loops
+
+ ChangeLog@1.1937 +2 -0
+ B[ug 3449] ntpq - display "loop" instead of refid for peers which are flagged as loops
+
+ ntpq/ntpq-subs.c@1.126 +6 -1
+ B[ug 3449] ntpq - display "loop" instead of refid for peers which are flagged as loops
+
+ChangeSet@1.3806, 2018-04-11 19:26:04+02:00, perlinger@ntp.org
+ [Bug 3484] ntpq response from ntpd is incorrect when REFID is null
+
+ ChangeLog@1.1936 +1 -0
+ [Bug 3484] ntpq response from ntpd is incorrect when REFID is null
+
+ ntpd/ntp_control.c@1.230 +6 -6
+ [Bug 3484] ntpq response from ntpd is incorrect when REFID is null
+
+ChangeSet@1.3805, 2018-04-11 18:38:12+02:00, perlinger@ntp.org
+ [Bug 3475] modify prettydate() to suppress output of zero time
+
+ ChangeLog@1.1935 +2 -0
+ [Bug 3475] modify prettydate() to suppress output of zero time
+
+ libntp/prettydate.c@1.21 +5 -0
+ [Bug 3475] modify prettydate() to suppress output of zero time
+
+ChangeSet@1.3804, 2018-04-11 18:23:03+02:00, perlinger@ntp.org
+ [Bug 3482] Fixes for compilation warnings (ntp_io.c & ntpq-subs.c)
+
+ ChangeLog@1.1934 +2 -0
+ [Bug 3482] Fixes for compilation warnings (ntp_io.c & ntpq-subs.c)
+
+ ntpq/ntpq-subs.c@1.125 +15 -7
+ [Bug 3482] Fixes for compilation warnings (ntp_io.c & ntpq-subs.c)
+
+ChangeSet@1.3803, 2018-04-11 07:59:51+02:00, perlinger@ntp.org
+ [Bug 3485] Undefined sockaddr used in error messages in ntp_config.c
+
+ ChangeLog@1.1933 +2 -0
+ [Bug 3485] Undefined sockaddr used in error messages in ntp_config.c
+
+ ntpd/ntp_config.c@1.364 +3 -5
+ [Bug 3485] Undefined sockaddr used in error messages in ntp_config.c
+
+ChangeSet@1.3802, 2018-04-11 07:39:36+02:00, perlinger@ntp.org
+ [Bug 3476] ctl_putstr() sends empty unquoted string if data is Null / zero length
+
+ ChangeLog@1.1932 +2 -0
+ [Bug 3476] ctl_putstr() sends empty unquoted string if data is Null / zero length
+
+ ntpd/ntp_control.c@1.229 +3 -1
+ [Bug 3476] ctl_putstr() sends empty unquoted string if data is Null / zero length
+
+ChangeSet@1.3801, 2018-04-11 06:47:08+02:00, perlinger@ntp.org
+ [Bug 3469] Incomplete string compare [...] in is_refclk_addr
+
+ ChangeLog@1.1931 +2 -0
+ [Bug 3469] Incomplete string compare [...] in is_refclk_addr
+
+ ntpd/ntp_config.c@1.363 +1 -1
+ [Bug 3469] Incomplete string compare [...] in is_refclk_addr
+
+ChangeSet@1.3800, 2018-04-10 08:19:44+02:00, perlinger@ntp.org
+ [Bug 3474] Missing pmode in mode7 peer info response
+
+ ChangeLog@1.1930 +2 -0
+ [Bug 3474] Missing pmode in mode7 peer info response
+
+ ntpd/ntp_request.c@1.127 +1 -0
+ [Bug 3474] Missing pmode in mode7 peer info response
+
+ChangeSet@1.3799, 2018-04-10 08:10:56+02:00, perlinger@ntp.org
+ [Bug 3479] ctl_putrefid() allows unsafe characters through to ntpq
+
+ ChangeLog@1.1929 +2 -0
+ [Bug 3479] ctl_putrefid() allows unsafe characters through to ntpq
+
+ ntpd/ntp_control.c@1.228 +3 -1
+ [Bug 3479] ctl_putrefid() allows unsafe characters through to ntpq
+
+ChangeSet@1.3798, 2018-04-10 08:09:59+02:00, perlinger@ntp.org
+ [Bug 3480] Refclock sample filter not cleared on clock STEP
+
+ ChangeLog@1.1928 +2 -0
+ [Bug 3480] Refclock sample filter not cleared on clock STEP
+
+ ntpd/ntp_proto.c@1.419 +4 -0
+ [Bug 3480] Refclock sample filter not cleared on clock STEP
+
+ChangeSet@1.3797, 2018-04-08 12:17:35+02:00, perlinger@ntp.org
+ [Bug 3461] refclock_shm.c: clear error status on clock recovery
+
+ ChangeLog@1.1927 +2 -0
+ [Bug 3461] refclock_shm.c: clear error status on clock recovery
+
+ ntpd/ntp_io.c@1.429 +1 -1
+ [Bug 3461] refclock_shm.c: clear error status on clock recovery
+ - fixed minor (non-functional) regression
+
+ ntpd/ntp_refclock.c@1.127 +1 -1
+ [Bug 3461] refclock_shm.c: clear error status on clock recovery
+ - dont't step 'lastevent' if NOMINAL
+
+ ntpd/refclock_shm.c@1.40 +1 -0
+ [Bug 3461] refclock_shm.c: clear error status on clock recovery
+
+ChangeSet@1.3794.1.1, 2018-04-08 09:13:33+00:00, stenn@psp-deb1.ntp.org
+ cleanup ChangeLog
+
+ ChangeLog@1.1924.1.1 +2 -4
+ cleanup
+
+ChangeSet@1.3795, 2018-04-08 11:07:13+02:00, perlinger@ntp.org
+ [Bug 3467] Potential memory fault in ntpq [...]
+
+ ChangeLog@1.1925 +4 -4
+ [Bug 3467] Potential memory fault in ntpq [...]
+
+ configure.ac@1.614 +4 -0
+ [Bug 3467] Potential memory fault in ntpq [...]
+ - check for presence of sigsetjmp/siglongjmp in setjmp.h
+
+ libntp/syssignal.c@1.16 +4 -3
+ [Bug 3467] Potential memory fault in ntpq [...]
+ - installing and removing CTRL-C handlers is sequence order sensitive
+
+ ntpd/ntp_parser.c@1.113 +339 -338
+ [Bug 3467] Potential memory fault in ntpq [...]
+ - sidekick: add missing header decl
+
+ ntpd/ntp_parser.h@1.75 +1 -1
+ [Bug 3467] Potential memory fault in ntpq [...]
+ - sidekick: add missing header decl
+
+ ntpd/ntp_parser.y@1.101 +1 -0
+ [Bug 3467] Potential memory fault in ntpq [...]
+ - sidekick: add missing header decl
+
+ ntpdc/ntpdc.c@1.111 +37 -16
+ [Bug 3467] Potential memory fault in ntpq [...]
+ - closed file handles become NULL, check bfore writing
+ - use 'sig{set,long}jmp()' instead of '{set,long}jmp()' when possible
+ - unclutter jumping out of signal handler
+
+ ntpq/ntpq-subs.c@1.124 +1 -1
+ [Bug 3467] Potential memory fault in ntpq [...]
+ - removed leading linefeed
+
+ ntpq/ntpq.c@1.186 +234 -211
+ [Bug 3467] Potential memory fault in ntpq [...]
+ - closed file handles become NULL, check bfore writing
+ - use 'sig{set,long}jmp()' instead of '{set,long}jmp()' when possible
+ - unclutter jumping out of signal handler
+
+ChangeSet@1.3790.5.2, 2018-04-07 09:39:54+00:00, stenn@psp-deb1.ntp.org
+ tweak the Changelog
+
+ ChangeLog@1.1920.5.2 +1 -0
+ tweak
+
+ChangeSet@1.3790.5.1, 2018-04-07 10:03:14+02:00, jnperlin@hydra.localnet
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ChangeLog@1.1920.5.1 +4 -0
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ libntp/ntp_calendar.c@1.20 +1 -1
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpd/ntp_config.c@1.360.1.1 +2 -2
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpd/ntp_control.c@1.227 +6 -6
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpd/ntp_io.c@1.428 +47 -6
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpd/rc_cmdlength.c@1.3 +2 -0
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpd/refclock_datum.c@1.24 +2 -1
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpd/refclock_gpsdjson.c@1.29 +2 -2
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpd/refclock_jupiter.c@1.31 +1 -2
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpd/refclock_true.c@1.26 +1 -1
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpdc/ntpdc.c@1.110 +1 -1
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpq/ntpq-subs.c@1.123 +1 -1
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ ntpq/ntpq.c@1.183.1.1 +5 -5
+ [Bug 2821] minor build issues
+ + bug fixes
+
+ChangeSet@1.3790.4.1, 2018-03-16 06:37:19+01:00, perlinger@ntp.org
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - cond-compile if CMAC not supported
+ - fix tests when CMAC not available
+ - add #define ENABLE_CMAC support in configure
+
+ ChangeLog@1.1920.4.1 +4 -0
+ [Bug 3471] Check for openssl/[ch]mac.h
+ ---
+ Bug 3471: add --enable-cmac support in configure
+ ---
+ Bug 3471: add #define ENABLE_CMAC support in configure
+
+ configure.ac@1.610.1.1 +11 -0
+ Bug 3471: add --enable-cmac support in configure
+ - add #define ENABLE_CMAC support in configure
+
+ include/ntp_md5.h@1.14 +6 -1
+ [Bug 3471] Check for openssl/[ch]mac.h
+ ---
+ cleanup
+
+ libntp/a_md5encrypt.c@1.49.1.1 +6 -9
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - cond-compile if CMAC not supported
+ ---
+ cleanup
+
+ libntp/ssl_init.c@1.30 +17 -10
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - cond-compile if CMAC not supported
+
+ ntpq/ntpq.c@1.184 +15 -12
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - cond-compile if CMAC not supported
+
+ sntp/crypto.c@1.38 +1 -8
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - cond-compile if CMAC not supported
+
+ sntp/m4/ntp_openssl.m4@1.29.1.1 +1 -0
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - header lookup
+
+ sntp/tests/crypto.c@1.16 +2 -2
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - fix tests when CMAC not available
+
+ sntp/tests/packetProcessing.c@1.17 +8 -0
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - fix tests when CMAC not available
+
+ tests/libntp/ssl_init.c@1.11 +4 -4
+ [Bug 3471] Check for openssl/[ch]mac.h
+ - fix tests when CMAC not available
+
+ChangeSet@1.3790.3.3, 2018-03-15 23:16:22+00:00, stenn@psp-deb1.ntp.org
+ Bug 3471: add #define ENABLE_CMAC support in configure
+
+ ChangeLog@1.1920.3.3 +1 -1
+ Bug 3471: add #define ENABLE_CMAC support in configure
+
+ configure.ac@1.612 +6 -13
+ Bug 3471: add #define ENABLE_CMAC support in configure
+
+ChangeSet@1.3790.3.2, 2018-03-15 07:55:58+00:00, stenn@psp-deb1.ntp.org
+ Bug 3471: add --enable-cmac support in configure
+
+ ChangeLog@1.1920.3.2 +1 -0
+ Bug 3471: add --enable-cmac support in configure
+
+ configure.ac@1.611 +18 -0
+ Bug 3471: add --enable-cmac support in configure
+
+ChangeSet@1.3790.3.1, 2018-03-15 06:55:28+00:00, stenn@psp-deb1.ntp.org
+ [Bug 3471] Check for openssl/[ch]mac.h
+
+ ChangeLog@1.1920.3.1 +3 -0
+ [Bug 3471] Check for openssl/[ch]mac.h
+
+ sntp/m4/ntp_openssl.m4@1.30 +1 -0
+ [Bug 3471] Check for openssl/[ch]mac.h
+
+ChangeSet@1.3790.2.1, 2018-03-12 16:36:51+01:00, perlinger@ntp.org
+ [Bug 3456] Use uintptr_t rather than size_t to store an integer in a pointer
+
+ ChangeLog@1.1920.2.1 +4 -0
+ [Bug 3456] Use uintptr_t rather than size_t to store an integer in a pointer
+
+ libntp/work_thread.c@1.23 +15 -2
+ [Bug 3456] Use uintptr_t rather than size_t to store an integer in a pointer
+ (sidekick: Check return value of write-to-pipe)
+
+ChangeSet@1.3790.1.1, 2018-03-12 08:28:18+01:00, perlinger@ntp.org
+ [Bug 3470] ntpd4.2.8p11 fails to compile without OpenSSL
+
+ ChangeLog@1.1920.1.1 +3 -0
+ [Bug 3470] ntpd4.2.8p11 fails to compile without OpenSSL
+
+ libntp/a_md5encrypt.c@1.50 +1 -1
+ [Bug 3470] ntpd4.2.8p11 fails to compile without OpenSSL
+
+ util/sht.c@1.6 +4 -4
+ [Bug 3470] ntpd4.2.8p11 fails to compile without OpenSSL
+
+ChangeSet@1.3791, 2018-03-08 18:59:17+01:00, perlinger@ntp.org
+ [Bug 3465] Default TTL values cannot be used
+
+ ChangeLog@1.1921 +3 -0
+ [Bug 3465] Default TTL values cannot be used
+
+ ntpd/ntp_config.c@1.361 +6 -1
+ [Bug 3465] Default TTL values cannot be used
+ - config_ttl(): update 'sys_ttlmax' only when there was a table update, too!
+
+ChangeSet@1.3790, 2018-02-27 18:21:17-05:00, stenn@deacon.udel.edu
+ NTP_4_2_8P11
+ TAG: NTP_4_2_8P11
+
+ ChangeLog@1.1920 +1 -0
+ NTP_4_2_8P11
+
+ ntpd/invoke-ntp.conf.texi@1.214 +1 -1
+ NTP_4_2_8P11
+
+ ntpd/invoke-ntp.keys.texi@1.200 +1 -1
+ NTP_4_2_8P11
+
+ ntpd/invoke-ntpd.texi@1.515 +2 -2
+ NTP_4_2_8P11
+
+ ntpd/ntp.conf.5man@1.248 +3 -3
+ NTP_4_2_8P11
+
+ ntpd/ntp.conf.5mdoc@1.248 +1 -1
+ NTP_4_2_8P11
+
+ ntpd/ntp.conf.html@1.196 +95 -108
+ NTP_4_2_8P11
+
+ ntpd/ntp.conf.man.in@1.248 +3 -3
+ NTP_4_2_8P11
+
+ ntpd/ntp.conf.mdoc.in@1.248 +1 -1
+ NTP_4_2_8P11
+
+ ntpd/ntp.keys.5man@1.234 +2 -2
+ NTP_4_2_8P11
+
+ ntpd/ntp.keys.5mdoc@1.234 +2 -2
+ NTP_4_2_8P11
+
+ ntpd/ntp.keys.html@1.196 +17 -29
+ NTP_4_2_8P11
+
+ ntpd/ntp.keys.man.in@1.234 +2 -2
+ NTP_4_2_8P11
+
+ ntpd/ntp.keys.mdoc.in@1.234 +2 -2
+ NTP_4_2_8P11
+
+ ntpd/ntpd-opts.c@1.537 +7 -7
+ NTP_4_2_8P11
+
+ ntpd/ntpd-opts.h@1.536 +3 -3
+ NTP_4_2_8P11
+
+ ntpd/ntpd.1ntpdman@1.344 +3 -3
+ NTP_4_2_8P11
+
+ ntpd/ntpd.1ntpdmdoc@1.344 +1 -1
+ NTP_4_2_8P11
+
+ ntpd/ntpd.html@1.189 +101 -145
+ NTP_4_2_8P11
+
+ ntpd/ntpd.man.in@1.344 +3 -3
+ NTP_4_2_8P11
+
+ ntpd/ntpd.mdoc.in@1.344 +1 -1
+ NTP_4_2_8P11
+
+ ntpdc/invoke-ntpdc.texi@1.512 +2 -2
+ NTP_4_2_8P11
+
+ ntpdc/ntpdc-opts.c@1.530 +7 -7
+ NTP_4_2_8P11
+
+ ntpdc/ntpdc-opts.h@1.529 +3 -3
+ NTP_4_2_8P11
+
+ ntpdc/ntpdc.1ntpdcman@1.343 +3 -3
+ NTP_4_2_8P11
+
+ ntpdc/ntpdc.1ntpdcmdoc@1.343 +1 -1
+ NTP_4_2_8P11
+
+ ntpdc/ntpdc.html@1.357 +57 -77
+ NTP_4_2_8P11
+
+ ntpdc/ntpdc.man.in@1.343 +3 -3
+ NTP_4_2_8P11
+
+ ntpdc/ntpdc.mdoc.in@1.343 +1 -1
+ NTP_4_2_8P11
+
+ ntpq/invoke-ntpq.texi@1.522 +2 -2
+ NTP_4_2_8P11
+
+ ntpq/ntpq-opts.c@1.539 +7 -7
+ NTP_4_2_8P11
+
+ ntpq/ntpq-opts.h@1.537 +3 -3
+ NTP_4_2_8P11
+
+ ntpq/ntpq.1ntpqman@1.350 +3 -3
+ NTP_4_2_8P11
+
+ ntpq/ntpq.1ntpqmdoc@1.350 +1 -1
+ NTP_4_2_8P11
+
+ ntpq/ntpq.html@1.188 +106 -130
+ NTP_4_2_8P11
+
+ ntpq/ntpq.man.in@1.350 +3 -3
+ NTP_4_2_8P11
+
+ ntpq/ntpq.mdoc.in@1.350 +1 -1
+ NTP_4_2_8P11
+
+ ntpsnmpd/invoke-ntpsnmpd.texi@1.514 +11 -10
+ NTP_4_2_8P11
+
+ ntpsnmpd/ntpsnmpd-opts.c@1.532 +7 -7
+ NTP_4_2_8P11
+
+ ntpsnmpd/ntpsnmpd-opts.h@1.531 +3 -3
+ NTP_4_2_8P11
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.343 +3 -3
+ NTP_4_2_8P11
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.343 +1 -1
+ NTP_4_2_8P11
+
+ ntpsnmpd/ntpsnmpd.html@1.183 +10 -14
+ NTP_4_2_8P11
+
+ ntpsnmpd/ntpsnmpd.man.in@1.343 +3 -3
+ NTP_4_2_8P11
+
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.343 +1 -1
+ NTP_4_2_8P11
+
+ packageinfo.sh@1.540 +2 -2
+ NTP_4_2_8P11
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.104 +3 -3
+ NTP_4_2_8P11
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.105 +1 -1
+ NTP_4_2_8P11
+
+ scripts/calc_tickadj/calc_tickadj.html@1.105 +22 -34
+ NTP_4_2_8P11
+
+ scripts/calc_tickadj/calc_tickadj.man.in@1.103 +3 -3
+ NTP_4_2_8P11
+
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.105 +1 -1
+ NTP_4_2_8P11
+
+ scripts/calc_tickadj/invoke-calc_tickadj.texi@1.108 +1 -1
+ NTP_4_2_8P11
+
+ scripts/invoke-plot_summary.texi@1.126 +2 -2
+ NTP_4_2_8P11
+
+ scripts/invoke-summary.texi@1.125 +2 -2
+ NTP_4_2_8P11
+
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.335 +2 -2
+ NTP_4_2_8P11
+
+ scripts/ntp-wait/ntp-wait-opts@1.71 +2 -2
+ NTP_4_2_8P11
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.332 +3 -3
+ NTP_4_2_8P11
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.333 +1 -1
+ NTP_4_2_8P11
+
+ scripts/ntp-wait/ntp-wait.html@1.353 +31 -49
+ NTP_4_2_8P11
+
+ scripts/ntp-wait/ntp-wait.man.in@1.332 +3 -3
+ NTP_4_2_8P11
+
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.333 +1 -1
+ NTP_4_2_8P11
+
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.123 +2 -2
+ NTP_4_2_8P11
+
+ scripts/ntpsweep/ntpsweep-opts@1.73 +2 -2
+ NTP_4_2_8P11
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.111 +3 -3
+ NTP_4_2_8P11
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.111 +1 -1
+ NTP_4_2_8P11
+
+ scripts/ntpsweep/ntpsweep.html@1.125 +33 -44
+ NTP_4_2_8P11
+
+ scripts/ntpsweep/ntpsweep.man.in@1.111 +3 -3
+ NTP_4_2_8P11
+
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.112 +1 -1
+ NTP_4_2_8P11
+
+ scripts/ntptrace/invoke-ntptrace.texi@1.124 +2 -2
+ NTP_4_2_8P11
+
+ scripts/ntptrace/ntptrace-opts@1.73 +2 -2
+ NTP_4_2_8P11
+
+ scripts/ntptrace/ntptrace.1ntptraceman@1.111 +3 -3
+ NTP_4_2_8P11
+
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.112 +1 -1
+ NTP_4_2_8P11
+
+ scripts/ntptrace/ntptrace.html@1.126 +27 -36
+ NTP_4_2_8P11
+
+ scripts/ntptrace/ntptrace.man.in@1.111 +3 -3
+ NTP_4_2_8P11
+
+ scripts/ntptrace/ntptrace.mdoc.in@1.113 +1 -1
+ NTP_4_2_8P11
+
+ scripts/plot_summary-opts@1.74 +2 -2
+ NTP_4_2_8P11
+
+ scripts/plot_summary.1plot_summaryman@1.124 +3 -3
+ NTP_4_2_8P11
+
+ scripts/plot_summary.1plot_summarymdoc@1.124 +1 -1
+ NTP_4_2_8P11
+
+ scripts/plot_summary.html@1.128 +29 -47
+ NTP_4_2_8P11
+
+ scripts/plot_summary.man.in@1.124 +3 -3
+ NTP_4_2_8P11
+
+ scripts/plot_summary.mdoc.in@1.124 +1 -1
+ NTP_4_2_8P11
+
+ scripts/summary-opts@1.73 +2 -2
+ NTP_4_2_8P11
+
+ scripts/summary.1summaryman@1.123 +3 -3
+ NTP_4_2_8P11
+
+ scripts/summary.1summarymdoc@1.123 +1 -1
+ NTP_4_2_8P11
+
+ scripts/summary.html@1.127 +27 -39
+ NTP_4_2_8P11
+
+ scripts/summary.man.in@1.123 +3 -3
+ NTP_4_2_8P11
+
+ scripts/summary.mdoc.in@1.123 +1 -1
+ NTP_4_2_8P11
+
+ scripts/update-leap/invoke-update-leap.texi@1.24 +75 -1
+ NTP_4_2_8P11
+
+ scripts/update-leap/update-leap-opts@1.24 +2 -2
+ NTP_4_2_8P11
+
+ scripts/update-leap/update-leap.1update-leapman@1.24 +3 -3
+ NTP_4_2_8P11
+
+ scripts/update-leap/update-leap.1update-leapmdoc@1.24 +1 -1
+ NTP_4_2_8P11
+
+ scripts/update-leap/update-leap.html@1.25 +35 -59
+ NTP_4_2_8P11
+
+ scripts/update-leap/update-leap.man.in@1.24 +3 -3
+ NTP_4_2_8P11
+
+ scripts/update-leap/update-leap.mdoc.in@1.24 +1 -1
+ NTP_4_2_8P11
+
+ sntp/invoke-sntp.texi@1.514 +27 -23
+ NTP_4_2_8P11
+
+ sntp/sntp-opts.c@1.533 +7 -7
+ NTP_4_2_8P11
+
+ sntp/sntp-opts.h@1.531 +3 -3
+ NTP_4_2_8P11
+
+ sntp/sntp.1sntpman@1.349 +3 -3
+ NTP_4_2_8P11
+
+ sntp/sntp.1sntpmdoc@1.349 +1 -1
+ NTP_4_2_8P11
+
+ sntp/sntp.html@1.529 +110 -130
+ NTP_4_2_8P11
+
+ sntp/sntp.man.in@1.349 +3 -3
+ NTP_4_2_8P11
+
+ sntp/sntp.mdoc.in@1.349 +1 -1
+ NTP_4_2_8P11
+
+ util/invoke-ntp-keygen.texi@1.516 +18 -20
+ NTP_4_2_8P11
+
+ util/ntp-keygen-opts.c@1.534 +7 -7
+ NTP_4_2_8P11
+
+ util/ntp-keygen-opts.h@1.532 +3 -3
+ NTP_4_2_8P11
+
+ util/ntp-keygen.1ntp-keygenman@1.344 +3 -3
+ NTP_4_2_8P11
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.344 +1 -1
+ NTP_4_2_8P11
+
+ util/ntp-keygen.html@1.189 +149 -207
+ NTP_4_2_8P11
+
+ util/ntp-keygen.man.in@1.344 +3 -3
+ NTP_4_2_8P11
+
+ util/ntp-keygen.mdoc.in@1.344 +1 -1
+ NTP_4_2_8P11
+
+ChangeSet@1.3789, 2018-02-27 16:55:23-05:00, stenn@deacon.udel.edu
+ update-leap: check for -h/--help early. HStenn
+
+ ChangeLog@1.1919 +1 -0
+ update-leap: check for -h/--help early. HStenn
+
+ scripts/update-leap/update-leap.in@1.6 +7 -7
+ update-leap: check for -h/--help early. HStenn
+
+ChangeSet@1.3788, 2018-02-27 09:58:39-05:00, stenn@deacon.udel.edu
+ Some tests need LIBM on some OSes
+
+ ChangeLog@1.1918 +1 -0
+ Some tests need LIBM on some OSes
+
+ tests/bug-2803/Makefile.am@1.19 +1 -0
+ Some tests need LIBM on some OSes
+
+ tests/sandbox/Makefile.am@1.13 +1 -0
+ Some tests need LIBM on some OSes
+
+ tests/sec-2853/Makefile.am@1.9 +1 -0
+ Some tests need LIBM on some OSes
+
+ChangeSet@1.3787, 2018-02-27 08:09:05-05:00, stenn@deacon.udel.edu
+ ntp-4.2.8p11 prep
+
+ NEWS@1.191 +1 -1
+ ntp-4.2.8p11 prep
+
+ packageinfo.sh@1.539 +1 -1
+ ntp-4.2.8p11 prep
+
+ChangeSet@1.3720.59.1, 2018-02-27 05:59:07-05:00, stenn@deacon.udel.edu
+ Tweaks to UpdatePoint
+
+ scripts/build/UpdatePoint@1.8 +21 -1
+ Tweaks to UpdatePoint
+
+ChangeSet@1.3785, 2018-02-27 07:54:59+00:00, stenn@psp-deb1.ntp.org
+ p11 prep
+
+ ntpd/invoke-ntp.conf.texi@1.213 +4 -4
+ p11 prep
+
+ ntpd/invoke-ntp.keys.texi@1.199 +1 -1
+ p11 prep
+
+ ntpd/invoke-ntpd.texi@1.514 +1 -1
+ p11 prep
+
+ ntpd/ntp.conf.5man@1.247 +5 -5
+ p11 prep
+
+ ntpd/ntp.conf.5mdoc@1.247 +5 -5
+ p11 prep
+
+ ntpd/ntp.conf.html@1.195 +193 -184
+ p11 prep
+
+ ntpd/ntp.conf.man.in@1.247 +5 -5
+ p11 prep
+
+ ntpd/ntp.conf.mdoc.in@1.247 +5 -5
+ p11 prep
+
+ ntpd/ntp.keys.5man@1.233 +2 -2
+ p11 prep
+
+ ntpd/ntp.keys.5mdoc@1.233 +2 -2
+ p11 prep
+
+ ntpd/ntp.keys.man.in@1.233 +2 -2
+ p11 prep
+
+ ntpd/ntp.keys.mdoc.in@1.233 +2 -2
+ p11 prep
+
+ ntpd/ntpd-opts.c@1.536 +1 -1
+ p11 prep
+
+ ntpd/ntpd-opts.h@1.535 +1 -1
+ p11 prep
+
+ ntpd/ntpd.1ntpdman@1.343 +2 -2
+ p11 prep
+
+ ntpd/ntpd.1ntpdmdoc@1.343 +2 -2
+ p11 prep
+
+ ntpd/ntpd.man.in@1.343 +2 -2
+ p11 prep
+
+ ntpd/ntpd.mdoc.in@1.343 +2 -2
+ p11 prep
+
+ ntpdc/invoke-ntpdc.texi@1.511 +1 -1
+ p11 prep
+
+ ntpdc/ntpdc-opts.c@1.529 +1 -1
+ p11 prep
+
+ ntpdc/ntpdc-opts.h@1.528 +1 -1
+ p11 prep
+
+ ntpdc/ntpdc.1ntpdcman@1.342 +2 -2
+ p11 prep
+
+ ntpdc/ntpdc.1ntpdcmdoc@1.342 +2 -2
+ p11 prep
+
+ ntpdc/ntpdc.man.in@1.342 +2 -2
+ p11 prep
+
+ ntpdc/ntpdc.mdoc.in@1.342 +2 -2
+ p11 prep
+
+ ntpq/invoke-ntpq.texi@1.521 +2 -2
+ p11 prep
+
+ ntpq/ntpq-opts.c@1.538 +7 -7
+ p11 prep
+
+ ntpq/ntpq-opts.h@1.536 +3 -3
+ p11 prep
+
+ ntpq/ntpq.1ntpqman@1.349 +2 -2
+ p11 prep
+
+ ntpq/ntpq.1ntpqmdoc@1.349 +2 -2
+ p11 prep
+
+ ntpq/ntpq.html@1.187 +4 -2
+ p11 prep
+
+ ntpq/ntpq.man.in@1.349 +2 -2
+ p11 prep
+
+ ntpq/ntpq.mdoc.in@1.349 +2 -2
+ p11 prep
+
+ ntpsnmpd/invoke-ntpsnmpd.texi@1.513 +2 -2
+ p11 prep
+
+ ntpsnmpd/ntpsnmpd-opts.c@1.531 +1 -1
+ p11 prep
+
+ ntpsnmpd/ntpsnmpd-opts.h@1.530 +1 -1
+ p11 prep
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.342 +2 -2
+ p11 prep
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.342 +2 -2
+ p11 prep
+
+ ntpsnmpd/ntpsnmpd.man.in@1.342 +2 -2
+ p11 prep
+
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.342 +2 -2
+ p11 prep
+
+ packageinfo.sh@1.538 +1 -1
+ p11 prep
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.103 +2 -2
+ p11 prep
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.104 +2 -2
+ p11 prep
+
+ scripts/calc_tickadj/calc_tickadj.man.in@1.102 +2 -2
+ p11 prep
+
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.104 +2 -2
+ p11 prep
+
+ scripts/calc_tickadj/invoke-calc_tickadj.texi@1.107 +1 -1
+ p11 prep
+
+ scripts/invoke-plot_summary.texi@1.125 +1 -1
+ p11 prep
+
+ scripts/invoke-summary.texi@1.124 +1 -1
+ p11 prep
+
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.334 +1 -1
+ p11 prep
+
+ scripts/ntp-wait/ntp-wait-opts@1.70 +1 -1
+ p11 prep
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.331 +2 -2
+ p11 prep
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.332 +2 -2
+ p11 prep
+
+ scripts/ntp-wait/ntp-wait.man.in@1.331 +2 -2
+ p11 prep
+
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.332 +2 -2
+ p11 prep
+
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.122 +1 -1
+ p11 prep
+
+ scripts/ntpsweep/ntpsweep-opts@1.72 +1 -1
+ p11 prep
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.110 +2 -2
+ p11 prep
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.110 +2 -2
+ p11 prep
+
+ scripts/ntpsweep/ntpsweep.man.in@1.110 +2 -2
+ p11 prep
+
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.111 +2 -2
+ p11 prep
+
+ scripts/ntptrace/invoke-ntptrace.texi@1.123 +1 -1
+ p11 prep
+
+ scripts/ntptrace/ntptrace-opts@1.72 +1 -1
+ p11 prep
+
+ scripts/ntptrace/ntptrace.1ntptraceman@1.110 +2 -2
+ p11 prep
+
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.111 +2 -2
+ p11 prep
+
+ scripts/ntptrace/ntptrace.man.in@1.110 +2 -2
+ p11 prep
+
+ scripts/ntptrace/ntptrace.mdoc.in@1.112 +2 -2
+ p11 prep
+
+ scripts/plot_summary-opts@1.73 +1 -1
+ p11 prep
+
+ scripts/plot_summary.1plot_summaryman@1.123 +2 -2
+ p11 prep
+
+ scripts/plot_summary.1plot_summarymdoc@1.123 +2 -2
+ p11 prep
+
+ scripts/plot_summary.man.in@1.123 +2 -2
+ p11 prep
+
+ scripts/plot_summary.mdoc.in@1.123 +2 -2
+ p11 prep
+
+ scripts/summary-opts@1.72 +1 -1
+ p11 prep
+
+ scripts/summary.1summaryman@1.122 +2 -2
+ p11 prep
+
+ scripts/summary.1summarymdoc@1.122 +2 -2
+ p11 prep
+
+ scripts/summary.man.in@1.122 +2 -2
+ p11 prep
+
+ scripts/summary.mdoc.in@1.122 +2 -2
+ p11 prep
+
+ scripts/update-leap/invoke-update-leap.texi@1.23 +1 -50
+ p11 prep
+
+ scripts/update-leap/update-leap-opts@1.23 +1 -1
+ p11 prep
+
+ scripts/update-leap/update-leap.1update-leapman@1.23 +2 -2
+ p11 prep
+
+ scripts/update-leap/update-leap.1update-leapmdoc@1.23 +2 -2
+ p11 prep
+
+ scripts/update-leap/update-leap.html@1.24 +1 -50
+ p11 prep
+
+ scripts/update-leap/update-leap.man.in@1.23 +2 -2
+ p11 prep
+
+ scripts/update-leap/update-leap.mdoc.in@1.23 +2 -2
+ p11 prep
+
+ sntp/invoke-sntp.texi@1.513 +1 -1
+ p11 prep
+
+ sntp/sntp-opts.c@1.532 +1 -1
+ p11 prep
+
+ sntp/sntp-opts.h@1.530 +1 -1
+ p11 prep
+
+ sntp/sntp.1sntpman@1.348 +2 -2
+ p11 prep
+
+ sntp/sntp.1sntpmdoc@1.348 +2 -2
+ p11 prep
+
+ sntp/sntp.man.in@1.348 +2 -2
+ p11 prep
+
+ sntp/sntp.mdoc.in@1.348 +2 -2
+ p11 prep
+
+ util/invoke-ntp-keygen.texi@1.515 +2 -2
+ p11 prep
+
+ util/ntp-keygen-opts.c@1.533 +174 -174
+ p11 prep
+
+ util/ntp-keygen-opts.h@1.531 +3 -3
+ p11 prep
+
+ util/ntp-keygen.1ntp-keygenman@1.343 +2 -2
+ p11 prep
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.343 +2 -2
+ p11 prep
+
+ util/ntp-keygen.man.in@1.343 +2 -2
+ p11 prep
+
+ util/ntp-keygen.mdoc.in@1.343 +2 -2
+ p11 prep
+
+ChangeSet@1.3784, 2018-02-24 06:46:21+00:00, stenn@psp-deb1.ntp.org
+ VU # update to NEWS file
+
+ NEWS@1.190 +5 -5
+ VU # update to NEWS file
+
+ChangeSet@1.3783, 2018-02-21 00:51:56+00:00, stenn@psp-deb1.ntp.org
+ Add CVEs for security bugs in p11
+
+ NEWS@1.189 +6 -5
+ Add CVEs for security bugs in p11
+
+ChangeSet@1.3782, 2018-02-16 02:47:21-08:00, harlan@mb6.tal1.ntfo.org
+ Update description of Bug 3454 in the NEWS file.
+
+ NEWS@1.188 +37 -1
+ Update description of Bug 3454 in the NEWS file.
+
+ChangeSet@1.3781, 2018-02-16 02:45:50-08:00, harlan@mb6.tal1.ntfo.org
+ ntp_proto.c:receive(): Fix typos in 2 diagnostic debug lines
+
+ ntpd/ntp_proto.c@1.418 +2 -2
+ ntp_proto.c:receive(): Fix typos in 2 diagnostic debug lines
+
+ChangeSet@1.3780, 2018-02-13 01:31:39+00:00, stenn@psp-deb1.ntp.org
+ NEWS file updates
+
+ NEWS@1.187 +256 -10
+ NEWS file updates
+
+ChangeSet@1.3779, 2018-02-11 11:02:07+00:00, stenn@psp-deb1.ntp.org
+ Use consistent 4th arg type for [gs]etsockopt
+
+ ChangeLog@1.1917 +1 -0
+ Use consistent 4th arg type for [gs]etsockopt
+
+ NEWS@1.186 +1 -1
+ Use consistent 4th arg type for [gs]etsockopt
+
+ packageinfo.sh@1.537 +1 -1
+ Use consistent 4th arg type for [gs]etsockopt
+
+ChangeSet@1.3777, 2018-02-11 11:47:25+01:00, perlinger@ntp.org
+ getsockopt: 4th argument should be (void*)
+
+ ntpd/refclock_gpsdjson.c@1.28 +1 -1
+ getsockopt: 4th argument should be (void*)
+
+ ports/winnt/ntpd/ntp_iocompletionport.c@1.80 +1 -1
+ getsockopt: 4th argument should be (void*)
+
+ChangeSet@1.3775.1.1, 2018-02-11 02:20:02-08:00, harlan@mb6.tal1.ntfo.org
+ Initialize ippeerlimit in restrict_def[46]. HStenn
+
+ ntpd/ntp_restrict.c@1.46 +6 -0
+ Initialize ippeerlimit in restrict_def[46]. HStenn
+
+ChangeSet@1.3776, 2018-02-11 09:26:47+01:00, perlinger@ntp.org
+ consistent casting of 'setsockopt' argument
+
+ ntpd/ntp_io.c@1.427 +20 -20
+ consistent casting of 'setsockopt' argument
+
+ ntpd/refclock_gpsdjson.c@1.27 +1 -1
+ consistent casting of 'setsockopt' argument
+
+ ntpdc/ntpdc.c@1.109 +2 -2
+ consistent casting of 'setsockopt' argument
+
+ ntpq/ntpq.c@1.183 +2 -2
+ consistent casting of 'setsockopt' argument
+
+ChangeSet@1.3772.1.1, 2018-02-09 16:05:30-08:00, harlan@mb6.tal1.ntfo.org
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ ChangeLog@1.1913.1.1 +2 -0
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ include/ntp.h@1.230 +12 -9
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ include/ntp_request.h@1.51 +1 -1
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ include/ntpd.h@1.203 +2 -1
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ ntpd/ntp_config.c@1.360 +72 -59
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ ntpd/ntp_control.c@1.224.1.1 +2 -1
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ ntpd/ntp_io.c@1.424.1.1 +2 -2
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ ntpd/ntp_peer.c@1.165 +6 -0
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ ntpd/ntp_request.c@1.126 +17 -5
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ ntpd/ntp_restrict.c@1.45 +134 -27
+ Rename restrict flags to rflags. Use an enum for their values. Provide dump_restricts().
+
+ ntpdc/layout.std@1.14 +1 -1
+ Rename restrict flags to rflags
+
+ ntpdc/ntpdc_ops.c@1.83 +3 -3
+ Rename restrict flags to rflags
+
+ tests/ntpd/ntp_restrict.c@1.7 +8 -8
+ Rename restrict flags to rflags
+
+ChangeSet@1.3773, 2018-02-07 08:14:35+01:00, perlinger@ntp.org
+ [Bug 3457] OpenSSL FIPS mode regression
+
+ ChangeLog@1.1914 +1 -0
+ [Bug 3457] OpenSSL FIPS mode regression
+
+ libntp/a_md5encrypt.c@1.49 +7 -4
+ [Bug 3457] OpenSSL FIPS mode regression
+
+ ntpd/ntp_control.c@1.225 +6 -0
+ [Bug 3457] OpenSSL FIPS mode regression
+
+ ntpd/ntp_crypto.c@1.190 +12 -0
+ [Bug 3457] OpenSSL FIPS mode regression
+
+ sntp/crypto.c@1.37 +14 -5
+ [Bug 3457] OpenSSL FIPS mode regression
+
+ChangeSet@1.3772, 2018-02-05 02:18:59-08:00, harlan@psp-at0.tal1.ntfo.org
+ libntp/ssl_init.h only needs MD5_LENGTH if we don't have OpenSSL
+
+ libntp/ssl_init.c@1.29 +2 -1
+ libntp/ssl_init.h only needs MD5_LENGTH if we don't have OpenSSL
+
+ChangeSet@1.3771, 2018-02-04 03:54:19-08:00, harlan@max.pfcs.com
+ [Sec 3453] Interleaved symmetric mode cannot recover from bad state
+
+ ChangeLog@1.1913 +1 -0
+ [Sec 3453] Interleaved symmetric mode cannot recover from bad state
+
+ ntpd/ntp_proto.c@1.417 +2 -0
+ [Sec 3453] Interleaved symmetric mode cannot recover from bad state
+
+ChangeSet@1.3768.2.2, 2018-02-03 01:35:05-08:00, harlan@psp-at0.tal1.ntfo.org
+ [Sec 3454] Unauthenticated packet can reset authenticated interleave associations
+
+ ChangeLog@1.1910.2.1 +2 -0
+ [Sec 3454] Unauthenticated packet can reset authenticated interleave associations
+
+ ntpd/ntp_proto.c@1.416 +142 -15
+ [Sec 3454] Unauthenticated packet can reset authenticated interleave associations
+
+ChangeSet@1.3768.2.1, 2018-02-03 01:22:07-08:00, harlan@psp-at0.tal1.ntfo.org
+ cleanup
+
+ ntpd/ntp.conf.def@1.31 +3 -3
+ cleanup
+
+ChangeSet@1.3768.1.2, 2018-02-02 07:37:12+01:00, perlinger@ntp.org
+ [Bug 3455] ntpd doesn't use scope id when binding multicast
+
+ ChangeLog@1.1910.1.1 +2 -0
+ [Bug 3455] ntpd doesn't use scope id when binding multicast
+
+ ntpd/ntp_io.c@1.425 +1 -0
+ [Bug 3455] ntpd doesn't use scope id when binding multicast
+
+ChangeSet@1.3768.1.1, 2018-01-26 16:58:55-08:00, harlan@psp-at0.tal1.ntfo.org
+ type
+
+ ntpd/ntp.conf.def@1.30 +1 -1
+ type
+
+ChangeSet@1.3769, 2018-01-26 17:12:19+01:00, perlinger@ntp.org
+ [Bug 3452] PARSE driver prints uninitialized memory
+
+ ChangeLog@1.1911 +1 -0
+ [Bug 3452] PARSE driver prints uninitialized memory
+
+ ntpd/refclock_parse.c@1.86 +10 -3
+ [Bug 3452] PARSE driver prints uninitialized memory
+ - avoid underflow in buffer length calculation
+
+ChangeSet@1.3768, 2018-01-25 22:47:05-08:00, harlan@psp-at0.tal1.ntfo.org
+ Properly set ippeerlimit in hack_restrict()
+
+ ntpd/ntp_restrict.c@1.44 +1 -0
+ Properly set ippeerlimit in hack_restrict()
+
+ChangeSet@1.3767, 2018-01-26 05:24:23+00:00, stenn@psp-deb1.ntp.org
+ Show ippeerlimit for the address of the incoming packet
+
+ ntpd/ntp_proto.c@1.415 +2 -2
+ Show ippeerlimit for the address of the incoming packet
+
+ChangeSet@1.3766, 2018-01-24 08:44:24+00:00, stenn@psp-deb1.ntp.org
+ Update ntpq peer documentation to describe the 'p' type
+
+ ChangeLog@1.1910 +1 -0
+ Update ntpq peer documentation to describe the 'p' type
+
+ NEWS@1.185 +1 -1
+ Update ntpq peer documentation to describe the 'p' type
+
+ html/ntpq.html@1.52 +11 -4
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/invoke-ntpq.texi@1.520 +4 -2
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/ntpq-opts.c@1.537 +7 -7
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/ntpq-opts.def@1.32 +2 -0
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/ntpq-opts.h@1.535 +3 -3
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/ntpq.1ntpqman@1.348 +4 -2
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/ntpq.1ntpqmdoc@1.348 +4 -2
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/ntpq.html@1.186 +1 -1
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/ntpq.man.in@1.348 +4 -2
+ Update ntpq peer documentation to describe the 'p' type
+
+ ntpq/ntpq.mdoc.in@1.348 +4 -2
+ Update ntpq peer documentation to describe the 'p' type
+
+ChangeSet@1.3765, 2018-01-24 07:51:14+00:00, stenn@psp-deb1.ntp.org
+ NEWS update
+
+ NEWS@1.184 +15 -16
+ NEWS update
+
+ChangeSet@1.3761.1.1, 2018-01-23 23:03:23-08:00, harlan@psp-at0.tal1.ntfo.org
+ Pass ippeerlimit to all newpeer() calls.
+
+ ntpd/ntp_proto.c@1.414 +14 -12
+ Pass ippeerlimit to all newpeer() calls.
+
+ChangeSet@1.3763, 2018-01-23 12:43:17+00:00, stenn@psp-deb1.ntp.org
+ Update NEWS file
+
+ NEWS@1.183 +39 -3
+ Update NEWS file
+
+ChangeSet@1.3762, 2018-01-22 12:35:36+00:00, stenn@psp-deb1.ntp.org
+ Update the documentation for ippeerlimit and noepeer
+
+ html/accopt.html@1.47 +139 -45
+ Update the documentation for ippeerlimit and noepeer
+
+ ntpd/invoke-ntp.conf.texi@1.212 +26 -18
+ Update the documentation for ippeerlimit and noepeer
+
+ ntpd/ntp.conf.5man@1.246 +28 -20
+ Update the documentation for ippeerlimit and noepeer
+
+ ntpd/ntp.conf.5mdoc@1.246 +30 -8
+ Update the documentation for ippeerlimit and noepeer
+
+ ntpd/ntp.conf.def@1.29 +28 -6
+ Update the documentation for ippeerlimit and noepeer
+
+ ntpd/ntp.conf.man.in@1.246 +28 -20
+ Update the documentation for ippeerlimit and noepeer
+
+ ntpd/ntp.conf.mdoc.in@1.246 +30 -8
+ Update the documentation for ippeerlimit and noepeer
+
+ tests/ntpd/run-ntp_restrict.c@1.8 +6 -6
+ Update the test runner for the updated restrictions() code
+
+ChangeSet@1.3761, 2018-01-22 02:55:41-08:00, harlan@psp-at0.tal1.ntfo.org
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ ChangeLog@1.1909 +1 -0
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ include/ntp.h@1.229 +6 -0
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ include/ntpd.h@1.202 +7 -7
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ ntpd/ntp_config.c@1.359 +7 -0
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ ntpd/ntp_peer.c@1.164 +15 -1
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ ntpd/ntp_proto.c@1.413 +18 -13
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ ntpd/ntp_request.c@1.125 +4 -1
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ ntpd/ntp_restrict.c@1.43 +16 -10
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ ntpd/ntpsim.c@1.33 +1 -0
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ tests/ntpd/ntp_restrict.c@1.6 +21 -8
+ restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit.
+
+ChangeSet@1.3760, 2018-01-21 12:45:31+00:00, stenn@psp-deb1.ntp.org
+ ntp.conf.def tweaks
+
+ ntpd/invoke-ntp.conf.texi@1.211 +6 -6
+ ntp.conf.def tweaks
+
+ ntpd/ntp.conf.5man@1.245 +3358 -6
+ ntp.conf.def tweaks
+
+ ntpd/ntp.conf.5mdoc@1.245 +3192 -6
+ ntp.conf.def tweaks
+
+ ntpd/ntp.conf.def@1.28 +5 -5
+ ntp.conf.def tweaks
+
+ ntpd/ntp.conf.html@1.194 +267 -68
+ ntp.conf.def tweaks
+
+ ntpd/ntp.conf.man.in@1.245 +3358 -6
+ ntp.conf.def tweaks
+
+ ntpd/ntp.conf.mdoc.in@1.245 +3192 -6
+ ntp.conf.def tweaks
+
+ ntpd/ntp.keys.html@1.195 +10 -2
+ ntp.conf.def tweaks
+
+ChangeSet@1.3759, 2018-01-21 03:34:08-08:00, harlan@psp-at0.tal1.ntfo.org
+ ntp_parser.y, ntp_parser.c, ChangeLog:
+ Warn the user if deprecated "driftfile name WanderThreshold" is used
+ Many files:
+ Update the documentation in ntp.conf.def
+
+ ChangeLog@1.1908 +1 -0
+ Update the documentation in ntp.conf.def
+
+ ChangeLog@1.1907 +1 -0
+ Warn the user if deprecated "driftfile name WanderThreshold" is used
+
+ ntpd/invoke-ntp.conf.texi@1.210 +238 -22
+ Update the documentation in ntp.conf.def
+
+ ntpd/ntp.conf.5man@1.244 +2 -2
+ Update the documentation in ntp.conf.def
+
+ ntpd/ntp.conf.5mdoc@1.244 +2 -2
+ Update the documentation in ntp.conf.def
+
+ ntpd/ntp.conf.def@1.27 +269 -27
+ Update the documentation in ntp.conf.def
+
+ ntpd/ntp.conf.man.in@1.244 +2 -2
+ Update the documentation in ntp.conf.def
+
+ ntpd/ntp.conf.mdoc.in@1.244 +2 -2
+ Update the documentation in ntp.conf.def
+
+ ntpd/ntp_parser.c@1.112 +107 -103
+ Warn the user if deprecated "driftfile name WanderThreshold" is used
+
+ ntpd/ntp_parser.y@1.100 +4 -0
+ Warn the user if deprecated "driftfile name WanderThreshold" is used
+
+ChangeSet@1.3758, 2018-01-20 20:45:47-08:00, harlan@psp-at1.tal1.ntfo.org
+ Decode interface flags on receive() debug output
+
+ ChangeLog@1.1906 +1 -0
+ Decode interface flags on receive() debug output
+
+ include/ntp.h@1.228 +2 -1
+ Decode interface flags on receive() debug output
+
+ ntpd/ntp_config.c@1.358 +92 -19
+ Decode interface flags on receive() debug output
+
+ ntpd/ntp_proto.c@1.412 +3 -2
+ Decode interface flags on receive() debug output
+
+ChangeSet@1.3757, 2018-01-20 03:41:34-08:00, harlan@psp-at1.tal1.ntfo.org
+ Decode restrict flags on receive() debug output
+
+ ChangeLog@1.1905 +1 -0
+ Decode restrict flags on receive() debug output
+
+ include/ntp.h@1.227 +3 -0
+ Decode restrict flags on receive() debug output
+
+ ntpd/ntp_config.c@1.357 +141 -4
+ Decode restrict flags on receive() debug output
+
+ ntpd/ntp_proto.c@1.411 +3 -2
+ Decode restrict flags on receive() debug output
+
+ChangeSet@1.3756, 2018-01-20 00:35:52-08:00, harlan@mb6.tal1.ntfo.org
+ typo
+
+ ntpd/ntp_config.c@1.356 +2 -2
+ typo
+
+ChangeSet@1.3755, 2018-01-20 00:33:06-08:00, harlan@mb6.tal1.ntfo.org
+ When dumping restrict nodes, use const char * for address and mask
+
+ ntpd/ntp_config.c@1.355 +5 -2
+ When dumping restrict nodes, use const char * for address and mask
+
+ChangeSet@1.3754, 2018-01-19 23:19:41-08:00, harlan@mb6.tal1.ntfo.org
+ Improve saveconfig output
+
+ ChangeLog@1.1904 +1 -0
+ Improve saveconfig output
+
+ ntpd/ntp_config.c@1.354 +33 -3
+ Improve saveconfig output
+
+ChangeSet@1.3753, 2018-01-17 22:12:36-08:00, harlan@psp-at0.tal1.ntfo.org
+ Rename the configuration flag fifo variables
+
+ ChangeLog@1.1903 +1 -0
+ Rename the configuration flag fifo variables
+
+ include/ntp_config.h@1.86 +1 -1
+ Rename the configuration flag fifo variables
+
+ ntpd/ntp_config.c@1.353 +21 -21
+ Rename the configuration flag fifo variables
+
+ChangeSet@1.3752, 2018-01-17 04:34:17-08:00, harlan@psp-at1.tal1.ntfo.org
+ Add DPRINTF(2,...) lines to receive() for packet drops
+
+ ChangeLog@1.1902 +1 -0
+ Add DPRINTF(2,...) lines to receive() for packet drops
+
+ ntpd/ntp_proto.c@1.410 +49 -1
+ Add DPRINTF(2,...) lines to receive() for packet drops
+
+ChangeSet@1.3751, 2018-01-16 20:06:43-08:00, harlan@psp-at1.tal1.ntfo.org
+ ippeerlimt: hook in ip_count support
+
+ include/ntpd.h@1.201 +1 -1
+ ippeerlimt: hook in ip_count support
+
+ ntpd/ntp_config.c@1.352 +2 -2
+ ippeerlimt: hook in ip_count support
+
+ ntpd/ntp_peer.c@1.163 +27 -12
+ ippeerlimt: hook in ip_count support
+
+ ntpd/ntp_proto.c@1.409 +6 -6
+ ippeerlimt: hook in ip_count support
+
+ ntpd/ntp_refclock.c@1.126 +2 -2
+ ippeerlimt: hook in ip_count support
+
+ ntpd/ntp_request.c@1.124 +9 -9
+ ippeerlimt: hook in ip_count support
+
+ChangeSet@1.3750, 2018-01-15 23:35:22-08:00, harlan@psp-at1.tal1.ntfo.org
+ Bug 3415: implement ippeerlimit
+
+ ChangeLog@1.1901 +1 -1
+ Bug 3415: implement ippeerlimit
+
+ include/ntp.h@1.226 +6 -5
+ Bug 3415: implement ippeerlimit
+
+ include/ntp_config.h@1.85 +7 -5
+ Bug 3415: implement ippeerlimit
+
+ include/ntp_request.h@1.50 +1 -0
+ Bug 3415: implement ippeerlimit
+
+ include/ntpd.h@1.200 +1 -1
+ Bug 3415: implement ippeerlimit
+
+ ntpd/complete.conf.in@1.33 +8 -8
+ Bug 3415: implement ippeerlimit
+
+ ntpd/keyword-gen-utd@1.32 +1 -1
+ Bug 3415: implement ippeerlimit
+
+ ntpd/keyword-gen.c@1.38 +1 -0
+ Bug 3415: implement ippeerlimit
+
+ ntpd/ntp_config.c@1.351 +17 -11
+ Bug 3415: implement ippeerlimit
+
+ ntpd/ntp_io.c@1.424 +2 -2
+ Bug 3415: implement ippeerlimit
+
+ ntpd/ntp_keyword.h@1.34 +784 -774
+ Bug 3415: implement ippeerlimit
+
+ ntpd/ntp_parser.c@1.111 +1089 -1055
+ Bug 3415: implement ippeerlimit
+
+ ntpd/ntp_parser.h@1.74 +274 -272
+ Bug 3415: implement ippeerlimit
+
+ ntpd/ntp_parser.y@1.99 +36 -13
+ Bug 3415: implement ippeerlimit
+
+ ntpd/ntp_request.c@1.123 +2 -1
+ Bug 3415: implement ippeerlimit
+
+ ntpd/ntp_restrict.c@1.42 +8 -5
+ Bug 3415: implement ippeerlimit
+
+ ntpdc/layout.std@1.13 +7 -6
+ Bug 3415: implement ippeerlimit
+
+ tests/ntpd/ntp_restrict.c@1.5 +12 -12
+ Bug 3415: implement ippeerlimit
+
+ChangeSet@1.3747.1.1, 2018-01-13 00:42:58-08:00, harlan@psp-at0.tal1.ntfo.org
+ Cleanup description of Sec 3415
+
+ ChangeLog@1.1898.1.1 +2 -1
+ Cleanup description of Sec 3415
+
+ChangeSet@1.3747, 2018-01-12 01:29:33-08:00, harlan@psp-at0.tal1.ntfo.org
+ Distribute testconf.yml
+
+ ChangeLog@1.1898 +1 -0
+ Distribute testconf.yml
+
+ sntp/tests/Makefile.am@1.72 +1 -0
+ Distribute testconf.yml
+
+ tests/bug-2803/Makefile.am@1.18 +4 -0
+ Distribute testconf.yml
+
+ tests/libntp/Makefile.am@1.99 +4 -0
+ Distribute testconf.yml
+
+ tests/ntpd/Makefile.am@1.36 +4 -0
+ Distribute testconf.yml
+
+ tests/ntpq/Makefile.am@1.14 +4 -0
+ Distribute testconf.yml
+
+ tests/sandbox/Makefile.am@1.12 +4 -0
+ Distribute testconf.yml
+
+ tests/sec-2853/Makefile.am@1.8 +4 -0
+ Distribute testconf.yml
+
+ChangeSet@1.3746, 2018-01-12 01:24:20-08:00, harlan@psp-at0.tal1.ntfo.org
+ [Sec 3415] Multiple authenticated ephemeral associations.
+
+ ChangeLog@1.1897 +1 -0
+ [Sec 3415] Multiple authenticated ephemeral associations.
+
+ChangeSet@1.3745, 2018-01-11 12:25:17+00:00, stenn@psp-deb1.ntp.org
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ChangeLog@1.1896 +2 -0
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ NEWS@1.182 +3 -0
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ html/keygen.html@1.36 +350 -138
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ include/ntp_request.h@1.49 +2 -0
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ include/ntpd.h@1.199 +10 -9
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ libntp/systime.c@1.74 +12 -6
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/invoke-ntp.keys.texi@1.198 +11 -3
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp.keys.5man@1.232 +12 -4
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp.keys.5mdoc@1.232 +12 -4
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp.keys.def@1.12 +10 -2
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp.keys.man.in@1.232 +12 -4
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp.keys.mdoc.in@1.232 +12 -4
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp_control.c@1.224 +109 -97
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp_parser.c@1.110 +154 -154
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp_parser.h@1.73 +4 -4
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp_proto.c@1.408 +2 -0
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpd/ntp_request.c@1.122 +2 -0
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpdc/layout.std@1.12 +3 -1
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ ntpq/ntpq-subs.c@1.122 +4 -0
+ sys_lamport and sys_tsrounding. Document .../N in ntp.keys
+
+ChangeSet@1.3744, 2018-01-10 17:48:26+01:00, perlinger@ntp.org
+ [Bug 3450] Dubious error messages from plausibility checks in get_systime()
+
+ ChangeLog@1.1895 +2 -0
+ [Bug 3450] Dubious error messages from plausibility checks in get_systime()
+
+ libntp/systime.c@1.73 +31 -31
+ [Bug 3450] Dubious error messages from plausibility checks in get_systime()
+ - use ceiling when converting sys_fuzz to nsecs
+ - make sure the time stamps in l_fp format increase when truncation errors hit
+ - use DPRINTF() instead of syslog -- this is expected to happen from time to time
+
+ChangeSet@1.3743, 2018-01-08 04:20:20-08:00, harlan@psp-at0.tal1.ntfo.org
+ [Sec 3012] Sybil vulnerability: noepeer support
+
+ ChangeLog@1.1894 +1 -1
+ [Sec 3012] Sybil vulnerability: noepeer support
+
+ChangeSet@1.3742, 2018-01-08 00:02:07-08:00, harlan@psp-at0.tal1.ntfo.org
+ Document noepeer
+
+ html/accopt.html@1.46 +2 -2
+ Document noepeer
+
+ ntpd/invoke-ntp.conf.texi@1.209 +10 -6
+ Document noepeer
+
+ ntpd/ntp.conf.5man@1.243 +9 -3127
+ Document noepeer
+
+ ntpd/ntp.conf.5mdoc@1.243 +7 -2947
+ Document noepeer
+
+ ntpd/ntp.conf.def@1.26 +9 -5
+ Document noepeer
+
+ ntpd/ntp.conf.man.in@1.243 +9 -3127
+ Document noepeer
+
+ ntpd/ntp.conf.mdoc.in@1.243 +7 -2947
+ Document noepeer
+
+ChangeSet@1.3741, 2018-01-06 03:43:02-08:00, harlan@psp-at0.tal1.ntfo.org
+ noepeer support
+
+ ChangeLog@1.1893 +1 -0
+ noepeer support
+
+ html/accopt.html@1.45 +3 -1
+ noepeer support
+
+ include/ntp.h@1.225 +12 -10
+ noepeer support
+
+ libntp/statestr.c@1.30 +147 -137
+ noepeer support
+
+ ntpd/keyword-gen-utd@1.31 +1 -1
+ noepeer support
+
+ ntpd/keyword-gen.c@1.37 +2 -0
+ noepeer support
+
+ ntpd/ntp_config.c@1.350 +5 -1
+ noepeer support
+
+ ntpd/ntp_keyword.h@1.33 +902 -891
+ noepeer support
+
+ ntpd/ntp_parser.c@1.109 +1120 -1120
+ noepeer support
+
+ ntpd/ntp_parser.h@1.72 +326 -322
+ noepeer support
+
+ ntpd/ntp_parser.y@1.98 +5 -1
+ noepeer support
+
+ ntpd/ntp_proto.c@1.407 +36 -28
+ noepeer support
+
+ChangeSet@1.3737.1.2, 2018-01-02 14:59:21+01:00, perlinger@ntp.org
+ fix typo / warning for VisualC
+
+ libntp/a_md5encrypt.c@1.48 +2 -2
+ fix typo / warning for VisualC
+
+ChangeSet@1.3739, 2017-12-31 02:49:37-08:00, harlan@psp-at0.tal1.ntfo.org
+ authistrustedip() - use it in more places
+
+ ChangeLog@1.1892 +2 -1
+ authistrustedip() - use it in more places
+
+ ntpd/ntp_control.c@1.223 +1 -1
+ authistrustedip() - use it in more places
+
+ ntpd/ntp_request.c@1.121 +1 -0
+ authistrustedip() - use it in more places
+
+ChangeSet@1.3737.1.1, 2017-12-31 11:03:00+01:00, perlinger@ntp.org
+ make 'authistrustedip()' more flexible
+
+ libntp/authkeys.c@1.41 +6 -7
+ make 'authistrustedip()' more flexible
+
+ChangeSet@1.3726.6.1, 2017-12-30 03:54:30-08:00, harlan@psp-at0.tal1.ntfo.org
+ record_raw_stats cleanup
+
+ ntpd/ntp_proto.c@1.406 +53 -4
+ record_raw_stats cleanup
+
+ChangeSet@1.3737, 2017-12-30 10:01:53+01:00, perlinger@ntp.org
+ unit tests: avoid CD to source dir when calling ruby
+
+ sntp/tests/Makefile.am@1.71 +10 -10
+ unit tests: avoid CD to source dir when calling ruby
+
+ sntp/unity/auto/generate_test_runner.rb@1.12 +2 -2
+ generator emits only module name, not module path, to generated code
+
+ tests/bug-2803/Makefile.am@1.17 +2 -2
+ unit tests: avoid CD to source dir when calling ruby
+
+ tests/libntp/Makefile.am@1.98 +40 -40
+ unit tests: avoid CD to source dir when calling ruby
+
+ tests/ntpd/Makefile.am@1.35 +7 -7
+ unit tests: avoid CD to source dir when calling ruby
+
+ tests/ntpq/Makefile.am@1.13 +2 -2
+ unit tests: avoid CD to source dir when calling ruby
+
+ tests/sandbox/Makefile.am@1.11 +4 -4
+ unit tests: avoid CD to source dir when calling ruby
+
+ tests/sec-2853/Makefile.am@1.7 +2 -2
+ unit tests: avoid CD to source dir when calling ruby
+
+ChangeSet@1.3736, 2017-12-30 08:10:36+00:00, stenn@psp-deb1.ntp.org
+ Clean up directory paths for test programs
+
+ sntp/tests/Makefile.am@1.70 +3 -3
+ Clean up directory paths for test programs
+
+ tests/bug-2803/Makefile.am@1.16 +3 -3
+ Clean up directory paths for test programs
+
+ tests/libntp/Makefile.am@1.97 +3 -3
+ Clean up directory paths for test programs
+
+ tests/ntpd/Makefile.am@1.34 +3 -3
+ Clean up directory paths for test programs
+
+ tests/ntpq/Makefile.am@1.12 +3 -3
+ Clean up directory paths for test programs
+
+ tests/sandbox/Makefile.am@1.10 +3 -3
+ Clean up directory paths for test programs
+
+ tests/sec-2853/Makefile.am@1.6 +3 -3
+ Clean up directory paths for test programs
+
+ChangeSet@1.3735, 2017-12-30 07:49:54+01:00, perlinger@ntp.org
+ address matching: cleanup & unit tests
+
+ libntp/authkeys.c@1.40 +29 -3
+ address matching: cleanup & unit tests
+ - improve handling of invalid addresses
+
+ tests/libntp/authkeys.c@1.16 +173 -45
+ address matching: cleanup & unit tests
+ - add test cases
+
+ tests/libntp/run-authkeys.c@1.14 +19 -7
+ address matching: cleanup & unit tests
+ - update auto-generated file
+
+ChangeSet@1.3734, 2017-12-29 10:53:55+01:00, perlinger@ntp.org
+ implement mask/prefix match on addresses for key lookup
+
+ include/ntp_keyacc.h@1.4 +6 -2
+ implement mask/prefix match on addresses for key lookup
+
+ libntp/authkeys.c@1.39 +73 -2
+ implement mask/prefix match on addresses for key lookup
+
+ libntp/authreadkeys.c@1.32 +13 -19
+ cleanup of mask parsing, accept excessive masks
+
+ libntp/ssl_init.c@1.28 +1 -2
+ cleanup use of loval vars
+
+ChangeSet@1.3730.1.9, 2017-12-28 22:48:21-08:00, harlan@psp-at0.tal1.ntfo.org
+ Allow .../N to specify subnet bits for IPs in ntp.keys
+
+ ChangeLog@1.1891 +1 -0
+ Allow .../N to specify subnet bits for IPs in ntp.keys
+
+ include/ntp_keyacc.h@1.3 +3 -1
+ Allow .../N to specify subnet bits for IPs in ntp.keys
+
+ libntp/authkeys.c@1.38 +4 -1
+ Allow .../N to specify subnet bits for IPs in ntp.keys
+
+ libntp/authreadkeys.c@1.31 +47 -7
+ Allow .../N to specify subnet bits for IPs in ntp.keys
+
+ChangeSet@1.3730.1.8, 2017-12-28 22:42:07-08:00, harlan@psp-at0.tal1.ntfo.org
+ [Bug 2900] libntp build order problem
+
+ ChangeLog@1.1890 +1 -0
+ [Bug 2900] libntp build order problem
+
+ Makefile.am@1.136 +1 -1
+ [Bug 2900] libntp build order problem
+
+ sntp/check-libntp.mf@1.3 +0 -1
+ [Bug 2900] libntp build order problem
+
+ChangeSet@1.3730.1.7, 2017-12-28 00:09:57-08:00, harlan@psp-at1.tal1.ntfo.org
+ sntp: show the IP of who sent us a crypto-NAK
+
+ ChangeLog@1.1889 +1 -0
+ sntp: show the IP of who sent us a crypto-NAK
+
+ sntp/networking.c@1.69 +6 -2
+ sntp: show the IP of who sent us a crypto-NAK
+
+ChangeSet@1.3730.1.6, 2017-12-25 19:53:47-08:00, harlan@psp-at0.tal1.ntfo.org
+ Clean up libevent configure checks
+
+ ChangeLog@1.1888 +1 -0
+ Clean up libevent configure checks
+
+ sntp/m4/ntp_libevent.m4@1.20 +6 -7
+ Clean up libevent configure checks
+
+ChangeSet@1.3730.1.5, 2017-12-25 18:07:37-08:00, harlan@psp-at0.tal1.ntfo.org
+ prepend "yes, " to the displayed value of pkg-config --modversion
+
+ sntp/m4/ntp_libevent.m4@1.19 +1 -1
+ prepend "yes, " to the displayed value of pkg-config --modversion
+
+ sntp/m4/ntp_openssl.m4@1.29 +1 -1
+ prepend "yes, " to the displayed value of pkg-config --modversion
+
+ChangeSet@1.3730.2.1, 2017-12-25 04:53:42-08:00, harlan@psp-at1.tal1.ntfo.org
+ When using pkg-config, report --modversion
+
+ ChangeLog@1.1887 +1 -0
+ When using pkg-config, report --modversion
+
+ sntp/m4/ntp_libevent.m4@1.18 +6 -1
+ When using pkg-config, report --modversion
+
+ sntp/m4/ntp_openssl.m4@1.28 +6 -1
+ When using pkg-config, report --modversion
+
+ChangeSet@1.3726.5.2, 2017-12-22 14:53:55+01:00, perlinger@ntp.org
+ SNTP: separate MAC computation from copy or compare
+
+ sntp/crypto.c@1.36 +85 -56
+ separate MAC computation from copy or compare
+
+ChangeSet@1.3726.4.1, 2017-12-21 07:59:17+01:00, perlinger@ntp.org
+ zero-pad or truncate AES128CMAC keys to exactly 16byte
+
+ libntp/a_md5encrypt.c@1.47 +14 -6
+ zero-pad or truncate AES128CMAC keys to exactly 16byte
+
+ sntp/crypto.c@1.32.1.1 +15 -23
+ zero-pad or truncate AES128CMAC keys to exactly 16byte
+
+ChangeSet@1.3726.1.17, 2017-12-13 20:30:41-08:00, harlan@psp-at0.tal1.ntfo.org
+ update-leap: updates from Paul McMath
+
+ ChangeLog@1.1885 +1 -0
+ update-leap: updates from Paul McMath
+
+ scripts/update-leap/update-leap.in@1.5 +13 -12
+ update-leap: updates from Paul McMath
+
+ChangeSet@1.3726.3.9, 2017-12-13 03:21:32-08:00, harlan@psp-at0.tal1.ntfo.org
+ sntp: pkt_output(): Improve debug output.
+
+ ChangeLog@1.1876.5.8 +1 -0
+ sntp: pkt_output(): Improve debug output.
+
+ libntp/authreadkeys.c@1.27.1.2 +1 -0
+ Minor cleanup
+
+ sntp/utilities.c@1.20 +1 -1
+ sntp: pkt_output(): Improve debug output.
+
+ChangeSet@1.3726.3.8, 2017-12-13 02:14:15-08:00, harlan@psp-at0.tal1.ntfo.org
+ sntp: tweak key file logging.
+
+ ChangeLog@1.1876.5.7 +1 -0
+ sntp: tweak key file logging.
+
+ sntp/crypto.c@1.25.1.4 +10 -4
+ sntp: tweak key file logging.
+
+ sntp/main.c@1.102 +1 -2
+ sntp: tweak key file logging.
+
+ChangeSet@1.3726.3.7, 2017-12-12 19:15:09-08:00, harlan@psp-at0.tal1.ntfo.org
+ [Bug 3405] update-leap.in: general cleanup, HTTPS support. Paul McMath.
+
+ ChangeLog@1.1876.5.6 +1 -0
+ [Bug 3405] update-leap.in: general cleanup, HTTPS support. Paul McMath.
+
+ NEWS@1.181 +6 -0
+ [Bug 3405] update-leap.in: general cleanup, HTTPS support. Paul McMath.
+
+ scripts/update-leap/update-leap.in@1.4 +358 -312
+ [Bug 3405] update-leap.in: general cleanup, HTTPS support. Paul McMath.
+
+ChangeSet@1.3726.3.6, 2017-12-11 11:55:35+00:00, stenn@psp-deb1.ntp.org
+ Deal with NULL src when calling record_raw_stats()
+
+ ntpd/ntp_io.c@1.423 +1 -1
+ Deal with NULL src when calling record_raw_stats()
+
+ChangeSet@1.3726.3.5, 2017-12-11 03:31:22-08:00, harlan@psp-at0.tal1.ntfo.org
+ Handle a null srcadr in record_raw_stats()
+
+ ntpd/ntp_util.c@1.119 +2 -1
+ Handle a null srcadr in record_raw_stats()
+
+ChangeSet@1.3726.1.14, 2017-12-11 08:52:38+00:00, stenn@psp-deb1.ntp.org
+ merge cleanup
+
+ sntp/invoke-sntp.texi@1.512 +1 -1
+ merge cleanup
+
+ sntp/sntp-opts.c@1.531 +95 -92
+ merge cleanup
+
+ sntp/sntp-opts.h@1.529 +1 -1
+ merge cleanup
+
+ sntp/sntp.1sntpman@1.347 +7 -2
+ merge cleanup
+
+ sntp/sntp.1sntpmdoc@1.347 +7 -2
+ merge cleanup
+
+ sntp/sntp.man.in@1.347 +7 -2
+ merge cleanup
+
+ sntp/sntp.mdoc.in@1.347 +7 -2
+ merge cleanup
+
+ChangeSet@1.3726.1.12, 2017-12-09 10:39:12+01:00, jnperlin@hydra.localnet
+ [Bug 2878] Tests are cluttering up syslog
+
+ ChangeLog@1.1882 +1 -0
+ [Bug 2878] Tests are cluttering up syslog
+
+ sntp/tests/Makefile.am@1.69 +3 -2
+ [Bug 2878] Tests are cluttering up syslog
+ - use YAML config to setup test suites
+
+ sntp/tests/run-crypto.c@1.8 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ sntp/tests/run-keyFile.c@1.10 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ sntp/tests/run-kodDatabase.c@1.10 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ sntp/tests/run-kodFile.c@1.8 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ sntp/tests/run-networking.c@1.4 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ sntp/tests/run-packetHandling.c@1.7 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ sntp/tests/run-packetProcessing.c@1.13 +8 -0
+ Bug 2878 - Tests are cluttering up syslog
+
+ sntp/tests/run-t-log.c@1.6 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ sntp/tests/run-utilities.c@1.7 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ sntp/tests/testconf.yml@1.1 +9 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - generator configuration to redirect syslog to stderr
+
+ sntp/tests/testconf.yml@1.0 +0 -0
+
+ sntp/unity/auto/generate_test_runner.rb@1.11 +1 -1
+ [Bug 2878] Tests are cluttering up syslog
+ - fix prototype of generated 'suite_setup()' function
+
+ tests/bug-2803/Makefile.am@1.15 +2 -1
+ [Bug 2878] Tests are cluttering up syslog
+ - use YAML config to setup test suites
+
+ tests/bug-2803/run-bug-2803.c@1.10 +8 -2
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/bug-2803/testconf.yml@1.1 +9 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - generator configuration to redirect syslog to stderr
+
+ tests/bug-2803/testconf.yml@1.0 +0 -0
+
+ tests/bug-3102/testconf.yml@1.1 +9 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - generator configuration to redirect syslog to stderr
+
+ tests/bug-3102/testconf.yml@1.0 +0 -0
+
+ tests/libntp/Makefile.am@1.96 +3 -2
+ [Bug 2878] Tests are cluttering up syslog
+ - use YAML config to setup test suites
+
+ tests/libntp/run-a_md5encrypt.c@1.16 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-atoint.c@1.9 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-atouint.c@1.10 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-authkeys.c@1.13 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-buftvtots.c@1.7 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-calendar.c@1.13 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-caljulian.c@1.14 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-caltontp.c@1.6 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-calyearstart.c@1.8 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-clocktime.c@1.11 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-decodenetnum.c@1.12 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-hextoint.c@1.10 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-hextolfp.c@1.9 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-humandate.c@1.8 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-lfpfunc.c@1.20 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-lfptostr.c@1.9 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-modetoa.c@1.13 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-msyslog.c@1.10 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-netof.c@1.9 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-numtoa.c@1.12 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-numtohost.c@1.12 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-octtoint.c@1.8 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-prettydate.c@1.7 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-recvbuff.c@1.6 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-refidsmear.c@1.9 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-refnumtoa.c@1.10 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-sfptostr.c@1.8 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-socktoa.c@1.15 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-ssl_init.c@1.10 +17 -5
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-statestr.c@1.12 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-strtolfp.c@1.7 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-timespecops.c@1.12 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-timevalops.c@1.15 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-tsafememcmp.c@1.2 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-tstotv.c@1.6 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-tvtots.c@1.7 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-uglydate.c@1.12 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-vi64ops.c@1.9 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/run-ymd2yd.c@1.12 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/libntp/testconf.yml@1.1 +9 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - generator configuration to redirect syslog to stderr
+
+ tests/libntp/testconf.yml@1.0 +0 -0
+
+ tests/ntpd/Makefile.am@1.33 +2 -1
+ [Bug 2878] Tests are cluttering up syslog
+ - use YAML config to setup test suites
+
+ tests/ntpd/run-leapsec.c@1.6.1.1 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/ntpd/run-ntp_prio_q.c@1.4.1.1 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/ntpd/run-ntp_restrict.c@1.5.1.1 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/ntpd/run-rc_cmdlength.c@1.4.1.1 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/ntpd/run-t-ntp_scanner.c@1.5.1.1 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/ntpd/run-t-ntp_signd.c@1.12 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/ntpd/testconf.yml@1.1 +9 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - generator configuration to redirect syslog to stderr
+
+ tests/ntpd/testconf.yml@1.0 +0 -0
+
+ tests/ntpq/Makefile.am@1.11 +2 -1
+ [Bug 2878] Tests are cluttering up syslog
+ - use YAML config to setup test suites
+
+ tests/ntpq/run-t-ntpq.c@1.4 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/ntpq/testconf.yml@1.1 +9 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - generator configuration to redirect syslog to stderr
+
+ tests/ntpq/testconf.yml@1.0 +0 -0
+
+ tests/sandbox/Makefile.am@1.9 +2 -1
+ [Bug 2878] Tests are cluttering up syslog
+ - use YAML config to setup test suites
+
+ tests/sandbox/run-modetoa.c@1.4 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/sandbox/run-uglydate.c@1.8 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/sandbox/run-ut-2803.c@1.3 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/sandbox/testconf.yml@1.1 +9 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - generator configuration to redirect syslog to stderr
+
+ tests/sandbox/testconf.yml@1.0 +0 -0
+
+ tests/sec-2853/Makefile.am@1.5 +4 -2
+ [Bug 2878] Tests are cluttering up syslog
+ - use YAML config to setup test suites
+
+ tests/sec-2853/run-sec-2853.c@1.6 +8 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - auto-regenerated test driver
+
+ tests/sec-2853/testconf.yml@1.1 +9 -0
+ [Bug 2878] Tests are cluttering up syslog
+ - generator configuration to redirect syslog to stderr
+
+ tests/sec-2853/testconf.yml@1.0 +0 -0
+
+ChangeSet@1.3726.1.11, 2017-12-08 07:14:36+01:00, perlinger@ntp.org
+ [Bug 3447] AES-128-CMAC (fixes)
+ - refactoring the MAC code, too
+
+ ChangeLog@1.1881 +1 -0
+ [Bug 3447] AES-128-CMAC (fixes)
+ - refactoring the MAC code, too
+
+ include/ntp_stdlib.h@1.86 +2 -2
+ [Bug 3447] AES-128-CMAC (fixes)
+ - refactoring the MAC code, too
+
+ libntp/a_md5encrypt.c@1.46 +163 -174
+ [Bug 3447] AES-128-CMAC (fixes)
+ - refactoring the MAC code, too
+
+ libntp/authkeys.c@1.37 +6 -3
+ [Bug 3447] AES-128-CMAC (fixes)
+ - refactoring the MAC code, too
+
+ libntp/libssl_compat.c@1.5 +4 -1
+ [Bug 3447] AES-128-CMAC (fixes)
+ - refactoring the MAC code, too
+
+ tests/libntp/a_md5encrypt.c@1.16 +4 -8
+ [Bug 3447] AES-128-CMAC (fixes)
+ - refactoring the MAC code, too
+
+ChangeSet@1.3726.3.4, 2017-12-07 10:56:10+00:00, stenn@psp-deb1.ntp.org
+ Update monopt.html with the new rawstats information
+
+ html/monopt.html@1.41 +21 -5
+ Update monopt.html with the new rawstats information
+
+ChangeSet@1.3726.1.10, 2017-12-06 21:15:12+01:00, perlinger@ntp.org
+ [Bug 3447] AES-128-CMAC (fixes)
+
+ ChangeLog@1.1880 +1 -0
+ [Bug 3447] AES-128-CMAC (fixes)
+
+ libntp/a_md5encrypt.c@1.45 +151 -168
+ [Bug 3447] AES-128-CMAC (fixes)
+
+ sntp/crypto.c@1.32 +77 -82
+ [Bug 3447] AES-128-CMAC (fixes)
+
+ChangeSet@1.3726.3.3, 2017-12-05 20:23:17-08:00, harlan@psp-at0.tal1.ntfo.org
+ [Bug 3433] sntp crashes when run with -a
+
+ ChangeLog@1.1876.5.5 +1 -0
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/crypto.c@1.25.1.3 +1 -0
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/invoke-sntp.texi@1.509.1.1 +1 -1
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/main.c@1.101 +19 -7
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/sntp-opts.c@1.528.1.1 +95 -92
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/sntp-opts.def@1.48 +1 -0
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/sntp-opts.h@1.526.1.1 +1 -1
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/sntp.1sntpman@1.342.1.3 +8 -3
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/sntp.1sntpmdoc@1.342.1.3 +7 -2
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/sntp.html@1.523.2.3 +104 -80
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/sntp.man.in@1.342.1.3 +8 -3
+ [Bug 3433] sntp crashes when run with -a
+
+ sntp/sntp.mdoc.in@1.342.1.3 +7 -2
+ [Bug 3433] sntp crashes when run with -a
+
+ChangeSet@1.3726.3.2, 2017-12-05 18:48:06-08:00, harlan@psp-at0.tal1.ntfo.org
+ Add comment about client-mode pkt->rootdisp
+
+ ntpd/ntp_io.c@1.422 +1 -0
+ Add comment about client-mode pkt->rootdisp
+
+ChangeSet@1.3726.3.1, 2017-12-04 00:24:49-08:00, harlan@psp-at0.tal1.ntfo.org
+ record_raw_stats(): Log entire packet. Log writes.
+
+ ChangeLog@1.1876.5.4 +1 -0
+ record_raw_stats(): Log entire packet. Log writes.
+
+ include/ntpd.h@1.198 +1 -1
+ record_raw_stats(): Log entire packet. Log writes.
+
+ ntpd/ntp_io.c@1.421 +13 -0
+ record_raw_stats(): Log entire packet. Log writes.
+
+ ntpd/ntp_proto.c@1.405 +2 -1
+ record_raw_stats(): Log entire packet. Log writes.
+
+ ntpd/ntp_util.c@1.118 +15 -2
+ record_raw_stats(): Log entire packet. Log writes.
+
+ChangeSet@1.3726.1.9, 2017-12-03 02:49:10-08:00, harlan@psp-at0.tal1.ntfo.org
+ Many files:
+ new file
+
+ libntp/aes/FROM@1.1 +1 -0
+ BitKeeper file libntp/aes/FROM
+
+ libntp/aes/FROM@1.0 +0 -0
+
+ libntp/aes/Makefile.am@1.1 +24 -0
+ BitKeeper file libntp/aes/Makefile.am
+
+ libntp/aes/Makefile.am@1.0 +0 -0
+
+ libntp/aes/README@1.1 +56 -0
+ BitKeeper file libntp/aes/README
+
+ libntp/aes/README@1.0 +0 -0
+
+ libntp/aes/aes-omac1.c@1.1 +118 -0
+ BitKeeper file libntp/aes/aes-omac1.c
+
+ libntp/aes/aes-omac1.c@1.0 +0 -0
+
+ libntp/aes/aes.h@1.1 +21 -0
+ BitKeeper file libntp/aes/aes.h
+
+ libntp/aes/aes.h@1.0 +0 -0
+
+ libntp/aes/aes_wrap.h@1.1 +64 -0
+ BitKeeper file libntp/aes/aes_wrap.h
+
+ libntp/aes/aes_wrap.h@1.0 +0 -0
+
+ libntp/aes/ar-lib@1.1 +270 -0
+ BitKeeper file libntp/aes/ar-lib
+
+ libntp/aes/ar-lib@1.0 +0 -0
+
+ libntp/aes/build_config.h@1.1 +77 -0
+ BitKeeper file libntp/aes/build_config.h
+
+ libntp/aes/build_config.h@1.0 +0 -0
+
+ libntp/aes/common.h@1.1 +489 -0
+ BitKeeper file libntp/aes/common.h
+
+ libntp/aes/common.h@1.0 +0 -0
+
+ libntp/aes/compile@1.1 +347 -0
+ BitKeeper file libntp/aes/compile
+
+ libntp/aes/compile@1.0 +0 -0
+
+ libntp/aes/configure.ac@1.1 +37 -0
+ BitKeeper file libntp/aes/configure.ac
+
+ libntp/aes/configure.ac@1.0 +0 -0
+
+ libntp/aes/depcomp@1.1 +791 -0
+ BitKeeper file libntp/aes/depcomp
+
+ libntp/aes/depcomp@1.0 +0 -0
+
+ libntp/aes/includes.h@1.1 +50 -0
+ BitKeeper file libntp/aes/includes.h
+
+ libntp/aes/includes.h@1.0 +0 -0
+
+ libntp/aes/missing@1.1 +215 -0
+ BitKeeper file libntp/aes/missing
+
+ libntp/aes/missing@1.0 +0 -0
+
+ libntp/aes/os.h@1.1 +539 -0
+ BitKeeper file libntp/aes/os.h
+
+ libntp/aes/os.h@1.0 +0 -0
+
+ libntp/aes/rfc4493-test.c@1.1 +256 -0
+ BitKeeper file libntp/aes/rfc4493-test.c
+
+ libntp/aes/rfc4493-test.c@1.0 +0 -0
+
+ libntp/aes/test-aes-libtomcrypt.c@1.1 +101 -0
+ BitKeeper file libntp/aes/test-aes-libtomcrypt.c
+
+ libntp/aes/test-aes-libtomcrypt.c@1.0 +0 -0
+
+ libntp/aes/test-aes-openssl.c@1.1 +71 -0
+ BitKeeper file libntp/aes/test-aes-openssl.c
+
+ libntp/aes/test-aes-openssl.c@1.0 +0 -0
+
+ libntp/aes/validate-aes.c@1.1 +122 -0
+ BitKeeper file libntp/aes/validate-aes.c
+
+ libntp/aes/validate-aes.c@1.0 +0 -0
+
+ libntp/aes/wpa_debug.c@1.1 +688 -0
+ BitKeeper file libntp/aes/wpa_debug.c
+
+ libntp/aes/wpa_debug.c@1.0 +0 -0
+
+ libntp/aes/wpa_debug.h@1.1 +291 -0
+ BitKeeper file libntp/aes/wpa_debug.h
+
+ libntp/aes/wpa_debug.h@1.0 +0 -0
+
+ libntp/aes/wpabuf.c@1.1 +303 -0
+ BitKeeper file libntp/aes/wpabuf.c
+
+ libntp/aes/wpabuf.c@1.0 +0 -0
+
+ libntp/aes/wpabuf.h@1.1 +162 -0
+ BitKeeper file libntp/aes/wpabuf.h
+
+ libntp/aes/wpabuf.h@1.0 +0 -0
+
+ChangeSet@1.3726.1.8, 2017-11-28 08:44:31+00:00, stenn@psp-deb1.ntp.org
+ Identify AES-128-CMAC workers
+
+ ChangeLog@1.1879 +1 -1
+ Identify AES-128-CMAC workers
+
+ChangeSet@1.3726.1.7, 2017-11-28 00:12:53-08:00, harlan@mb6.tal1.ntfo.org
+ Continue AES-128-CMAC test development
+
+ sntp/tests/crypto.c@1.15 +10 -6
+ Continue AES-128-CMAC test development
+
+ChangeSet@1.3726.2.1, 2017-11-28 07:08:15+00:00, stenn@psp-deb1.ntp.org
+ Merge cleanup
+
+ libntp/ssl_init.c@1.27 +1 -0
+ Merge cleanup
+
+ ntpd/ntpd.html@1.188 +1 -1
+ Merge cleanup
+
+ ntpq/ntpq.c@1.181 +1 -0
+ Merge cleanup
+
+ ntpq/ntpq.html@1.185 +1 -1
+ Merge cleanup
+
+ sntp/crypto.c@1.30 +13 -13
+ Merge cleanup
+
+ sntp/crypto.h@1.14 +2 -1
+ Merge cleanup
+
+ sntp/tests/crypto.c@1.13 +2 -2
+ Merge cleanup
+
+ sntp/tests/packetProcessing.c@1.16 +1 -1
+ Merge cleanup
+
+ sntp/tests/run-crypto.c@1.7 +10 -6
+ Merge cleanup
+
+ sntp/tests/run-packetProcessing.c@1.12 +20 -18
+ Merge cleanup
+
+ChangeSet@1.3720.58.1, 2017-11-27 22:35:12-08:00, harlan@mb6.tal1.ntfo.org
+ aes-128-cmac support
+
+ sntp/crypto.c@1.28.1.1 +23 -15
+ aes-128-cmac support
+
+ sntp/tests/crypto.c@1.11.1.1 +27 -4
+ aes-128-cmac support
+
+ChangeSet@1.3726.1.3, 2017-11-13 22:54:14-08:00, harlan@psp-at0.tal1.ntfo.org
+ Fix bug in the override portion of the compiler hardening macro
+
+ ChangeLog@1.1876.5.3 +1 -0
+ Fix bug in the override portion of the compiler hardening macro
+
+ html/access.html@1.3, harlan@max.pfcs.com +2 -2
+ whitespace cleanup
+
+ html/accopt.html@1.44, harlan@max.pfcs.com +4 -4
+ whitespace cleanup
+
+ sntp/m4/ntp_harden.m4@1.2 +6 -6
+ Fix bug in the override portion of the compiler hardening macro
+
+ChangeSet@1.3731, 2017-10-31 07:33:33+01:00, perlinger@ntp.org
+ Fix trivial warnings from 'make check'
+ - printf format clashes
+
+ tests/libntp/timespecops.c@1.12 +9 -6
+ Fix trivial warnings from 'make check'
+ - printf format clashes
+
+ tests/libntp/timevalops.c@1.15 +8 -8
+ Fix trivial warnings from 'make check'
+ - printf format clashes
+
+ChangeSet@1.3730, 2017-10-30 09:46:03+01:00, perlinger@ntp.org
+ Fix trivial warnings from 'make check'
+
+ ChangeLog@1.1876.1.7 +1 -0
+ Fix trivial warnings from 'make check'
+
+ tests/ntpd/leapsec.c@1.5 +97 -193
+ Fix trivial warnings from 'make check'
+
+ tests/ntpd/ntp_prio_q.c@1.4 +24 -16
+ Fix trivial warnings from 'make check'
+
+ tests/ntpd/ntp_restrict.c@1.4 +34 -22
+ Fix trivial warnings from 'make check'
+
+ tests/ntpd/rc_cmdlength.c@1.4 +3 -4
+ Fix trivial warnings from 'make check'
+
+ tests/ntpd/run-leapsec.c@1.7 +34 -33
+ Fix trivial warnings from 'make check' (auto-regenerated file)
+
+ tests/ntpd/run-ntp_prio_q.c@1.5 +6 -6
+ Fix trivial warnings from 'make check' (auto-regenerated file)
+
+ tests/ntpd/run-ntp_restrict.c@1.6 +8 -8
+ Fix trivial warnings from 'make check' (auto-regenerated file)
+
+ tests/ntpd/run-rc_cmdlength.c@1.5 +1 -1
+ Fix trivial warnings from 'make check' (auto-regenerated file)
+
+ tests/ntpd/run-t-ntp_scanner.c@1.6 +11 -11
+ Fix trivial warnings from 'make check' (auto-regenerated file)
+
+ tests/ntpd/t-ntp_scanner.c@1.8 +33 -37
+ Fix trivial warnings from 'make check'
+
+ChangeSet@1.3726.1.2, 2017-10-27 04:01:06-04:00, stenn@psp-deb2.ntp.org
+ Build ntpq and libntpq.a with NTP_HARD_*FLAGS
+
+ ChangeLog@1.1876.5.2 +1 -0
+ Build ntpq and libntpq.a with NTP_HARD_*FLAGS
+
+ ntpq/Makefile.am@1.73 +5 -1
+ Build ntpq and libntpq.a with NTP_HARD_*FLAGS
+
+ChangeSet@1.3726.1.1, 2017-10-15 07:52:15+00:00, stenn@psp-deb1.ntp.org
+ refclock_jjy.c: Add missing "%s" to an msyslog() call
+
+ ChangeLog@1.1876.5.1 +1 -0
+ refclock_jjy.c: Add missing "%s" to an msyslog() call
+
+ ntpd/refclock_jjy.c@1.36 +1 -1
+ refclock_jjy.c: Add missing "%s" to an msyslog() call
+
+ChangeSet@1.3720.56.9, 2017-10-15 04:51:52+00:00, stenn@psp-deb1.ntp.org
+ [Bug 3441] Validate the assumption that AF_UNSPEC is 0
+
+ ChangeLog@1.1876.4.8 +1 -0
+ [Bug 3441] Validate the assumption that AF_UNSPEC is 0
+
+ configure.ac@1.610 +2 -0
+ [Bug 3441] Validate the assumption that AF_UNSPEC is 0
+
+ sntp/m4/ntp_af_unspec.m4@1.2 +1 -1
+ [Bug 3441] Validate the assumption that AF_UNSPEC is 0
+
+ sntp/m4/ntp_af_unspec.m4@1.1 +23 -0
+ BitKeeper file sntp/m4/ntp_af_unspec.m4
+
+ sntp/m4/ntp_af_unspec.m4@1.0 +0 -0
+
+ChangeSet@1.3720.56.8, 2017-10-15 01:07:22+00:00, stenn@psp-deb1.ntp.org
+ regenerate ntp_parser.[ch]
+
+ ntpd/ntp_parser.c@1.108 +1176 -1157
+ regenerate ntp_parser.[ch]
+
+ ntpd/ntp_parser.h@1.71 +5 -5
+ regenerate ntp_parser.[ch]
+
+ChangeSet@1.3720.53.2, 2017-10-14 08:37:26+02:00, perlinger@ntp.org
+ [Bug 3435] anchor NTP era alignment
+
+ html/miscopt.html@1.87.1.2 +1 -1
+ [Bug 3435] anchor NTP era alignment
+
+ ntpd/ntp_config.c@1.348 +16 -5
+ [Bug 3435] anchor NTP era alignment
+
+ChangeSet@1.3720.56.6, 2017-10-13 08:17:25+00:00, stenn@psp-deb1.ntp.org
+ cleanup
+
+ ChangeLog@1.1876.4.6 +2 -2
+ cleanup
+
+ChangeSet@1.3720.57.1, 2017-10-13 09:18:19+02:00, perlinger@ntp.org
+ [Bug 3437] ntpd tries to open socket with AF_UNSPEC domain
+
+ ChangeLog@1.1873.23.1 +4 -0
+ [Bug 3437] ntpd tries to open socket with AF_UNSPEC domain
+
+ ntpd/ntp_io.c@1.420 +11 -0
+ [Bug 3437] ntpd tries to open socket with AF_UNSPEC domain
+
+ChangeSet@1.3720.29.23, 2017-10-13 03:35:03+00:00, stenn@psp-deb1.ntp.org
+ Note 3412 is a Security bug
+
+ ChangeLog@1.1876.2.16 +1 -1
+ Note 3412 is a Security bug
+
+ChangeSet@1.3720.29.22, 2017-10-13 03:31:58+00:00, stenn@psp-deb1.ntp.org
+ [Bug 3412] ctl_getitem(): Don't compare names past NUL
+
+ ChangeLog@1.1876.2.15 +1 -0
+ [Bug 3412] ctl_getitem(): Don't compare names past NUL
+
+ ntpd/ntp_control.c@1.222 +3 -1
+ [Bug 3412] ctl_getitem(): Don't compare names past NUL
+
+ChangeSet@1.3720.29.19, 2017-10-13 02:20:50+00:00, stenn@psp-deb1.ntp.org
+ test_ntp_scanner_LDADD needs ntpd/ntp_io.o
+
+ ChangeLog@1.1876.2.12 +1 -0
+ test_ntp_scanner_LDADD needs ntpd/ntp_io.o
+
+ tests/ntpd/Makefile.am@1.32 +1 -0
+ test_ntp_scanner_LDADD needs ntpd/ntp_io.o
+
+ChangeSet@1.3720.55.2, 2017-10-12 12:55:29+02:00, perlinger@ntp.org
+ [Bug 3439] (ntpq) When running multiple commands / hosts in ntpq...
+
+ ChangeLog@1.1873.22.2 +2 -0
+ [Bug 3439] (ntpq) When running multiple commands / hosts in ntpq...
+
+ ntpq/ntpq.c@1.174.3.1 +8 -2
+ [Bug 3439] (ntpq) When running multiple commands / hosts in ntpq...
+ - applied patch by ggarvey
+
+ChangeSet@1.3720.55.1, 2017-10-12 12:51:50+02:00, perlinger@ntp.org
+ [Bug 3438] (ntpq) Negative values and values > 999 days in...
+ - make sure negative values are curbed and excessive days are converted to years
+
+ ChangeLog@1.1873.22.1 +4 -0
+ [Bug 3438] (ntpq) Negative values and values > 999 days in...
+
+ ntpq/ntpq-subs.c@1.119.4.1 +10 -1
+ [Bug 3438] (ntpq) Negative values and values > 999 days in...
+ - make sure negative values are curbed and excessive days are converted to years
+
+ChangeSet@1.3720.29.12, 2017-10-12 09:35:01+00:00, stenn@psp-deb1.ntp.org
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html <abe@ntp.org>
+
+ html/drivers/driver40-ja.html@1.7 +1 -1
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html <abe@ntp.org>
+
+ html/drivers/driver40.html@1.22 +1 -1
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html <abe@ntp.org>
+
+ html/miscopt.html@1.89 +1 -2
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html <abe@ntp.org>
+
+ChangeSet@1.3720.29.9, 2017-10-12 08:21:13+00:00, stenn@psp-deb1.ntp.org
+ [Bug 2737] Wrong phone number listed for USNO
+
+ html/drivers/driver18.html@1.22 +1 -1
+ [Bug 2737] Wrong phone number listed for USNO
+
+ChangeSet@1.3720.29.6, 2017-10-12 07:26:49+00:00, stenn@psp-deb1.ntp.org
+ [Bug 948] Trustedkey config directive leaks memory
+
+ ChangeLog@1.1876.2.1 +1 -0
+ [Bug 948] Trustedkey config directive leaks memory
+
+ include/ntp_config.h@1.84 +13 -0
+ [Bug 948] Trustedkey config directive leaks memory
+
+ ntpd/ntp_config.c@1.346.1.1 +35 -3
+ [Bug 948] Trustedkey config directive leaks memory
+
+ ntpd/ntp_parser.c@1.105.1.1 +551 -548
+ [Bug 948] Trustedkey config directive leaks memory
+
+ ntpd/ntp_parser.h@1.68.1.1 +3 -3
+ [Bug 948] Trustedkey config directive leaks memory
+
+ ntpd/ntp_parser.y@1.95.1.1 +7 -6
+ [Bug 948] Trustedkey config directive leaks memory
+
+ChangeSet@1.3720.53.1, 2017-10-10 08:44:16+02:00, perlinger@ntp.org
+ [Bug 3435] anchor NTP era alignment
+
+ ChangeLog@1.1873.21.1 +3 -0
+ [Bug 3435] anchor NTP era alignment
+
+ html/miscopt.html@1.87.1.1 +3 -1
+ [Bug 3435] anchor NTP era alignment
+ - explain "tos basedate"
+
+ include/ntp_calendar.h@1.19 +23 -0
+ [Bug 3435] anchor NTP era alignment
+ - add support far 'basedate' calculations
+
+ include/ntp_fp.h@1.34 +1 -0
+ [Bug 3435] anchor NTP era alignment
+ - check/clamp system time based on 'basedate'
+
+ libntp/ntp_calendar.c@1.19 +109 -0
+ [Bug 3435] anchor NTP era alignment
+ - add support far 'basedate' calculations
+
+ libntp/systime.c@1.72 +173 -95
+ [Bug 3435] anchor NTP era alignment
+ - check/clamp system time based on 'basedate'
+
+ ntpd/keyword-gen-utd@1.30 +1 -1
+ [Bug 3435] anchor NTP era alignment
+ - add 'basedate' keyword
+
+ ntpd/keyword-gen.c@1.36 +1 -0
+ [Bug 3435] anchor NTP era alignment
+ - add 'basedate' keyword
+
+ ntpd/ntp_config.c@1.347 +56 -3
+ [Bug 3435] anchor NTP era alignment
+ - add 'basedate' statement to TOS line
+
+ ntpd/ntp_keyword.h@1.32 +1082 -1074
+ [Bug 3435] anchor NTP era alignment
+ - add 'basedate' keyword
+
+ ntpd/ntp_parser.c@1.106 +1176 -1155
+ [Bug 3435] anchor NTP era alignment
+ - add 'basedate' statement to TOS line
+
+ ntpd/ntp_parser.h@1.69 +377 -375
+ [Bug 3435] anchor NTP era alignment
+ - add 'basedate' statement to TOS line
+
+ ntpd/ntp_parser.y@1.96 +7 -0
+ [Bug 3435] anchor NTP era alignment
+ - add 'basedate' statement to TOS line
+
+ChangeSet@1.3720.44.2, 2017-09-11 09:37:31+02:00, perlinger@ntp.org
+ [Bug 3424] Trimble Thunderbolt 1024 week millenium bug
+ - fix type & annoying but harmless signed/unsigned clash
+
+ ntpd/refclock_palisade.c@1.45 +2 -2
+ [Bug 3424] Trimble Thunderbolt 1024 week millenium bug
+ - fix type & annoying but harmless signed/unsigned clash
+
+ChangeSet@1.3720.52.1, 2017-09-09 08:05:52+02:00, perlinger@ntp.org
+ [Bug 2737] Wrong phone number listed for USNO
+
+ ChangeLog@1.1873.20.1 +3 -0
+ [Bug 2737] Wrong phone number listed for USNO
+
+ html/drivers/driver18.html@1.21 +1 -1
+ [Bug 2737] Wrong phone number listed for USNO
+
+ChangeSet@1.3720.51.1, 2017-09-08 07:54:24+02:00, perlinger@ntp.org
+ [Bug 3411] problem about SIGN(6) packet handling for ntp-4.2.8p10
+
+ ChangeLog@1.1873.19.1 +4 -0
+ [Bug 3411] problem about SIGN(6) packet handling for ntp-4.2.8p10
+
+ include/recvbuff.h@1.27 +3 -2
+ [Bug 3411] problem about SIGN(6) packet handling for ntp-4.2.8p10
+ - raised receive buffer size to 1200
+
+ChangeSet@1.3720.37.2, 2017-09-07 15:47:26+02:00, perlinger@ntp.org
+ [Bug 3397] ctl_putstr() asserts that data fits in its buffer
+ - restore logic of 'ctl_putstr()'/'ctl_putunqstr()' for empty strings (just name, no assign)
+
+ ntpd/ntp_control.c@1.221 +20 -14
+ [Bug 3397] ctl_putstr() asserts that data fits in its buffer
+ - restore logic of 'ctl_putstr()'/'ctl_putunqstr()' for empty strings (just name, no assign)
+
+ChangeSet@1.3720.50.4, 2017-09-07 15:44:14+02:00, perlinger@ntp.org
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - side kick: missing linefeed in 'ifstat' warning messes up screen
+
+ ntpq/ntpq-subs.c@1.119.3.1 +2 -2
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - side kick: missing linefeed in 'ifstat' warning messes up screen
+
+ChangeSet@1.3720.50.3, 2017-09-07 11:11:08+02:00, perlinger@ntp.org
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - sidekick: permit longer key type (hash algo names) for SNTP
+
+ sntp/crypto.c@1.25.1.2 +1 -1
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - sidekick: permit longer key type (hash algo names) for SNTP
+
+ sntp/crypto.h@1.11.1.2 +1 -1
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - sidekick: permit longer key type (hash algo names) for SNTP
+
+ChangeSet@1.3720.50.2, 2017-09-06 13:10:55+02:00, perlinger@ntp.org
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - fix MD5 fallback: only 'M' as keytype accepted
+ - provide full digest list with MSVC for OpenSSL v1.0.1 and above
+
+ libntp/ssl_init.c@1.22.1.2 +1 -1
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - fix MD5 fallback: only 'M' as keytype accepted
+
+ ntpq/ntpq.c@1.174.2.2 +6 -0
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - with MSVC, enable HAVE_EVP_MD_DO_ALL_SORTED for OpenSSL v1.0.1 and above
+
+ChangeSet@1.3720.50.1, 2017-09-06 10:16:25+02:00, perlinger@ntp.org
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+
+ ChangeLog@1.1873.18.1 +5 -0
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+
+ include/ntp.h@1.224 +6 -4
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - macros for key id size & max digest size in MAC
+
+ include/ntp_request.h@1.48 +2 -2
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - use macro for max digest size
+
+ libntp/a_md5encrypt.c@1.40.1.1 +10 -9
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - use macros for key id size & max digest size in MAC
+
+ libntp/authreadkeys.c@1.27.1.1 +1 -6
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - 'keytype_from_text' only returns valid algorithms
+
+ libntp/ssl_init.c@1.22.1.1 +35 -39
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - separate OpenSSL and non-SSL code in 'keytype_from_text'
+ - assure the algorithm is valid, not just known
+ - drop length check (we support truncated hashes)
+
+ ntpq/ntpq.c@1.174.2.1 +28 -37
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - keep key type selection in sync with NTPD
+
+ sntp/crypto.c@1.25.1.1 +17 -10
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - decode & check hash algo only when reading the key file (early error detection)
+ - support truncated digest for long hash algos
+ - use macros for key and digest size
+
+ sntp/crypto.h@1.11.1.1 +2 -1
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - decode & check hash algo only when reading the key file
+
+ sntp/main.c@1.100 +2 -3
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - use macros for key and digest size
+
+ sntp/tests/crypto.c@1.10.1.1 +13 -7
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - resolve algorithm before running MAC
+ - use strlcpy(), not memcpy() for string values
+
+ sntp/tests/keyFile.c@1.14 +3 -3
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - resolve algorithm before running MAC
+ - use strlcpy(), not memcpy() for string values
+
+ sntp/tests/packetHandling.c@1.7 +3 -2
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - resolve algorithm before running MAC
+ - use strlcpy(), not memcpy() for string values
+ - fix sizing bug
+
+ sntp/tests/packetProcessing.c@1.12.3.1 +10 -8
+ [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - resolve algorithm before running MAC
+ - use strlcpy(), not memcpy() for string values
+ - use macros for key & digest size
+
+ChangeSet@1.3720.49.1, 2017-09-05 08:40:47+02:00, perlinger@ntp.org
+ [Bug 3394] Leap second deletion does not work on ntpd clients
+
+ ChangeLog@1.1873.17.1 +4 -0
+ [Bug 3394] Leap second deletion does not work on ntpd clients
+
+ ntpd/ntp_leapsec.c@1.23 +16 -6
+ [Bug 3394] Leap second deletion does not work on ntpd clients
+ - fixed handling of dynamic deletion w/o leap file
+
+ChangeSet@1.3720.48.1, 2017-08-25 21:32:40+00:00, perlinger@ntp.org
+ [Bug 3399] NTP: linker error in 4.2.8p10 during Linux cross-compilation
+
+ ChangeLog@1.1873.16.1 +4 -0
+ [Bug 3399] NTP: linker error in 4.2.8p10 during Linux cross-compilation
+
+ sntp/harden/linux@1.2 +2 -2
+ [Bug 3399] NTP: linker error in 4.2.8p10 during Linux cross-compilation
+ - changed '-z foo' to '-Wl,-z,foo' for portability (older GCC, CLANG)
+ - '-pie' is linker flag, '-fPIE' or '-fpie' is code generation: '-pie' moved to linker flags
+
+ tests/ntpd/Makefile.am@1.31 +6 -1
+ Bug 3399 - SNTP: linker error in 4.2.8p10 during Linux cross-compilation
+ - missing forward of AM_CFLAGS for individual targets broke link
+
+ChangeSet@1.3720.47.1, 2017-08-25 21:48:38+02:00, perlinger@ntp.org
+ [Bug 2557] Thunderbolt init is wrong
+
+ ChangeLog@1.1873.15.1 +3 -0
+ [Bug 2557] Thunderbolt init is wrong
+
+ ntpd/refclock_palisade.c@1.43.1.1 +1 -1
+ [Bug 2557] Thunderbolt init is wrong
+
+ChangeSet@1.3720.46.1, 2017-08-25 07:24:59+02:00, perlinger@ntp.org
+ [Bug 3423] QNX adjtime() implementation error checking is wrong
+
+ ChangeLog@1.1873.14.1 +3 -0
+ [Bug 3423] QNX adjtime() implementation error checking is wrong
+
+ libntp/adjtime.c@1.8 +2 -2
+ [Bug 3423] QNX adjtime() implementation error checking is wrong
+
+ChangeSet@1.3720.45.1, 2017-08-25 06:15:17+02:00, perlinger@ntp.org
+ [Bug 3016] wrong error position reported for bad ":config pool"
+
+ ChangeLog@1.1873.13.1 +4 -0
+ [Bug 3016] wrong error position reported for bad ":config pool"
+
+ ntpd/ntp_scanner.c@1.51 +1 -0
+ [Bug 3016] wrong error position reported for bad ":config pool"
+ - fixed location count (get/unget imbalance)
+
+ ntpq/ntpq-subs.c@1.119.2.1 +6 -7
+ [Bug 3016] wrong error position reported for bad ":config pool"
+ - changed error indicator output
+
+ChangeSet@1.3720.44.1, 2017-08-24 20:04:12+00:00, perlinger@psp-deb1.ntp.org
+ [Bug 3424] Trimble Thunderbolt 1024 week millenium bug
+
+ ChangeLog@1.1873.12.1 +4 -0
+ [Bug 3424] Trimble Thunderbolt 1024 week millenium bug
+
+ ntpd/refclock_palisade.c@1.44 +82 -38
+ [Bug 3424] Trimble Thunderbolt 1024 week millenium bug
+ - if necessary, warp effective time stamp by GPS cycles to be on or after build date
+ - adjusted code to print/log the effective resulting date
+ - made sure the leap second check uses the adjusted dates, too
+
+ChangeSet@1.3720.43.1, 2017-08-21 19:46:03+02:00, perlinger@ntp.org
+ [Bug 3367] Faulty LinuxPPS NMEA clock support in 4.2.8
+
+ ChangeLog@1.1873.11.1 +4 -0
+ [Bug 3367] Faulty LinuxPPS NMEA clock support in 4.2.8
+
+ ntpd/ntp_refclock.c@1.123.1.1 +13 -5
+ [Bug 3367] Faulty LinuxPPS NMEA clock support in 4.2.8
+ - revert handling of 'time_pps_kcbind()' and flag3 to state of revision 1.118
+
+ChangeSet@1.3720.42.1, 2017-08-20 07:49:58+02:00, perlinger@ntp.org
+ [Bug 3398] tests fail with core dump
+
+ ChangeLog@1.1873.10.1 +4 -0
+ [Bug 3398] tests fail with core dump
+
+ sntp/tests/packetProcessing.c@1.12.2.1 +1 -1
+ [Bug 3398] tests fail with core dump
+ - use srtlcpy() to set ASCIIZ string
+
+ChangeSet@1.3720.41.1, 2017-07-23 10:53:14+02:00, perlinger@ntp.org
+ [Bug 3417] ntpq ifstats packet counters can be negative
+
+ ChangeLog@1.1873.9.1 +4 -0
+ [Bug 3417] ntpq ifstats packet counters can be negative
+
+ ntpq/ntpq-subs.c@1.119.1.1 +13 -13
+ [Bug 3417] ntpq ifstats packet counters can be negative
+ - made IFSTATS counter quantities unsigned & adjusted scan/print formats
+
+ChangeSet@1.3720.29.5, 2017-07-12 06:40:04-04:00, stenn@psp-deb2.ntp.org
+ Use strlcpy() to copy strings, not memcpy()
+
+ ChangeLog@1.1876.1.1 +1 -0
+ Use strlcpy() to copy strings, not memcpy()
+
+ sntp/tests/packetProcessing.c@1.12.1.1 +1 -1
+ Use strlcpy() to copy strings, not memcpy()
+
+ChangeSet@1.3720.40.1, 2017-07-08 00:43:56+02:00, perlinger@ntp.org
+ [Sec 3414] ntpq: decodearr() can write beyond its 'buf' limits
+
+ ChangeLog@1.1873.8.1 +4 -0
+ [Sec 3414] ntpq: decodearr() can write beyond its 'buf' limits
+
+ ntpq/ntpq.c@1.174.1.2 +62 -48
+ [Sec 3414] ntpq: decodearr() can write beyond its 'buf' limits
+ - dest-length limited copy
+ - many buggy casts in calls to CTYPE 'isfoobar()' functions
+
+ChangeSet@1.3724, 2017-07-07 02:35:10-07:00, harlan@max.pfcs.com
+ typo
+
+ ChangeLog@1.1873.7.1 +4 -2
+ typo
+
+ html/monopt.html@1.40 +2 -2
+ typo
+
+ libntp/work_thread.c@1.22 +1 -1
+ typo
+
+ ntpsnmpd/netsnmp_daemonize.c@1.6 +1 -1
+ typo
+
+ChangeSet@1.3720.39.2, 2017-07-02 09:42:42+02:00, perlinger@ntp.org
+ [Bug 3404] revert change
+
+ include/ssl_applink.c@1.6 +3 -1
+ [Bug 3404] revert change
+
+ChangeSet@1.3720.39.1, 2017-07-02 09:16:39+02:00, perlinger@ntp.org
+ [Bug 3404] Fix openSSL DLL usage under Windows
+
+ ChangeLog@1.1873.6.1 +4 -0
+ [Bug 3404] Fix openSSL DLL usage under Windows
+
+ include/ssl_applink.c@1.5 +14 -12
+ [Bug 3404] Fix openSSL DLL usage under Windows
+
+ ports/winnt/include/msvc_ssl_autolib.h@1.2 +23 -9
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - DON'T use tagged libraries by default
+
+ ports/winnt/vs2008/debug-x64.vsprops@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2008/debug.vsprops@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2008/release-x64.vsprops@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2008/release.vsprops@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2013/debug-x64.props@1.4 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2013/debug.props@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2013/release-x64.props@1.4 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2013/release.props@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2015/debug-x64.props@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2015/debug.props@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2015/release-x64.props@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ ports/winnt/vs2015/release.props@1.3 +1 -1
+ [Bug 3404] Fix openSSL DLL usage under Windows
+ - fix/drop assumptions on OpenSSL libs directory layout
+
+ChangeSet@1.3720.33.6, 2017-05-29 13:41:48-06:00, bwi@nwtime.org
+ libntp/a_md5encrypt.c(MD5authdecrypt) force AES 128 key size
+
+ libntp/a_md5encrypt.c@1.43 +1 -1
+ libntp/a_md5encrypt.c(MD5authdecrypt) force AES 128 key size
+
+ChangeSet@1.3720.33.5, 2017-05-29 19:23:32+01:00, Brian@bwinglisd.
+ libntp/a_md5encrypt.c(MD5authencrypt): force CMAC AES 128 key size
+
+ libntp/a_md5encrypt.c@1.42 +3 -2
+ libntp/a_md5encrypt.c(MD5authencrypt): force CMAC AES 128 key size
+
+ChangeSet@1.3720.33.4, 2017-05-26 19:28:01+01:00, Brian@bwinglisd.
+ libntp/a_md5encrypt.c: add AES128CMAC and better OpenSSL support,
+ libntp/authreadkeys.c: add AES128CMAC support,
+ ports/winnt/ntpd/nt_ppsimpl.c: fix environment termination
+
+ libntp/a_md5encrypt.c@1.41 +176 -13
+ add AES128CMAC and better OpenSSL support
+
+ libntp/authreadkeys.c@1.28 +2 -1
+ add AES128CMAC support
+
+ ports/winnt/ntpd/nt_ppsimpl.c@1.3 +3 -2
+ fix environment termination
+
+ChangeSet@1.3720.1.42, 2017-05-19 12:38:05+00:00, stenn@psp-deb1.ntp.org
+ autogen updates
+
+ ntpd/invoke-ntp.conf.texi@1.208 +1 -1
+ autogen updates
+
+ ntpd/invoke-ntp.keys.texi@1.197 +1 -1
+ autogen updates
+
+ ntpd/invoke-ntpd.texi@1.513 +2 -2
+ autogen updates
+
+ ntpd/ntp.conf.5man@1.242 +3 -3
+ autogen updates
+
+ ntpd/ntp.conf.5mdoc@1.242 +2 -2
+ autogen updates
+
+ ntpd/ntp.conf.html@1.193 +1 -1
+ autogen updates
+
+ ntpd/ntp.conf.man.in@1.242 +3 -3
+ autogen updates
+
+ ntpd/ntp.conf.mdoc.in@1.242 +2 -2
+ autogen updates
+
+ ntpd/ntp.keys.5man@1.231 +2 -2
+ autogen updates
+
+ ntpd/ntp.keys.5mdoc@1.231 +3 -3
+ autogen updates
+
+ ntpd/ntp.keys.html@1.194 +1 -1
+ autogen updates
+
+ ntpd/ntp.keys.man.in@1.231 +2 -2
+ autogen updates
+
+ ntpd/ntp.keys.mdoc.in@1.231 +3 -3
+ autogen updates
+
+ ntpd/ntpd-opts.c@1.535 +1 -1
+ autogen updates
+
+ ntpd/ntpd-opts.h@1.534 +1 -1
+ autogen updates
+
+ ntpd/ntpd.1ntpdman@1.342 +3 -3
+ autogen updates
+
+ ntpd/ntpd.1ntpdmdoc@1.342 +2 -2
+ autogen updates
+
+ ntpd/ntpd.html@1.187 +2 -2
+ autogen updates
+
+ ntpd/ntpd.man.in@1.342 +3 -3
+ autogen updates
+
+ ntpd/ntpd.mdoc.in@1.342 +2 -2
+ autogen updates
+
+ ntpdc/invoke-ntpdc.texi@1.510 +2 -2
+ autogen updates
+
+ ntpdc/ntpdc-opts.c@1.528 +1 -1
+ autogen updates
+
+ ntpdc/ntpdc-opts.h@1.527 +1 -1
+ autogen updates
+
+ ntpdc/ntpdc.1ntpdcman@1.341 +3 -3
+ autogen updates
+
+ ntpdc/ntpdc.1ntpdcmdoc@1.341 +2 -2
+ autogen updates
+
+ ntpdc/ntpdc.html@1.356 +2 -2
+ autogen updates
+
+ ntpdc/ntpdc.man.in@1.341 +3 -3
+ autogen updates
+
+ ntpdc/ntpdc.mdoc.in@1.341 +2 -2
+ autogen updates
+
+ ntpq/invoke-ntpq.texi@1.519 +3 -3
+ autogen updates
+
+ ntpq/ntpq-opts.c@1.536 +114 -114
+ autogen updates
+
+ ntpq/ntpq-opts.h@1.534 +3 -3
+ autogen updates
+
+ ntpq/ntpq.1ntpqman@1.347 +3 -3
+ autogen updates
+
+ ntpq/ntpq.1ntpqmdoc@1.347 +3 -3
+ autogen updates
+
+ ntpq/ntpq.html@1.184 +254 -171
+ autogen updates
+
+ ntpq/ntpq.man.in@1.347 +3 -3
+ autogen updates
+
+ ntpq/ntpq.mdoc.in@1.347 +3 -3
+ autogen updates
+
+ ntpsnmpd/invoke-ntpsnmpd.texi@1.512 +10 -11
+ autogen updates
+
+ ntpsnmpd/ntpsnmpd-opts.c@1.530 +1 -1
+ autogen updates
+
+ ntpsnmpd/ntpsnmpd-opts.h@1.529 +1 -1
+ autogen updates
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.341 +3 -3
+ autogen updates
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.341 +2 -2
+ autogen updates
+
+ ntpsnmpd/ntpsnmpd.html@1.182 +1 -1
+ autogen updates
+
+ ntpsnmpd/ntpsnmpd.man.in@1.341 +3 -3
+ autogen updates
+
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.341 +2 -2
+ autogen updates
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.102 +3 -3
+ autogen updates
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.103 +2 -2
+ autogen updates
+
+ scripts/calc_tickadj/calc_tickadj.html@1.104 +33 -21
+ autogen updates
+
+ scripts/calc_tickadj/calc_tickadj.man.in@1.101 +3 -3
+ autogen updates
+
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.103 +2 -2
+ autogen updates
+
+ scripts/calc_tickadj/invoke-calc_tickadj.texi@1.106 +1 -1
+ autogen updates
+
+ scripts/invoke-plot_summary.texi@1.124 +1 -1
+ autogen updates
+
+ scripts/invoke-summary.texi@1.123 +1 -1
+ autogen updates
+
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.333 +1 -1
+ autogen updates
+
+ scripts/ntp-wait/ntp-wait-opts@1.69 +1 -1
+ autogen updates
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.330 +3 -3
+ autogen updates
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.331 +2 -2
+ autogen updates
+
+ scripts/ntp-wait/ntp-wait.html@1.352 +2 -2
+ autogen updates
+
+ scripts/ntp-wait/ntp-wait.man.in@1.330 +3 -3
+ autogen updates
+
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.331 +2 -2
+ autogen updates
+
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.121 +1 -1
+ autogen updates
+
+ scripts/ntpsweep/ntpsweep-opts@1.71 +1 -1
+ autogen updates
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.109 +3 -3
+ autogen updates
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.109 +2 -2
+ autogen updates
+
+ scripts/ntpsweep/ntpsweep.html@1.124 +2 -2
+ autogen updates
+
+ scripts/ntpsweep/ntpsweep.man.in@1.109 +3 -3
+ autogen updates
+
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.110 +2 -2
+ autogen updates
+
+ scripts/ntptrace/invoke-ntptrace.texi@1.122 +1 -1
+ autogen updates
+
+ scripts/ntptrace/ntptrace-opts@1.71 +1 -1
+ autogen updates
+
+ scripts/ntptrace/ntptrace.1ntptraceman@1.109 +3 -3
+ autogen updates
+
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.110 +2 -2
+ autogen updates
+
+ scripts/ntptrace/ntptrace.html@1.125 +2 -2
+ autogen updates
+
+ scripts/ntptrace/ntptrace.man.in@1.109 +3 -3
+ autogen updates
+
+ scripts/ntptrace/ntptrace.mdoc.in@1.111 +2 -2
+ autogen updates
+
+ scripts/plot_summary-opts@1.72 +1 -1
+ autogen updates
+
+ scripts/plot_summary.1plot_summaryman@1.122 +3 -3
+ autogen updates
+
+ scripts/plot_summary.1plot_summarymdoc@1.122 +2 -2
+ autogen updates
+
+ scripts/plot_summary.html@1.127 +2 -2
+ autogen updates
+
+ scripts/plot_summary.man.in@1.122 +3 -3
+ autogen updates
+
+ scripts/plot_summary.mdoc.in@1.122 +2 -2
+ autogen updates
+
+ scripts/summary-opts@1.71 +1 -1
+ autogen updates
+
+ scripts/summary.1summaryman@1.121 +3 -3
+ autogen updates
+
+ scripts/summary.1summarymdoc@1.121 +2 -2
+ autogen updates
+
+ scripts/summary.html@1.126 +2 -2
+ autogen updates
+
+ scripts/summary.man.in@1.121 +3 -3
+ autogen updates
+
+ scripts/summary.mdoc.in@1.121 +2 -2
+ autogen updates
+
+ scripts/update-leap/invoke-update-leap.texi@1.22 +1 -1
+ autogen updates
+
+ scripts/update-leap/update-leap-opts@1.22 +1 -1
+ autogen updates
+
+ scripts/update-leap/update-leap.1update-leapman@1.22 +3 -3
+ autogen updates
+
+ scripts/update-leap/update-leap.1update-leapmdoc@1.22 +2 -2
+ autogen updates
+
+ scripts/update-leap/update-leap.html@1.23 +1 -1
+ autogen updates
+
+ scripts/update-leap/update-leap.man.in@1.22 +3 -3
+ autogen updates
+
+ scripts/update-leap/update-leap.mdoc.in@1.22 +2 -2
+ autogen updates
+
+ sntp/invoke-sntp.texi@1.510 +1 -1
+ autogen updates
+
+ sntp/sntp-opts.c@1.529 +1 -1
+ autogen updates
+
+ sntp/sntp-opts.h@1.527 +1 -1
+ autogen updates
+
+ sntp/sntp.1sntpman@1.345 +3 -3
+ autogen updates
+
+ sntp/sntp.1sntpmdoc@1.345 +2 -2
+ autogen updates
+
+ sntp/sntp.html@1.527 +2 -2
+ autogen updates
+
+ sntp/sntp.man.in@1.345 +3 -3
+ autogen updates
+
+ sntp/sntp.mdoc.in@1.345 +2 -2
+ autogen updates
+
+ util/invoke-ntp-keygen.texi@1.514 +2 -2
+ autogen updates
+
+ util/ntp-keygen-opts.c@1.532 +173 -173
+ autogen updates
+
+ util/ntp-keygen-opts.h@1.530 +3 -3
+ autogen updates
+
+ util/ntp-keygen.1ntp-keygenman@1.342 +2 -2
+ autogen updates
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.342 +2 -2
+ autogen updates
+
+ util/ntp-keygen.html@1.188 +608 -448
+ autogen updates
+
+ util/ntp-keygen.man.in@1.342 +2 -2
+ autogen updates
+
+ util/ntp-keygen.mdoc.in@1.342 +2 -2
+ autogen updates
+
+ChangeSet@1.3720.38.1, 2017-05-07 02:38:45+00:00, abe@psp-deb1.ntp.org
+ refclock_jjy.c, ChangeLog:
+ [Bug 3408] refclock_jjy.c : Avoid a wrong report of the coverity static analysis tool.
+
+ ChangeLog@1.1873.5.1 +3 -0
+ [Bug 3408] refclock_jjy.c : Avoid a wrong report of the coverity static analysis tool.
+
+ ntpd/refclock_jjy.c@1.35 +24 -4
+ [Bug 3408] refclock_jjy.c : Avoid a wrong report of the coverity static analysis tool.
+
+ChangeSet@1.3720.37.1, 2017-05-01 07:36:51+02:00, perlinger@ntp.org
+ [Bug 3397] ctl_putstr() asserts that data fits in its buffer
+
+ ChangeLog@1.1873.4.1 +5 -0
+ [Bug 3397] ctl_putstr() asserts that data fits in its buffer
+
+ ntpd/ntp_control.c@1.220 +131 -102
+ [Bug 3397] ctl_putstr() asserts that data fits in its buffer
+ rework of formatting & data transfer stuff in 'ntp_control.c'
+ avoids unecessary buffers and size limitations.
+
+ChangeSet@1.3720.1.39, 2017-03-28 02:51:14+00:00, stenn@psp-deb1.ntp.org
+ Note in the ChangeLog that this repo contains the AES-128-CMAC work
+
+ ChangeLog@1.1873.3.1 +4 -0
+ Note in the ChangeLog that this repo contains the AES-128-CMAC work
+
+ChangeSet@1.3720.36.1, 2017-03-27 08:33:02+02:00, perlinger@ntp.org
+ [Bug 3391] ntpd segfaults on startup due to small warmup thread stack size
+
+ ChangeLog@1.1873.2.1 +4 -0
+ [Bug 3391] ntpd segfaults on startup due to small warmup thread stack size
+
+ ntpd/ntpd.c@1.173 +10 -5
+ [Bug 3391] ntpd segfaults on startup due to small warmup thread stack size
+ - increased mimimum stack size to 32kB
+
+ChangeSet@1.3720.31.11, 2017-03-23 07:36:54+00:00, stenn@psp-deb1.ntp.org
+ cleanup
+
+ ChangeLog@1.1873.1.5 +1 -2
+ cleanup
+
+ChangeSet@1.3720.29.2, 2017-03-23 05:45:08+00:00, stenn@psp-deb1.ntp.org
+ [Bug 3358] Spurious KoD log messages in .INIT. phase
+
+ ntpd/ntp_proto.c@1.404 +8 -6
+ [Bug 3358] Spurious KoD log messages in .INIT. phase
+
+ChangeSet@1.3720.31.10, 2017-03-21 11:01:54-04:00, stenn@deacon.udel.edu
+ NTP_4_2_8P10
+ TAG: NTP_4_2_8P10
+
+ ntpd/invoke-ntp.conf.texi@1.205.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/invoke-ntp.keys.texi@1.194.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/invoke-ntpd.texi@1.510.1.2 +17 -22
+ NTP_4_2_8P10
+
+ ntpd/ntp.conf.5man@1.239.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpd/ntp.conf.5mdoc@1.239.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/ntp.conf.html@1.189.2.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/ntp.conf.man.in@1.239.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpd/ntp.conf.mdoc.in@1.239.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/ntp.keys.5man@1.228.1.2 +2 -2
+ NTP_4_2_8P10
+
+ ntpd/ntp.keys.5mdoc@1.228.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/ntp.keys.html@1.190.2.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/ntp.keys.man.in@1.228.1.2 +2 -2
+ NTP_4_2_8P10
+
+ ntpd/ntp.keys.mdoc.in@1.228.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/ntpd-opts.c@1.532.1.2 +245 -245
+ NTP_4_2_8P10
+
+ ntpd/ntpd-opts.h@1.531.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpd/ntpd.1ntpdman@1.339.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpd/ntpd.1ntpdmdoc@1.339.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpd/ntpd.html@1.183.2.2 +2 -2
+ NTP_4_2_8P10
+
+ ntpd/ntpd.man.in@1.339.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpd/ntpd.mdoc.in@1.339.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpdc/invoke-ntpdc.texi@1.507.1.2 +16 -22
+ NTP_4_2_8P10
+
+ ntpdc/ntpdc-opts.c@1.525.1.2 +107 -107
+ NTP_4_2_8P10
+
+ ntpdc/ntpdc-opts.h@1.524.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpdc/ntpdc.1ntpdcman@1.338.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpdc/ntpdc.1ntpdcmdoc@1.338.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpdc/ntpdc.html@1.352.2.2 +16 -22
+ NTP_4_2_8P10
+
+ ntpdc/ntpdc.man.in@1.338.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpdc/ntpdc.mdoc.in@1.338.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpq/invoke-ntpq.texi@1.515.2.2 +21 -18
+ NTP_4_2_8P10
+
+ ntpq/ntpq-opts.c@1.532.2.2 +114 -114
+ NTP_4_2_8P10
+
+ ntpq/ntpq-opts.h@1.530.2.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpq/ntpq.1ntpqman@1.343.2.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpq/ntpq.1ntpqmdoc@1.343.2.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpq/ntpq.html@1.180.2.2 +2 -2
+ NTP_4_2_8P10
+
+ ntpq/ntpq.man.in@1.343.2.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpq/ntpq.mdoc.in@1.343.2.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpsnmpd/invoke-ntpsnmpd.texi@1.511 +1 -1
+ NTP_4_2_8P10
+
+ ntpsnmpd/ntpsnmpd-opts.c@1.529 +68 -68
+ NTP_4_2_8P10
+
+ ntpsnmpd/ntpsnmpd-opts.h@1.528 +3 -3
+ NTP_4_2_8P10
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.338.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.338.1.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpsnmpd/ntpsnmpd.html@1.178.2.2 +1 -1
+ NTP_4_2_8P10
+
+ ntpsnmpd/ntpsnmpd.man.in@1.338.1.2 +3 -3
+ NTP_4_2_8P10
+
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.338.1.2 +1 -1
+ NTP_4_2_8P10
+
+ packageinfo.sh@1.534.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.99.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.100.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/calc_tickadj/calc_tickadj.html@1.101.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/calc_tickadj/calc_tickadj.man.in@1.98.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.100.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/calc_tickadj/invoke-calc_tickadj.texi@1.105 +1 -1
+ NTP_4_2_8P10
+
+ scripts/invoke-plot_summary.texi@1.121.1.2 +74 -56
+ NTP_4_2_8P10
+
+ scripts/invoke-summary.texi@1.120.1.2 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.330.1.2 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntp-wait/ntp-wait-opts@1.68 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.327.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.328.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/ntp-wait/ntp-wait.html@1.348.2.2 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntp-wait/ntp-wait.man.in@1.327.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.328.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.118.1.2 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntpsweep/ntpsweep-opts@1.70 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.106.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.106.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/ntpsweep/ntpsweep.html@1.120.2.2 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntpsweep/ntpsweep.man.in@1.106.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.107.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/ntptrace/invoke-ntptrace.texi@1.119.1.2 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntptrace/ntptrace-opts@1.70 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntptrace/ntptrace.1ntptraceman@1.106.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.107.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/ntptrace/ntptrace.html@1.121.2.2 +2 -2
+ NTP_4_2_8P10
+
+ scripts/ntptrace/ntptrace.man.in@1.106.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/ntptrace/ntptrace.mdoc.in@1.108.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/plot_summary-opts@1.71 +2 -2
+ NTP_4_2_8P10
+
+ scripts/plot_summary.1plot_summaryman@1.119.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/plot_summary.1plot_summarymdoc@1.119.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/plot_summary.html@1.123.2.2 +87 -61
+ NTP_4_2_8P10
+
+ scripts/plot_summary.man.in@1.119.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/plot_summary.mdoc.in@1.119.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/summary-opts@1.70 +2 -2
+ NTP_4_2_8P10
+
+ scripts/summary.1summaryman@1.118.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/summary.1summarymdoc@1.118.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/summary.html@1.122.2.2 +2 -2
+ NTP_4_2_8P10
+
+ scripts/summary.man.in@1.118.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/summary.mdoc.in@1.118.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/update-leap/invoke-update-leap.texi@1.21 +1 -1
+ NTP_4_2_8P10
+
+ scripts/update-leap/update-leap-opts@1.21 +2 -2
+ NTP_4_2_8P10
+
+ scripts/update-leap/update-leap.1update-leapman@1.19.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/update-leap/update-leap.1update-leapmdoc@1.19.1.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/update-leap/update-leap.html@1.19.2.2 +1 -1
+ NTP_4_2_8P10
+
+ scripts/update-leap/update-leap.man.in@1.19.1.2 +3 -3
+ NTP_4_2_8P10
+
+ scripts/update-leap/update-leap.mdoc.in@1.19.1.2 +1 -1
+ NTP_4_2_8P10
+
+ sntp/invoke-sntp.texi@1.509 +23 -27
+ NTP_4_2_8P10
+
+ sntp/sntp-opts.c@1.528 +159 -159
+ NTP_4_2_8P10
+
+ sntp/sntp-opts.h@1.526 +3 -3
+ NTP_4_2_8P10
+
+ sntp/sntp.1sntpman@1.342.1.2 +3 -3
+ NTP_4_2_8P10
+
+ sntp/sntp.1sntpmdoc@1.342.1.2 +1 -1
+ NTP_4_2_8P10
+
+ sntp/sntp.html@1.523.2.2 +23 -27
+ NTP_4_2_8P10
+
+ sntp/sntp.man.in@1.342.1.2 +3 -3
+ NTP_4_2_8P10
+
+ sntp/sntp.mdoc.in@1.342.1.2 +1 -1
+ NTP_4_2_8P10
+
+ util/invoke-ntp-keygen.texi@1.510.2.2 +17 -15
+ NTP_4_2_8P10
+
+ util/ntp-keygen-opts.c@1.528.2.2 +173 -173
+ NTP_4_2_8P10
+
+ util/ntp-keygen-opts.h@1.526.2.2 +3 -3
+ NTP_4_2_8P10
+
+ util/ntp-keygen.1ntp-keygenman@1.338.2.2 +3 -3
+ NTP_4_2_8P10
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.338.2.2 +1 -1
+ NTP_4_2_8P10
+
+ util/ntp-keygen.html@1.184.2.2 +2 -2
+ NTP_4_2_8P10
+
+ util/ntp-keygen.man.in@1.338.2.2 +3 -3
+ NTP_4_2_8P10
+
+ util/ntp-keygen.mdoc.in@1.338.2.2 +1 -1
+ NTP_4_2_8P10
+
+ChangeSet@1.3720.31.9, 2017-03-21 09:40:52-04:00, stenn@deacon.udel.edu
+ NTP_4_2_8P10_WIN_BETA1
+ TAG: NTP_4_2_8P10_WIN_BETA1
+
+ ChangeLog@1.1873.1.4 +1 -0
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/invoke-ntp.conf.texi@1.205.1.1 +1 -1
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/invoke-ntp.keys.texi@1.194.1.1 +1 -1
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/invoke-ntpd.texi@1.510.1.1 +22 -17
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.conf.5man@1.239.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.conf.5mdoc@1.239.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.conf.html@1.189.2.1 +1192 -1541
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.conf.man.in@1.239.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.conf.mdoc.in@1.239.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.keys.5man@1.228.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.keys.5mdoc@1.228.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.keys.html@1.190.2.1 +115 -162
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.keys.man.in@1.228.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntp.keys.mdoc.in@1.228.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntpd-opts.c@1.532.1.1 +245 -245
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntpd-opts.h@1.531.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntpd.1ntpdman@1.339.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntpd.1ntpdmdoc@1.339.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntpd.html@1.183.2.1 +677 -752
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntpd.man.in@1.339.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpd/ntpd.mdoc.in@1.339.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpdc/invoke-ntpdc.texi@1.507.1.1 +22 -16
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpdc/ntpdc-opts.c@1.525.1.1 +107 -107
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpdc/ntpdc-opts.h@1.524.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpdc/ntpdc.1ntpdcman@1.338.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpdc/ntpdc.1ntpdcmdoc@1.338.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpdc/ntpdc.html@1.352.2.1 +371 -434
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpdc/ntpdc.man.in@1.338.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpdc/ntpdc.mdoc.in@1.338.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpq/invoke-ntpq.texi@1.515.2.1 +18 -21
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpq/ntpq-opts.c@1.532.2.1 +114 -114
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpq/ntpq-opts.h@1.530.2.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpq/ntpq.1ntpqman@1.343.2.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpq/ntpq.1ntpqmdoc@1.343.2.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpq/ntpq.html@1.180.2.1 +1283 -1438
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpq/ntpq.man.in@1.343.2.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpq/ntpq.mdoc.in@1.343.2.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpsnmpd/invoke-ntpsnmpd.texi@1.510 +11 -10
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpsnmpd/ntpsnmpd-opts.c@1.528 +68 -68
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpsnmpd/ntpsnmpd-opts.h@1.527 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.338.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.338.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpsnmpd/ntpsnmpd.html@1.178.2.1 +59 -92
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpsnmpd/ntpsnmpd.man.in@1.338.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.338.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ packageinfo.sh@1.534.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.99.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.100.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/calc_tickadj/calc_tickadj.html@1.101.1.1 +22 -34
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/calc_tickadj/calc_tickadj.man.in@1.98.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.100.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/calc_tickadj/invoke-calc_tickadj.texi@1.104 +1 -1
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/invoke-plot_summary.texi@1.121.1.1 +56 -74
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/invoke-summary.texi@1.120.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.330.1.1 +1 -1
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntp-wait/ntp-wait-opts@1.67 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.327.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.328.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntp-wait/ntp-wait.html@1.348.2.1 +141 -189
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntp-wait/ntp-wait.man.in@1.327.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.328.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.118.1.1 +1 -1
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntpsweep/ntpsweep-opts@1.69 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.106.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.106.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntpsweep/ntpsweep.html@1.120.2.1 +148 -196
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntpsweep/ntpsweep.man.in@1.106.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.107.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntptrace/invoke-ntptrace.texi@1.119.1.1 +1 -1
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntptrace/ntptrace-opts@1.69 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntptrace/ntptrace.1ntptraceman@1.106.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.107.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntptrace/ntptrace.html@1.121.2.1 +126 -175
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntptrace/ntptrace.man.in@1.106.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/ntptrace/ntptrace.mdoc.in@1.108.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/plot_summary-opts@1.70 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/plot_summary.1plot_summaryman@1.119.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/plot_summary.1plot_summarymdoc@1.119.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/plot_summary.html@1.123.2.1 +139 -211
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/plot_summary.man.in@1.119.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/plot_summary.mdoc.in@1.119.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/summary-opts@1.69 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/summary.1summaryman@1.118.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/summary.1summarymdoc@1.118.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/summary.html@1.122.2.1 +132 -180
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/summary.man.in@1.118.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/summary.mdoc.in@1.118.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/update-leap/invoke-update-leap.texi@1.20 +1 -1
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/update-leap/update-leap-opts@1.20 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/update-leap/update-leap.1update-leapman@1.19.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/update-leap/update-leap.1update-leapmdoc@1.19.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/update-leap/update-leap.html@1.19.2.1 +199 -247
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/update-leap/update-leap.man.in@1.19.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ scripts/update-leap/update-leap.mdoc.in@1.19.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ sntp/invoke-sntp.texi@1.508 +27 -23
+ NTP_4_2_8P10_WIN_BETA1
+
+ sntp/sntp-opts.c@1.527 +159 -159
+ NTP_4_2_8P10_WIN_BETA1
+
+ sntp/sntp-opts.h@1.525 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ sntp/sntp.1sntpman@1.342.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ sntp/sntp.1sntpmdoc@1.342.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ sntp/sntp.html@1.523.2.1 +441 -509
+ NTP_4_2_8P10_WIN_BETA1
+
+ sntp/sntp.man.in@1.342.1.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ sntp/sntp.mdoc.in@1.342.1.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ util/invoke-ntp-keygen.texi@1.510.2.1 +15 -17
+ NTP_4_2_8P10_WIN_BETA1
+
+ util/ntp-keygen-opts.c@1.528.2.1 +173 -173
+ NTP_4_2_8P10_WIN_BETA1
+
+ util/ntp-keygen-opts.h@1.526.2.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ util/ntp-keygen.1ntp-keygenman@1.338.2.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.338.2.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ util/ntp-keygen.html@1.184.2.1 +1006 -1082
+ NTP_4_2_8P10_WIN_BETA1
+
+ util/ntp-keygen.man.in@1.338.2.1 +3 -3
+ NTP_4_2_8P10_WIN_BETA1
+
+ util/ntp-keygen.mdoc.in@1.338.2.1 +2 -2
+ NTP_4_2_8P10_WIN_BETA1
+
+ChangeSet@1.3720.31.8, 2017-03-21 07:11:32-04:00, stenn@deacon.udel.edu
+ Disable some triggers for now
+
+ BitKeeper/triggers/2mirrors@1.10 +3 -0
+ Disable some triggers for now
+
+ BitKeeper/triggers/trigger.cfg@1.15 +3 -2
+ Disable some triggers for now
+
+ChangeSet@1.3720.35.2, 2017-03-21 06:34:14-04:00, stenn@deacon.udel.edu
+ bk hostname cleanup for bk7
+
+ BitKeeper/triggers/paranoid@1.5 +1 -1
+ bk hostname cleanup for bk7
+
+ChangeSet@1.3720.31.6, 2017-03-21 05:51:48-04:00, stenn@psp-deb2.ntp.org
+ Updated NEWS for p9-win
+
+ NEWS@1.177.1.30 +10 -0
+ Updated NEWS for p9-win
+
+ChangeSet@1.3720.31.4, 2017-03-21 08:39:07+00:00, stenn@psp-deb1.ntp.org
+ Bug 3393 is a normal bug
+
+ ChangeLog@1.1873.1.1 +1 -1
+ Bug 3393 is a normal bug
+
+ChangeSet@1.3720.34.2, 2017-03-21 04:19:53-04:00, stenn@deacon.udel.edu
+ bk-7 trigger updates
+
+ BitKeeper/triggers/send@1.16.1.1 +2 -2
+ bk-7 trigger updates
+
+ ChangeLog@1.1853.11.2 +4 -0
+ bk-7 trigger updates
+
+ChangeSet@1.3720.34.1, 2017-03-21 04:06:39-04:00, stenn@deacon.udel.edu
+ cleanup
+
+ ChangeLog@1.1853.11.1 +0 -2
+ cleanup
+
+ChangeSet@1.3720.33.3, 2017-03-20 17:07:56+00:00, bwi@psp-deb1.ntp.org
+ Checkin Autogen-ed docs
+
+ ntpq/invoke-ntpq.texi@1.515.1.2 +2 -2
+ Checkin Autogen-ed docs
+
+ ntpq/ntpq-opts.c@1.532.1.2 +1 -1
+ Checkin Autogen-ed docs
+
+ ntpq/ntpq-opts.h@1.530.1.1 +1 -1
+ Checkin Autogen-ed docs
+
+ ntpq/ntpq.1ntpqman@1.343.1.2 +3 -3
+ Checkin Autogen-ed docs
+
+ ntpq/ntpq.1ntpqmdoc@1.343.1.2 +3 -3
+ Checkin Autogen-ed docs
+
+ ntpq/ntpq.man.in@1.343.1.2 +3 -3
+ Checkin Autogen-ed docs
+
+ ntpq/ntpq.mdoc.in@1.343.1.2 +3 -3
+ Checkin Autogen-ed docs
+
+ scripts/invoke-plot_summary.texi@1.122 +1 -1
+ Checkin Autogen-ed docs
+
+ scripts/invoke-summary.texi@1.121 +1 -1
+ Checkin Autogen-ed docs
+
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.331 +1 -1
+ Checkin Autogen-ed docs
+
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.119 +1 -1
+ Checkin Autogen-ed docs
+
+ scripts/ntptrace/invoke-ntptrace.texi@1.120 +1 -1
+ Checkin Autogen-ed docs
+
+ChangeSet@1.3720.33.2, 2017-03-20 17:38:08+01:00, bwi@nwtime.org
+ ntpq/ntpq-opts.def(addvars): add missing Oc to match Oo
+
+ ntpq/ntpq-opts.def@1.31 +1 -1
+ ntpq/ntpq-opts.def(addvars): add missing Oc to match Oo
+
+ChangeSet@1.3720.33.1, 2017-03-20 16:25:04+00:00, bwi@psp-deb1.ntp.org
+ Checkin Autogen-ed docs and sources
+
+ ntpd/invoke-ntp.conf.texi@1.206 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ ntpd/invoke-ntp.keys.texi@1.195 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ ntpd/invoke-ntpd.texi@1.511 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.conf.5man@1.240 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.conf.5mdoc@1.240 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.conf.html@1.189.1.1 +1193 -1529
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.conf.man.in@1.240 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.conf.mdoc.in@1.240 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.keys.5man@1.229 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.keys.5mdoc@1.229 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.keys.html@1.190.1.1 +123 -158
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.keys.man.in@1.229 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntp.keys.mdoc.in@1.229 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntpd-opts.c@1.533 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntpd-opts.h@1.532 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntpd.1ntpdman@1.340 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntpd.1ntpdmdoc@1.340 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntpd.html@1.183.1.1 +681 -712
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntpd.man.in@1.340 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpd/ntpd.mdoc.in@1.340 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpdc/invoke-ntpdc.texi@1.508 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ ntpdc/ntpdc-opts.c@1.526 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ ntpdc/ntpdc-opts.h@1.525 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ ntpdc/ntpdc.1ntpdcman@1.339 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpdc/ntpdc.1ntpdcmdoc@1.339 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpdc/ntpdc.html@1.352.1.1 +354 -403
+ Checkin Autogen-ed docs and sources
+
+ ntpdc/ntpdc.man.in@1.339 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpdc/ntpdc.mdoc.in@1.339 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpq/invoke-ntpq.texi@1.515.1.1 +296 -202
+ Checkin Autogen-ed docs and sources
+
+ ntpq/ntpq-opts.c@1.532.1.1 +109 -109
+ Checkin Autogen-ed docs and sources
+
+ ntpq/ntpq.1ntpqman@1.343.1.1 +394 -250
+ Checkin Autogen-ed docs and sources
+
+ ntpq/ntpq.1ntpqmdoc@1.343.1.1 +399 -330
+ Checkin Autogen-ed docs and sources
+
+ ntpq/ntpq.html@1.180.1.1 +1425 -1475
+ Checkin Autogen-ed docs and sources
+
+ ntpq/ntpq.man.in@1.343.1.1 +394 -250
+ Checkin Autogen-ed docs and sources
+
+ ntpq/ntpq.mdoc.in@1.343.1.1 +399 -330
+ Checkin Autogen-ed docs and sources
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.339 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.339 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpsnmpd/ntpsnmpd.html@1.178.1.1 +61 -90
+ Checkin Autogen-ed docs and sources
+
+ ntpsnmpd/ntpsnmpd.man.in@1.339 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.339 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.100 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.101 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/calc_tickadj/calc_tickadj.html@1.102 +1 -1
+ Checkin Autogen-ed docs and sources
+
+ scripts/calc_tickadj/calc_tickadj.man.in@1.99 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.101 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.328 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.329 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntp-wait/ntp-wait.html@1.348.1.1 +151 -181
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntp-wait/ntp-wait.man.in@1.328 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.329 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.107 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.107 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntpsweep/ntpsweep.html@1.120.1.1 +151 -188
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntpsweep/ntpsweep.man.in@1.107 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.108 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntptrace/ntptrace.1ntptraceman@1.107 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.108 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntptrace/ntptrace.html@1.121.1.1 +128 -168
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntptrace/ntptrace.man.in@1.107 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/ntptrace/ntptrace.mdoc.in@1.109 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/plot_summary.1plot_summaryman@1.120 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/plot_summary.1plot_summarymdoc@1.120 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/plot_summary.html@1.123.1.1 +160 -188
+ Checkin Autogen-ed docs and sources
+
+ scripts/plot_summary.man.in@1.120 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/plot_summary.mdoc.in@1.120 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/summary.1summaryman@1.119 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/summary.1summarymdoc@1.119 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/summary.html@1.122.1.1 +135 -171
+ Checkin Autogen-ed docs and sources
+
+ scripts/summary.man.in@1.119 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/summary.mdoc.in@1.119 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/update-leap/update-leap.1update-leapman@1.20 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/update-leap/update-leap.1update-leapmdoc@1.20 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/update-leap/update-leap.html@1.19.1.1 +212 -236
+ Checkin Autogen-ed docs and sources
+
+ scripts/update-leap/update-leap.man.in@1.20 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ scripts/update-leap/update-leap.mdoc.in@1.20 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ sntp/sntp.1sntpman@1.343 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ sntp/sntp.1sntpmdoc@1.343 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ sntp/sntp.html@1.523.1.1 +419 -467
+ Checkin Autogen-ed docs and sources
+
+ sntp/sntp.man.in@1.343 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ sntp/sntp.mdoc.in@1.343 +2 -2
+ Checkin Autogen-ed docs and sources
+
+ util/invoke-ntp-keygen.texi@1.510.1.1 +597 -426
+ Checkin Autogen-ed docs and sources
+
+ util/ntp-keygen-opts.c@1.528.1.1 +155 -154
+ Checkin Autogen-ed docs and sources
+
+ util/ntp-keygen-opts.h@1.526.1.1 +17 -17
+ Checkin Autogen-ed docs and sources
+
+ util/ntp-keygen.1ntp-keygenman@1.338.1.1 +591 -440
+ Checkin Autogen-ed docs and sources
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.338.1.1 +570 -418
+ Checkin Autogen-ed docs and sources
+
+ util/ntp-keygen.html@1.184.1.1 +1414 -1271
+ Checkin Autogen-ed docs and sources
+
+ util/ntp-keygen.man.in@1.338.1.1 +591 -440
+ Checkin Autogen-ed docs and sources
+
+ util/ntp-keygen.mdoc.in@1.338.1.1 +570 -418
+ Checkin Autogen-ed docs and sources
+
+ChangeSet@1.3720.1.38, 2017-03-19 10:13:40+00:00, stenn@psp-deb1.ntp.org
+ AES-128-CMAC autogen updates
+
+ ntpd/ntp.conf.html@1.190 +1193 -1529
+ AES-128-CMAC autogen updates
+
+ ntpd/ntp.keys.html@1.191 +123 -158
+ AES-128-CMAC autogen updates
+
+ ntpd/ntpd.html@1.184 +681 -712
+ AES-128-CMAC autogen updates
+
+ ntpdc/ntpdc.html@1.353 +354 -403
+ AES-128-CMAC autogen updates
+
+ ntpq/invoke-ntpq.texi@1.516 +296 -202
+ AES-128-CMAC autogen updates
+
+ ntpq/ntpq-opts.c@1.533 +109 -109
+ AES-128-CMAC autogen updates
+
+ ntpq/ntpq-opts.h@1.531 +1 -1
+ AES-128-CMAC autogen updates
+
+ ntpq/ntpq.1ntpqman@1.344 +394 -250
+ AES-128-CMAC autogen updates
+
+ ntpq/ntpq.1ntpqmdoc@1.344 +399 -330
+ AES-128-CMAC autogen updates
+
+ ntpq/ntpq.html@1.181 +1281 -1412
+ AES-128-CMAC autogen updates
+
+ ntpq/ntpq.man.in@1.344 +394 -250
+ AES-128-CMAC autogen updates
+
+ ntpq/ntpq.mdoc.in@1.344 +399 -330
+ AES-128-CMAC autogen updates
+
+ ntpsnmpd/ntpsnmpd.html@1.179 +61 -90
+ AES-128-CMAC autogen updates
+
+ scripts/ntp-wait/ntp-wait.html@1.349 +151 -181
+ AES-128-CMAC autogen updates
+
+ scripts/ntpsweep/ntpsweep.html@1.121 +151 -188
+ AES-128-CMAC autogen updates
+
+ scripts/ntptrace/ntptrace.html@1.122 +128 -168
+ AES-128-CMAC autogen updates
+
+ scripts/plot_summary.html@1.124 +160 -188
+ AES-128-CMAC autogen updates
+
+ scripts/summary.html@1.123 +135 -171
+ AES-128-CMAC autogen updates
+
+ scripts/update-leap/update-leap.html@1.20 +212 -236
+ AES-128-CMAC autogen updates
+
+ sntp/sntp.html@1.524 +419 -467
+ AES-128-CMAC autogen updates
+
+ util/invoke-ntp-keygen.texi@1.511 +597 -426
+ AES-128-CMAC autogen updates
+
+ util/ntp-keygen-opts.c@1.529 +155 -154
+ AES-128-CMAC autogen updates
+
+ util/ntp-keygen-opts.h@1.527 +17 -17
+ AES-128-CMAC autogen updates
+
+ util/ntp-keygen.1ntp-keygenman@1.339 +591 -440
+ AES-128-CMAC autogen updates
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.339 +570 -418
+ AES-128-CMAC autogen updates
+
+ util/ntp-keygen.html@1.185 +1031 -1048
+ AES-128-CMAC autogen updates
+
+ util/ntp-keygen.man.in@1.339 +591 -440
+ AES-128-CMAC autogen updates
+
+ util/ntp-keygen.mdoc.in@1.339 +570 -418
+ AES-128-CMAC autogen updates
+
+ChangeSet@1.3720.1.37, 2017-03-19 06:23:57+01:00, bwi@nwtime.org
+ ntpq/ntpq-opts.def name resolution need not involve DNS, replace command_keyword with command and optionally add name, \& quote recommended operators, change clearlist to clearvars, add Ns macros around |, reset some option strings to No;
+ ntpq/ntpq-subs.c(doprintpeers) space over on next line allowing for host + sp if > 1 host and regular tally + source + sp if wide output and long source name
+
+ ntpq/ntpq-opts.def@1.30 +49 -49
+ name resolution need not involve DNS, replace command_keyword with command and optionally add name, \& quote recommended operators, change clearlist to clearvars, add Ns macros around |, reset some option strings to No,
+
+ ntpq/ntpq-subs.c@1.120 +5 -1
+ space over on next line allowing for host + sp if > 1 host and regular tally + source + sp if wide output and long source name
+
+ChangeSet@1.3720.31.3, 2017-03-16 07:48:09+00:00, stenn@psp-deb1.ntp.org
+ Updates
+
+ NEWS@1.177.1.29 +24 -25
+ Updates
+
+ChangeSet@1.3720.1.36, 2017-03-14 22:06:13+01:00, bwi@nwtime.org
+ ntpq/ntpq-opts.def restore Ba to | as unsupported by mdoc; util/ntp-keygen-opts.def restore Ba to | as unsupported by mdoc and backslash escape ` to try to avoid build errors
+
+ ntpq/ntpq-opts.def@1.29 +11 -11
+ restore Ba to | as unsupported by mdoc
+
+ util/ntp-keygen-opts.def@1.31 +5 -5
+ restore Ba to | as unsupported by mdoc and backslash escape ` to try to avoid build errors
+
+ChangeSet@1.3720.1.35, 2017-03-14 06:58:02+01:00, bwi@nwtime.org
+ packageinfo.sh comment out special win, util/ntp-keygen-opts.def quote @ { } with prefix @ for texinfo
+
+ packageinfo.sh@1.535 +1 -1
+ comment out special win
+
+ util/ntp-keygen-opts.def@1.30 +12 -12
+ quote @ { } with prefix @ for texinfo
+
+ChangeSet@1.3720.1.34, 2017-03-13 23:19:02+01:00, bwi@nwtime.org
+ clean up ntpq/ntpq-opts.def and util/ntp-keygen-opts.def:
+ reconcile internally, with implementation, and updates to generated files;
+ make markup and wording consistent and clearer
+
+ ntpq/ntpq-opts.def@1.28 +385 -325
+ remove old RFC ref, NTPv4 differences, some refs to messages as mode 6 and control, deprecation of man page;
+ add missing commands (including poll as it is visible in help), variables, statistics, and counters;
+ made optional arguments so;
+ say what happens with no arguments;
+ say when clients are shown with peers;
+ say what counters or statistics are shown in display commands;
+ say display instead of print, read, show;
+ word like help where better;
+ reorder commands listed out of alphabetic order without any grouping;
+ Xr commands in section 1 not functions in section 3 as devel docs may not be installed;
+ ID lowercased to not look like acronym or shout;
+ add \& as recommended;
+ commands use Ic, variables and named values Cm not Ic, flags use Fl, Ba instead of |;
+ wrap long lines;
+ correct poll interval units from log2 s to seconds;
+ define jitter as offset RMS error estimate
+
+ util/ntp-keygen-opts.def@1.29 +584 -426
+ reconcile three embedded Running the Program sections (two of them pure duplicates);
+ remove duplicated paragraphs;
+ move apparently orphan paragraphs to appropriate places;
+ reword chunks with repeated content;
+ reconcile Command Line Options section with options, add missing options, add long option flags;
+ specify explicitly when other program commands and configuration files are referenced;
+ change external references from section 3 functions to section 1 commands;
+ use markup consistently
+
+ChangeSet@1.3720.31.1, 2017-03-10 10:00:39+01:00, burnicki@pc-martin4.py.meinberg.de
+ Include openssl/applink.c only for openSSL versions < 1.1.0.
+
+ include/ssl_applink.c@1.4 +3 -1
+ Include openssl/applink.c only for openSSL versions < 1.1.0.
+
+ChangeSet@1.3720.30.2, 2017-03-09 21:59:34+01:00, perlinger@ntp.org
+ [Sec 3384] followup: fixed a comment typo.
+
+ ports/winnt/instsrv/instsrv.c@1.11 +1 -1
+ [Sec 3384] followup: fixed a comment typo.
+
+ChangeSet@1.3720.1.33, 2017-03-08 21:51:39+00:00, bwi@nwtime.org
+ ports/winnt/instsrv/instsrv.c(addSourceToRegistry) prefix use of snprintf with _ required for VS < 2015
+
+ ports/winnt/instsrv/instsrv.c@1.9.1.1 +1 -1
+ prefix addSourceToRegistry() use of snprintf with _ required for VS < 2015
+
+ChangeSet@1.3720.30.1, 2017-03-08 22:34:08+01:00, perlinger@ntp.org
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - VS2008 compatibility restored
+
+ ports/winnt/instsrv/instsrv.c@1.10 +4 -0
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - VS2008 compatibility restored
+
+ChangeSet@1.3720.1.32, 2017-03-08 17:32:15+00:00, bwi@nwtime.org
+ add AES128CMAC to MAC selections list in ntpq.texi (replacing earlier change directly to ntpq.html)
+
+ ntpq/ntpq.texi@1.5 +1 -1
+ add AES128CMAC to MAC selections list (replacing earlier change directly to ntpq.html)
+
+ChangeSet@1.3720.29.1, 2017-03-08 06:11:49-05:00, stenn@psp-fb3.ntp.org
+ [Bug 3358] Spurious KoD log messages in .INIT. phase
+
+ ChangeLog@1.1874 +4 -0
+ [Bug 3358] Spurious KoD log messages in .INIT. phase
+
+ ntpd/ntp_proto.c@1.403 +8 -11
+ [Bug 3358] Spurious KoD log messages in .INIT. phase
+
+ChangeSet@1.3720.1.30, 2017-03-06 21:07:41+00:00, stenn@psp-deb1.ntp.org
+ CVE updates for 4.2.8p10
+
+ NEWS@1.177.1.28 +15 -15
+ CVE updates for 4.2.8p10
+
+ChangeSet@1.3720.1.29, 2017-03-06 13:54:35+00:00, stenn@psp-deb1.ntp.org
+ NEWS for p10
+
+ NEWS@1.177.1.27 +447 -1
+ NEWS for p10
+
+ChangeSet@1.3720.1.28, 2017-03-06 11:52:11+00:00, stenn@psp-deb1.ntp.org
+ cleanup
+
+ ChangeLog@1.1873 +2 -4
+ cleanup
+
+ChangeSet@1.3720.25.7, 2017-03-05 11:23:32-07:00, bwi@bwinglisrpi1.(none)
+ ntpd/ntp_refclock.c(refclock_params) report time_pps_kcbind errors but only return failure if error other than not supported, allowing PPS to work
+
+ ntpd/ntp_refclock.c@1.124 +4 -1
+ report time_pps_kcbind errors but only return failure if error other than not supported, allowing PPS to work
+
+ChangeSet@1.3720.1.27, 2017-03-05 14:56:43+01:00, perlinger@ntp.org
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - load PPS providers from registry
+ - disable PPSAPI_HACK envvar
+ - major cleanup of 'instsrv'
+
+ ChangeLog@1.1872 +4 -0
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - load PPS providers from registry, disable PPSAPI_HACK envvar
+
+ include/ntp_stdlib.h@1.85 +6 -2
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - side kick: fix array allocation for DEBUG builds
+
+ include/ntpd.h@1.197 +1 -1
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - sidekick: signed/unsigned clashes on 'sys_ttlmax'
+
+ ntpd/ntp_config.c@1.346 +1 -1
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - sidekick: signed/unsigned clashes on 'sys_ttlmax'
+
+ ntpd/ntp_proto.c@1.402 +2 -2
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - sidekick: signed/unsigned clashes on 'sys_ttlmax'
+
+ ports/winnt/include/ntp_iocpltypes.h@1.4 +1 -0
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - track use of PPS API on serial channels
+
+ ports/winnt/instsrv/instsrv.c@1.9 +378 -347
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - major cleanup
+ - add command line arguments for service
+ - set PPS API provider list in service entry
+
+ ports/winnt/ntpd/nt_ppsimpl.c@1.2 +290 -70
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - load PPS providers from registry
+ - disable PPSAPI_HACK envvar
+ - track use of PPS API on serial channels
+
+ ports/winnt/ntpd/ntp_iocompletionport.c@1.79 +7 -19
+ [Sec 3384] NTP-01-009 NTP: Privileged execution of User Library code (Pentest report 01.2017)
+ - disable PPSAPI_HACK envvar, use tracking from PPS API loader instead
+
+ChangeSet@1.3720.25.6, 2017-03-04 04:41:52+00:00, Brian@bwinglisd.
+ ensure Windows system32 added to start of PATH
+
+ ports/winnt/scripts/mkver.bat@1.18 +4 -0
+ ensure Windows system32 from COMSPEC added to start of PATH in case other find commands are on PATH
+
+ChangeSet@1.3720.1.26, 2017-03-02 17:34:00-05:00, stenn@psp-deb2.ntp.org
+ [Sec 3385] NTP-01-010: ereallocarray()/eallocarray() underused: zero out new memory
+
+ include/ntp_stdlib.h@1.84 +6 -6
+ [Sec 3385] NTP-01-010: ereallocarray()/eallocarray() underused: zero out new memory
+
+ libntp/authkeys.c@1.36 +1 -1
+ [Sec 3385] NTP-01-010: ereallocarray()/eallocarray() underused: zero out new memory
+
+ libntp/emalloc.c@1.21 +3 -3
+ [Sec 3385] NTP-01-010: ereallocarray()/eallocarray() underused: zero out new memory
+
+ChangeSet@1.3720.1.25, 2017-03-02 05:35:49+00:00, stenn@stenn.ntp.org
+ [Sec 3376] Support build "hardening" flags: NetBSD
+
+ sntp/harden/netbsd7.0@1.1 +4 -0
+ BitKeeper file sntp/harden/netbsd7.0
+
+ sntp/harden/netbsd7.0@1.0 +0 -0
+
+ sntp/harden/netbsd7.99@1.1 +4 -0
+ BitKeeper file sntp/harden/netbsd7.99
+
+ sntp/harden/netbsd7.99@1.0 +0 -0
+
+ChangeSet@1.3720.1.23, 2017-03-01 09:44:54+00:00, stenn@psp-deb1.ntp.org
+ [Sec 3376] Support build "hardening" flags
+
+ sntp/m4/ntp_prog_cc.m4@1.3 +1 -1
+ [Sec 3376] Support build "hardening" flags
+
+ChangeSet@1.3720.1.22, 2017-03-01 09:30:03+00:00, stenn@psp-deb1.ntp.org
+ [Sec 3376] Support build "hardening" flags
+
+ configure.ac@1.609 +5 -4
+ [Sec 3376] Support build "hardening" flags
+
+ sntp/configure.ac@1.85 +4 -4
+ [Sec 3376] Support build "hardening" flags
+
+ sntp/harden/freebsd11@1.2 +1 -1
+ [Sec 3376] Support build "hardening" flags
+
+ sntp/harden/freebsd12@1.2 +1 -1
+ [Sec 3376] Support build "hardening" flags
+
+ sntp/m4/ntp_compiler.m4@1.6 +14 -2
+ [Sec 3376] Support build "hardening" flags
+
+ sntp/m4/ntp_prog_cc.m4@1.2 +12 -11
+ [Sec 3376] Support build "hardening" flags
+
+ChangeSet@1.3720.26.3, 2017-03-01 09:16:03+00:00, stenn@psp-deb1.ntp.org
+ merge cleanup
+
+ ChangeLog@1.1869.1.3 +1 -3
+ merge cleanup
+
+ChangeSet@1.3720.28.1, 2017-02-28 06:46:17-05:00, stenn@psp-fb4.ntp.org
+ [Sec 3361] 0rigin (zero origin) DoS.
+
+ ChangeLog@1.1869.3.1 +1 -0
+ [Sec 3361] 0rigin (zero origin) DoS.
+
+ ntpd/ntp_proto.c@1.400 +4 -0
+ [Sec 3361] 0rigin (zero origin) DoS.
+
+ChangeSet@1.3720.27.1, 2017-02-28 06:13:45-05:00, stenn@psp-fb4.ntp.org
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ ChangeLog@1.1869.2.1 +1 -0
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ include/ntp_stdlib.h@1.83 +7 -5
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ libntp/authkeys.c@1.35 +1 -1
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ libntp/emalloc.c@1.20 +5 -4
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ libntp/recvbuff.c@1.42 +1 -1
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ ntpd/ntp_loopfilter.c@1.190 +1 -2
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ ntpd/ntp_peer.c@1.162 +1 -1
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ ntpd/ntp_restrict.c@1.41 +2 -2
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ sntp/kod_management.c@1.34 +3 -1
+ [Sec 3385] NTP-01-010 NTP: ereallocarray()/eallocarray() underused. HStenn
+
+ChangeSet@1.3720.26.1, 2017-02-26 08:20:56+00:00, perlinger@ntp.org
+ [Sec 3393] clang scan-build findings
+
+ ChangeLog@1.1869.1.1 +3 -0
+ [Sec 3393] clang scan-build findings
+
+ libntp/ntp_intres.c@1.102 +1 -1
+ [Sec 3393] clang scan-build findings
+ - test proper source pointer, not memcpy result
+
+ ntpd/ntp_config.c@1.344 +28 -46
+ [Sec 3393] clang scan-build findings
+ - provide non-returning error function, triggered only by programming error (mismatch between
+ parser and evaluator)
+ - fix assignment to wrong variable in tos stratum check
+
+ ntpd/ntp_control.c@1.218 +1 -1
+ [Sec 3393] clang scan-build findings
+ - minor signed/unsigned clash
+
+ ntpd/ntp_scanner.c@1.50 +0 -1
+ [Sec 3393] clang scan-build findings
+ - dead assignment
+
+ ntpd/refclock_gpsdjson.c@1.26 +8 -6
+ [Sec 3393] clang scan-build findings
+ - never feed NULL to memcpy(), even with zero-length
+
+ ntpd/refclock_jjy.c@1.34 +2 -2
+ [Sec 3393] clang scan-build findings
+ - use memcpy() instead or strncpy() when the number of bytes is known
+
+ ntpd/refclock_nmea.c@1.79 +0 -3
+ [Sec 3393] clang scan-build findings
+ - dead initialisations: always overwritten
+
+ ntpd/refclock_oncore.c@1.102.1.1 +3 -3
+ [Sec 3393] clang scan-build findings
+ - dead initialisations and assignments: always overwritten
+
+ ntpd/refclock_parse.c@1.85 +12 -8
+ [Sec 3393] clang scan-build findings
+ - dead initialisations and assignments: always overwritten
+ - buggy use of snprintf result
+
+ ntpdate/ntpdate.c@1.99 +2 -0
+ [Sec 3393] clang scan-build findings
+ - INSIST() on sys_samples in range
+
+ ntpdc/ntpdc.c@1.108 +1 -1
+ [Sec 3393] clang scan-build findings
+ - make sure result of recv() is used
+
+ ntpq/ntpq.c@1.174.1.1 +42 -26
+ [Sec 3393] clang scan-build findings
+ - make sure result of recv() is used
+ - initialise tables
+ - rework hexdump utility function
+
+ChangeSet@1.3720.25.5, 2017-02-24 21:36:43-07:00, bwi@bwinglisrpi1.(none)
+ add missing change comment in mkver.bat
+
+ ports/winnt/scripts/mkver.bat@1.17 +5 -1
+ add missing change comment in mkver.bat
+
+ChangeSet@1.3720.25.4, 2017-02-24 19:33:50+00:00, Brian@bwinglisd.
+ allow EVP_MD_do_all_sorted to be used on Windows with OpenSSL 1+
+
+ ntpq/ntpq.c@1.178 +6 -0
+ define HAVE_EVP_MD_DO_ALL_SORTED on Windows with OpenSSL 1+
+
+ChangeSet@1.3720.1.21, 2017-02-24 06:26:16-05:00, stenn@psp-deb2.ntp.org
+ [Sec 3376] Support build "hardening" flags.
+
+ ChangeLog@1.1870 +1 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ adjtimed/Makefile.am@1.16 +4 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ clockstuff/Makefile.am@1.22 +3 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ configure.ac@1.608 +2 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ libntp/Makefile.am@1.81 +4 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ libparse/Makefile.am@1.32 +4 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpd/Makefile.am@1.135 +3 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpd/ntp.conf.html@1.189 +1541 -1192
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpd/ntp.keys.html@1.190 +162 -115
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpd/ntpd.html@1.183 +753 -678
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpdate/Makefile.am@1.38 +3 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpdc/Makefile.am@1.76 +3 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpdc/ntpdc.html@1.352 +404 -355
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpq/Makefile.am@1.72 +4 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpq/ntpq.html@1.180 +1439 -1284
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpsnmpd/Makefile.am@1.41 +5 -2
+ [Sec 3376] Support build "hardening" flags.
+
+ ntpsnmpd/ntpsnmpd.html@1.178 +92 -59
+ [Sec 3376] Support build "hardening" flags.
+
+ parseutil/Makefile.am@1.18 +5 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ scripts/ntp-wait/ntp-wait.html@1.348 +182 -152
+ [Sec 3376] Support build "hardening" flags.
+
+ scripts/ntpsweep/ntpsweep.html@1.120 +189 -152
+ [Sec 3376] Support build "hardening" flags.
+
+ scripts/ntptrace/ntptrace.html@1.121 +168 -128
+ [Sec 3376] Support build "hardening" flags.
+
+ scripts/plot_summary.html@1.123 +188 -160
+ [Sec 3376] Support build "hardening" flags.
+
+ scripts/summary.html@1.122 +171 -135
+ [Sec 3376] Support build "hardening" flags.
+
+ scripts/update-leap/update-leap.html@1.19 +247 -199
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/Makefile.am@1.91 +6 -2
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/configure.ac@1.84 +2 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/harden/README@1.1 +11 -0
+ BitKeeper file sntp/harden/README
+
+ sntp/harden/README@1.0 +0 -0
+
+ sntp/harden/default@1.1 +4 -0
+ BitKeeper file sntp/harden/default
+
+ sntp/harden/default@1.0 +0 -0
+
+ sntp/harden/freebsd10@1.1 +4 -0
+ BitKeeper file sntp/harden/freebsd10
+
+ sntp/harden/freebsd10@1.0 +0 -0
+
+ sntp/harden/freebsd11@1.1 +4 -0
+ BitKeeper file sntp/harden/freebsd11
+
+ sntp/harden/freebsd11@1.0 +0 -0
+
+ sntp/harden/freebsd12@1.1 +4 -0
+ BitKeeper file sntp/harden/freebsd12
+
+ sntp/harden/freebsd12@1.0 +0 -0
+
+ sntp/harden/linux@1.1 +4 -0
+ BitKeeper file sntp/harden/linux
+
+ sntp/harden/linux@1.0 +0 -0
+
+ sntp/libevent/Makefile.am@1.15 +5 -3
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/libevent/configure.ac@1.18 +4 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/libopts/Makefile.am@1.28 +4 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/m4/ntp_harden.m4@1.1 +52 -0
+ BitKeeper file sntp/m4/ntp_harden.m4
+
+ sntp/m4/ntp_harden.m4@1.0 +0 -0
+
+ sntp/m4/ntp_libevent.m4@1.17 +3 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/scripts/Makefile.am@1.4 +1 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/scripts/genHardFlags@1.1 +152 -0
+ BitKeeper file sntp/scripts/genHardFlags
+
+ sntp/scripts/genHardFlags@1.0 +0 -0
+
+ sntp/sntp.html@1.523 +468 -420
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/tests/Makefile.am@1.68 +4 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ sntp/unity/Makefile.am@1.11 +5 -0
+ [Sec 3376] Support build "hardening" flags.
+
+ tests/bug-2803/Makefile.am@1.14 +4 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ tests/libntp/Makefile.am@1.95 +5 -2
+ [Sec 3376] Support build "hardening" flags.
+
+ tests/ntpd/Makefile.am@1.30 +4 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ tests/ntpq/Makefile.am@1.10 +4 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ tests/sandbox/Makefile.am@1.8 +4 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ tests/sec-2853/Makefile.am@1.4 +4 -1
+ [Sec 3376] Support build "hardening" flags.
+
+ util/Makefile.am@1.79 +5 -2
+ [Sec 3376] Support build "hardening" flags.
+
+ util/ntp-keygen.html@1.184 +1083 -1007
+ [Sec 3376] Support build "hardening" flags.
+
+ChangeSet@1.3720.25.3, 2017-02-23 05:53:09+00:00, Brian@bwinglisd.
+ increase struct key member type size from 10 to 16 to allow AES128CMAC and future longer types up to 15 chars, refactor ntpq digest list CMAC insertion into function, fix packetProcessing tests, add debug output to check CMAC working
+
+ libntp/ssl_init.c@1.25 +15 -0
+ add debug output to validate CMAC being handled
+
+ ntpq/ntpq.c@1.177 +158 -98
+ include stddef.h for prtdiff_t, refactor CMAC insertion into MD list into insert_cmac() called from list_digest_names(), use EVP_MD_size() instead of EVP_Digest..() calls in list_md_fn(), remove associated variables, move check earlier in function, minor style and line length cleanups
+
+ sntp/crypto.c@1.28 +9 -1
+ increase max key type length to 15 to reflect struct key type size 16, add debug output to check CMAC operation
+
+ sntp/crypto.h@1.12 +1 -1
+ increase struct key member type size from 10 to 16 to allow AES128CMAC and future longer types
+ this should be considered for future length checking when handling digest names
+
+ sntp/tests/packetProcessing.c@1.14 +5 -4
+ fix PrepareAuthenticationTest() to use args and not hard wire MD5, increase CMAC key to mandatory length 16, fix exten to match key id
+
+ChangeSet@1.3720.25.2, 2017-02-21 04:21:19+00:00, Brian@bwinglisd.
+ fix typos caught by gcc not encountered with Windows build
+
+ include/ntp_md5.h@1.13 +0 -1
+ remove cmac include
+
+ libntp/ssl_init.c@1.24 +11 -13
+ indent nested include/define, drop unused array digest, make const md var and initialize
+
+ ntpq/ntpq.c@1.176 +19 -9
+ move SORTED K_... defines outside MAIN and LIB ifdef, fix var typos and char arg caught by gcc missed by VS/VC
+
+ ports/winnt/scripts/mkver.bat@1.16 +1 -1
+ restore initial echo off
+
+ sntp/crypto.c@1.27 +18 -4
+ add CMAC include and define name removed elsewhere, make_mac() fix assign instead of compare typo, ensure len 0 if error, check for NULL CTX even for internal MD5
+
+ChangeSet@1.3720.25.1, 2017-02-20 05:21:29+00:00, Brian@bwinglisd.
+ add AES-128 CMAC digest support as key type AES128CMAC length *MUST BE* 16 bytes
+
+ html/authentic.html@1.16 +32 -6
+ mention AES-128 CMAC, provide text figure of key file with key 20 AES128CMAC as table with caption instead of fuzzy gif
+
+ html/keygen.html@1.35 +63 -37
+ mention AES-128 cmac, change random <dd>...</dd> to <p>...</p>, change keys file figure from fuzzy gif to text with key 20 AES128CMAC, remove dated timing and references from Bugs comment
+
+ html/ntpq.html@1.51 +1 -1
+ add AES128CMAC to list of digest algorithms
+
+ include/ntp_md5.h@1.12 +1 -0
+ include OpenSSL cmac.h for callers
+
+ libntp/ssl_init.c@1.23 +55 -20
+ include OpenSSL cmac.h, define MD5_LENGTH, CMAC_LENGTH, and CMAC name, recognise CMAC name and set NID_cmac
+
+ ntpq/ntpq.c@1.175 +61 -3
+ define CMAC name, move sorted digest list defines up, add variables and code to detect or append CMAC name, as CMAC is not a registered MAC
+
+ ports/winnt/scripts/mkver.bat@1.15 +3 -1
+ add support for Windows 10 (Home maybe others) rename of registry Time Zone info from ActiveTimeBias to Bias
+
+ sntp/crypto.c@1.26 +74 -8
+ support AES-128 CMAC digest, add similar error checking to OpenSSL MAC digests, leave local MD5 digest as is
+
+ sntp/tests/crypto.c@1.11 +67 -0
+ define CMAC name and length, add CMAC tests like SHA1 tests
+
+ sntp/tests/packetProcessing.c@1.13 +26 -0
+ add CMAC name and test like SHA1 test
+
+ tests/libntp/ssl_init.c@1.10 +31 -0
+ add CMAC name, length, tests like SHA1 tests
+
+ util/ntp-keygen-opts.def@1.28 +4 -8
+ mention AES-128 CMAC, fix garbled sentence, remove outdated timing and references from Bugs
+
+ChangeSet@1.3720.24.1, 2017-02-12 18:15:23+01:00, perlinger@ntp.org
+ [Sec 3380] NTP-01-005: Off-by-one in Oncore GPS Receiver
+
+ ChangeLog@1.1853.10.1 +4 -0
+ [Sec 3380] NTP-01-005: Off-by-one in Oncore GPS Receiver
+
+ ntpd/refclock_oncore.c@1.103 +1 -1
+ [Sec 3380] NTP-01-005: Off-by-one in Oncore GPS Receiver
+
+ChangeSet@1.3720.23.1, 2017-02-12 17:35:27+01:00, perlinger@ntp.org
+ [Sec 3382] NTP-01-007: Data Structure terminated insufficiently
+ [Sec 3383] NTP-01-008: Stack Buffer Overflow from Command Line
+
+ ChangeLog@1.1853.9.1 +6 -0
+ [Sec 3382] NTP-01-007: Data Structure terminated insufficiently
+ [Sec 3383] NTP-01-008: Stack Buffer Overflow from Command Line
+
+ ports/winnt/instsrv/instsrv.c@1.8 +52 -55
+ [Sec 3382] NTP-01-007: Data Structure terminated insufficiently
+ - use static const char ARRAY of defined length to hold MULTISZ value
+ [Sec 3383] NTP-01-008: Stack Buffer Overflow from Command Line
+ - use result-checked 'snprintf()' do concat the strings in a buffer of static size
+
+ChangeSet@1.3720.22.1, 2017-02-12 13:46:35+01:00, perlinger@ntp.org
+ [Sec 3388] NTP-01-014: Buffer Overflow in DPTS Clock
+
+ ChangeLog@1.1853.8.1 +4 -0
+ [Sec 3388] NTP-01-014: Buffer Overflow in DPTS Clock
+
+ ntpd/refclock_datum.c@1.23 +10 -9
+ [Sec 3388] NTP-01-014: Buffer Overflow in DPTS Clock
+
+ChangeSet@1.3720.21.1, 2017-02-12 12:35:04+01:00, perlinger@ntp.org
+ [Sec 3386] NTP-01-011: ntpq_stripquotes() returns incorrect Value
+
+ ChangeLog@1.1853.7.1 +4 -0
+ [Sec 3386] NTP-01-011: ntpq_stripquotes() returns incorrect Value
+
+ ntpq/libntpq.c@1.14 +35 -32
+ [Sec 3386] NTP-01-011: ntpq_stripquotes() returns incorrect Value
+
+ChangeSet@1.3720.20.1, 2017-02-12 11:08:16+01:00, perlinger@ntp.org
+ [Sec 3387] NTP-01-012: Authenticated DoS via Malicious Config Option
+
+ ChangeLog@1.1853.6.1 +4 -0
+ [Sec 3387] NTP-01-012: Authenticated DoS via Malicious Config Option
+
+ ntpd/ntp_config.c@1.340.3.1 +12 -15
+ [Sec 3387] NTP-01-012: Authenticated DoS via Malicious Config Option
+
+ChangeSet@1.3720.19.1, 2017-02-12 09:49:29+01:00, perlinger@ntp.org
+ [Sec 3389] NTP-01-016: Denial of Service via Malformed Config
+
+ ChangeLog@1.1853.5.1 +4 -0
+ [Sec 3389] NTP-01-016: Denial of Service via Malformed Config
+
+ ntpd/ntp_config.c@1.340.2.1 +23 -2
+ [Sec 3389] NTP-01-016: Denial of Service via Malformed Config
+ - allow 'ttl' only for network peers and 'mode' only for refclocks
+
+ ntpd/ntp_proto.c@1.398.1.1 +11 -9
+ [Sec 3389] NTP-01-016: Denial of Service via Malformed Config
+ clamp access to 'sys_ttl' to avoid OOB conditions / undefined behaviour
+
+ChangeSet@1.3720.18.1, 2017-02-12 08:03:30+01:00, perlinger@ntp.org
+ [Sec 3379] NTP-01-004 Potential Overflows in ctl_put() functions
+
+ ChangeLog@1.1853.4.1 +4 -0
+ [Sec 3379] NTP-01-004 Potential Overflows in ctl_put() functions
+
+ ntpd/ntp_control.c@1.215.1.1 +99 -174
+ [Sec 3379] NTP-01-004 Potential Overflows in ctl_put() functions
+
+ChangeSet@1.3720.17.1, 2017-02-11 20:47:37+01:00, perlinger@ntp.org
+ [Sec 3378] NTP-01-003 Improper use of snprintf() in mx4200_send()
+
+ ChangeLog@1.1853.3.1 +4 -0
+ [Sec 3378] NTP-01-003 Improper use of snprintf() in mx4200_send()
+
+ ntpd/refclock_mx4200.c@1.31 +20 -12
+ [Sec 3378] NTP-01-003 Improper use of snprintf() in mx4200_send()
+
+ChangeSet@1.3720.16.10, 2017-02-11 19:30:47+01:00, perlinger@ntp.org
+ [Sec 3377] NTP-01-002 Buffer Overflow in ntpq when fetching reslist
+
+ ChangeLog@1.1853.2.6 +4 -0
+ [Sec 3377] NTP-01-002 Buffer Overflow in ntpq when fetching reslist
+
+ ntpq/ntpq-subs.c@1.119 +4 -2
+ [Sec 3377] NTP-01-002 Buffer Overflow in ntpq when fetching reslist
+
+ChangeSet@1.3720.16.9, 2017-02-01 08:07:13-05:00, stenn@deacon.udel.edu
+ cleanup
+
+ ChangeLog@1.1853.2.5 +0 -2
+ cleanup
+
+ChangeSet@1.3720.16.8, 2017-02-01 08:05:36-05:00, stenn@deacon.udel.edu
+ Update triggers for bk-7
+
+ BitKeeper/triggers/post-incoming.license-warn@1.10 +3 -0
+ Update triggers for bk-7
+
+ BitKeeper/triggers/pre-resolve.license-chk@1.11 +3 -0
+ Update triggers for bk-7
+
+ BitKeeper/triggers/send@1.17 +2 -2
+ Update triggers for bk-7
+
+ChangeSet@1.3720.16.7, 2017-02-01 07:39:35-05:00, stenn@deacon.udel.edu
NTP_4_2_8P9_WIN
TAG: NTP_4_2_8P9_WIN
- ChangeLog@1.1857 +3 -0
+ ChangeLog@1.1853.2.4 +3 -0
NTP_4_2_8P9_WIN
- ntpd/invoke-ntp.conf.texi@1.204 +1 -1
+ ntpd/invoke-ntp.conf.texi@1.203.1.1 +1 -1
NTP_4_2_8P9_WIN
- ntpd/invoke-ntp.keys.texi@1.193 +1 -1
+ ntpd/invoke-ntp.keys.texi@1.192.1.1 +1 -1
NTP_4_2_8P9_WIN
- ntpd/invoke-ntpd.texi@1.509 +2 -2
+ ntpd/invoke-ntpd.texi@1.508.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpd/ntp.conf.5man@1.238 +3 -3
+ ntpd/ntp.conf.5man@1.237.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpd/ntp.conf.5mdoc@1.238 +2 -2
+ ntpd/ntp.conf.5mdoc@1.237.1.1 +2 -2
NTP_4_2_8P9_WIN
ntpd/ntp.conf.html@1.188 +1 -1
NTP_4_2_8P9_WIN
- ntpd/ntp.conf.man.in@1.238 +3 -3
+ ntpd/ntp.conf.man.in@1.237.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpd/ntp.conf.mdoc.in@1.238 +2 -2
+ ntpd/ntp.conf.mdoc.in@1.237.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpd/ntp.keys.5man@1.227 +2 -2
+ ntpd/ntp.keys.5man@1.226.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpd/ntp.keys.5mdoc@1.227 +2 -2
+ ntpd/ntp.keys.5mdoc@1.226.1.1 +2 -2
NTP_4_2_8P9_WIN
ntpd/ntp.keys.html@1.189 +1 -1
NTP_4_2_8P9_WIN
- ntpd/ntp.keys.man.in@1.227 +2 -2
+ ntpd/ntp.keys.man.in@1.226.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpd/ntp.keys.mdoc.in@1.227 +2 -2
+ ntpd/ntp.keys.mdoc.in@1.226.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpd/ntpd-opts.c@1.531 +245 -245
+ ntpd/ntpd-opts.c@1.530.1.1 +245 -245
NTP_4_2_8P9_WIN
- ntpd/ntpd-opts.h@1.530 +3 -3
+ ntpd/ntpd-opts.h@1.529.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpd/ntpd.1ntpdman@1.338 +3 -3
+ ntpd/ntpd.1ntpdman@1.337.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpd/ntpd.1ntpdmdoc@1.338 +2 -2
+ ntpd/ntpd.1ntpdmdoc@1.337.1.1 +2 -2
NTP_4_2_8P9_WIN
ntpd/ntpd.html@1.182 +2 -2
NTP_4_2_8P9_WIN
- ntpd/ntpd.man.in@1.338 +3 -3
+ ntpd/ntpd.man.in@1.337.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpd/ntpd.mdoc.in@1.338 +2 -2
+ ntpd/ntpd.mdoc.in@1.337.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpdc/invoke-ntpdc.texi@1.506 +2 -2
+ ntpdc/invoke-ntpdc.texi@1.505.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpdc/ntpdc-opts.c@1.524 +107 -107
+ ntpdc/ntpdc-opts.c@1.523.1.1 +107 -107
NTP_4_2_8P9_WIN
- ntpdc/ntpdc-opts.h@1.523 +3 -3
+ ntpdc/ntpdc-opts.h@1.522.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpdc/ntpdc.1ntpdcman@1.337 +3 -3
+ ntpdc/ntpdc.1ntpdcman@1.336.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpdc/ntpdc.1ntpdcmdoc@1.337 +2 -2
+ ntpdc/ntpdc.1ntpdcmdoc@1.336.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpdc/ntpdc.html@1.350 +2 -2
+ ntpdc/ntpdc.html@1.349.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpdc/ntpdc.man.in@1.337 +3 -3
+ ntpdc/ntpdc.man.in@1.336.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpdc/ntpdc.mdoc.in@1.337 +2 -2
+ ntpdc/ntpdc.mdoc.in@1.336.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpq/invoke-ntpq.texi@1.514 +2 -2
+ ntpq/invoke-ntpq.texi@1.513.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpq/ntpq-opts.c@1.531 +114 -114
+ ntpq/ntpq-opts.c@1.530.1.1 +114 -114
NTP_4_2_8P9_WIN
- ntpq/ntpq-opts.h@1.529 +3 -3
+ ntpq/ntpq-opts.h@1.528.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpq/ntpq.1ntpqman@1.342 +3 -3
+ ntpq/ntpq.1ntpqman@1.341.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpq/ntpq.1ntpqmdoc@1.342 +2 -2
+ ntpq/ntpq.1ntpqmdoc@1.341.1.1 +2 -2
NTP_4_2_8P9_WIN
ntpq/ntpq.html@1.179 +2 -2
NTP_4_2_8P9_WIN
- ntpq/ntpq.man.in@1.342 +3 -3
+ ntpq/ntpq.man.in@1.341.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpq/ntpq.mdoc.in@1.342 +2 -2
+ ntpq/ntpq.mdoc.in@1.341.1.1 +2 -2
NTP_4_2_8P9_WIN
- ntpsnmpd/invoke-ntpsnmpd.texi@1.508 +11 -10
+ ntpsnmpd/invoke-ntpsnmpd.texi@1.507.1.1 +11 -10
NTP_4_2_8P9_WIN
- ntpsnmpd/ntpsnmpd-opts.c@1.526 +68 -68
+ ntpsnmpd/ntpsnmpd-opts.c@1.525.1.1 +68 -68
NTP_4_2_8P9_WIN
- ntpsnmpd/ntpsnmpd-opts.h@1.525 +3 -3
+ ntpsnmpd/ntpsnmpd-opts.h@1.524.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.337 +3 -3
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.336.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.337 +2 -2
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.336.1.1 +2 -2
NTP_4_2_8P9_WIN
ntpsnmpd/ntpsnmpd.html@1.177 +1 -1
NTP_4_2_8P9_WIN
- ntpsnmpd/ntpsnmpd.man.in@1.337 +3 -3
+ ntpsnmpd/ntpsnmpd.man.in@1.336.1.1 +3 -3
NTP_4_2_8P9_WIN
- ntpsnmpd/ntpsnmpd.mdoc.in@1.337 +2 -2
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.336.1.1 +2 -2
NTP_4_2_8P9_WIN
packageinfo.sh@1.534 +1 -1
NTP_4_2_8P9_WIN
- scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.98 +3 -3
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.97.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.99 +2 -2
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.98.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/calc_tickadj/calc_tickadj.html@1.100 +1 -1
+ scripts/calc_tickadj/calc_tickadj.html@1.99.1.1 +1 -1
NTP_4_2_8P9_WIN
- scripts/calc_tickadj/calc_tickadj.man.in@1.97 +3 -3
+ scripts/calc_tickadj/calc_tickadj.man.in@1.96.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/calc_tickadj/calc_tickadj.mdoc.in@1.99 +2 -2
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.98.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/calc_tickadj/invoke-calc_tickadj.texi@1.102 +1 -1
+ scripts/calc_tickadj/invoke-calc_tickadj.texi@1.101.1.1 +1 -1
NTP_4_2_8P9_WIN
- scripts/invoke-plot_summary.texi@1.120 +2 -2
+ scripts/invoke-plot_summary.texi@1.119.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/invoke-summary.texi@1.119 +2 -2
+ scripts/invoke-summary.texi@1.118.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntp-wait/invoke-ntp-wait.texi@1.329 +2 -2
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.328.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntp-wait/ntp-wait-opts@1.65 +2 -2
+ scripts/ntp-wait/ntp-wait-opts@1.64.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntp-wait/ntp-wait.1ntp-waitman@1.326 +3 -3
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.325.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.327 +2 -2
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.326.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntp-wait/ntp-wait.html@1.346 +2 -2
+ scripts/ntp-wait/ntp-wait.html@1.345.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntp-wait/ntp-wait.man.in@1.326 +3 -3
+ scripts/ntp-wait/ntp-wait.man.in@1.325.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/ntp-wait/ntp-wait.mdoc.in@1.327 +2 -2
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.326.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntpsweep/invoke-ntpsweep.texi@1.117 +2 -2
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.116.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntpsweep/ntpsweep-opts@1.67 +2 -2
+ scripts/ntpsweep/ntpsweep-opts@1.66.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntpsweep/ntpsweep.1ntpsweepman@1.105 +3 -3
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.104.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.105 +2 -2
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.104.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntpsweep/ntpsweep.html@1.118 +2 -2
+ scripts/ntpsweep/ntpsweep.html@1.117.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntpsweep/ntpsweep.man.in@1.105 +3 -3
+ scripts/ntpsweep/ntpsweep.man.in@1.104.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/ntpsweep/ntpsweep.mdoc.in@1.106 +2 -2
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.105.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntptrace/invoke-ntptrace.texi@1.118 +2 -2
+ scripts/ntptrace/invoke-ntptrace.texi@1.117.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntptrace/ntptrace-opts@1.67 +2 -2
+ scripts/ntptrace/ntptrace-opts@1.66.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntptrace/ntptrace.1ntptraceman@1.105 +3 -3
+ scripts/ntptrace/ntptrace.1ntptraceman@1.104.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/ntptrace/ntptrace.1ntptracemdoc@1.106 +2 -2
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.105.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntptrace/ntptrace.html@1.119 +2 -2
+ scripts/ntptrace/ntptrace.html@1.118.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/ntptrace/ntptrace.man.in@1.105 +3 -3
+ scripts/ntptrace/ntptrace.man.in@1.104.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/ntptrace/ntptrace.mdoc.in@1.107 +2 -2
+ scripts/ntptrace/ntptrace.mdoc.in@1.106.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/plot_summary-opts@1.68 +2 -2
+ scripts/plot_summary-opts@1.67.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/plot_summary.1plot_summaryman@1.118 +3 -3
+ scripts/plot_summary.1plot_summaryman@1.117.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/plot_summary.1plot_summarymdoc@1.118 +2 -2
+ scripts/plot_summary.1plot_summarymdoc@1.117.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/plot_summary.html@1.121 +2 -2
+ scripts/plot_summary.html@1.120.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/plot_summary.man.in@1.118 +3 -3
+ scripts/plot_summary.man.in@1.117.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/plot_summary.mdoc.in@1.118 +2 -2
+ scripts/plot_summary.mdoc.in@1.117.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/summary-opts@1.67 +2 -2
+ scripts/summary-opts@1.66.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/summary.1summaryman@1.117 +3 -3
+ scripts/summary.1summaryman@1.116.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/summary.1summarymdoc@1.117 +2 -2
+ scripts/summary.1summarymdoc@1.116.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/summary.html@1.120 +2 -2
+ scripts/summary.html@1.119.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/summary.man.in@1.117 +3 -3
+ scripts/summary.man.in@1.116.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/summary.mdoc.in@1.117 +2 -2
+ scripts/summary.mdoc.in@1.116.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/update-leap/invoke-update-leap.texi@1.18 +1 -1
+ scripts/update-leap/invoke-update-leap.texi@1.17.1.1 +1 -1
NTP_4_2_8P9_WIN
- scripts/update-leap/update-leap-opts@1.18 +2 -2
+ scripts/update-leap/update-leap-opts@1.17.1.1 +2 -2
NTP_4_2_8P9_WIN
- scripts/update-leap/update-leap.1update-leapman@1.18 +3 -3
+ scripts/update-leap/update-leap.1update-leapman@1.17.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/update-leap/update-leap.1update-leapmdoc@1.18 +2 -2
+ scripts/update-leap/update-leap.1update-leapmdoc@1.17.1.1 +2 -2
NTP_4_2_8P9_WIN
scripts/update-leap/update-leap.html@1.18 +1 -1
NTP_4_2_8P9_WIN
- scripts/update-leap/update-leap.man.in@1.18 +3 -3
+ scripts/update-leap/update-leap.man.in@1.17.1.1 +3 -3
NTP_4_2_8P9_WIN
- scripts/update-leap/update-leap.mdoc.in@1.18 +2 -2
+ scripts/update-leap/update-leap.mdoc.in@1.17.1.1 +2 -2
NTP_4_2_8P9_WIN
- sntp/invoke-sntp.texi@1.506 +2 -2
+ sntp/invoke-sntp.texi@1.505.1.1 +2 -2
NTP_4_2_8P9_WIN
- sntp/sntp-opts.c@1.525 +159 -159
+ sntp/sntp-opts.c@1.524.1.1 +159 -159
NTP_4_2_8P9_WIN
- sntp/sntp-opts.h@1.523 +3 -3
+ sntp/sntp-opts.h@1.522.1.1 +3 -3
NTP_4_2_8P9_WIN
- sntp/sntp.1sntpman@1.341 +3 -3
+ sntp/sntp.1sntpman@1.340.1.1 +3 -3
NTP_4_2_8P9_WIN
- sntp/sntp.1sntpmdoc@1.341 +2 -2
+ sntp/sntp.1sntpmdoc@1.340.1.1 +2 -2
NTP_4_2_8P9_WIN
- sntp/sntp.html@1.521 +2 -2
+ sntp/sntp.html@1.520.1.1 +2 -2
NTP_4_2_8P9_WIN
- sntp/sntp.man.in@1.341 +3 -3
+ sntp/sntp.man.in@1.340.1.1 +3 -3
NTP_4_2_8P9_WIN
- sntp/sntp.mdoc.in@1.341 +2 -2
+ sntp/sntp.mdoc.in@1.340.1.1 +2 -2
NTP_4_2_8P9_WIN
- util/invoke-ntp-keygen.texi@1.509 +2 -2
+ util/invoke-ntp-keygen.texi@1.508.1.1 +2 -2
NTP_4_2_8P9_WIN
- util/ntp-keygen-opts.c@1.527 +173 -173
+ util/ntp-keygen-opts.c@1.526.1.1 +173 -173
NTP_4_2_8P9_WIN
- util/ntp-keygen-opts.h@1.525 +3 -3
+ util/ntp-keygen-opts.h@1.524.1.1 +3 -3
NTP_4_2_8P9_WIN
- util/ntp-keygen.1ntp-keygenman@1.337 +3 -3
+ util/ntp-keygen.1ntp-keygenman@1.336.1.1 +3 -3
NTP_4_2_8P9_WIN
- util/ntp-keygen.1ntp-keygenmdoc@1.337 +2 -2
+ util/ntp-keygen.1ntp-keygenmdoc@1.336.1.1 +2 -2
NTP_4_2_8P9_WIN
util/ntp-keygen.html@1.183 +2 -2
NTP_4_2_8P9_WIN
- util/ntp-keygen.man.in@1.337 +3 -3
+ util/ntp-keygen.man.in@1.336.1.1 +3 -3
NTP_4_2_8P9_WIN
- util/ntp-keygen.mdoc.in@1.337 +2 -2
+ util/ntp-keygen.mdoc.in@1.336.1.1 +2 -2
NTP_4_2_8P9_WIN
-ChangeSet@1.3728, 2017-01-28 09:32:36-05:00, stenn@pogo.udel.edu
+ChangeSet@1.3720.16.6, 2017-01-28 09:32:36-05:00, stenn@pogo.udel.edu
typos
- sntp/m4/ntp_openssl.m4@1.26 +13 -13
+ sntp/m4/ntp_openssl.m4@1.25.1.1 +13 -13
typos
-ChangeSet@1.3726, 2017-01-27 11:21:38+00:00, stenn@psp-deb1.ntp.org
+ChangeSet@1.3720.16.4, 2017-01-27 11:21:38+00:00, stenn@psp-deb1.ntp.org
ntp-4.2.8p9-win
- ChangeLog@1.1855 +4 -1
+ ChangeLog@1.1853.2.2 +4 -1
ntp-4.2.8p9-win
packageinfo.sh@1.533 +1 -1
ntp-4.2.8p9-win
-ChangeSet@1.3725, 2017-01-27 11:09:20+00:00, stenn@psp-deb1.ntp.org
+ChangeSet@1.3720.16.3, 2017-01-27 11:09:20+00:00, stenn@psp-deb1.ntp.org
bk-7 repos don't have a ChangeSet file
- sntp/Makefile.am@1.89 +1 -1
+ sntp/Makefile.am@1.88.1.1 +1 -1
bk-7 repos don't have a ChangeSet file
-ChangeSet@1.3724, 2017-01-21 15:12:35+01:00, perlinger@ntp.org
+ChangeSet@1.3720.16.2, 2017-01-21 15:12:35+01:00, perlinger@ntp.org
[Bug 3144] NTP does not build without openSSL <perlinger@ntp.org>
- pulled missing changeset, minor warning fixes
- ChangeLog@1.1854 +2 -1
+ ChangeLog@1.1853.2.1 +2 -1
[Bug 3144] NTP does not build without openSSL <perlinger@ntp.org>
- pulled missing changeset, minor warning fixes
@@ -369,16 +6904,22 @@ ChangeSet@1.3724, 2017-01-21 15:12:35+01:00, perlinger@ntp.org
[Bug 3144] NTP does not build without openSSL <perlinger@ntp.org>
- pulled missing changeset, minor warning fixes
-ChangeSet@1.3720.1.2, 2017-01-10 06:07:05-05:00, stenn@pogo.udel.edu
+ChangeSet@1.3720.1.18, 2017-01-10 11:14:17+00:00, stenn@psp-deb1.ntp.org
+ s/DNL/dnl/ in ntp_openssl.m4
+
+ sntp/m4/ntp_openssl.m4@1.26 +13 -13
+ s/DNL/dnl/ in ntp_openssl.m4
+
+ChangeSet@1.3720.15.2, 2017-01-10 06:07:05-05:00, stenn@pogo.udel.edu
configure.ac cleanup
- ChangeLog@1.1852.1.1 +5 -0
+ ChangeLog@1.1852.13.1 +5 -0
configure.ac cleanup
configure.ac@1.607 +1 -1
configure.ac cleanup
-ChangeSet@1.3720.1.1, 2017-01-10 06:05:44-05:00, stenn@pogo.udel.edu
+ChangeSet@1.3720.15.1, 2017-01-10 06:05:44-05:00, stenn@pogo.udel.edu
openssl configure cleanup
sntp/m4/ntp_libntp.m4@1.34 +1 -3
@@ -387,7 +6928,586 @@ ChangeSet@1.3720.1.1, 2017-01-10 06:05:44-05:00, stenn@pogo.udel.edu
sntp/m4/ntp_openssl.m4@1.25 +19 -1
openssl configure cleanup
-ChangeSet@1.3722, 2016-11-23 08:34:52+01:00, perlinger@ntp.org
+ChangeSet@1.3720.1.14, 2017-01-08 11:33:47+00:00, stenn@psp-deb1.ntp.org
+ typo
+
+ ChangeLog@1.1864 +1 -1
+ typo
+
+ChangeSet@1.3720.14.1, 2017-01-08 11:16:33+01:00, perlinger@ntp.org
+ [Bug 3062] Change the process name of forked DNS worker
+ - applied patch by Reinhard Max. See bugzilla for limitations.
+
+ ChangeLog@1.1852.12.1 +4 -1
+ [Bug 3062] Change the process name of forked DNS worker
+ - applied patch by Reinhard Max.
+
+ include/ntpd.h@1.194.1.1 +2 -0
+ [Bug 3062] Change the process name of forked DNS worker
+ - applied patch by Reinhard Max.
+
+ libntp/work_fork.c@1.17.1.1 +18 -0
+ [Bug 3062] Change the process name of forked DNS worker
+ - applied patch by Reinhard Max.
+
+ ntpd/ntpd.c@1.172 +2 -0
+ [Bug 3062] Change the process name of forked DNS worker
+ - applied patch by Reinhard Max.
+
+ChangeSet@1.3720.1.7, 2017-01-08 09:30:07+00:00, stenn@psp-deb1.ntp.org
+ [Bug 2896] logging message cleanup
+
+ ntpd/ntp_config.c@1.343 +2 -2
+ [Bug 2896] logging message cleanup
+
+ChangeSet@1.3720.12.1, 2017-01-07 04:30:19+00:00, abe@psp-deb1.ntp.org
+ miscopt.html, driver40.html, driver40-ja.html, ChangeLog:
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html
+
+ ChangeLog@1.1852.11.1 +2 -0
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html
+
+ html/drivers/driver40-ja.html@1.6 +2 -1
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html
+
+ html/drivers/driver40.html@1.21 +2 -1
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html
+
+ html/miscopt.html@1.88 +4 -1
+ [Bug 3365] Updates driver40(-ja).html and miscopt.html
+
+ChangeSet@1.3720.1.3, 2017-01-06 23:24:33+01:00, jnperlin@hydra.localnet
+ [Bug 3363] Support for openssl-1.1.0 without compatibility modes
+
+ ChangeLog@1.1854 +2 -0
+ [Bug 3363] Support for openssl-1.1.0 without compatibility modes
+
+ include/libssl_compat.h@1.3 +19 -0
+ [Bug 3363] Support for openssl-1.1.0 without compatibility modes
+
+ include/ntp_crypto.h@1.52 +1 -0
+ [Bug 3363] Support for openssl-1.1.0 without compatibility modes
+
+ libntp/ssl_init.c@1.22 +33 -20
+ [Bug 3363] Support for openssl-1.1.0 without compatibility modes
+
+ ntpd/ntp_crypto.c@1.189 +12 -7
+ [Bug 3363] Support for openssl-1.1.0 without compatibility modes
+
+ sntp/libevent/test/regress_ssl.c@1.8 +18 -4
+ [Bug 3363] Support for openssl-1.1.0 without compatibility modes
+
+ util/ntp-keygen.c@1.110 +17 -5
+ [Bug 3363] Support for openssl-1.1.0 without compatibility modes
+
+ChangeSet@1.3720.11.1, 2017-01-04 10:46:52+01:00, jnperlin@hydra.localnet
+ [Bug 2923] Trap Configuration Fail
+
+ ChangeLog@1.1852.10.1 +4 -1
+ [Bug 2923] Trap Configuration Fail
+
+ ntpd/ntp_config.c@1.340.1.1 +2 -2
+ [Bug 2923] Trap Configuration Fail
+
+ChangeSet@1.3720.10.2, 2017-01-02 12:09:21+00:00, stenn@psp-deb1.ntp.org
+ Update copyright year
+
+ ChangeLog@1.1852.9.2 +3 -0
+ Update copyright year
+
+ html/copyright.html@1.68 +5 -5
+ Update copyright year
+
+ ntpd/invoke-ntp.conf.texi@1.204 +1 -1
+ Update copyright year
+
+ ntpd/invoke-ntp.keys.texi@1.193 +1 -1
+ Update copyright year
+
+ ntpd/invoke-ntpd.texi@1.509 +1 -1
+ Update copyright year
+
+ ntpd/ntp.conf.5man@1.238 +4 -4
+ Update copyright year
+
+ ntpd/ntp.conf.5mdoc@1.238 +3 -3
+ Update copyright year
+
+ ntpd/ntp.conf.man.in@1.238 +4 -4
+ Update copyright year
+
+ ntpd/ntp.conf.mdoc.in@1.238 +3 -3
+ Update copyright year
+
+ ntpd/ntp.keys.5man@1.227 +3 -3
+ Update copyright year
+
+ ntpd/ntp.keys.5mdoc@1.227 +4 -4
+ Update copyright year
+
+ ntpd/ntp.keys.man.in@1.227 +3 -3
+ Update copyright year
+
+ ntpd/ntp.keys.mdoc.in@1.227 +4 -4
+ Update copyright year
+
+ ntpd/ntpd-opts.c@1.531 +4 -4
+ Update copyright year
+
+ ntpd/ntpd-opts.h@1.530 +2 -2
+ Update copyright year
+
+ ntpd/ntpd.1ntpdman@1.338 +4 -4
+ Update copyright year
+
+ ntpd/ntpd.1ntpdmdoc@1.338 +3 -3
+ Update copyright year
+
+ ntpd/ntpd.man.in@1.338 +4 -4
+ Update copyright year
+
+ ntpd/ntpd.mdoc.in@1.338 +3 -3
+ Update copyright year
+
+ ntpdc/invoke-ntpdc.texi@1.506 +1 -1
+ Update copyright year
+
+ ntpdc/ntpdc-opts.c@1.524 +4 -4
+ Update copyright year
+
+ ntpdc/ntpdc-opts.h@1.523 +2 -2
+ Update copyright year
+
+ ntpdc/ntpdc.1ntpdcman@1.337 +4 -4
+ Update copyright year
+
+ ntpdc/ntpdc.1ntpdcmdoc@1.337 +3 -3
+ Update copyright year
+
+ ntpdc/ntpdc.html@1.350 +75 -55
+ Update copyright year
+
+ ntpdc/ntpdc.man.in@1.337 +4 -4
+ Update copyright year
+
+ ntpdc/ntpdc.mdoc.in@1.337 +3 -3
+ Update copyright year
+
+ ntpq/invoke-ntpq.texi@1.514 +1 -1
+ Update copyright year
+
+ ntpq/ntpq-opts.c@1.531 +4 -4
+ Update copyright year
+
+ ntpq/ntpq-opts.h@1.529 +2 -2
+ Update copyright year
+
+ ntpq/ntpq.1ntpqman@1.342 +4 -4
+ Update copyright year
+
+ ntpq/ntpq.1ntpqmdoc@1.342 +3 -3
+ Update copyright year
+
+ ntpq/ntpq.man.in@1.342 +4 -4
+ Update copyright year
+
+ ntpq/ntpq.mdoc.in@1.342 +3 -3
+ Update copyright year
+
+ ntpsnmpd/invoke-ntpsnmpd.texi@1.508 +1 -1
+ Update copyright year
+
+ ntpsnmpd/ntpsnmpd-opts.c@1.526 +4 -4
+ Update copyright year
+
+ ntpsnmpd/ntpsnmpd-opts.h@1.525 +2 -2
+ Update copyright year
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdman@1.337 +4 -4
+ Update copyright year
+
+ ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc@1.337 +3 -3
+ Update copyright year
+
+ ntpsnmpd/ntpsnmpd.man.in@1.337 +4 -4
+ Update copyright year
+
+ ntpsnmpd/ntpsnmpd.mdoc.in@1.337 +3 -3
+ Update copyright year
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjman@1.98 +3 -3
+ Update copyright year
+
+ scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc@1.99 +2 -2
+ Update copyright year
+
+ scripts/calc_tickadj/calc_tickadj.html@1.100 +33 -21
+ Update copyright year
+
+ scripts/calc_tickadj/calc_tickadj.man.in@1.97 +3 -3
+ Update copyright year
+
+ scripts/calc_tickadj/calc_tickadj.mdoc.in@1.99 +2 -2
+ Update copyright year
+
+ scripts/calc_tickadj/invoke-calc_tickadj.texi@1.102 +1 -1
+ Update copyright year
+
+ scripts/invoke-plot_summary.texi@1.120 +1 -1
+ Update copyright year
+
+ scripts/invoke-summary.texi@1.119 +1 -1
+ Update copyright year
+
+ scripts/ntp-wait/invoke-ntp-wait.texi@1.329 +1 -1
+ Update copyright year
+
+ scripts/ntp-wait/ntp-wait-opts@1.65 +1 -1
+ Update copyright year
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitman@1.326 +3 -3
+ Update copyright year
+
+ scripts/ntp-wait/ntp-wait.1ntp-waitmdoc@1.327 +2 -2
+ Update copyright year
+
+ scripts/ntp-wait/ntp-wait.html@1.346 +47 -29
+ Update copyright year
+
+ scripts/ntp-wait/ntp-wait.man.in@1.326 +3 -3
+ Update copyright year
+
+ scripts/ntp-wait/ntp-wait.mdoc.in@1.327 +2 -2
+ Update copyright year
+
+ scripts/ntpsweep/invoke-ntpsweep.texi@1.117 +1 -1
+ Update copyright year
+
+ scripts/ntpsweep/ntpsweep-opts@1.67 +1 -1
+ Update copyright year
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepman@1.105 +3 -3
+ Update copyright year
+
+ scripts/ntpsweep/ntpsweep.1ntpsweepmdoc@1.105 +2 -2
+ Update copyright year
+
+ scripts/ntpsweep/ntpsweep.html@1.118 +42 -31
+ Update copyright year
+
+ scripts/ntpsweep/ntpsweep.man.in@1.105 +3 -3
+ Update copyright year
+
+ scripts/ntpsweep/ntpsweep.mdoc.in@1.106 +2 -2
+ Update copyright year
+
+ scripts/ntptrace/invoke-ntptrace.texi@1.118 +1 -1
+ Update copyright year
+
+ scripts/ntptrace/ntptrace-opts@1.67 +1 -1
+ Update copyright year
+
+ scripts/ntptrace/ntptrace.1ntptraceman@1.105 +3 -3
+ Update copyright year
+
+ scripts/ntptrace/ntptrace.1ntptracemdoc@1.106 +2 -2
+ Update copyright year
+
+ scripts/ntptrace/ntptrace.html@1.119 +34 -25
+ Update copyright year
+
+ scripts/ntptrace/ntptrace.man.in@1.105 +3 -3
+ Update copyright year
+
+ scripts/ntptrace/ntptrace.mdoc.in@1.107 +2 -2
+ Update copyright year
+
+ scripts/plot_summary-opts@1.68 +1 -1
+ Update copyright year
+
+ scripts/plot_summary.1plot_summaryman@1.118 +3 -3
+ Update copyright year
+
+ scripts/plot_summary.1plot_summarymdoc@1.118 +2 -2
+ Update copyright year
+
+ scripts/plot_summary.html@1.121 +45 -27
+ Update copyright year
+
+ scripts/plot_summary.man.in@1.118 +3 -3
+ Update copyright year
+
+ scripts/plot_summary.mdoc.in@1.118 +2 -2
+ Update copyright year
+
+ scripts/summary-opts@1.67 +1 -1
+ Update copyright year
+
+ scripts/summary.1summaryman@1.117 +3 -3
+ Update copyright year
+
+ scripts/summary.1summarymdoc@1.117 +2 -2
+ Update copyright year
+
+ scripts/summary.html@1.120 +37 -25
+ Update copyright year
+
+ scripts/summary.man.in@1.117 +3 -3
+ Update copyright year
+
+ scripts/summary.mdoc.in@1.117 +2 -2
+ Update copyright year
+
+ scripts/update-leap/invoke-update-leap.texi@1.18 +1 -1
+ Update copyright year
+
+ scripts/update-leap/update-leap-opts@1.18 +1 -1
+ Update copyright year
+
+ scripts/update-leap/update-leap.1update-leapman@1.18 +3 -3
+ Update copyright year
+
+ scripts/update-leap/update-leap.1update-leapmdoc@1.18 +2 -2
+ Update copyright year
+
+ scripts/update-leap/update-leap.man.in@1.18 +3 -3
+ Update copyright year
+
+ scripts/update-leap/update-leap.mdoc.in@1.18 +2 -2
+ Update copyright year
+
+ sntp/include/copyright.def@1.27 +1 -1
+ Update copyright year
+
+ sntp/invoke-sntp.texi@1.506 +1 -1
+ Update copyright year
+
+ sntp/sntp-opts.c@1.525 +4 -4
+ Update copyright year
+
+ sntp/sntp-opts.h@1.523 +2 -2
+ Update copyright year
+
+ sntp/sntp.1sntpman@1.341 +4 -4
+ Update copyright year
+
+ sntp/sntp.1sntpmdoc@1.341 +3 -3
+ Update copyright year
+
+ sntp/sntp.html@1.521 +107 -83
+ Update copyright year
+
+ sntp/sntp.man.in@1.341 +4 -4
+ Update copyright year
+
+ sntp/sntp.mdoc.in@1.341 +3 -3
+ Update copyright year
+
+ util/invoke-ntp-keygen.texi@1.509 +1 -1
+ Update copyright year
+
+ util/ntp-keygen-opts.c@1.527 +4 -4
+ Update copyright year
+
+ util/ntp-keygen-opts.h@1.525 +2 -2
+ Update copyright year
+
+ util/ntp-keygen.1ntp-keygenman@1.337 +4 -4
+ Update copyright year
+
+ util/ntp-keygen.1ntp-keygenmdoc@1.337 +3 -3
+ Update copyright year
+
+ util/ntp-keygen.man.in@1.337 +4 -4
+ Update copyright year
+
+ util/ntp-keygen.mdoc.in@1.337 +3 -3
+ Update copyright year
+
+ChangeSet@1.3720.10.1, 2017-01-02 11:53:32+00:00, stenn@psp-deb1.ntp.org
+ cleanup
+
+ ChangeLog@1.1852.9.1 +0 -1
+ cleanup
+
+ChangeSet@1.3720.9.1, 2016-12-30 10:39:31+01:00, jnperlin@hydra.localnet
+ [Bug 3356] Bugfix 3072 breaks multicastclient
+
+ ChangeLog@1.1852.8.1 +3 -0
+ [Bug 3356] Bugfix 3072 breaks multicastclient
+
+ ntpd/ntp_peer.c@1.161 +2 -1
+ [Bug 3356] Bugfix 3072 breaks multicastclient
+ (see bugs.ntp.org for details)
+
+ChangeSet@1.3720.8.2, 2016-12-11 11:53:32+01:00, perlinger@ntp.org
+ [Bug 3065] Quiet warnings on NetBSD (take II)
+
+ ntpq/ntpq.c@1.174 +1 -1
+ [Bug 3065] Quiet warnings on NetBSD
+ - repair of repair
+
+ChangeSet@1.3720.8.1, 2016-12-11 11:39:49+01:00, perlinger@ntp.org
+ [Bug 3065] Quiet warnings on NetBSD
+
+ ChangeLog@1.1852.7.1 +5 -1
+ [Bug 3065] Quiet warnings on NetBSD
+
+ include/ntp_fp.h@1.33 +1 -1
+ [Bug 3065] Quiet warnings on NetBSD
+ - GPS time units are unsigned -- gpstolfp should reflect this
+
+ libparse/clk_trimtsip.c@1.14 +4 -4
+ [Bug 3065] Quiet warnings on NetBSD
+ - GPS time units are unsigned
+
+ libparse/gpstolfp.c@1.13 +2 -2
+ [Bug 3065] Quiet warnings on NetBSD
+ - GPS time units are unsigned -- gpstolfp should reflect this
+
+ ntpd/refclock_jjy.c@1.33 +7 -6
+ [Bug 3065] Quiet warnings on NetBSD
+ - length counters should better be unsigned
+
+ ntpd/refclock_parse.c@1.84 +5 -5
+ [Bug 3065] Quiet warnings on NetBSD
+ - GPS time units are unsigned
+
+ ntpq/ntpq.c@1.173 +3 -3
+ [Bug 3065] Quiet warnings on NetBSD
+
+ChangeSet@1.3686.26.1, 2016-12-08 08:28:15+01:00, perlinger@ntp.org
+ [Bug 2645] out-of-bound pointers in ctl_putsys and decode_bitflags
+
+ ChangeLog@1.1834.26.1 +5 -0
+ [Bug 2645] out-of-bound pointers in ctl_putsys and decode_bitflags
+
+ lib/isc/inet_pton.c@1.8 +3 -3
+ [Bug 2645] out-of-bound pointers in ctl_putsys and decode_bitflags
+
+ libntp/statestr.c@1.29 +4 -5
+ [Bug 2645] out-of-bound pointers in ctl_putsys and decode_bitflags
+
+ ntpd/ntp_control.c@1.209.7.1 +5 -5
+ [Bug 2645] out-of-bound pointers in ctl_putsys and decode_bitflags
+
+ ntpd/ntp_io.c@1.417.1.1 +3 -4
+ [Bug 2645] out-of-bound pointers in ctl_putsys and decode_bitflags
+ - sidekick: counters should be unsigned, if it's really just for counting
+
+ ntpdc/ntpdc_ops.c@1.82 +1 -1
+ [Bug 2645] out-of-bound pointers in ctl_putsys and decode_bitflags
+ - sidekick: flags should not be counters
+
+ sntp/crypto.c@1.21.2.1 +2 -2
+ [Bug 2645] out-of-bound pointers in ctl_putsys and decode_bitflags
+ sidekick: arithmetic on void pointers is a booboo.
+
+ChangeSet@1.3720.6.1, 2016-11-29 20:36:05+01:00, perlinger@ntp.org
+ [Bug 2896] Nothing happens if minsane < maxclock < minclock
+ - create error log, but stay responsive
+
+ ChangeLog@1.1852.5.1 +4 -0
+ [Bug 2896] Nothing happens if minsane < maxclock < minclock
+
+ include/ntpd.h@1.195 +1 -0
+ [Bug 2896] Nothing happens if minsane < maxclock < minclock
+ - list 'sys_maxclock', too, for constraint checks
+
+ ntpd/ntp_config.c@1.341 +73 -15
+ [Bug 2896] Nothing happens if minsane < maxclock < minclock
+ - check minsane/minclock/maxclock relation and drop error log on constraint violation
+
+ ntpd/ntp_parser.c@1.104 +152 -152
+ [Bug 2896] Nothing happens if minsane < maxclock < minclock
+ - sidekick: minclock/maxclock should be int, not float!
+
+ ntpd/ntp_parser.h@1.68 +1 -1
+ [Bug 2896] Nothing happens if minsane < maxclock < minclock
+ - sidekick: minclock/maxclock should be int, not float!
+
+ ntpd/ntp_parser.y@1.94 +4 -4
+ [Bug 2896] Nothing happens if minsane < maxclock < minclock
+ - sidekick: minclock/maxclock should be int, not float!
+
+ChangeSet@1.3720.5.1, 2016-11-27 21:09:17+01:00, perlinger@ntp.org
+ [Bug 3216] libntp audio ioctl() args incorrectly cast to int on 4.4BSD-Lite derived platforms
+
+ ChangeLog@1.1852.4.1 +5 -0
+ [Bug 3216] libntp audio ioctl() args incorrectly cast to int on 4.4BSD-Lite derived platforms
+
+ libntp/audio.c@1.38 +25 -11
+ [Bug 3216] libntp audio ioctl() args incorrectly cast to int on 4.4BSD-Lite derived platforms
+ - provide platform-dependent typedef for IOCTL request identifier
+ - remove explicit, unnecessary and potentially harmful casts to 'int' for literal IOCTL requests
+ - make module-global variables static to keep them out of global namespace
+
+ChangeSet@1.3720.4.1, 2016-11-27 10:18:17+01:00, perlinger@ntp.org
+ [Bug 3215] 'make distcheck' fails with newer BK repository format
+
+ ChangeLog@1.1852.3.1 +3 -0
+ [Bug 3215] 'make distcheck' fails with newer BK repository format
+
+ sntp/Makefile.am@1.89 +1 -2
+ [Bug 3215] 'make distcheck' fails with newer BK repository format
+ - use 'bk root' in receipe to test for working BK and source being a BK repo in one go
+
+ChangeSet@1.3720.3.1, 2016-11-26 18:10:01+01:00, perlinger@ntp.org
+ [Bug 3139] (...) time_pps_create: Exec format error
+
+ ChangeLog@1.1852.2.1 +6 -0
+ [Bug 3139] (...) time_pps_create: Exec format error
+
+ ports/winnt/include/timepps.h@1.4 +14 -386
+ [Bug 3139] (...) time_pps_create: Exec format error
+ - move loader API from 'inline' to proper source
+
+ ports/winnt/ntpd/nt_ppsimpl.c@1.1 +550 -0
+ [Bug 3139] (...) time_pps_create: Exec format error
+ - move loader API from 'inline' to proper source
+ - augment pathless dlls with absolute path to NTPD
+ - use 'msyslog()' instead of 'printf()' for reporting trouble
+
+ ports/winnt/ntpd/nt_ppsimpl.c@1.0 +0 -0
+
+ ports/winnt/vs2005/ntpd.vcproj@1.22 +4 -0
+ [Bug 3139] (...) time_pps_create: Exec format error
+ - move loader API from 'inline' to proper source
+
+ ports/winnt/vs2008/ntpd/ntpd.vcproj@1.52 +4 -0
+ [Bug 3139] (...) time_pps_create: Exec format error
+ - move loader API from 'inline' to proper source
+
+ ports/winnt/vs2013/ntpd/ntpd.vcxproj@1.10 +1 -0
+ [Bug 3139] (...) time_pps_create: Exec format error
+ - move loader API from 'inline' to proper source
+
+ ports/winnt/vs2013/ntpd/ntpd.vcxproj.filters@1.7 +3 -0
+ [Bug 3139] (...) time_pps_create: Exec format error
+ - move loader API from 'inline' to proper source
+
+ ports/winnt/vs2015/ntpd/ntpd.vcxproj@1.2 +1 -0
+ [Bug 3139] (...) time_pps_create: Exec format error
+ - move loader API from 'inline' to proper source
+
+ ports/winnt/vs2015/ntpd/ntpd.vcxproj.filters@1.2 +3 -0
+ [Bug 3139] (...) time_pps_create: Exec format error
+ - move loader API from 'inline' to proper source
+
+ChangeSet@1.3720.2.1, 2016-11-24 07:57:37+01:00, perlinger@ntp.org
+ [Bug 3173] forking async worker: interrupted pipe I/O
+
+ ChangeLog@1.1852.1.1 +4 -0
+ [Bug 3173] forking async worker: interrupted pipe I/O
+
+ libntp/work_fork.c@1.18 +90 -57
+ [Bug 3173] forking async worker: interrupted pipe I/O
+
+ ntpd/ntp_proto.c@1.397.1.1 +2 -1
+ [Bug 3173] forking async worker: interrupted pipe I/O
+ - sidekick: minor const/init cleanup
+
+ChangeSet@1.3720.1.2, 2016-11-23 08:34:52+01:00, perlinger@ntp.org
Bug 3144 - NTP does not build without openSSL
- fix SNTP to build '--without-crypto',too
- remove some warnings that result from '--without-crypto'
@@ -404,7 +7524,7 @@ ChangeSet@1.3722, 2016-11-23 08:34:52+01:00, perlinger@ntp.org
Bug 3144 - NTP does not build without openSSL
- fix SNTP to build '--without-crypto', too
-ChangeSet@1.3721, 2016-11-22 22:22:46+01:00, perlinger@ntp.org
+ChangeSet@1.3720.1.1, 2016-11-22 22:22:46+01:00, perlinger@ntp.org
[Bug 3144] NTP does not build without openSSL
ChangeLog@1.1853 +3 -1
@@ -436,6 +7556,13 @@ ChangeSet@1.3721, 2016-11-22 22:22:46+01:00, perlinger@ntp.org
[Bug 3144] NTP does not build without openSSL
- sidekick: Fix annoying warnings MSVC emits
+ChangeSet@1.3688.6.1, 2016-11-22 03:21:05-08:00, harlan@fb-x86-a.pfcs.com
+ NEWS:
+ NEWS
+
+ NEWS@1.178, harlan@max.pfcs.com +2 -0
+ NEWS
+
ChangeSet@1.3720, 2016-11-21 08:08:21-05:00, stenn@deacon.udel.edu
NTP_4_2_8P9
TAG: NTP_4_2_8P9
@@ -779,7 +7906,7 @@ ChangeSet@1.3719, 2016-11-21 07:07:04-05:00, stenn@deacon.udel.edu
ChangeSet@1.3718, 2016-11-21 03:47:58+00:00, stenn@psp-deb1.ntp.org
NEWS updates, final p9 testing
- NEWS@1.203 +25 -17
+ NEWS@1.177.1.26 +25 -17
NEWS updates, final p9 testing
packageinfo.sh@1.530 +2 -2
@@ -788,13 +7915,13 @@ ChangeSet@1.3718, 2016-11-21 03:47:58+00:00, stenn@psp-deb1.ntp.org
ChangeSet@1.3717, 2016-11-18 10:33:02+00:00, stenn@psp-deb1.ntp.org
NEWS update for 3142
- NEWS@1.202 +2 -1
+ NEWS@1.177.1.25 +2 -1
NEWS update for 3142
-ChangeSet@1.3686.23.1, 2016-11-18 08:55:13+01:00, perlinger@ntp.org
+ChangeSet@1.3686.25.1, 2016-11-18 08:55:13+01:00, perlinger@ntp.org
[Bug 3142] bug in netmask prefix length detection
- ChangeLog@1.1834.23.1 +3 -0
+ ChangeLog@1.1834.25.1 +3 -0
[Bug 3142] bug in netmask prefix length detection
lib/isc/netaddr.c@1.15 +0 -1
@@ -803,13 +7930,37 @@ ChangeSet@1.3686.23.1, 2016-11-18 08:55:13+01:00, perlinger@ntp.org
ChangeSet@1.3715, 2016-11-16 21:25:49-08:00, harlan@fb-x86-a.pfcs.com
NEWS file update
- NEWS@1.201 +7 -22
+ NEWS@1.177.1.24 +7 -22
NEWS file update
+ChangeSet@1.3686.24.1, 2016-11-16 22:14:26+01:00, perlinger@ntp.org
+ [Bug 2851] allow -4/-6 on restrict line with mask
+
+ ChangeLog@1.1834.24.1 +4 -0
+ [Bug 2851] allow -4/-6 on restrict line with mask
+
+ ntpd/ntp_parser.c@1.102.1.1 +248 -248
+ [Bug 2851] allow -4/-6 on restrict line with mask
+ - update bison-generated file
+
+ ntpd/ntp_parser.y@1.92.1.1 +1 -1
+ [Bug 2851] allow -4/-6 on restrict line with mask
+ - applied patch by Miroslav Lichvar for ntp4.2.6 compat
+
+ChangeSet@1.3686.23.1, 2016-11-15 23:02:51+01:00, perlinger@ntp.org
+ [Bug 3107] Incorrect Logic for Peer Event Limiting
+
+ ChangeLog@1.1834.23.1 +4 -0
+ [Bug 3107] Incorrect Logic for Peer Event Limiting
+
+ ntpd/ntp_control.c@1.209.6.1 +1 -1
+ [Bug 3107] Incorrect Logic for Peer Event Limiting
+ - applied patch by Matthew Van Gundy
+
ChangeSet@1.3707.1.1, 2016-11-13 21:59:31-08:00, harlan@fb-x86-a.pfcs.com
cleanup
- NEWS@1.197.1.1 +201 -77
+ NEWS@1.177.2.1 +201 -77
cleanup
ChangeSet@1.3713, 2016-11-13 21:56:18-08:00, harlan@hms-mbp11.pfcs.com
@@ -821,19 +7972,19 @@ ChangeSet@1.3713, 2016-11-13 21:56:18-08:00, harlan@hms-mbp11.pfcs.com
ChangeSet@1.3712, 2016-11-13 02:43:02+00:00, stenn@psp-deb1.ntp.org
NEWS updates
- NEWS@1.199 +17 -0
+ NEWS@1.177.1.22 +17 -0
NEWS updates
ChangeSet@1.3710, 2016-11-13 02:30:31+00:00, stenn@psp-deb1.ntp.org
NEWS cleanup
- NEWS@1.198 +2 -0
+ NEWS@1.177.1.21 +2 -0
NEWS cleanup
ChangeSet@1.3707, 2016-11-12 17:36:54-08:00, harlan@fb-x86-a.pfcs.com
NEWS cleanup
- NEWS@1.197 +41 -6
+ NEWS@1.177.1.20 +41 -6
NEWS cleanup
ChangeSet@1.3706, 2016-11-12 16:55:59-08:00, harlan@fb-x86-a.pfcs.com
@@ -842,7 +7993,7 @@ ChangeSet@1.3706, 2016-11-12 16:55:59-08:00, harlan@fb-x86-a.pfcs.com
ChangeLog@1.1846.1.2 +1 -0
[Bug 3067] Root distance calculation needs improvement. HStenn
- NEWS@1.196 +1 -0
+ NEWS@1.177.1.19 +1 -0
[Bug 3067] Root distance calculation needs improvement. HStenn
ntpd/ntp_proto.c@1.396 +16 -11
@@ -854,7 +8005,7 @@ ChangeSet@1.3705, 2016-11-12 15:57:34-08:00, harlan@fb-x86-a.pfcs.com
ChangeLog@1.1846.1.1 +1 -0
[Bug 3138] gpsdjson refclock should honor fudgetime1. stenn@ntp.org
- NEWS@1.195 +1 -0
+ NEWS@1.177.1.18 +1 -0
[Bug 3138] gpsdjson refclock should honor fudgetime1. stenn@ntp.org
ntpd/refclock_gpsdjson.c@1.25 +1 -1
@@ -963,7 +8114,7 @@ ChangeSet@1.3698.2.1, 2016-11-03 17:02:24-07:00, harlan@max.pfcs.com
ChangeSet@1.3699.1.2, 2016-10-31 10:56:33+00:00, stenn@psp-deb1.ntp.org
Add bug 3125 to the NEWS file
- NEWS@1.194 +2 -0
+ NEWS@1.177.1.17 +2 -0
Add bug 3125 to the NEWS file
ChangeSet@1.3701, 2016-10-24 07:37:25+02:00, perlinger@ntp.org
@@ -1511,19 +8662,19 @@ ChangeSet@1.3688.3.2, 2016-10-02 09:01:53+02:00, perlinger@ntp.org
ChangeSet@1.3698, 2016-10-01 10:52:11+00:00, stenn@psp-deb1.ntp.org
Update NEWS for 3119
- NEWS@1.193 +17 -0
+ NEWS@1.177.1.16 +17 -0
Update NEWS for 3119
ChangeSet@1.3696, 2016-10-01 10:43:24+00:00, stenn@psp-deb1.ntp.org
Update NEWS for 3118
- NEWS@1.192 +17 -0
+ NEWS@1.177.1.15 +17 -0
Update NEWS for 3118
ChangeSet@1.3694, 2016-10-01 10:29:06+00:00, stenn@psp-deb1.ntp.org
Update NEWS for 3110
- NEWS@1.191 +17 -0
+ NEWS@1.177.1.14 +17 -0
Update NEWS for 3110
ChangeSet@1.3688.3.1, 2016-10-01 11:36:55+02:00, perlinger@ntp.org
@@ -1557,13 +8708,13 @@ ChangeSet@1.3688.3.1, 2016-10-01 11:36:55+02:00, perlinger@ntp.org
ChangeSet@1.3691, 2016-10-01 09:18:25+00:00, stenn@psp-deb1.ntp.org
Update NEWS for 3082
- NEWS@1.190 +17 -0
+ NEWS@1.177.1.13 +17 -0
Update NEWS for 3082
ChangeSet@1.3688.1.33, 2016-10-01 08:32:28+00:00, stenn@psp-deb1.ntp.org
[Bug 3072] tweaks
- NEWS@1.189 +16 -1
+ NEWS@1.177.1.12 +16 -1
[Bug 3072] tweaks
ntpd/ntp_peer.c@1.160 +6 -1
@@ -1588,7 +8739,7 @@ ChangeSet@1.3688.1.31, 2016-09-29 20:53:30+00:00, perlinger@ntp.org
ChangeSet@1.3688.1.30, 2016-09-29 12:03:17+00:00, stenn@psp-deb1.ntp.org
NEWS update
- NEWS@1.188 +2 -0
+ NEWS@1.177.1.11 +2 -0
NEWS update
ChangeSet@1.3688.2.1, 2016-09-29 11:59:03+00:00, stenn@psp-deb1.ntp.org
@@ -1597,7 +8748,7 @@ ChangeSet@1.3688.2.1, 2016-09-29 11:59:03+00:00, stenn@psp-deb1.ntp.org
ChangeLog@1.1836.2.1, stenn@stenn.ntp.org +1 -0
Shim X509_get_signature_nid() if needed
- NEWS@1.187, stenn@stenn.ntp.org +1 -0
+ NEWS@1.177.1.10, stenn@stenn.ntp.org +1 -0
Shim X509_get_signature_nid() if needed
libntp/ssl_init.c@1.17.1.3 +1 -1
@@ -1609,13 +8760,13 @@ ChangeSet@1.3688.2.1, 2016-09-29 11:59:03+00:00, stenn@psp-deb1.ntp.org
ChangeSet@1.3688.1.27, 2016-09-28 11:28:56+00:00, stenn@psp-deb1.ntp.org
NEWS
- NEWS@1.186 +1 -0
+ NEWS@1.177.1.9 +1 -0
NEWS
ChangeSet@1.3688.1.25, 2016-09-28 11:24:36+00:00, stenn@psp-deb1.ntp.org
NEWS
- NEWS@1.185 +2 -0
+ NEWS@1.177.1.8 +2 -0
NEWS
ChangeSet@1.3688.1.23, 2016-09-28 11:17:22+00:00, stenn@psp-deb1.ntp.org
@@ -1624,25 +8775,25 @@ ChangeSet@1.3688.1.23, 2016-09-28 11:17:22+00:00, stenn@psp-deb1.ntp.org
ChangeLog@1.1836.1.19 +2 -2
Updated ChangeLog and NEWS
- NEWS@1.184 +2 -0
+ NEWS@1.177.1.7 +2 -0
Updated ChangeLog and NEWS
ChangeSet@1.3688.1.21, 2016-09-28 11:12:28+00:00, stenn@psp-deb1.ntp.org
NEWS
- NEWS@1.183 +2 -0
+ NEWS@1.177.1.6 +2 -0
NEWS
ChangeSet@1.3688.1.19, 2016-09-28 11:01:29+00:00, stenn@psp-deb1.ntp.org
NEWS
- NEWS@1.182 +3 -0
+ NEWS@1.177.1.5 +3 -0
NEWS
ChangeSet@1.3688.1.17, 2016-09-28 10:54:12+00:00, stenn@psp-deb1.ntp.org
Update ChangeLog and NEWS
- NEWS@1.181 +3 -0
+ NEWS@1.177.1.4 +3 -0
Update ChangeLog and NEWS
ChangeSet@1.3688.1.15, 2016-09-28 10:45:21+00:00, stenn@psp-deb1.ntp.org
@@ -1651,13 +8802,13 @@ ChangeSet@1.3688.1.15, 2016-09-28 10:45:21+00:00, stenn@psp-deb1.ntp.org
ChangeLog@1.1836.1.14 +2 -2
Update ChangeLog and NEWS
- NEWS@1.180 +2 -0
+ NEWS@1.177.1.3 +2 -0
Update ChangeLog and NEWS
ChangeSet@1.3688.1.13, 2016-09-28 10:37:17+00:00, stenn@psp-deb1.ntp.org
NEWS updates
- NEWS@1.179 +4 -0
+ NEWS@1.177.1.2 +4 -0
NEWS updates
ChangeSet@1.3688.1.11, 2016-09-28 10:25:01+00:00, stenn@psp-deb1.ntp.org
@@ -1666,7 +8817,7 @@ ChangeSet@1.3688.1.11, 2016-09-28 10:25:01+00:00, stenn@psp-deb1.ntp.org
ChangeLog@1.1836.1.11 +1 -1
Update ChangeLog and NEWS
- NEWS@1.178 +1 -0
+ NEWS@1.177.1.1 +1 -0
Update ChangeLog and NEWS
ChangeSet@1.3688.1.8, 2016-09-28 08:17:16+00:00, stenn@psp-deb1.ntp.org
@@ -146956,9 +154107,6 @@ ChangeSet@1.1436.15.74, 2009-12-08 08:23:12-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.26.2 +1 -1
NTP_4_2_4P8
- sntp/sntp.1@1.49.26.2 +2 -2
- NTP_4_2_4P8
-
util/ntp-keygen-opts.c@1.49.26.2 +2 -2
NTP_4_2_4P8
@@ -147038,9 +154186,6 @@ ChangeSet@1.1436.15.73, 2009-12-08 07:45:28-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.26.1 +54 -2
NTP_4_2_4P9_RC1
- sntp/sntp.1@1.49.26.1 +2 -2
- NTP_4_2_4P9_RC1
-
util/ntp-keygen-opts.c@1.49.26.1 +5 -5
NTP_4_2_4P9_RC1
@@ -163972,9 +171117,6 @@ ChangeSet@1.1436.15.70, 2009-05-18 05:04:41-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.25.1 +1 -1
NTP_4_2_4P7
- sntp/sntp.1@1.49.25.1 +2 -2
- NTP_4_2_4P7
-
util/ntp-keygen-opts.c@1.49.25.1 +4 -4
NTP_4_2_4P7
@@ -164340,9 +171482,6 @@ ChangeSet@1.1436.15.64, 2009-05-12 02:41:56-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.24.1 +1 -1
NTP_4_2_4P7_RC7
- sntp/sntp.1@1.49.24.1 +3 -3
- NTP_4_2_4P7_RC7
-
util/ntp-keygen-opts.c@1.49.24.1 +3 -3
NTP_4_2_4P7_RC7
@@ -164816,9 +171955,6 @@ ChangeSet@1.1436.15.58, 2009-05-08 04:42:52-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.23.1 +1 -1
NTP_4_2_4P7_RC6
- sntp/sntp.1@1.49.23.1 +2 -2
- NTP_4_2_4P7_RC6
-
util/ntp-keygen-opts.c@1.49.23.1 +2 -2
NTP_4_2_4P7_RC6
@@ -165532,9 +172668,6 @@ ChangeSet@1.1436.15.50, 2009-05-02 02:38:49-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.22.1 +1 -1
NTP_4_2_4P7_RC5
- sntp/sntp.1@1.49.22.1 +2 -2
- NTP_4_2_4P7_RC5
-
util/ntp-keygen-opts.c@1.49.22.1 +2 -2
NTP_4_2_4P7_RC5
@@ -165932,9 +173065,6 @@ ChangeSet@1.1436.15.48, 2009-04-29 04:03:41-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.21.1 +1 -1
NTP_4_2_4P7_RC4
- sntp/sntp.1@1.49.21.1 +2 -2
- NTP_4_2_4P7_RC4
-
util/ntp-keygen-opts.c@1.49.21.1 +2 -2
NTP_4_2_4P7_RC4
@@ -166945,9 +174075,6 @@ ChangeSet@1.1436.15.44, 2009-04-22 08:18:29-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.20.1 +1 -1
NTP_4_2_4P7_RC3
- sntp/sntp.1@1.49.20.1 +2 -2
- NTP_4_2_4P7_RC3
-
util/ntp-keygen-opts.c@1.49.20.1 +2 -2
NTP_4_2_4P7_RC3
@@ -167569,9 +174696,6 @@ ChangeSet@1.1436.15.30, 2009-04-09 07:44:06-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.19.1 +1 -1
NTP_4_2_4P7_RC2
- sntp/sntp.1@1.49.19.1 +2 -2
- NTP_4_2_4P7_RC2
-
util/ntp-keygen-opts.c@1.49.19.1 +2 -2
NTP_4_2_4P7_RC2
@@ -168111,9 +175235,6 @@ ChangeSet@1.1436.15.26, 2009-03-30 06:47:41-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.18.1 +1 -1
NTP_4_2_4P7_RC1
- sntp/sntp.1@1.49.18.1 +2 -2
- NTP_4_2_4P7_RC1
-
util/ntp-keygen-opts.c@1.49.18.1 +2 -2
NTP_4_2_4P7_RC1
@@ -169448,9 +176569,6 @@ ChangeSet@1.1436.15.12, 2009-01-08 06:21:48-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.17.2 +1 -1
NTP_4_2_4P6
- sntp/sntp.1@1.49.17.2 +2 -2
- NTP_4_2_4P6
-
util/ntp-keygen-opts.c@1.49.17.2 +2 -2
NTP_4_2_4P6
@@ -169530,9 +176648,6 @@ ChangeSet@1.1436.15.11, 2009-01-08 04:49:23-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.17.1 +1 -1
NTP_4_2_4P5
- sntp/sntp.1@1.49.17.1 +2 -2
- NTP_4_2_4P5
-
util/ntp-keygen-opts.c@1.49.17.1 +1 -1
NTP_4_2_4P5
@@ -172785,9 +179900,6 @@ ChangeSet@1.1735.4.1, 2008-08-30 22:09:29-04:00, stenn@whimsy.udel.edu
ChangeSet@1.1759, 2008-08-22 21:27:59-04:00, stenn@pogo.udel.edu
remove bogus .o file
- BitKeeper/deleted/.del-utilities.o@1.2 +0 -0
- Delete: gsoc_sntp/utilities.o
-
ChangeSet@1.1735.1.29, 2008-08-21 05:05:19+00:00, gopal@pogo.udel.edu
driver20.html:
[BUG 610] Documentation update for NMEA reference clock driver.
@@ -173066,9 +180178,6 @@ ChangeSet@1.1436.15.4, 2008-08-17 05:30:47-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.16.1 +1 -1
NTP_4_2_4P5
- sntp/sntp.1@1.49.16.1 +2 -2
- NTP_4_2_4P5
-
util/ntp-keygen-opts.c@1.49.16.1 +2 -2
NTP_4_2_4P5
@@ -173190,11 +180299,6 @@ ChangeSet@1.1755, 2008-08-16 06:41:28+09:00, Amidamaru@yumi.mxiesoft.com
gsoc_sntp/utilities.h@1.0 +0 -0
- gsoc_sntp/utilities.o@1.1 +177 -0
- BitKeeper file /geom_mobile/home/Amidamaru/projects/sntp/repo/ntp-dev/gsoc_sntp/utilities.o
-
- gsoc_sntp/utilities.o@1.0 +0 -0
-
ChangeSet@1.1436.1.105, 2008-08-10 21:56:17-04:00, clemens@pogo.udel.edu
BUG[1052] Minor reordering of previous patch to make it more robust.
@@ -173352,9 +180456,6 @@ ChangeSet@1.1436.1.101, 2008-08-10 07:44:31-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.15.1 +2 -3
NTP_4_2_4P5_RC2
- sntp/sntp.1@1.49.15.1 +3 -3
- NTP_4_2_4P5_RC2
-
util/ntp-keygen-opts.c@1.49.15.1 +2 -2
NTP_4_2_4P5_RC2
@@ -174815,9 +181916,6 @@ ChangeSet@1.1436.1.95, 2008-05-20 03:51:01-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.14.1 +1 -1
NTP_4_2_4P5_RC1
- sntp/sntp.1@1.49.14.1 +2 -2
- NTP_4_2_4P5_RC1
-
util/ntp-keygen-opts.c@1.49.14.1 +6 -7
NTP_4_2_4P5_RC1
@@ -180076,9 +187174,6 @@ ChangeSet@1.1436.1.84, 2007-09-10 20:40:19-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.13.1 +1 -1
NTP_4_2_4P4
- sntp/sntp.1@1.49.13.1 +2 -2
- NTP_4_2_4P4
-
util/ntp-keygen-opts.c@1.49.13.1 +2 -2
NTP_4_2_4P4
@@ -180385,9 +187480,6 @@ ChangeSet@1.1436.1.81, 2007-08-28 15:34:55-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.12.1 +1 -1
NTP_4_2_4P4_RC2
- sntp/sntp.1@1.49.12.1 +2 -2
- NTP_4_2_4P4_RC2
-
util/ntp-keygen-opts.c@1.49.12.1 +4 -4
NTP_4_2_4P4_RC2
@@ -180775,9 +187867,6 @@ ChangeSet@1.1436.1.78, 2007-08-18 17:11:19-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.11.1 +1 -1
NTP_4_2_4P4_RC1
- sntp/sntp.1@1.49.11.1 +2 -2
- NTP_4_2_4P4_RC1
-
util/ntp-keygen-opts.c@1.49.11.1 +2 -2
NTP_4_2_4P4_RC1
@@ -182125,9 +189214,6 @@ ChangeSet@1.1436.1.66, 2007-06-29 15:46:00-04:00, stenn@deacon.udel.edu
sntp/sntp-opts.texi@1.46.10.1 +1 -1
NTP_4_2_4P3
- sntp/sntp.1@1.49.10.1 +2 -2
- NTP_4_2_4P3
-
util/ntp-keygen-opts.c@1.49.10.1 +2 -2
NTP_4_2_4P3
@@ -182377,9 +189463,6 @@ ChangeSet@1.1436.1.63, 2007-06-27 07:46:44-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.9.1 +1 -1
NTP_4_2_4P3_RC1
- sntp/sntp.1@1.49.9.1 +2 -2
- NTP_4_2_4P3_RC1
-
util/ntp-keygen-opts.c@1.49.9.1 +2 -2
NTP_4_2_4P3_RC1
@@ -182875,9 +189958,6 @@ ChangeSet@1.1436.1.59, 2007-06-20 07:45:57-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.8.1 +1 -1
NTP_4_2_4P2
- sntp/sntp.1@1.49.8.1 +2 -2
- NTP_4_2_4P2
-
util/ntp-keygen-opts.c@1.49.8.1 +2 -2
NTP_4_2_4P2
@@ -183525,9 +190605,6 @@ ChangeSet@1.1436.1.57, 2007-06-10 07:58:59-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.7.1 +1 -1
NTP_4_2_4P2_RC6
- sntp/sntp.1@1.49.7.1 +2 -2
- NTP_4_2_4P2_RC6
-
util/ntp-keygen-opts.c@1.49.7.1 +2 -2
NTP_4_2_4P2_RC6
@@ -184282,9 +191359,6 @@ ChangeSet@1.1436.1.54, 2007-05-29 07:43:58-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.6.1 +1 -1
NTP_4_2_4P2_RC5
- sntp/sntp.1@1.49.6.1 +2 -2
- NTP_4_2_4P2_RC5
-
util/ntp-keygen-opts.c@1.49.6.1 +2 -2
NTP_4_2_4P2_RC5
@@ -184542,9 +191616,6 @@ ChangeSet@1.1436.1.51, 2007-05-27 07:45:05-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.5.1 +1 -1
NTP_4_2_4P2_RC4
- sntp/sntp.1@1.49.5.1 +2 -2
- NTP_4_2_4P2_RC4
-
util/ntp-keygen-opts.c@1.49.5.1 +2 -2
NTP_4_2_4P2_RC4
@@ -184755,9 +191826,6 @@ ChangeSet@1.1436.3.9, 2007-05-25 07:44:43-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.4.1 +1 -1
NTP_4_2_4P2_RC3
- sntp/sntp.1@1.49.4.1 +2 -2
- NTP_4_2_4P2_RC3
-
util/ntp-keygen-opts.c@1.49.4.1 +2 -2
NTP_4_2_4P2_RC3
@@ -185084,9 +192152,6 @@ ChangeSet@1.1436.3.3, 2007-05-19 07:53:57-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.3.2 +1 -1
NTP_4_2_4P2_RC2
- sntp/sntp.1@1.49.3.2 +2 -2
- NTP_4_2_4P2_RC2
-
util/ntp-keygen-opts.c@1.49.3.2 +4 -4
NTP_4_2_4P2_RC2
@@ -185830,9 +192895,6 @@ ChangeSet@1.1436.3.2, 2007-05-19 02:33:04-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.3.1 +1 -1
We need to use the upgraded autogen/libopts in -stable too.
- sntp/sntp.1@1.49.3.1 +2 -2
- We need to use the upgraded autogen/libopts in -stable too.
-
util/ntp-keygen-opts.c@1.49.3.1 +23 -14
We need to use the upgraded autogen/libopts in -stable too.
@@ -187887,9 +194949,6 @@ ChangeSet@1.1436.1.44, 2007-04-14 19:05:07-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.2.2 +1 -1
NTP_4_2_4P2_RC1
- sntp/sntp.1@1.49.2.2 +2 -2
- NTP_4_2_4P2_RC1
-
util/ntp-keygen-opts.c@1.49.2.3 +2 -2
NTP_4_2_4P2_RC1
@@ -187975,9 +195034,6 @@ ChangeSet@1.1436.1.42, 2007-04-14 07:53:43-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.2.1 +1 -1
NTP_4_2_4P1_RC1
- sntp/sntp.1@1.49.2.1 +2 -2
- NTP_4_2_4P1_RC1
-
util/ntp-keygen-opts.c@1.49.2.2 +2 -2
NTP_4_2_4P1_RC1
@@ -190138,9 +197194,6 @@ ChangeSet@1.1436.1.36, 2007-03-07 06:46:09-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.1.6 +1 -1
NTP_4_2_4P0
- sntp/sntp.1@1.49.1.6 +2 -2
- NTP_4_2_4P0
-
util/ntp-keygen-opts.c@1.49.1.6 +2 -2
NTP_4_2_4P0
@@ -190310,9 +197363,6 @@ ChangeSet@1.1440.1.60, 2007-03-03 22:41:27-05:00, stenn@whimsy.udel.edu
BitKeeper/deleted/.del-sntp-opts.texi@1.68 +0 -0
Delete: sntp/sntp-opts.texi
- BitKeeper/deleted/.del-sntp.1@1.71 +0 -0
- Delete: sntp/sntp.1
-
ntpd/ntpd-opts.c@1.1 +1055 -0
BitKeeper file /deacon/backroom/ntp-dev/ntpd/ntpd-opts.c
@@ -190506,9 +197556,6 @@ ChangeSet@1.1440.1.58, 2007-03-03 06:43:50-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.66 +1 -1
NTP_4_2_5P15
- sntp/sntp.1@1.69 +2 -2
- NTP_4_2_5P15
-
util/ntp-keygen-opts.c@1.69 +2 -2
NTP_4_2_5P15
@@ -190598,9 +197645,6 @@ ChangeSet@1.1440.1.55, 2007-02-26 06:42:31-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.65 +1 -1
NTP_4_2_5P14
- sntp/sntp.1@1.68 +2 -2
- NTP_4_2_5P14
-
util/ntp-keygen-opts.c@1.68 +2 -2
NTP_4_2_5P14
@@ -190694,9 +197738,6 @@ ChangeSet@1.1440.1.52, 2007-02-25 06:42:44-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.64 +1 -1
NTP_4_2_5P13
- sntp/sntp.1@1.67 +2 -2
- NTP_4_2_5P13
-
util/ntp-keygen-opts.c@1.67 +2 -2
NTP_4_2_5P13
@@ -190789,9 +197830,6 @@ ChangeSet@1.1440.1.50, 2007-02-24 08:33:25-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.63 +1 -1
NTP_4_2_5P12
- sntp/sntp.1@1.66 +2 -2
- NTP_4_2_5P12
-
util/ntp-keygen-opts.c@1.66 +2 -2
NTP_4_2_5P12
@@ -190868,9 +197906,6 @@ ChangeSet@1.1436.1.33, 2007-02-24 06:42:26-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.1.5 +1 -1
NTP_4_2_4P0_RC5
- sntp/sntp.1@1.49.1.5 +2 -2
- NTP_4_2_4P0_RC5
-
util/ntp-keygen-opts.c@1.49.1.5 +2 -2
NTP_4_2_4P0_RC5
@@ -190959,9 +197994,6 @@ ChangeSet@1.1440.1.47, 2007-02-23 06:42:48-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.62 +1 -1
NTP_4_2_5P11
- sntp/sntp.1@1.65 +2 -2
- NTP_4_2_5P11
-
util/ntp-keygen-opts.c@1.65 +2 -2
NTP_4_2_5P11
@@ -191053,9 +198085,6 @@ ChangeSet@1.1440.1.44, 2007-02-22 06:46:29-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.61 +1 -1
NTP_4_2_5P10
- sntp/sntp.1@1.64 +2 -2
- NTP_4_2_5P10
-
util/ntp-keygen-opts.c@1.64 +2 -2
NTP_4_2_5P10
@@ -191138,9 +198167,6 @@ ChangeSet@1.1440.1.42, 2007-02-19 08:43:35-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.59 +1 -1
NTP_4_2_5P9
- sntp/sntp.1@1.62 +2 -2
- NTP_4_2_5P9
-
util/ntp-keygen-opts.c@1.62 +2 -2
NTP_4_2_5P9
@@ -191217,9 +198243,6 @@ ChangeSet@1.1436.1.30, 2007-02-19 06:46:30-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.1.4 +1 -1
NTP_4_2_4P0_RC4
- sntp/sntp.1@1.49.1.4 +2 -2
- NTP_4_2_4P0_RC4
-
util/ntp-keygen-opts.c@1.49.1.4 +2 -2
NTP_4_2_4P0_RC4
@@ -191329,9 +198352,6 @@ ChangeSet@1.1440.1.39, 2007-02-17 06:42:34-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.57 +1 -1
NTP_4_2_5P8
- sntp/sntp.1@1.60 +2 -2
- NTP_4_2_5P8
-
util/ntp-keygen-opts.c@1.60 +2 -2
NTP_4_2_5P8
@@ -191417,9 +198437,6 @@ ChangeSet@1.1440.1.37, 2007-02-16 06:42:39-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.56 +1 -1
NTP_4_2_5P7
- sntp/sntp.1@1.59 +2 -2
- NTP_4_2_5P7
-
util/ntp-keygen-opts.c@1.59 +2 -2
NTP_4_2_5P7
@@ -191520,9 +198537,6 @@ ChangeSet@1.1440.1.34, 2007-02-05 08:45:44-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.55 +1 -1
NTP_4_2_5P6
- sntp/sntp.1@1.58 +2 -2
- NTP_4_2_5P6
-
util/ntp-keygen-opts.c@1.58 +2 -2
NTP_4_2_5P6
@@ -191599,9 +198613,6 @@ ChangeSet@1.1436.1.27, 2007-02-05 06:47:44-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.1.3 +1 -1
NTP_4_2_4_RC3
- sntp/sntp.1@1.49.1.3 +2 -2
- NTP_4_2_4_RC3
-
util/ntp-keygen-opts.c@1.49.1.3 +2 -2
NTP_4_2_4_RC3
@@ -191747,9 +198758,6 @@ ChangeSet@1.1440.1.29, 2007-01-31 06:42:22-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.53 +1 -1
NTP_4_2_5P5
- sntp/sntp.1@1.56 +2 -2
- NTP_4_2_5P5
-
util/ntp-keygen-opts.c@1.56 +2 -2
NTP_4_2_5P5
@@ -191832,9 +198840,6 @@ ChangeSet@1.1440.1.27, 2007-01-30 08:41:43-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.52 +1 -1
NTP_4_2_5P4
- sntp/sntp.1@1.55 +2 -2
- NTP_4_2_5P4
-
util/ntp-keygen-opts.c@1.55 +2 -2
NTP_4_2_5P4
@@ -191911,9 +198916,6 @@ ChangeSet@1.1436.1.20, 2007-01-30 06:44:11-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.1.2 +1 -1
NTP_4_2_4_RC2
- sntp/sntp.1@1.49.1.2 +2 -2
- NTP_4_2_4_RC2
-
util/ntp-keygen-opts.c@1.49.1.2 +2 -2
NTP_4_2_4_RC2
@@ -192059,9 +199061,6 @@ ChangeSet@1.1440.1.21, 2007-01-25 18:30:28-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.51 +1 -1
NTP_4_2_5P3
- sntp/sntp.1@1.54 +2 -2
- NTP_4_2_5P3
-
util/ntp-keygen-opts.c@1.54 +2 -2
NTP_4_2_5P3
@@ -192144,9 +199143,6 @@ ChangeSet@1.1436.1.14, 2007-01-23 04:47:08-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46.1.1 +1 -1
NTP_4_2_4_RC1
- sntp/sntp.1@1.49.1.1 +2 -2
- NTP_4_2_4_RC1
-
util/ntp-keygen-opts.c@1.49.1.1 +2 -2
NTP_4_2_4_RC1
@@ -192376,9 +199372,6 @@ ChangeSet@1.1440.1.13, 2007-01-08 06:01:47-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.49 +1 -1
NTP_4_2_5P2
- sntp/sntp.1@1.52 +2 -2
- NTP_4_2_5P2
-
util/ntp-keygen-opts.c@1.52 +2 -2
NTP_4_2_5P2
@@ -192496,9 +199489,6 @@ ChangeSet@1.1440.1.10, 2007-01-06 05:35:24-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.48 +1 -1
NTP_4_2_5P1
- sntp/sntp.1@1.51 +2 -2
- NTP_4_2_5P1
-
util/ntp-keygen-opts.c@1.51 +2 -2
NTP_4_2_5P1
@@ -193130,9 +200120,6 @@ ChangeSet@1.1440, 2006-12-29 06:43:02-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.45.1.2 +1 -1
NTP_4_2_5P0
- sntp/sntp.1@1.48.1.2 +2 -2
- NTP_4_2_5P0
-
util/ntp-keygen-opts.c@1.48.1.2 +2 -2
NTP_4_2_5P0
@@ -193242,9 +200229,6 @@ ChangeSet@1.1438, 2006-12-28 21:29:25-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.45.1.1 +1 -1
NTP_4_2_5
- sntp/sntp.1@1.48.1.1 +2 -2
- NTP_4_2_5
-
util/ntp-keygen-opts.c@1.48.1.1 +2 -2
NTP_4_2_5
@@ -193321,9 +200305,6 @@ ChangeSet@1.1436.1.1, 2006-12-28 19:21:25-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.46 +1 -1
NTP_4_2_4
- sntp/sntp.1@1.49 +2 -2
- NTP_4_2_4
-
util/ntp-keygen-opts.c@1.49 +2 -2
NTP_4_2_4
@@ -193502,9 +200483,6 @@ ChangeSet@1.1426, 2006-11-25 06:41:49-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.45 +1 -1
NTP_4_2_3P70_RC
- sntp/sntp.1@1.48 +2 -2
- NTP_4_2_3P70_RC
-
util/ntp-keygen-opts.c@1.48 +2 -2
NTP_4_2_3P70_RC
@@ -193590,9 +200568,6 @@ ChangeSet@1.1424, 2006-11-24 06:42:33-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.44 +9 -1
NTP_4_2_3P69_RC
- sntp/sntp.1@1.47 +8 -64
- NTP_4_2_3P69_RC
-
util/ntp-keygen-opts.c@1.47 +2 -2
NTP_4_2_3P69_RC
@@ -193684,9 +200659,6 @@ ChangeSet@1.1422, 2006-11-22 06:42:29-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.43 +1 -1
NTP_4_2_3P68_RC
- sntp/sntp.1@1.46 +2 -2
- NTP_4_2_3P68_RC
-
util/ntp-keygen-opts.c@1.46 +2 -2
NTP_4_2_3P68_RC
@@ -193781,9 +200753,6 @@ ChangeSet@1.1419, 2006-11-21 06:42:26-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.42 +1 -1
NTP_4_2_3P67_RC
- sntp/sntp.1@1.45 +2 -2
- NTP_4_2_3P67_RC
-
util/ntp-keygen-opts.c@1.45 +2 -2
NTP_4_2_3P67_RC
@@ -193881,9 +200850,6 @@ ChangeSet@1.1415, 2006-11-19 06:45:35-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.41 +1 -1
NTP_4_2_3P66_RC
- sntp/sntp.1@1.44 +2 -2
- NTP_4_2_3P66_RC
-
util/ntp-keygen-opts.c@1.44 +2 -2
NTP_4_2_3P66_RC
@@ -193978,9 +200944,6 @@ ChangeSet@1.1412, 2006-11-10 06:41:45-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.40 +1 -1
NTP_4_2_3P65_RC
- sntp/sntp.1@1.43 +2 -2
- NTP_4_2_3P65_RC
-
util/ntp-keygen-opts.c@1.43 +2 -2
NTP_4_2_3P65_RC
@@ -194069,9 +201032,6 @@ ChangeSet@1.1409, 2006-11-09 06:42:28-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.39 +1 -1
NTP_4_2_3P64_RC
- sntp/sntp.1@1.42 +2 -2
- NTP_4_2_3P64_RC
-
util/ntp-keygen-opts.c@1.42 +2 -2
NTP_4_2_3P64_RC
@@ -194164,9 +201124,6 @@ ChangeSet@1.1406, 2006-11-06 06:47:05-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.38 +1 -1
NTP_4_2_3P63_RC
- sntp/sntp.1@1.41 +2 -2
- NTP_4_2_3P63_RC
-
util/ntp-keygen-opts.c@1.41 +2 -2
NTP_4_2_3P63_RC
@@ -194276,9 +201233,6 @@ ChangeSet@1.1400, 2006-11-01 06:45:21-05:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.37 +1 -1
NTP_4_2_3P62_RC
- sntp/sntp.1@1.40 +2 -2
- NTP_4_2_3P62_RC
-
util/ntp-keygen-opts.c@1.40 +2 -2
NTP_4_2_3P62_RC
@@ -194370,9 +201324,6 @@ ChangeSet@1.1397, 2006-10-23 07:48:24-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.36 +1 -1
NTP_4_2_3P61_RC
- sntp/sntp.1@1.39 +2 -2
- NTP_4_2_3P61_RC
-
util/ntp-keygen-opts.c@1.39 +2 -2
NTP_4_2_3P61_RC
@@ -194458,9 +201409,6 @@ ChangeSet@1.1379.12.3, 2006-10-20 07:45:30-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.35 +1 -1
NTP_4_2_3P60_RC
- sntp/sntp.1@1.38 +2 -2
- NTP_4_2_3P60_RC
-
util/ntp-keygen-opts.c@1.38 +2 -2
NTP_4_2_3P60_RC
@@ -194556,9 +201504,6 @@ ChangeSet@1.1379.1.52, 2006-10-15 07:42:15-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.34 +1 -1
NTP_4_2_3P59
- sntp/sntp.1@1.37 +2 -2
- NTP_4_2_3P59
-
util/ntp-keygen-opts.c@1.37 +2 -2
NTP_4_2_3P59
@@ -194661,9 +201606,6 @@ ChangeSet@1.1379.1.50, 2006-10-14 07:41:41-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.33 +1 -1
NTP_4_2_3P58
- sntp/sntp.1@1.36 +2 -2
- NTP_4_2_3P58
-
util/ntp-keygen-opts.c@1.36 +2 -2
NTP_4_2_3P58
@@ -194763,9 +201705,6 @@ ChangeSet@1.1379.1.48, 2006-10-13 07:48:30-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.32 +1 -1
NTP_4_2_3P57
- sntp/sntp.1@1.35 +2 -2
- NTP_4_2_3P57
-
util/ntp-keygen-opts.c@1.35 +4 -4
NTP_4_2_3P57
@@ -195163,9 +202102,6 @@ ChangeSet@1.1379.1.42, 2006-10-12 07:40:55-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.31 +1 -1
NTP_4_2_3P56
- sntp/sntp.1@1.34 +2 -2
- NTP_4_2_3P56
-
util/ntp-keygen-opts.c@1.32 +2 -2
NTP_4_2_3P56
@@ -195260,9 +202196,6 @@ ChangeSet@1.1379.1.39, 2006-10-11 07:44:18-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.30 +1 -1
NTP_4_2_3P55
- sntp/sntp.1@1.33 +2 -2
- NTP_4_2_3P55
-
util/ntp-keygen-opts.c@1.31 +2 -2
NTP_4_2_3P55
@@ -195357,9 +202290,6 @@ ChangeSet@1.1379.1.36, 2006-10-10 07:46:00-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.29 +1 -1
NTP_4_2_3P54
- sntp/sntp.1@1.32 +2 -2
- NTP_4_2_3P54
-
util/ntp-keygen-opts.c@1.30 +2 -2
NTP_4_2_3P54
@@ -195454,9 +202384,6 @@ ChangeSet@1.1379.1.33, 2006-10-09 07:41:25-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.28 +1 -1
NTP_4_2_3P53
- sntp/sntp.1@1.31 +2 -2
- NTP_4_2_3P53
-
util/ntp-keygen-opts.c@1.29 +2 -2
NTP_4_2_3P53
@@ -195542,9 +202469,6 @@ ChangeSet@1.1379.1.31, 2006-10-08 19:39:10-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.27 +1 -1
NTP_4_2_3P52
- sntp/sntp.1@1.30 +2 -2
- NTP_4_2_3P52
-
util/ntp-keygen-opts.c@1.28 +4 -4
NTP_4_2_3P52
@@ -195825,9 +202749,6 @@ ChangeSet@1.1379.1.25, 2006-09-26 16:16:30-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.26 +1 -1
autogen update
- sntp/sntp.1@1.29 +1 -1
- autogen update
-
util/ntp-keygen-opts.c@1.26 +3 -3
autogen update
@@ -195904,9 +202825,6 @@ ChangeSet@1.1379.1.24, 2006-09-25 07:49:15-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.25 +1 -1
NTP_4_2_3P51
- sntp/sntp.1@1.28 +2 -2
- NTP_4_2_3P51
-
util/ntp-keygen-opts.c@1.25 +4 -4
NTP_4_2_3P51
@@ -196186,9 +203104,6 @@ ChangeSet@1.1379.1.23, 2006-09-25 01:53:46-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.24 +1 -1
autogen upgrade
- sntp/sntp.1@1.27 +2 -2
- autogen upgrade
-
util/ntp-keygen-opts.c@1.24 +3 -2
autogen upgrade
@@ -196265,9 +203180,6 @@ ChangeSet@1.1379.1.22, 2006-09-24 05:30:52-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.23 +1 -1
NTP_4_2_3P50
- sntp/sntp.1@1.26 +2 -2
- NTP_4_2_3P50
-
util/ntp-keygen-opts.c@1.23 +43 -43
NTP_4_2_3P50
@@ -196731,9 +203643,6 @@ ChangeSet@1.1379.1.16, 2006-09-21 07:42:50-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.22 +1 -1
NTP_4_2_3P49
- sntp/sntp.1@1.25 +2 -2
- NTP_4_2_3P49
-
util/ntp-keygen-opts.c@1.22 +2 -2
NTP_4_2_3P49
@@ -196828,9 +203737,6 @@ ChangeSet@1.1379.1.13, 2006-09-19 07:43:25-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.21 +1 -1
NTP_4_2_3P48
- sntp/sntp.1@1.24 +2 -2
- NTP_4_2_3P48
-
util/ntp-keygen-opts.c@1.21 +2 -2
NTP_4_2_3P48
@@ -196938,9 +203844,6 @@ ChangeSet@1.1379.2.35, 2006-09-16 18:54:38-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.20 +1 -1
NTP_4_2_3P47
- sntp/sntp.1@1.23 +2 -2
- NTP_4_2_3P47
-
util/ntp-keygen-opts.c@1.20 +2 -2
NTP_4_2_3P47
@@ -197036,9 +203939,6 @@ ChangeSet@1.1379.2.33, 2006-09-13 07:43:13-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.19 +1 -1
NTP_4_2_3P46
- sntp/sntp.1@1.22 +2 -2
- NTP_4_2_3P46
-
util/ntp-keygen-opts.c@1.19 +2 -2
NTP_4_2_3P46
@@ -197136,9 +204036,6 @@ ChangeSet@1.1379.2.29, 2006-09-12 07:42:34-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.18 +1 -1
NTP_4_2_3P45
- sntp/sntp.1@1.21 +2 -2
- NTP_4_2_3P45
-
util/ntp-keygen-opts.c@1.18 +2 -2
NTP_4_2_3P45
@@ -197237,9 +204134,6 @@ ChangeSet@1.1379.2.25, 2006-09-11 07:47:06-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.17 +1 -1
NTP_4_2_3P44
- sntp/sntp.1@1.20 +2 -2
- NTP_4_2_3P44
-
util/ntp-keygen-opts.c@1.17 +2 -2
NTP_4_2_3P44
@@ -197406,9 +204300,6 @@ ChangeSet@1.1379.2.23, 2006-09-10 18:03:04-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.16 +1 -1
NTP_4_2_3P43
- sntp/sntp.1@1.19 +2 -2
- NTP_4_2_3P43
-
util/ntp-keygen-opts.c@1.16 +2 -2
NTP_4_2_3P43
@@ -197491,9 +204382,6 @@ ChangeSet@1.1379.2.21, 2006-09-10 07:48:06-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.15 +1 -1
NTP_4_2_3P42
- sntp/sntp.1@1.18 +2 -2
- NTP_4_2_3P42
-
util/ntp-keygen-opts.c@1.15 +2 -2
NTP_4_2_3P42
@@ -197678,9 +204566,6 @@ ChangeSet@1.1379.5.1, 2006-09-09 05:19:19-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.14 +1 -1
NTP_4_2_3P41
- sntp/sntp.1@1.17 +2 -2
- NTP_4_2_3P41
-
util/ntp-keygen-opts.c@1.14 +2 -2
NTP_4_2_3P41
@@ -197811,9 +204696,6 @@ ChangeSet@1.1379.2.11, 2006-09-07 21:45:01-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.13 +1 -1
NTP_4_2_3P39
- sntp/sntp.1@1.16 +2 -2
- NTP_4_2_3P39
-
util/ntp-keygen-opts.c@1.13 +2 -2
NTP_4_2_3P39
@@ -197965,9 +204847,6 @@ ChangeSet@1.1379.2.4, 2006-08-31 02:06:16-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.12 +1 -1
NTP_4_2_3P38
- sntp/sntp.1@1.15 +2 -2
- NTP_4_2_3P38
-
util/ntp-keygen-opts.c@1.12 +2 -2
NTP_4_2_3P38
@@ -198093,9 +204972,6 @@ ChangeSet@1.1379.1.3, 2006-08-28 21:48:10-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.11 +1 -1
NTP_4_2_3P37
- sntp/sntp.1@1.14 +2 -2
- NTP_4_2_3P37
-
util/ntp-keygen-opts.c@1.11 +2 -2
NTP_4_2_3P37
@@ -198208,9 +205084,6 @@ ChangeSet@1.1353.21.3, 2006-08-26 15:10:29-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.10 +1 -1
NTP_4_2_3P36
- sntp/sntp.1@1.13 +2 -2
- NTP_4_2_3P36
-
util/ntp-keygen-opts.c@1.10 +2 -2
NTP_4_2_3P36
@@ -198294,9 +205167,6 @@ ChangeSet@1.1353.22.1, 2006-08-26 05:05:56-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.9 +1 -1
NTP_4_2_3P35
- sntp/sntp.1@1.12 +2 -2
- NTP_4_2_3P35
-
util/ntp-keygen-opts.c@1.9 +2 -2
NTP_4_2_3P35
@@ -198436,9 +205306,6 @@ ChangeSet@1.1353.9.42, 2006-08-20 20:18:08-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.8 +1 -1
NTP_4_2_3P34
- sntp/sntp.1@1.11 +2 -2
- NTP_4_2_3P34
-
util/ntp-keygen-opts.c@1.8 +2 -2
NTP_4_2_3P34
@@ -198521,9 +205388,6 @@ ChangeSet@1.1353.9.39, 2006-08-19 23:34:01-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.7 +1 -1
NTP_4_2_3P33
- sntp/sntp.1@1.10 +2 -2
- NTP_4_2_3P33
-
util/ntp-keygen-opts.c@1.7 +2 -2
NTP_4_2_3P33
@@ -198689,9 +205553,6 @@ ChangeSet@1.1353.17.1, 2006-08-17 00:52:10-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.6 +1 -1
run autogen after point release
- sntp/sntp.1@1.9 +2 -2
- run autogen after point release
-
util/ntp-keygen-opts.c@1.6 +2 -2
run autogen after point release
@@ -198821,9 +205682,6 @@ ChangeSet@1.1353.9.29, 2006-08-15 05:53:43-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.5 +1 -1
regenerate autogen-erated files
- sntp/sntp.1@1.8 +2 -2
- regenerate autogen-erated files
-
util/ntp-keygen-opts.c@1.5 +29 -4
regenerate autogen-erated files
@@ -198917,9 +205775,6 @@ ChangeSet@1.1353.15.9, 2006-08-10 21:41:32-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.4 +1 -1
NTP_4_2_3P29
- sntp/sntp.1@1.7 +82 -3
- NTP_4_2_3P29
-
util/ntp-keygen-opts.c@1.4 +2 -2
NTP_4_2_3P29
@@ -199412,12 +206267,6 @@ ChangeSet@1.1353.1.96, 2006-08-02 20:21:23-04:00, stenn@whimsy.udel.edu
sntp/sntp-opts.texi@1.2 +0 -0
Change mode to -rw-r--r--
- sntp/sntp.1@1.6 +129 -64
- autogen upgrade
-
- sntp/sntp.1@1.5 +0 -0
- Change mode to -rw-r--r--
-
util/ntp-keygen-opts.c@1.3 +54 -36
autogen upgrade
@@ -202195,7 +209044,7 @@ ChangeSet@1.1251.85.2, 2006-04-20 23:59:56-04:00, stenn@whimsy.udel.edu
[Bug 527] Lose signalled IO.
configure.ac@1.359.1.28 +7 -2
- [Bug 527] Losed signalled IO.
+ [Bug 527] Lose signalled IO.
ChangeSet@1.1251.85.1, 2006-04-18 05:58:13-04:00, stenn@whimsy.udel.edu
there are 240 ntp-dev patch releases so far
@@ -203644,7 +210493,7 @@ ChangeSet@1.1251.67.12, 2005-10-27 21:38:04-04:00, stenn@deacon.udel.edu
[Bug 516] unprotected crypto_update() call fix from Dave Mills
ChangeSet@1.1251.67.11, 2005-10-25 20:15:47-04:00, stenn@deacon.udel.edu
- [Bug 517] Allow dynamic SSL libraries
+ [Bug 519] Allow dynamic SSL libraries
configure.ac@1.359.1.24 +3 -2
[Bug 519] Allow dynamic SSL libraries: also check /usr/sfw/{lib,include}
@@ -209124,6 +215973,7 @@ ChangeSet@1.1251.1.28, 2004-11-28 03:35:01-05:00, stenn@whimsy.udel.edu
ntpdate/ntpdate.c@1.48 +2 -2
[Bug 363] ntpdate: use -1 to represent an invalid fd
+ Fix from Rainer Weikusat.
ChangeSet@1.1251.1.27, 2004-11-21 21:33:09-05:00, stenn@whimsy.udel.edu
[Bug 349] Patches from Takao Abe
@@ -209824,9 +216674,6 @@ ChangeSet@1.1202.5.2, 2004-10-23 03:09:05-04:00, stenn@whimsy.udel.edu
sntp/main.c@1.5 +19 -115
Lose broadcast and server modes.
- sntp/sntp.1@1.4 +0 -23
- Lose broadcast and server modes.
-
sntp/socket.c@1.4 +6 -22
Lose broadcast and server modes.
@@ -210214,17 +217061,6 @@ ChangeSet@1.1202.1.16, 2004-08-25 01:16:52-04:00, stenn@whimsy.udel.edu
sntp/main.c@1.4 +8 -8
added sntp.1 and did a little cleanup
- sntp/sntp.1@1.3 +25 -15
- added sntp.1 and did a little cleanup
-
- sntp/sntp.1@1.2 +0 -0
- Rename: sntp/msntp.1 -> sntp/sntp.1
-
- sntp/msntp.1@1.1 +325 -0
-
- sntp/msntp.1@1.0 +0 -0
- BitKeeper file /deacon/backroom/ntp-dev/sntp/msntp.1
-
ChangeSet@1.1202.1.15, 2004-08-23 22:08:55-04:00, stenn@www.ntp.org
make propdelay compile/link
diff --git a/contrib/ntp/Makefile.in b/contrib/ntp/Makefile.in
index 0cb05d3..7353076 100644
--- a/contrib/ntp/Makefile.in
+++ b/contrib/ntp/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -830,7 +830,7 @@ distdir: $(DISTFILES)
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r "$(distdir)"
dist-gzip: distdir
- tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
$(am__post_remove_distdir)
dist-bzip2: distdir
@@ -856,7 +856,7 @@ dist-shar: distdir
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
- shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
$(am__post_remove_distdir)
dist-zip: distdir
@@ -874,7 +874,7 @@ dist dist-all:
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
- GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lz*) \
@@ -884,7 +884,7 @@ distcheck: dist
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
- GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
diff --git a/contrib/ntp/NEWS b/contrib/ntp/NEWS
index b30f187..5cae937 100644
--- a/contrib/ntp/NEWS
+++ b/contrib/ntp/NEWS
@@ -1,7 +1,130 @@
+---
+NTP 4.2.8p13 (Harlan Stenn <stenn@ntp.org>, 2019 Mar 07)
+
+Focus: Security, Bug fixes, enhancements.
+
+Severity: MEDIUM
+
+This release fixes a bug that allows an attacker with access to an
+explicitly trusted source to send a crafted malicious mode 6 (ntpq)
+packet that can trigger a NULL pointer dereference, crashing ntpd.
+It also provides 17 other bugfixes and 1 other improvement:
+
+* [Sec 3565] Crafted null dereference attack in authenticated
+ mode 6 packet <perlinger@ntp.org>
+ - reported by Magnus Stubman
+* [Bug 3560] Fix build when HAVE_DROPROOT is not defined <perlinger@ntp.org>
+ - applied patch by Ian Lepore
+* [Bug 3558] Crash and integer size bug <perlinger@ntp.org>
+ - isolate and fix linux/windows specific code issue
+* [Bug 3556] ntp_loopfilter.c snprintf compilation warnings <perlinger@ntp.org>
+ - provide better function for incremental string formatting
+* [Bug 3555] Tidy up print alignment of debug output from ntpdate <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3554] config revoke stores incorrect value <perlinger@ntp.org>
+ - original finding by Gerry Garvey, additional cleanup needed
+* [Bug 3549] Spurious initgroups() error message <perlinger@ntp.org>
+ - patch by Christous Zoulas
+* [Bug 3548] Signature not verified on windows system <perlinger@ntp.org>
+ - finding by Chen Jiabin, plus another one by me
+* [Bug 3541] patch to fix STA_NANO struct timex units <perlinger@ntp.org>
+ - applied patch by Maciej Szmigiero
+* [Bug 3540] Cannot set minsane to 0 anymore <perlinger@ntp.org>
+ - applied patch by Andre Charbonneau
+* [Bug 3539] work_fork build fails when droproot is not supported <perlinger@ntp.org>
+ - applied patch by Baruch Siach
+* [Bug 3538] Build fails for no-MMU targets <perlinger@ntp.org>
+ - applied patch by Baruch Siach
+* [Bug 3535] libparse won't handle GPS week rollover <perlinger@ntp.org>
+ - refactored handling of GPS era based on 'tos basedate' for
+ parse (TSIP) and JUPITER clocks
+* [Bug 3529] Build failures on Mac OS X 10.13 (High Sierra) <perlinger@ntp.org>
+ - patch by Daniel J. Luke; this does not fix a potential linker
+ regression issue on MacOS.
+* [Bug 3527 - Backward Incompatible] mode7 clockinfo fudgeval2 packet
+ anomaly <perlinger@ntp.org>, reported by GGarvey.
+ - --enable-bug3527-fix support by HStenn
+* [Bug 3526] Incorrect poll interval in packet <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+* [Bug 3471] Check for openssl/[ch]mac.h. <perlinger@ntp.org>
+ - added missing check, reported by Reinhard Max <perlinger@ntp.org>
+* [Bug 1674] runtime crashes and sync problems affecting both x86 and x86_64
+ - this is a variant of [bug 3558] and should be fixed with it
+* Implement 'configure --disable-signalled-io'
+
--
-NTP 4.2.8p11 (Harlan Stenn <stenn@ntp.org>, 2018/02/27)
+NTP 4.2.8p12 (Harlan Stenn <stenn@ntp.org>, 2018/14/09)
-NOTE: this NEWS file will be undergoing more revisions.
+Focus: Security, Bug fixes, enhancements.
+
+Severity: MEDIUM
+
+This release fixes a "hole" in the noepeer capability introduced to ntpd
+in ntp-4.2.8p11, and a buffer overflow in the openhost() function used by
+ntpq and ntpdc. It also provides 26 other bugfixes, and 4 other improvements:
+
+* [Sec 3505] Buffer overflow in the openhost() call of ntpq and ntpdc.
+
+* [Sec 3012] Fix a hole in the new "noepeer" processing.
+
+* Bug Fixes:
+ [Bug 3521] Fix a logic bug in the INVALIDNAK checks. <stenn@ntp.org>
+ [Bug 3509] Add support for running as non-root on FreeBSD, Darwin,
+ other TrustedBSD platforms
+ - applied patch by Ian Lepore <perlinger@ntp.org>
+ [Bug 3506] Service Control Manager interacts poorly with NTPD <perlinger@ntp.org>
+ - changed interaction with SCM to signal pending startup
+ [Bug 3486] Buffer overflow in ntpq/ntpq.c:tstflags() <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+ [Bug 3485] Undefined sockaddr used in error messages in ntp_config.c <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+ [Bug 3484] ntpq response from ntpd is incorrect when REFID is null <perlinger@ntp.org>
+ - rework of ntpq 'nextvar()' key/value parsing
+ [Bug 3482] Fixes for compilation warnings (ntp_io.c & ntpq-subs.c) <perlinger@ntp.org>
+ - applied patch by Gerry Garvey (with mods)
+ [Bug 3480] Refclock sample filter not cleared on clock STEP <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+ [Bug 3479] ctl_putrefid() allows unsafe characters through to ntpq <perlinger@ntp.org>
+ - applied patch by Gerry Garvey (with mods)
+ [Bug 3476]ctl_putstr() sends empty unquoted string [...] <perlinger@ntp.org>
+ - applied patch by Gerry Garvey (with mods); not sure if that's bug or feature, though
+ [Bug 3475] modify prettydate() to suppress output of zero time <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+ [Bug 3474] Missing pmode in mode7 peer info response <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+ [Bug 3471] Check for openssl/[ch]mac.h. HStenn.
+ - add #define ENABLE_CMAC support in configure. HStenn.
+ [Bug 3470] ntpd4.2.8p11 fails to compile without OpenSSL <perlinger@ntp.org>
+ [Bug 3469] Incomplete string compare [...] in is_refclk_addr <perlinger@ntp.org>
+ - patch by Stephen Friedl
+ [Bug 3467] Potential memory fault in ntpq [...] <perlinger@ntp.org>
+ - fixed IO redirection and CTRL-C handling in ntq and ntpdc
+ [Bug 3465] Default TTL values cannot be used <perlinger@ntp.org>
+ [Bug 3461] refclock_shm.c: clear error status on clock recovery <perlinger@ntp.org>
+ - initial patch by Hal Murray; also fixed refclock_report() trouble
+ [Bug 3460] Fix typo in ntpq.texi, reported by Kenyon Ralph. <stenn@ntp.org>
+ [Bug 3456] Use uintptr_t rather than size_t to store an integer in a pointer
+ - According to Brooks Davis, there was only one location <perlinger@ntp.org>
+ [Bug 3449] ntpq - display "loop" instead of refid [...] <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+ [Bug 3445] Symmetric peer won't sync on startup <perlinger@ntp.org>
+ - applied patch by Gerry Garvey
+ [Bug 3442] Fixes for ntpdate as suggested by Gerry Garvey,
+ with modifications
+ New macro REFID_ISTEXT() which is also used in ntpd/ntp_control.c.
+ [Bug 3434] ntpd clears STA_UNSYNC on start <perlinger@ntp.org>
+ - applied patch by Miroslav Lichvar
+ [Bug 3426] ntpdate.html -t default is 2 seconds. Leonid Evdokimov.
+ [Bug 3121] Drop root privileges for the forked DNS worker <perlinger@ntp.org>
+ - integrated patch by Reinhard Max
+ [Bug 2821] minor build issues <perlinger@ntp.org>
+ - applied patches by Christos Zoulas, including real bug fixes
+ html/authopt.html: cleanup, from <stenn@ntp.org>
+ ntpd/ntpd.c: DROPROOT cleanup. <stenn@ntp.org>
+ Symmetric key range is 1-65535. Update docs. <stenn@ntp.org>
+
+--
+NTP 4.2.8p11 (Harlan Stenn <stenn@ntp.org>, 2018/02/27)
Focus: Security, Bug fixes, enhancements.
diff --git a/contrib/ntp/aclocal.m4 b/contrib/ntp/aclocal.m4
index b692416..ec9f3a5 100644
--- a/contrib/ntp/aclocal.m4
+++ b/contrib/ntp/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -20,126 +20,121 @@ You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
-# serial 9 -*- Autoconf -*-
-# Enable extensions on systems that normally disable them.
+# longlong.m4 serial 17
+dnl Copyright (C) 1999-2007, 2009-2016 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
-# Copyright (C) 2003, 2006-2010 Free Software Foundation, Inc.
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+dnl From Paul Eggert.
-# This definition of AC_USE_SYSTEM_EXTENSIONS is stolen from CVS
-# Autoconf. Perhaps we can remove this once we can assume Autoconf
-# 2.62 or later everywhere, but since CVS Autoconf mutates rapidly
-# enough in this area it's likely we'll need to redefine
-# AC_USE_SYSTEM_EXTENSIONS for quite some time.
-
-# If autoconf reports a warning
-# warning: AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS
-# or warning: AC_RUN_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS
-# the fix is
-# 1) to ensure that AC_USE_SYSTEM_EXTENSIONS is never directly invoked
-# but always AC_REQUIREd,
-# 2) to ensure that for each occurrence of
-# AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
-# or
-# AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
-# the corresponding gnulib module description has 'extensions' among
-# its dependencies. This will ensure that the gl_USE_SYSTEM_EXTENSIONS
-# invocation occurs in gl_EARLY, not in gl_INIT.
-
-# AC_USE_SYSTEM_EXTENSIONS
-# ------------------------
-# Enable extensions on systems that normally disable them,
-# typically due to standards-conformance issues.
-# Remember that #undef in AH_VERBATIM gets replaced with #define by
-# AC_DEFINE. The goal here is to define all known feature-enabling
-# macros, then, if reports of conflicts are made, disable macros that
-# cause problems on some platforms (such as __EXTENSIONS__).
-AC_DEFUN_ONCE([AC_USE_SYSTEM_EXTENSIONS],
-[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
-AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
-
- AC_REQUIRE([AC_CANONICAL_HOST])
-
- AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=])
- if test "$MINIX" = yes; then
- AC_DEFINE([_POSIX_SOURCE], [1],
- [Define to 1 if you need to in order for `stat' and other
- things to work.])
- AC_DEFINE([_POSIX_1_SOURCE], [2],
- [Define to 2 if the system does not provide POSIX.1 features
- except with this defined.])
- AC_DEFINE([_MINIX], [1],
- [Define to 1 if on MINIX.])
+# Define HAVE_LONG_LONG_INT if 'long long int' works.
+# This fixes a bug in Autoconf 2.61, and can be faster
+# than what's in Autoconf 2.62 through 2.68.
+
+# Note: If the type 'long long int' exists but is only 32 bits large
+# (as on some very old compilers), HAVE_LONG_LONG_INT will not be
+# defined. In this case you can treat 'long long int' like 'long int'.
+
+AC_DEFUN([AC_TYPE_LONG_LONG_INT],
+[
+ AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
+ AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int],
+ [ac_cv_type_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+ if test $ac_cv_type_long_long_int = yes; then
+ dnl Catch a bug in Tandem NonStop Kernel (OSS) cc -O circa 2004.
+ dnl If cross compiling, assume the bug is not important, since
+ dnl nobody cross compiles for this platform as far as we know.
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[@%:@include <limits.h>
+ @%:@ifndef LLONG_MAX
+ @%:@ define HALF \
+ (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+ @%:@ define LLONG_MAX (HALF - 1 + HALF)
+ @%:@endif]],
+ [[long long int n = 1;
+ int i;
+ for (i = 0; ; i++)
+ {
+ long long int m = n << i;
+ if (m >> i != n)
+ return 1;
+ if (LLONG_MAX / 2 < m)
+ break;
+ }
+ return 0;]])],
+ [],
+ [ac_cv_type_long_long_int=no],
+ [:])
+ fi
+ fi])
+ if test $ac_cv_type_long_long_int = yes; then
+ AC_DEFINE([HAVE_LONG_LONG_INT], [1],
+ [Define to 1 if the system has the type 'long long int'.])
fi
+])
- dnl HP-UX 11.11 defines mbstate_t only if _XOPEN_SOURCE is defined to 500,
- dnl regardless of whether the flags -Ae or _D_HPUX_SOURCE=1 are already
- dnl provided.
- case "$host_os" in
- hpux*)
- AC_DEFINE([_XOPEN_SOURCE], [500],
- [Define to 500 only on HP-UX.])
- ;;
- esac
+# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works.
+# This fixes a bug in Autoconf 2.61, and can be faster
+# than what's in Autoconf 2.62 through 2.68.
+
+# Note: If the type 'unsigned long long int' exists but is only 32 bits
+# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT
+# will not be defined. In this case you can treat 'unsigned long long int'
+# like 'unsigned long int'.
- AH_VERBATIM([__EXTENSIONS__],
-[/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# undef _ALL_SOURCE
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
+AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT],
+[
+ AC_CACHE_CHECK([for unsigned long long int],
+ [ac_cv_type_unsigned_long_long_int],
+ [ac_cv_type_unsigned_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ AC_LINK_IFELSE(
+ [_AC_TYPE_LONG_LONG_SNIPPET],
+ [],
+ [ac_cv_type_unsigned_long_long_int=no])
+ fi])
+ if test $ac_cv_type_unsigned_long_long_int = yes; then
+ AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], [1],
+ [Define to 1 if the system has the type 'unsigned long long int'.])
+ fi
])
- AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
- [ac_cv_safe_to_define___extensions__],
- [AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM([[
-# define __EXTENSIONS__ 1
- ]AC_INCLUDES_DEFAULT])],
- [ac_cv_safe_to_define___extensions__=yes],
- [ac_cv_safe_to_define___extensions__=no])])
- test $ac_cv_safe_to_define___extensions__ = yes &&
- AC_DEFINE([__EXTENSIONS__])
- AC_DEFINE([_ALL_SOURCE])
- AC_DEFINE([_GNU_SOURCE])
- AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
- AC_DEFINE([_TANDEM_SOURCE])
-])# AC_USE_SYSTEM_EXTENSIONS
-
-# gl_USE_SYSTEM_EXTENSIONS
-# ------------------------
-# Enable extensions on systems that normally disable them,
-# typically due to standards-conformance issues.
-AC_DEFUN_ONCE([gl_USE_SYSTEM_EXTENSIONS],
+
+# Expands to a C program that can be used to test for simultaneous support
+# of 'long long' and 'unsigned long long'. We don't want to say that
+# 'long long' is available if 'unsigned long long' is not, or vice versa,
+# because too many programs rely on the symmetry between signed and unsigned
+# integer types (excluding 'bool').
+AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET],
[
- dnl Require this macro before AC_USE_SYSTEM_EXTENSIONS.
- dnl gnulib does not need it. But if it gets required by third-party macros
- dnl after AC_USE_SYSTEM_EXTENSIONS is required, autoconf 2.62..2.63 emit a
- dnl warning: "AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS".
- dnl Note: We can do this only for one of the macros AC_AIX, AC_GNU_SOURCE,
- dnl AC_MINIX. If people still use AC_AIX or AC_MINIX, they are out of luck.
- AC_REQUIRE([AC_GNU_SOURCE])
-
- AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+ AC_LANG_PROGRAM(
+ [[/* For now, do not test the preprocessor; as of 2007 there are too many
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
+ /* Test literals. */
+ long long int ll = 9223372036854775807ll;
+ long long int nll = -9223372036854775807LL;
+ unsigned long long int ull = 18446744073709551615ULL;
+ /* Test constant expressions. */
+ typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
+ ? 1 : -1)];
+ typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
+ ? 1 : -1)];
+ int i = 63;]],
+ [[/* Test availability of runtime routines for shift and division. */
+ long long int llmax = 9223372036854775807ll;
+ unsigned long long int ullmax = 18446744073709551615ull;
+ return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));]])
])
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -154,7 +149,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.15'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
-m4_if([$1], [1.15], [],
+m4_if([$1], [1.15.1], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@@ -170,12 +165,12 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
-# Copyright (C) 2011-2014 Free Software Foundation, Inc.
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -237,7 +232,7 @@ AC_SUBST([AR])dnl
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -289,7 +284,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd`
# AM_CONDITIONAL -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -320,7 +315,7 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -511,7 +506,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
# Generate code to set up dependency tracking. -*- Autoconf -*-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -587,7 +582,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -784,7 +779,7 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -805,7 +800,7 @@ if test x"${install_sh+set}" != xset; then
fi
AC_SUBST([install_sh])])
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -826,7 +821,7 @@ AC_SUBST([am__leading_dot])])
# Check to see how 'make' treats includes. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -876,7 +871,7 @@ rm -f confinc confmf
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -915,7 +910,7 @@ fi
# Helper functions for option handling. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -944,7 +939,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -991,7 +986,7 @@ AC_LANG_POP([C])])
# For backward compatibility.
AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1010,7 +1005,7 @@ AC_DEFUN([AM_RUN_LOG],
# Check to make sure that the build environment is sane. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1091,7 +1086,7 @@ AC_CONFIG_COMMANDS_PRE(
rm -f conftest.file
])
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1151,7 +1146,7 @@ AC_SUBST([AM_BACKSLASH])dnl
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1179,7 +1174,7 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1198,7 +1193,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/adjtimed/Makefile.in b/contrib/ntp/adjtimed/Makefile.in
index 915d3f5..87e1fba 100644
--- a/contrib/ntp/adjtimed/Makefile.in
+++ b/contrib/ntp/adjtimed/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/build b/contrib/ntp/build
index 15fe39a..f6dca6b 100755
--- a/contrib/ntp/build
+++ b/contrib/ntp/build
@@ -52,7 +52,7 @@ esac
case "$NTP_BDIR" in
'')
case "$IAM" in
- *.ntp.org)
+ *.ntp.org | *.ntfo.org)
NTP_BDIR=host
;;
*.udel.edu)
diff --git a/contrib/ntp/clockstuff/Makefile.in b/contrib/ntp/clockstuff/Makefile.in
index 6297f44..0775b9a 100644
--- a/contrib/ntp/clockstuff/Makefile.in
+++ b/contrib/ntp/clockstuff/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/config.h.in b/contrib/ntp/config.h.in
index 13f9bc8..7170d83 100644
--- a/contrib/ntp/config.h.in
+++ b/contrib/ntp/config.h.in
@@ -296,6 +296,9 @@
/* use old autokey session key behavior? */
#undef DISABLE_BUG1243_FIX
+/* use old autokey session key behavior? */
+#undef DISABLE_BUG3527_FIX
+
/* synch TODR hourly? */
#undef DOSYNCTODR
@@ -311,6 +314,9 @@
/* Provide the explicit 127.0.0.0/8 martian filter? */
#undef ENABLE_BUG3020_FIX
+/* Enable CMAC support? */
+#undef ENABLE_CMAC
+
/* nls support in libopts */
#undef ENABLE_NLS
@@ -372,6 +378,14 @@
/* Define to 1 if you have the `daemon' function. */
#undef HAVE_DAEMON
+/* Define to 1 if you have the declaration of `siglongjmp', and to 0 if you
+ don't. */
+#undef HAVE_DECL_SIGLONGJMP
+
+/* Define to 1 if you have the declaration of `sigsetjmp', and to 0 if you
+ don't. */
+#undef HAVE_DECL_SIGSETJMP
+
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
don't. */
#undef HAVE_DECL_STRERROR_R
@@ -539,7 +553,7 @@
/* Define to 1 if the system has the type `long long'. */
#undef HAVE_LONG_LONG
-/* Define to 1 if the system has the type `long long int'. */
+/* Define to 1 if the system has the type 'long long int'. */
#undef HAVE_LONG_LONG_INT
/* if you have SunOS LWP package */
@@ -653,6 +667,12 @@
/* if you have NT Threads */
#undef HAVE_NT_THREADS
+/* Define to 1 if you have the <openssl/cmac.h> header file. */
+#undef HAVE_OPENSSL_CMAC_H
+
+/* Define to 1 if you have the <openssl/hmac.h> header file. */
+#undef HAVE_OPENSSL_HMAC_H
+
/* Define to 1 if the system has the type `pid_t'. */
#undef HAVE_PID_T
@@ -957,6 +977,9 @@
/* Define to 1 if you have the <sys/lock.h> header file. */
#undef HAVE_SYS_LOCK_H
+/* Define to 1 if you have the <sys/mac.h> header file. */
+#undef HAVE_SYS_MAC_H
+
/* Define to 1 if you have the <sys/mman.h> header file. */
#undef HAVE_SYS_MMAN_H
@@ -1117,6 +1140,9 @@
/* Do we have the TIO serial stuff? */
#undef HAVE_TIO_SERIAL_STUFF
+/* Are TrustedBSD MAC policy privileges available? */
+#undef HAVE_TRUSTEDBSD_MAC
+
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
@@ -1147,7 +1173,7 @@
/* deviant sigwait? */
#undef HAVE_UNIXWARE_SIGWAIT
-/* Define to 1 if the system has the type `unsigned long long int'. */
+/* Define to 1 if the system has the type 'unsigned long long int'. */
#undef HAVE_UNSIGNED_LONG_LONG_INT
/* Define to 1 if you have the `updwtmp' function. */
@@ -1588,6 +1614,28 @@ typedef unsigned int uintptr_t;
/* OK to use snprintb()? */
#undef USE_SNPRINTB
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
/* Can we use SIGPOLL for tty IO? */
#undef USE_TTY_SIGPOLL
@@ -1640,9 +1688,6 @@ typedef unsigned int uintptr_t;
/* enable thread safety */
#undef _THREAD_SAFE
-/* Define to 500 only on HP-UX. */
-#undef _XOPEN_SOURCE
-
/* Are we _special_? */
#undef __APPLE_USE_RFC_3542
@@ -1651,28 +1696,6 @@ typedef unsigned int uintptr_t;
# undef __CHAR_UNSIGNED__
#endif
-/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# undef _ALL_SOURCE
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-
-
/* deviant */
#undef adjtimex
diff --git a/contrib/ntp/configure b/contrib/ntp/configure
index 1ab45bc..ee313f0 100755
--- a/contrib/ntp/configure
+++ b/contrib/ntp/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for ntp 4.2.8p11.
+# Generated by GNU Autoconf 2.69 for ntp 4.2.8p13.
#
# Report bugs to <http://bugs.ntp.org./>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='ntp'
PACKAGE_TARNAME='ntp'
-PACKAGE_VERSION='4.2.8p11'
-PACKAGE_STRING='ntp 4.2.8p11'
+PACKAGE_VERSION='4.2.8p13'
+PACKAGE_STRING='ntp 4.2.8p13'
PACKAGE_BUGREPORT='http://bugs.ntp.org./'
PACKAGE_URL='http://www.ntp.org./'
@@ -968,6 +968,8 @@ enable_c99_snprintf
enable_clockctl
enable_linuxcaps
enable_solarisprivs
+enable_trustedbsd_mac
+enable_signalled_io
with_arlib
with_net_snmp_config
enable_libseccomp
@@ -1050,6 +1052,7 @@ enable_hourly_todr_sync
enable_kernel_fll_bug
enable_bug1243_fix
enable_bug3020_fix
+enable_bug3527_fix
enable_irig_sawtooth
enable_nist
enable_ntp_signd
@@ -1614,7 +1617,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures ntp 4.2.8p11 to adapt to many kinds of systems.
+\`configure' configures ntp 4.2.8p13 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1684,7 +1687,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of ntp 4.2.8p11:";;
+ short | recursive ) echo "Configuration of ntp 4.2.8p13:";;
esac
cat <<\_ACEOF
@@ -1731,6 +1734,9 @@ Optional Features and Packages:
--enable-clockctl s Use /dev/clockctl for non-root clock control
--enable-linuxcaps + Use Linux capabilities for non-root clock control
--enable-solarisprivs + Use Solaris privileges for non-root clock control
+ --enable-trustedbsd-mac s Use TrustedBSD MAC policy for non-root clock
+ control
+ --enable-signalled-io s Use signalled IO if we can
--with-arlib - deprecated, arlib not distributed
--with-net-snmp-config + =net-snmp-config
--enable-libseccomp EXPERIMENTAL: enable support for libseccomp
@@ -1823,6 +1829,7 @@ Optional Features and Packages:
--enable-kernel-fll-bug s if we should avoid a kernel FLL bug
--enable-bug1243-fix + use unmodified autokey session keys
--enable-bug3020-fix + Provide the explicit 127.0.0.0/8 martian filter
+ --enable-bug3527-fix + provide correct mode7 fudgetime2 behavior
--enable-irig-sawtooth s if we should enable the IRIG sawtooth filter
--enable-nist - if we should enable the NIST lockclock scheme
--enable-ntp-signd - Provide support for Samba's signing daemon,
@@ -1923,7 +1930,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-ntp configure 4.2.8p11
+ntp configure 4.2.8p13
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2632,7 +2639,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by ntp $as_me 4.2.8p11, which was
+It was created by ntp $as_me 4.2.8p13, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3633,7 +3640,7 @@ fi
# Define the identity of the package.
PACKAGE='ntp'
- VERSION='4.2.8p11'
+ VERSION='4.2.8p13'
cat >>confdefs.h <<_ACEOF
@@ -5113,8 +5120,6 @@ done
-
-
ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
if test "x$ac_cv_header_minix_config_h" = xyes; then :
MINIX=yes
@@ -5135,14 +5140,6 @@ $as_echo "#define _MINIX 1" >>confdefs.h
fi
- case "$host_os" in
- hpux*)
-
-$as_echo "#define _XOPEN_SOURCE 500" >>confdefs.h
-
- ;;
- esac
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
@@ -16090,18 +16087,18 @@ else
/* end confdefs.h. */
/* For now, do not test the preprocessor; as of 2007 there are too many
- implementations with broken preprocessors. Perhaps this can
- be revisited in 2012. In the meantime, code should not expect
- #if to work with literals wider than 32 bits. */
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
/* Test literals. */
long long int ll = 9223372036854775807ll;
long long int nll = -9223372036854775807LL;
unsigned long long int ull = 18446744073709551615ULL;
/* Test constant expressions. */
typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
- ? 1 : -1)];
+ ? 1 : -1)];
typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
- ? 1 : -1)];
+ ? 1 : -1)];
int i = 63;
int
main ()
@@ -16110,9 +16107,9 @@ main ()
long long int llmax = 9223372036854775807ll;
unsigned long long int ullmax = 18446744073709551615ull;
return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
- | (llmax / ll) | (llmax % ll)
- | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
- | (ullmax / ull) | (ullmax % ull));
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));
;
return 0;
}
@@ -16300,33 +16297,33 @@ if ${ac_cv_type_long_long_int+:} false; then :
else
ac_cv_type_long_long_int=yes
if test "x${ac_cv_prog_cc_c99-no}" = xno; then
- ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
- if test $ac_cv_type_long_long_int = yes; then
- if test "$cross_compiling" = yes; then :
+ ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+ if test $ac_cv_type_long_long_int = yes; then
+ if test "$cross_compiling" = yes; then :
:
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <limits.h>
- #ifndef LLONG_MAX
- # define HALF \
- (1LL << (sizeof (long long int) * CHAR_BIT - 2))
- # define LLONG_MAX (HALF - 1 + HALF)
- #endif
+ #ifndef LLONG_MAX
+ # define HALF \
+ (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+ # define LLONG_MAX (HALF - 1 + HALF)
+ #endif
int
main ()
{
long long int n = 1;
- int i;
- for (i = 0; ; i++)
- {
- long long int m = n << i;
- if (m >> i != n)
- return 1;
- if (LLONG_MAX / 2 < m)
- break;
- }
- return 0;
+ int i;
+ for (i = 0; ; i++)
+ {
+ long long int m = n << i;
+ if (m >> i != n)
+ return 1;
+ if (LLONG_MAX / 2 < m)
+ break;
+ }
+ return 0;
;
return 0;
}
@@ -16340,7 +16337,7 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
- fi
+ fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5
@@ -16363,18 +16360,18 @@ else
/* end confdefs.h. */
/* For now, do not test the preprocessor; as of 2007 there are too many
- implementations with broken preprocessors. Perhaps this can
- be revisited in 2012. In the meantime, code should not expect
- #if to work with literals wider than 32 bits. */
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
/* Test literals. */
long long int ll = 9223372036854775807ll;
long long int nll = -9223372036854775807LL;
unsigned long long int ull = 18446744073709551615ULL;
/* Test constant expressions. */
typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
- ? 1 : -1)];
+ ? 1 : -1)];
typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
- ? 1 : -1)];
+ ? 1 : -1)];
int i = 63;
int
main ()
@@ -16383,9 +16380,9 @@ main ()
long long int llmax = 9223372036854775807ll;
unsigned long long int ullmax = 18446744073709551615ull;
return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
- | (llmax / ll) | (llmax % ll)
- | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
- | (ullmax / ull) | (ullmax % ull));
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));
;
return 0;
}
@@ -24021,12 +24018,51 @@ case "$ntp_have_solarisprivs" in
$as_echo "#define HAVE_SOLARIS_PRIVS 1" >>confdefs.h
+ ;;
+ '') ntp_have_solarisprivs="no"
+ ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ntp_have_solarisprivs" >&5
$as_echo "$ntp_have_solarisprivs" >&6; }
-case "$ntp_use_dev_clockctl$ntp_have_linuxcaps$ntp_have_solarisprivs" in
+for ac_header in sys/mac.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/mac.h" "ac_cv_header_sys_mac_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mac_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_MAC_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# Check whether --enable-trustedbsd_mac was given.
+if test "${enable_trustedbsd_mac+set}" = set; then :
+ enableval=$enable_trustedbsd_mac; ntp_use_trustedbsd_mac=$enableval
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we should use TrustedBSD MAC privileges" >&5
+$as_echo_n "checking if we should use TrustedBSD MAC privileges... " >&6; }
+
+case "$ntp_use_trustedbsd_mac$ac_cv_header_sys_mac_h" in
+ yesyes)
+
+$as_echo "#define HAVE_TRUSTEDBSD_MAC 1" >>confdefs.h
+
+ ;;
+ *) ntp_use_trustedbsd_mac="no";
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ntp_use_trustedbsd_mac" >&5
+$as_echo "$ntp_use_trustedbsd_mac" >&6; }
+
+case "$ntp_use_dev_clockctl$ntp_have_linuxcaps$ntp_have_solarisprivs$ntp_use_trustedbsd_mac" in
*yes*)
$as_echo "#define HAVE_DROPROOT 1" >>confdefs.h
@@ -24540,6 +24576,16 @@ fi
done
+# HMS: does this need to be a cached variable?
+# Check whether --enable-signalled-io was given.
+if test "${enable_signalled_io+set}" = set; then :
+ enableval=$enable_signalled_io; use_signalled_io=$enableval
+else
+ use_signalled_io=yes
+
+fi
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SIGIO" >&5
$as_echo_n "checking for SIGIO... " >&6; }
if ${ntp_cv_hdr_def_sigio+:} false; then :
@@ -24614,13 +24660,24 @@ case "$ntp_cv_hdr_def_sigio" in
ans=no
;;
esac
+ case "$ans" in
+ no)
+ ans="Possible for $host but disabled because of reported problems"
+ ;;
+ esac
;;
esac
case "$ans" in
yes)
+ case "$use_signalled_io" in
+ yes)
$as_echo "#define HAVE_SIGNALED_IO 1" >>confdefs.h
+ ;;
+ *) ans="Allowed for $host but --disable-signalled-io was given"
+ ;;
+ esac
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ans" >&5
$as_echo "$ans" >&6; }
@@ -28627,6 +28684,62 @@ case "$ntp_ok" in
$as_echo "#define CLOCK_BANC 1" >>confdefs.h
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing bcStartPci" >&5
+$as_echo_n "checking for library containing bcStartPci... " >&6; }
+if ${ac_cv_search_bcStartPci+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char bcStartPci ();
+int
+main ()
+{
+return bcStartPci ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' bcsdk; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_bcStartPci=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_bcStartPci+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_bcStartPci+:} false; then :
+
+else
+ ac_cv_search_bcStartPci=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_bcStartPci" >&5
+$as_echo "$ac_cv_search_bcStartPci" >&6; }
+ac_res=$ac_cv_search_bcStartPci
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ntp_ok" >&5
@@ -30311,6 +30424,19 @@ $as_echo "$ntp_openssl" >&6; }
case "$ntp_openssl" in
yes)
+ for ac_header in openssl/cmac.h openssl/hmac.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
$as_echo "#define OPENSSL /**/" >>confdefs.h
@@ -30534,6 +30660,21 @@ LIBS="$NTPO_SAVED_LIBS"
{ ntp_openssl_from_pkg_config=; unset ntp_openssl_from_pkg_config;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we want to enable CMAC support" >&5
+$as_echo_n "checking if we want to enable CMAC support... " >&6; }
+case "$ac_cv_header_openssl_cmac_h" in
+ yes)
+
+$as_echo "#define ENABLE_CMAC 1" >>confdefs.h
+
+ ans="yes"
+ ;;
+ *) ans="no"
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ans" >&5
+$as_echo "$ans" >&6; }
+
@@ -31935,6 +32076,26 @@ $as_echo "#define ENABLE_BUG3020_FIX 1" >>confdefs.h
esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we want correct mode7 fudgetime2 behavior" >&5
+$as_echo_n "checking if we want correct mode7 fudgetime2 behavior... " >&6; }
+# Check whether --enable-bug3527-fix was given.
+if test "${enable_bug3527_fix+set}" = set; then :
+ enableval=$enable_bug3527_fix; ans=$enableval
+else
+ ans=yes
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ans" >&5
+$as_echo "$ans" >&6; }
+case "$ans" in
+ no)
+
+$as_echo "#define DISABLE_BUG3527_FIX 1" >>confdefs.h
+
+esac
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we should use the IRIG sawtooth filter" >&5
$as_echo_n "checking if we should use the IRIG sawtooth filter... " >&6; }
@@ -33223,6 +33384,32 @@ fi
###
+ac_fn_c_check_decl "$LINENO" "sigsetjmp" "ac_cv_have_decl_sigsetjmp" "#include <setjmp.h>
+"
+if test "x$ac_cv_have_decl_sigsetjmp" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SIGSETJMP $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "siglongjmp" "ac_cv_have_decl_siglongjmp" "#include <setjmp.h>
+"
+if test "x$ac_cv_have_decl_siglongjmp" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SIGLONGJMP $ac_have_decl
+_ACEOF
+
+
+###
+
prefix_NONE=
exec_prefix_NONE=
@@ -33964,7 +34151,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by ntp $as_me 4.2.8p11, which was
+This file was extended by ntp $as_me 4.2.8p13, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -34031,7 +34218,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-ntp config.status 4.2.8p11
+ntp config.status 4.2.8p13
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/contrib/ntp/configure.ac b/contrib/ntp/configure.ac
index 4e7e06a..7975d31 100644
--- a/contrib/ntp/configure.ac
+++ b/contrib/ntp/configure.ac
@@ -1749,6 +1749,7 @@ case "$ntp_ok" in
yes)
ntp_refclock=yes
AC_DEFINE([CLOCK_BANC], [1], [Datum/Bancomm bc635/VME interface?])
+ AC_SEARCH_LIBS([bcStartPci], [bcsdk], , , [])
;;
esac
AC_MSG_RESULT([$ntp_ok])
@@ -3014,6 +3015,17 @@ AC_MSG_RESULT([$ans])
NTP_OPENSSL
+AC_MSG_CHECKING([if we want to enable CMAC support])
+case "$ac_cv_header_openssl_cmac_h" in
+ yes)
+ AC_DEFINE([ENABLE_CMAC], [1], [Enable CMAC support?])
+ ans="yes"
+ ;;
+ *) ans="no"
+ ;;
+esac
+AC_MSG_RESULT([$ans])
+
NTP_CRYPTO_RAND
# if we are using OpenSSL (--with-crypto), by default Autokey is enabled
@@ -4183,6 +4195,24 @@ case "$ans" in
esac
+AC_MSG_CHECKING([if we want correct mode7 fudgetime2 behavior])
+AC_ARG_ENABLE(
+ [bug3527-fix],
+ [AS_HELP_STRING(
+ [--enable-bug3527-fix],
+ [+ provide correct mode7 fudgetime2 behavior]
+ )],
+ [ans=$enableval],
+ [ans=yes]
+)
+AC_MSG_RESULT([$ans])
+case "$ans" in
+ no)
+ AC_DEFINE([DISABLE_BUG3527_FIX], [1],
+ [use old autokey session key behavior?])
+esac
+
+
AC_MSG_CHECKING([if we should use the IRIG sawtooth filter])
case "$host" in
@@ -4380,6 +4410,10 @@ NTP_PROBLEM_TESTS
###
+AC_CHECK_DECLS([sigsetjmp,siglongjmp], [], [], [[#include <setjmp.h>]])
+
+###
+
AC_DEFINE_DIR([NTP_KEYSDIR], [sysconfdir],
[Default location of crypto key info])
diff --git a/contrib/ntp/html/authentic.html b/contrib/ntp/html/authentic.html
index 06bb67b..52703e4 100644
--- a/contrib/ntp/html/authentic.html
+++ b/contrib/ntp/html/authentic.html
@@ -1,91 +1,223 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
-<head>
-<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
-<meta name="generator" content="HTML Tidy, see www.w3.org">
-<title>Authentication Support</title>
-<link href="scripts/style.css" type="text/css" rel="stylesheet">
-<style type="text/css">
-<!--
-<style1 {
-color: #FF0000;
- font-weight: bold;
-}
-.style1 {color: #FF0000}
--->
-</style>
-</head>
-<body>
-<h3>Authentication Support</h3>
-<img src="pic/alice44.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/%7emills/pictures.html">from <i>Alice's Adventures in Wonderland</i>, Lewis Carroll</a>
-<p>Our resident cryptographer; now you see him, now you don't.</p>
-<p>Last update:
- <!-- #BeginDate format:En2m -->5-Feb-2016 09:13<!-- #EndDate -->
- UTC</p>
-<br clear="left">
-<h4>Related Links</h4>
-<script type="text/javascript" language="javascript" src="scripts/hand.txt"></script>
-<script type="text/javascript" language="javascript" src="scripts/authopt.txt"></script>
-<h4>Table of Contents</h4>
-<ul>
- <li class="inline"><a href="#auth">Introduction</a></li>
- <li class="inline"><a href="#symm">Symmetric Key Cryptography</a></li>
- <li class="inline"><a href="#windows">Microsoft Windows Authentication</a></li>
- <li class="inline"><a href="#pub">Public Key Cryptography</a></li>
-</ul>
-<hr>
-<h4 id="auth">Introduction</h4>
-<p>This page describes the various cryptographic authentication provisions in NTPv4. Authentication support allows the NTP client to verify that servers are in fact known and trusted and not intruders intending accidentally or intentionally to masquerade as a legitimate server. A detailed discussion of the NTP multi-layer security model and vulnerability analysis is in the white paper <a href="http://www.eecis.udel.edu/~mills/security.html">NTP Security Analysis</a>.</p>
-<p> The NTPv3 specification (RFC-1305) defined an authentication scheme properly described as <em>symmetric key cryptography</em>. It used the Data Encryption Standard (DES) algorithm operating in cipher-block chaining (CBC) mode. Subsequently, this algorithm was replaced by the RSA Message Digest 5 (MD5) algorithm commonly called keyed-MD5. Either algorithm computes a message digest or one-way hash which can be used to verify the client has the same message digest as the server. The MD5 message digest algorithm is included in the distribution, so without further cryptographic support, the distribution can be freely exported.</p>
-<p>If the OpenSSL cryptographic library is installed prior to building the distribution, all message digest algorithms included in the library may be used, including SHA and SHA1. However, if conformance to FIPS 140-2 is required, only a limited subset of these algorithms can be used. This library is available from <a href="http://www.openssl.org">http://www.openssl.org</a> and can be installed using the procedures outlined in the <a href="build.html">Building and Installing the Distribution</a> page. Once installed, the configure and build process automatically detects the library and links the library routines
-required.</p>
-<p>In addition to the symmetric key algorithms, this distribution includes support for the Autokey public key algorithms and protocol specified in RFC-5906 &quot;Network Time Protocol Version 4: Autokey Specification&quot;. This support is available only if the OpenSSL library has been installed and the <tt>--enable-autokey</tt> option is used when the distribution is built.</p>
-<p> Public key cryptography is generally considered more secure than symmetric key cryptography, since the security is based on private and public values which are generated by each participant and where the private value is never revealed. Autokey uses X.509 public certificates, which can be produced by commercial services, the OpenSSL application program, or the <a href="keygen.html"><tt>ntp-keygen</tt></a> utility program in the NTP software distribution.</p>
-<p>Note that according to US law, NTP binaries including OpenSSL library components, including the OpenSSL library itself, cannot be exported outside the US without license from the US Department of Commerce. Builders outside the US are advised to obtain the OpenSSL library directly from OpenSSL, which is outside the US, and build outside the US.</p>
-<p>Authentication is configured separately for each association using the <tt>key</tt> or <tt>autokey</tt> option of the <tt>server</tt> configuration command, as described in the <a href="confopt.html">Server Options</a> page. The <a href="keygen.html">ntp-keygen</a> page describes the files required for the various authentication schemes. Further details are in the briefings, papers and reports at the NTP project page linked from <a href="http://www.ntp.org">www.ntp.org</a>.</p>
-<p>By default, the client sends non-authenticated packets and the server responds with non-authenticated packets. If the client sends authenticated packets, the server responds with authenticated packets if correct, or a crypto-NAK packet if not. In the case of unsolicited packets which might consume significant resources, such as broadcast or symmetric mode packets, authentication is required, unless overridden by a <tt>disable auth</tt> command. In the current climate of targeted broadcast or &quot;letterbomb&quot; attacks, defeating this requirement would be decidedly dangerous. In any case, the <tt>notrust </tt>flag, described on the <a href="authopt.html">Access Control Options</a> page, can be used to disable access to all but correctly authenticated clients.</p>
-<h4 id="symm">Symmetric Key Cryptography</h4>
-<p>The original NTPv3 specification (RFC-1305), as well as the current NTPv4 specification (RFC-5905), allows any one of possibly 65,534 message digest keys (excluding zero), each distinguished by a 32-bit key ID, to authenticate an association. The servers and clients involved must agree on the key ID, key type and key to authenticate NTP packets.</p>
-<p>The message digest is a cryptographic hash computed by an algorithm such as MD5, SHA, or AES-128 CMAC. When authentication is specified, a message authentication code (MAC) is appended to the NTP packet header. The MAC consists of a 32-bit key identifier (key ID) followed by a 128- or 160-bit message digest. The algorithm computes the digest as the hash of a 128- or 160- bit message digest key concatenated with the NTP packet header fields with the exception of the MAC. On transmit, the message digest is computed and inserted in the MAC. On receive, the message digest is computed and compared with the MAC. The packet is accepted only if the two MACs are identical. If a discrepancy is found by the client, the client ignores the packet, but raises an alarm. If this happens at the server, the server returns a special message called a <em>crypto-NAK</em>. Since the crypto-NAK is protected by the loopback test, an intruder cannot disrupt the protocol by sending a bogus crypto-NAK.</p>
-<p>Keys and related information are specified in a keys file, which must be distributed and stored using secure means beyond the scope of the NTP protocol itself. Besides the keys used for ordinary NTP associations, additional keys can be used as passwords for the <tt><a href="ntpq.html">ntpq</a></tt> and <tt><a href="ntpdc.html">ntpdc</a></tt> utility programs. Ordinarily, the <tt>ntp.keys</tt> file is generated by the <tt><a href="keygen.html">ntp-keygen</a></tt> program, but it can be constructed and edited using an ordinary text editor.</p>
-<p> Each line of the keys file consists of three or four fields: a key ID in the range 1 to 65,534, inclusive, a key type, a message digest key consisting of a printable ASCII string less than 40 characters or a 40-character hex digit string, and an optional comma-separated list of IPs that are allowed to serve time. If the OpenSSL library is installed, the key type can be any message digest algorithm supported by the library. If the OpenSSL library is not installed, the only permitted key type is MD5.</p>
-<table>
- <caption style="caption-side: bottom;">
- Figure 1. Typical Symmetric Key File
- </caption>
- <tr><td style="border: 1px solid black; border-spacing: 0;">
- <pre style="color:grey;">
-# ntpkey_MD5key_bk.ntp.org.3595864945
-# Thu Dec 12 19:22:25 2013
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
+ <meta name="generator" content="HTML Tidy, see www.w3.org">
+ <title>Authentication Support</title>
+ <!-- Changed by: Harlan Stenn, 24-Jul-2018 -->
+ <link href="scripts/style.css" type="text/css" rel="stylesheet">
+ <style type="text/css">
+ <!--
+ <style1 {
+ color: #FF0000;
+ font-weight: bold;
+ }
+ .style1 {color: #FF0000}
+ -->
+ </style>
+ </head>
+ <body>
+ <h3>Authentication Support</h3>
+ <img src="pic/alice44.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/%7emills/pictures.html">from <i>Alice's Adventures in Wonderland</i>, Lewis Carroll</a>
+ <p>Our resident cryptographer; now you see him, now you don't.</p>
+ <p>Last update:
+ <!-- #BeginDate format:En2m -->24-Jul-2018 09:12<!-- #EndDate -->
+ UTC</p>
+ <br clear="left">
+ <h4>Related Links</h4>
+ <script type="text/javascript" language="javascript" src="scripts/hand.txt"></script>
+ <script type="text/javascript" language="javascript" src="scripts/authopt.txt"></script>
+ <h4>Table of Contents</h4>
+ <ul>
+ <li class="inline"><a href="#auth">Introduction</a></li>
+ <li class="inline"><a href="#symm">Symmetric Key Cryptography</a></li>
+ <li class="inline"><a href="#windows">Microsoft Windows Authentication</a></li>
+ <li class="inline"><a href="#pub">Public Key Cryptography</a></li>
+ </ul>
+ <hr>
+ <h4 id="auth">Introduction</h4>
+ <p>This page describes the various cryptographic authentication
+ provisions in NTPv4. Authentication support allows the NTP client to
+ verify that servers are in fact known and trusted and not intruders
+ intending accidentally or intentionally to masquerade as a legitimate
+ server. A detailed discussion of the NTP multi-layer security model
+ and vulnerability analysis is in the white
+ paper <a href="http://www.eecis.udel.edu/~mills/security.html">NTP
+ Security Analysis</a>.</p>
+ <p>The NTPv3 specification (RFC-1305) defined an authentication scheme
+ properly described as <em>symmetric key cryptography</em>. It used
+ the Data Encryption Standard (DES) algorithm operating in cipher-block
+ chaining (CBC) mode. Subsequently, this algorithm was replaced by the
+ RSA Message Digest 5 (MD5) algorithm commonly called keyed-MD5.
+ Either algorithm computes a message digest or one-way hash which can
+ be used to verify the client has the same message digest as the
+ server. The MD5 message digest algorithm is included in the
+ distribution, so without further cryptographic support, the
+ distribution can be freely exported.</p>
+ <p>If the OpenSSL cryptographic library is installed prior to building
+ the distribution, all message digest algorithms included in the
+ library may be used, including SHA and SHA1. However, if conformance
+ to FIPS 140-2 is required, only a limited subset of these algorithms
+ can be used. This library is available
+ from <a href="http://www.openssl.org">http://www.openssl.org</a> and
+ can be installed using the procedures outlined in
+ the <a href="build.html">Building and Installing the Distribution</a>
+ page. Once installed, the configure and build process automatically
+ detects the library and links the library routines required.</p>
+ <p>In addition to the symmetric key algorithms, this distribution
+ includes support for the Autokey public key algorithms and protocol
+ specified in RFC-5906 &quot;Network Time Protocol Version 4: Autokey
+ Specification&quot;. This support is available only if the OpenSSL
+ library has been installed and the <tt>--enable-autokey</tt> option is
+ used when the distribution is built.</p>
+ <p> Public key cryptography is generally considered more secure than
+ symmetric key cryptography, since the security is based on private and
+ public values which are generated by each participant and where the
+ private value is never revealed. Autokey uses X.509 public
+ certificates, which can be produced by commercial services, the
+ OpenSSL application program, or
+ the <a href="keygen.html"><tt>ntp-keygen</tt></a> utility program in
+ the NTP software distribution.</p>
+ <p>Note that according to US law, NTP binaries including OpenSSL library
+ components, including the OpenSSL library itself, cannot be exported
+ outside the US without license from the US Department of Commerce.
+ Builders outside the US are advised to obtain the OpenSSL library
+ directly from OpenSSL, which is outside the US, and build outside the
+ US.</p>
+ <p>Authentication is configured separately for each association using
+ the <tt>key</tt> or <tt>autokey</tt> option of the <tt>server</tt>
+ configuration command, as described in
+ the <a href="confopt.html">Server Options</a> page.
+ The <a href="keygen.html">ntp-keygen</a> page describes the files
+ required for the various authentication schemes. Further details are
+ in the briefings, papers and reports at the NTP project page linked
+ from <a href="http://www.ntp.org">www.ntp.org</a>.</p>
+ <p>By default, the client sends non-authenticated packets and the server
+ responds with non-authenticated packets. If the client sends
+ authenticated packets, the server responds with authenticated packets
+ if correct, or a crypto-NAK packet if not. In the case of unsolicited
+ packets which might consume significant resources, such as broadcast
+ or symmetric mode packets, authentication is required, unless
+ overridden by a <tt>disable auth</tt> command. In the current climate
+ of targeted broadcast or &quot;letterbomb&quot; attacks, defeating
+ this requirement would be decidedly dangerous. In any case,
+ the <tt>notrust </tt>flag, described on
+ the <a href="authopt.html">Access Control Options</a> page, can be
+ used to disable access to all but correctly authenticated clients.</p>
+ <h4 id="symm">Symmetric Key Cryptography</h4>
+ <p>The original NTPv3 specification (RFC-1305), as well as the current
+ NTPv4 specification (RFC-5905), allows any one of possibly 65,535
+ message digest keys (excluding zero), each distinguished by a 32-bit
+ key ID, to authenticate an association. The servers and clients
+ involved must agree on the key ID, key type and key to authenticate
+ NTP packets.</p>
+ <p>The message digest is a cryptographic hash computed by an algorithm
+ such as MD5, SHA, or AES-128 CMAC. When authentication is specified,
+ a message authentication code (MAC) is appended to the NTP packet
+ header. The MAC consists of a 32-bit key identifier (key ID) followed
+ by a 128- or 160-bit message digest. The algorithm computes the
+ digest as the hash of a 128- or 160- bit message digest key
+ concatenated with the NTP packet header fields with the exception of
+ the MAC. On transmit, the message digest is computed and inserted in
+ the MAC. On receive, the message digest is computed and compared with
+ the MAC. The packet is accepted only if the two MACs are identical.
+ If a discrepancy is found by the client, the client ignores the
+ packet, but raises an alarm. If this happens at the server, the
+ server returns a special message called a <em>crypto-NAK</em>. Since
+ the crypto-NAK is protected by the loopback test, an intruder cannot
+ disrupt the protocol by sending a bogus crypto-NAK.</p>
+ <p>Keys and related information are specified in a keys file, which must
+ be distributed and stored using secure means beyond the scope of the
+ NTP protocol itself. Besides the keys used for ordinary NTP
+ associations, additional keys can be used as passwords for
+ the <tt><a href="ntpq.html">ntpq</a></tt>
+ and <tt><a href="ntpdc.html">ntpdc</a></tt> utility programs.
+ Ordinarily, the <tt>ntp.keys</tt> file is generated by
+ the <tt><a href="keygen.html">ntp-keygen</a></tt> program, but it can
+ be constructed and edited using an ordinary text editor.</p>
+ <p> Each line of the keys file consists of three or four fields: a key
+ ID in the range 1 to 65,535, inclusive, a key type, a message digest
+ key consisting of a printable ASCII string less than 40 characters or
+ a 40-character hex digit string, and an optional comma-separated list
+ of IPs that are allowed to serve time. If the OpenSSL library is
+ installed, the key type can be any message digest algorithm supported
+ by the library. If the OpenSSL library is not installed, the only
+ permitted key type is MD5.</p>
+ <table>
+ <caption style="caption-side: bottom;">
+ Figure 1. Typical Symmetric Key File
+ </caption>
+ <tr><td style="border: 1px solid black; border-spacing: 0;">
+ <pre style="color:grey;">
+ # ntpkey_MD5key_bk.ntp.org.3595864945
+ # Thu Dec 12 19:22:25 2013
-1 MD5 L";Nw&lt;`.I&lt;f4U0)247"i # MD5 key
-2 MD5 &amp;&gt;l0%XXK9O'51VwV&lt;xq~ # MD5 key
-3 MD5 lb4zLW~d^!K:]RsD'qb6 # MD5 key
-4 MD5 Yue:tL[+vR)M`n~bY,'? # MD5 key
-5 MD5 B;fxlKgr/&amp;4ZTbL6=RxA # MD5 key
-6 MD5 4eYwa`o}3i@@V@..R9!l # MD5 key
-7 MD5 `A.([h+;wTQ|xfi%Sn_! # MD5 key
-8 MD5 45:V,r4]l6y^JH6"Sh?F # MD5 key
-9 MD5 3-5vcn*6l29DS?Xdsg)* # MD5 key
-10 MD5 2late4Me # MD5 key
-11 SHA1 a27872d3030a9025b8446c751b4551a7629af65c # SHA1 key
-12 SHA1 21bc3b4865dbb9e920902abdccb3e04ff97a5e74 # SHA1 key
-13 SHA1 2b7736fe24fef5ba85ae11594132ab5d6f6daba9 # SHA1 key
-14 SHA a5332809c8878dd3a5b918819108a111509aeceb # SHA key
-15 MD2 2fe16c88c760ff2f16d4267e36c1aa6c926e6964 # MD2 key
-16 MD4 b2691811dc19cfc0e2f9bcacd74213f29812183d # MD4 key
-17 MD5 e4d6735b8bdad58ec5ffcb087300a17f7fef1f7c # MD5 key
-18 MDC2 a8d5e2315c025bf3a79174c87fbd10477de2eabc # MDC2 key
-19 RIPEMD160 77ca332cafb30e3cafb174dcd5b80ded7ba9b3d2 # RIPEMD160 key
-20 AES128CMAC f92ff73eee86c1e7dc638d6489a04e4e555af878 # AES128CMAC key
- </pre></td></tr></table>
-<p>Figure 1 shows a typical keys file used by the reference implementation when the OpenSSL library is installed. In this figure, for key IDs in he range 1-10, the key is interpreted as a printable ASCII string. For key IDs in the range 11-20, the key is a 40-character hex digit string. The key is truncated or zero-filled internally to either 128 or 160 bits, depending on the key type. The line can be edited later or new lines can be added to change any field. The key can be changed to a password, such as <tt>2late4Me</tt> for key ID 10. Note that two or more keys files can be combined in any order as long as the key IDs are distinct.</p>
-<p>When <tt>ntpd</tt> is started, it reads the keys file specified by the <tt>keys</tt> command and installs the keys in the key cache. However, individual keys must be activated with the <tt>trustedkey</tt> configuration command before use. This allows, for instance, the installation of possibly several batches of keys and then activating a key remotely using <tt>ntpq</tt> or <tt>ntpdc</tt>. The <tt>requestkey</tt> command selects the key ID used as the password for the <tt>ntpdc</tt> utility, while the <tt>controlkey</tt> command selects the key ID used as the password for the <tt>ntpq</tt> utility.</p>
-<h4 id="windows">Microsoft Windows Authentication</h4>
-<p>In addition to the above means, <tt>ntpd</tt> now supports Microsoft Windows MS-SNTP authentication using Active Directory services. This support was contributed by the Samba Team and is still in development. It is enabled using the <tt>mssntp</tt> flag of the <tt>restrict</tt> command described on the <a href="accopt.html#restrict">Access Control Options</a> page. <span class="style1">Note: Potential users should be aware that these services involve a TCP connection to another process that could potentially block, denying services to other users. Therefore, this flag should be used only for a dedicated server with no clients other than MS-SNTP.</span></p>
-<h4 id="pub">Public Key Cryptography</h4>
-<p>See the <a href="autokey.html">Autokey Public-Key Authentication</a> page.</p>
-<hr>
-<script type="text/javascript" language="javascript" src="scripts/footer.txt"></script>
-</body>
+ 1 MD5 L";Nw&lt;`.I&lt;f4U0)247"i # MD5 key
+ 2 MD5 &amp;&gt;l0%XXK9O'51VwV&lt;xq~ # MD5 key
+ 3 MD5 lb4zLW~d^!K:]RsD'qb6 # MD5 key
+ 4 MD5 Yue:tL[+vR)M`n~bY,'? # MD5 key
+ 5 MD5 B;fxlKgr/&amp;4ZTbL6=RxA # MD5 key
+ 6 MD5 4eYwa`o}3i@@V@..R9!l # MD5 key
+ 7 MD5 `A.([h+;wTQ|xfi%Sn_! # MD5 key
+ 8 MD5 45:V,r4]l6y^JH6"Sh?F # MD5 key
+ 9 MD5 3-5vcn*6l29DS?Xdsg)* # MD5 key
+ 10 MD5 2late4Me # MD5 key
+ 11 SHA1 a27872d3030a9025b8446c751b4551a7629af65c # SHA1 key
+ 12 SHA1 21bc3b4865dbb9e920902abdccb3e04ff97a5e74 # SHA1 key
+ 13 SHA1 2b7736fe24fef5ba85ae11594132ab5d6f6daba9 # SHA1 key
+ 14 SHA a5332809c8878dd3a5b918819108a111509aeceb # SHA key
+ 15 MD2 2fe16c88c760ff2f16d4267e36c1aa6c926e6964 # MD2 key
+ 16 MD4 b2691811dc19cfc0e2f9bcacd74213f29812183d # MD4 key
+ 17 MD5 e4d6735b8bdad58ec5ffcb087300a17f7fef1f7c # MD5 key
+ 18 MDC2 a8d5e2315c025bf3a79174c87fbd10477de2eabc # MDC2 key
+ 19 RIPEMD160 77ca332cafb30e3cafb174dcd5b80ded7ba9b3d2 # RIPEMD160 key
+ 20 AES128CMAC f92ff73eee86c1e7dc638d6489a04e4e555af878 # AES128CMAC key
+ 21 MD5 sampo 10.1.2.3/24
+ </pre></td></tr></table>
+ <p>Figure 1 shows a typical symmetric keys file used by the reference
+ implementation when the OpenSSL library is installed. Each line of
+ the file contains three or four fields. The first field is an integer
+ between 1 and 65535, inclusive, representing the key identifier. The
+ second field is the digest algorithm, which in the absence of the
+ OpenSSL library must be <tt>MD5</tt>, which designates the MD5 message
+ digest algorithm. The third field is the key. The optional fourth
+ field is one or more comma-separated IPs. An IP may end with an
+ optional <tt>/subnetbits</tt> suffix, which limits the acceptance of
+ the key identifier to packets claiming to be from the described IP
+ space. In this example, for the key IDs in the range 1-10 the key is
+ interpreted as a printable ASCII string. For the key IDs in the range
+ 11-20, the key is a 40-character hex digit string. In either case,
+ the key is truncated or zero-filled internally to either 128 or 160
+ bits, depending on the key type. The line can be edited later or new
+ lines can be added to change any field. The key can be changed to a
+ password, such as <tt>2late4Me</tt> for key ID 10. Note that two or
+ more keys files can be combined in any order as long as the key IDs
+ are distinct.</p>
+ <p>When <tt>ntpd</tt> is started, it reads the keys file specified by
+ the <tt>keys</tt> command and installs the keys in the key cache.
+ However, individual keys must be activated with
+ the <tt>trustedkey</tt> configuration command before use. This
+ allows, for instance, the installation of possibly several batches of
+ keys and then activating a key remotely using <tt>ntpq</tt>
+ or <tt>ntpdc</tt>. The <tt>requestkey</tt> command selects the key ID
+ used as the password for the <tt>ntpdc</tt> utility, while
+ the <tt>controlkey</tt> command selects the key ID used as the
+ password for the <tt>ntpq</tt> utility.</p>
+ <h4 id="windows">Microsoft Windows Authentication</h4>
+ <p>In addition to the above means, <tt>ntpd</tt> now supports Microsoft
+ Windows MS-SNTP authentication using Active Directory services. This
+ support was contributed by the Samba Team and is still in development.
+ It is enabled using the <tt>mssntp</tt> flag of the <tt>restrict</tt>
+ command described on the <a href="accopt.html#restrict">Access Control
+ Options</a> page. <span class="style1">Note: Potential users should
+ be aware that these services involve a TCP connection to another
+ process that could potentially block, denying services to other users.
+ Therefore, this flag should be used only for a dedicated server with
+ no clients other than MS-SNTP.</span></p>
+ <h4 id="pub">Public Key Cryptography</h4>
+ <p>See the <a href="autokey.html">Autokey Public-Key Authentication</a>
+ page.</p>
+ <hr>
+ <script type="text/javascript" language="javascript" src="scripts/footer.txt"></script>
+ </body>
</html>
diff --git a/contrib/ntp/html/authopt.html b/contrib/ntp/html/authopt.html
index 9504deb..c9484ef 100644
--- a/contrib/ntp/html/authopt.html
+++ b/contrib/ntp/html/authopt.html
@@ -4,6 +4,7 @@
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<meta name="generator" content="HTML Tidy, see www.w3.org">
<title>Authentication Commands and Options</title>
+<!-- Changed by: stenn, 25-May-2018 -->
<link href="scripts/style.css" type="text/css" rel="stylesheet">
<style type="text/css">
.style1 {
@@ -17,7 +18,7 @@
<img src="pic/alice44.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/%7emills/pictures.html">from <i>Alice's Adventures in Wonderland</i>, Lewis Carroll</a>
<p>Our resident cryptographer; now you see him, now you don't.</p>
<p>Last update:
- <!-- #BeginDate format:En2m -->15-Oct-2011 01:00<!-- #EndDate -->
+ <!-- #BeginDate format:En2m -->24-Jul-2018 07:27<!-- #EndDate -->
UTC</p>
<br clear="left">
<h4>Related Links</h4>
@@ -28,65 +29,65 @@
<p>Unless noted otherwise, further information about these commands is on the <a href="authentic.html">Authentication Support</a> page.</p>
<dl>
<dt id=automax><tt>automax [<i>logsec</i>]</tt></dt>
- <dd>Specifies the interval between regenerations of the session key list used with the Autokey protocol, as a power of 2 in seconds. Note that the size of the key list for each association depends on this interval and the current poll interval. The default interval is 12 (about 1.1 hr). For poll intervals above the specified interval, a session key list with a single entry will be regenerated for every message sent. See the <a href="autokey.html">Autokey Public Key Authentication</a> page for further information.</dd>
+ <dd>Specifies the interval between regenerations of the session key list used with the Autokey protocol, as a power of 2 in seconds. Note that the size of the key list for each association depends on this interval and the current poll interval. The default interval is 12 (about 1.1 hr). For poll intervals above the specified interval, a session key list with a single entry will be regenerated for every message sent. See the <a href="autokey.html">Autokey Public Key Authentication</a> page for further information.</dd>
<dt id="controlkey"><tt>controlkey <i>keyid</i></tt></dt>
<dd>Specifies the key ID for the <a
href="ntpq.html"><tt>ntpq</tt></a> utility, which uses the
- standard protocol defined in RFC-1305. The <tt><i>keyid</i></tt> argument is the key ID for a <a href="#trustedkey">trusted
- key</a>, where the value can be in the range 1 to 65534,
+ standard protocol defined in RFC-1305. The <tt><i>keyid</i></tt> argument is the key ID for a <a href="#trustedkey">trusted
+ key</a>, where the value can be in the range 1 to 65535,
inclusive.</dd>
- <dt id="crypto"><tt>crypto [digest</tt> <em><tt>digest</tt></em><tt>]</tt> <tt>[host <i>name</i>] [ident <i>name</i>] [pw <i>password</i>] [randfile <i>file</i>]</tt></dt>
+ <dt id="crypto"><tt>crypto [digest <i>digest</i>] [host <i>name</i>] [ident <i>name</i>] [pw <i>password</i>] [randfile <i>file</i>]</tt></dt>
<dd>This command activates the Autokey public key cryptography
- and loads the required host keys and certificate. If one or more files
- are unspecified, the default names are used. Unless
+ and loads the required host keys and certificate. If one or more files
+ are unspecified, the default names are used. Unless
the complete path and name of the file are specified, the location of a file
is relative to the keys directory specified in the <tt>keysdir</tt> configuration
- command with default <tt>/usr/local/etc</tt>. See the <a href="autokey.html">Autokey Public Key Authentication</a> page for further information. Following are the options.</dd>
+ command with default <tt>/usr/local/etc</tt>. See the <a href="autokey.html">Autokey Public Key Authentication</a> page for further information. Following are the options.</dd>
<dd>
<dl>
- <dt><tt>digest</tt> <em><tt>digest</tt></em></dt>
+ <dt><tt>digest</tt> <i>digest</i></dt>
<dd>&nbsp;</dd>
<dd>Specify the message digest algorithm, with default MD5. If the OpenSSL library
is installed, <tt><i>digest</i></tt> can be be any message digest algorithm supported
- by the library. The current selections are: <tt>MD2</tt>, <tt>MD4</tt>, <tt>MD5,</tt> <tt>MDC2</tt>, <tt>RIPEMD160</tt>, <tt>SHA</tt> and <tt>SHA1</tt>. All
- participants in an Autokey subnet must use the same algorithm. The Autokey message digest algorithm is separate and distinct from the symmetric
- key message digest algorithm. Note: If compliance with FIPS 140-2 is required,
+ by the library. The current selections are: <tt>MD2</tt>, <tt>MD4</tt>, <tt>MD5,</tt> <tt>MDC2</tt>, <tt>RIPEMD160</tt>, <tt>SHA</tt> and <tt>SHA1</tt>. All
+ participants in an Autokey subnet must use the same algorithm. The Autokey message digest algorithm is separate and distinct from the symmetric
+ key message digest algorithm. Note: If compliance with FIPS 140-2 is required,
the algorithm must be ether <tt>SHA</tt> or <tt>SHA1</tt>.</dd>
<dt><tt>host <i>name</i></tt></dt>
- <dd>Specify the cryptographic media names for the host, sign and certificate files. If this option is not specified, the default name is the string returned by the Unix <tt>gethostname()</tt> routine.</dd>
+ <dd>Specify the cryptographic media names for the host, sign and certificate files. If this option is not specified, the default name is the string returned by the Unix <tt>gethostname()</tt> routine.</dd>
<dd><span class="style1">Note: In the latest Autokey version, this option has no effect other than to change the cryptographic media file names.</span></dd>
<dt><tt>ident <i>group</i></tt></dt>
- <dd>Specify the cryptographic media names for the identity scheme files. If this option is not specified, the default name is the string returned by the Unix <tt>gethostname()</tt> routine.</dd>
+ <dd>Specify the cryptographic media names for the identity scheme files. If this option is not specified, the default name is the string returned by the Unix <tt>gethostname()</tt> routine.</dd>
<dd><span class="style1">Note: In the latest Autokey version, this option has no effect other than to change the cryptographic media file names.</span></dd>
<dt><tt>pw <i>password</i></tt></dt>
- <dd>Specifies the password to decrypt files previously encrypted by the <tt>ntp-keygen</tt> program with the <tt>-p</tt> option. If this option is not specified, the default password is the string returned by the Unix <tt>gethostname()</tt> routine. </dd>
+ <dd>Specifies the password to decrypt files previously encrypted by the <tt>ntp-keygen</tt> program with the <tt>-p</tt> option. If this option is not specified, the default password is the string returned by the Unix <tt>gethostname()</tt> routine.</dd>
<dt><tt>randfile <i>file</i></tt></dt>
- <dd>Specifies the location of the random seed file used by the OpenSSL library. The defaults are described on the <a href="keygen.html"><tt>ntp-keygen</tt> page</a>.</dd>
+ <dd>Specifies the location of the random seed file used by the OpenSSL library. The defaults are described on the <a href="keygen.html"><tt>ntp-keygen</tt> page</a>.</dd>
</dl>
</dd>
<dt id="ident"><tt>ident <i>group</i></tt></dt>
- <dd>Specifies the group name for ephemeral associations mobilized by broadcast and symmetric passive modes. See the <a href="autokey.html">Autokey Public-Key Authentication</a> page for further information.</dd>
+ <dd>Specifies the group name for ephemeral associations mobilized by broadcast and symmetric passive modes. See the <a href="autokey.html">Autokey Public-Key Authentication</a> page for further information.</dd>
<dt id="keys"><tt>keys <i>path</i></tt></dt>
- <dd>Specifies the complete directory path for the key file containing the key IDs, key types and keys used by <tt>ntpd</tt>, <tt>ntpq</tt> and <tt>ntpdc</tt> when operating with symmetric key cryptography. The format of the keyfile is described on the <a href="keygen.html"><tt>ntp-keygen</tt> page</a>. This is the same operation as the <tt>-k</tt> command line option. Note that the directory path for Autokey cryptographic media is specified by the <tt>keysdir</tt> command.</dd>
+ <dd>Specifies the complete directory path for the key file containing the key IDs, key types and keys used by <tt>ntpd</tt>, <tt>ntpq</tt> and <tt>ntpdc</tt> when operating with symmetric key cryptography. The format of the keyfile is described on the <a href="keygen.html"><tt>ntp-keygen</tt> page</a>. This is the same operation as the <tt>-k</tt> command line option. Note that the directory path for Autokey cryptographic media is specified by the <tt>keysdir</tt> command.</dd>
<dt id="keysdir"><tt>keysdir <i>path</i></tt></dt>
- <dd>Specifies the complete directory path for the Autokey cryptographic keys, parameters and certificates. The default is <tt>/usr/local/etc/</tt>. Note that the path for the symmetric keys file is specified by the <tt>keys</tt> command.</dd>
+ <dd>Specifies the complete directory path for the Autokey cryptographic keys, parameters and certificates. The default is <tt>/usr/local/etc/</tt>. Note that the path for the symmetric keys file is specified by the <tt>keys</tt> command.</dd>
<dt id="requestkey"><tt>requestkey <i>keyid</i></tt></dt>
<dd>Specifies the key ID for the <a href="ntpdc.html"><tt>ntpdc</tt></a> utility program, which
- uses a proprietary protocol specific to this implementation of <tt>ntpd</tt>. The <tt><i>keyid</i></tt> argument is a key ID
+ uses a proprietary protocol specific to this implementation of <tt>ntpd</tt>. The <tt><i>keyid</i></tt> argument is a key ID
for a <a href="#trustedkey">trusted key</a>, in the range 1 to
- 65534, inclusive.</dd>
+ 65535, inclusive.</dd>
<dt id="revoke"><tt>revoke [<i>logsec</i>]</tt></dt>
<dd>Specifies the interval between re-randomization of certain cryptographic values used by the Autokey scheme, as a power of 2 in seconds, with default 17 (36 hr). See the <a href="autokey.html">Autokey Public-Key Authentication</a> page for further information.</dd>
<dt id="trustedkey"><tt>trustedkey [<i>keyid</i> | (<i>lowid</i> ... <i>highid</i>)] [...]</tt></dt>
<dd>Specifies the key ID(s) which are trusted for the purposes of
authenticating peers with symmetric key cryptography. Key IDs
used to authenticate <tt>ntpq</tt> and <tt>ntpdc</tt> operations
- must be listed here and additionally be enabled with <a href="#controlkey">controlkey</a> and/or <a href="#requestkey">requestkey</a>. The authentication
+ must be listed here and additionally be enabled with <a href="#controlkey">controlkey</a> and/or <a href="#requestkey">requestkey</a>. The authentication
procedure for time transfer requires that both the local and
remote NTP servers employ the same key ID and secret for this
purpose, although different keys IDs may be used with different
- servers. Ranges of trusted key IDs may be specified: <tt>trustedkey (1 ... 19) 1000 (100 ... 199)</tt> enables the
- lowest 120 key IDs which start with the digit 1. The spaces
+ servers. Ranges of trusted key IDs may be specified: <tt>trustedkey (1 ... 19) 1000 (100 ... 199)</tt> enables the
+ lowest 120 key IDs which start with the digit 1. The spaces
surrounding the ellipsis are required when specifying a range.</dd>
</dl>
<hr>
diff --git a/contrib/ntp/html/confopt.html b/contrib/ntp/html/confopt.html
index b964d24..f214f0f 100644
--- a/contrib/ntp/html/confopt.html
+++ b/contrib/ntp/html/confopt.html
@@ -13,7 +13,7 @@
Walt Kelly</a>
<p>The chicken is getting configuration advice.</p>
<p>Last update:
- <!-- #BeginDate format:En2m -->10-Mar-2014 05:01<!-- #EndDate -->
+ <!-- #BeginDate format:En2m -->24-Jul-2018 07:27<!-- #EndDate -->
UTC</p>
<br clear="left">
<h4>Related Links</h4>
@@ -67,7 +67,7 @@ Walt Kelly</a>
<dt><tt>ident</tt> <em><tt>group</tt></em></dt>
<dd>Specify the group name for the association. See the <a href="autokey.html">Autokey Public-Key Authentication</a> page for further information.</dd>
<dt><tt>key</tt> <i><tt>key</tt></i></dt>
- <dd>Send and receive packets authenticated by the symmetric key scheme described in the <a href="authentic.html">Authentication Support</a> page. The <i><tt>key</tt></i> specifies the key identifier with values from 1 to 65534, inclusive. This option is mutually exclusive with the <tt>autokey</tt> option.</dd> <dt><tt>minpoll <i>minpoll<br>
+ <dd>Send and receive packets authenticated by the symmetric key scheme described in the <a href="authentic.html">Authentication Support</a> page. The <i><tt>key</tt></i> specifies the key identifier with values from 1 to 65535, inclusive. This option is mutually exclusive with the <tt>autokey</tt> option.</dd> <dt><tt>minpoll <i>minpoll<br>
</i></tt><tt>maxpoll <i>maxpoll</i></tt></dt>
<dd>These options specify the minimum and maximum poll intervals for NTP messages, in seconds as a power of two. The maximum poll interval defaults to 10 (1024 s), but can be increased by the <tt>maxpoll</tt> option to an upper limit of 17 (36 hr). The minimum poll interval defaults to 6 (64 s), but can be decreased by the <tt>minpoll</tt> option to a lower limit of 3 (8 s). Additional information about this option is on the <a href="poll.html">Poll Program</a> page.</dd>
<dt><tt>mode <i>option</i></tt></dt>
diff --git a/contrib/ntp/html/keygen.html b/contrib/ntp/html/keygen.html
index 4f10a28..51577e3 100644
--- a/contrib/ntp/html/keygen.html
+++ b/contrib/ntp/html/keygen.html
@@ -11,7 +11,7 @@
<p><img src="pic/alice23.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/%7emills/pictures.html">from <i>Alice's Adventures in Wonderland</i>, Lewis Carroll</a></p>
<p>Alice holds the key.</p>
<p>Last update:
- <!-- #BeginDate format:En2m -->11-Jan-2018 11:55<!-- #EndDate -->
+ <!-- #BeginDate format:En2m -->24-Jul-2018 07:27<!-- #EndDate -->
UTC</p>
<br clear="left">
<h4>Related Links</h4>
@@ -313,7 +313,7 @@
</pre></td></tr></table>
<p>Figure 1 shows a typical symmetric keys file used by the reference
implementation. Each line of the file contains three or four fields,
- first an integer between 1 and 65534, inclusive, representing the key
+ first an integer between 1 and 65535, inclusive, representing the key
identifier used in the <tt>server</tt> and <tt>peer</tt> configuration
commands. Second is the key type for the message digest algorithm,
which in the absence of the OpenSSL library must be <tt>MD5</tt> to
diff --git a/contrib/ntp/html/ntpdate.html b/contrib/ntp/html/ntpdate.html
index 9216b6c..56e100d 100644
--- a/contrib/ntp/html/ntpdate.html
+++ b/contrib/ntp/html/ntpdate.html
@@ -11,7 +11,7 @@
<img src="pic/rabbit.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/~mills/pictures.html">from <i>Alice's Adventures in Wonderland</i>, Lewis Carroll</a>
<p>I told you it was eyeball and wristwatch.</p>
<p>Last update:
- <!-- #BeginDate format:En2m -->9-Feb-2014 03:34<!-- #EndDate -->
+ <!-- #BeginDate format:En2m -->21-Jul-2018 04:09<!-- #EndDate -->
UTC</p>
<br clear="left">
<hr>
@@ -63,7 +63,7 @@ Protocol (SNTP) Client</a> page. After a suitable period of mourning, the <tt>n
<dt><tt>-s</tt></dt>
<dd>Divert logging output from the standard output (default) to the system <tt>syslog</tt> facility. This is designed primarily for convenience of <tt>cron</tt> scripts.</dd>
<dt><tt>-t <i>timeout</i></tt></dt>
- <dd>Specify the maximum time waiting for a server response as the value <i>timeout</i>, in seconds and fraction. The value is is rounded to a multiple of 0.2 seconds. The default is 1 second, a value suitable for polling across a LAN.</dd>
+ <dd>Specify the maximum time waiting for a server response as the value <i>timeout</i>, in seconds and fraction. The value is is rounded to a multiple of 0.2 seconds. The default is 2 seconds, a value suitable for polling across a LAN.</dd>
<dt><tt>-u</tt></dt>
<dd>Direct <tt>ntpdate</tt> to use an unprivileged port for outgoing packets. This is most useful when behind a firewall that blocks incoming traffic to privileged ports, and you want to synchronize with hosts beyond the firewall. Note that the <tt>-d</tt> option always uses unprivileged ports.
<dt><tt>-<i>v</i></tt></dt>
diff --git a/contrib/ntp/include/Makefile.in b/contrib/ntp/include/Makefile.in
index 15a1e86..2e1ed92 100644
--- a/contrib/ntp/include/Makefile.in
+++ b/contrib/ntp/include/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/include/isc/Makefile.in b/contrib/ntp/include/isc/Makefile.in
index 192fe08..c730b3a 100644
--- a/contrib/ntp/include/isc/Makefile.in
+++ b/contrib/ntp/include/isc/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/include/ntp.h b/contrib/ntp/include/ntp.h
index fb739c7..cfbb7d2 100644
--- a/contrib/ntp/include/ntp.h
+++ b/contrib/ntp/include/ntp.h
@@ -610,6 +610,18 @@ struct pkt {
#define STRATUM_TO_PKT(s) ((u_char)(((s) == (STRATUM_UNSPEC)) ?\
(STRATUM_PKT_UNSPEC) : (s)))
+
+/*
+ * A test to determine if the refid should be interpreted as text string.
+ * This is usually the case for a refclock, which has stratum 0 internally,
+ * which results in sys_stratum 1 if the refclock becomes system peer, or
+ * in case of a kiss-of-death (KoD) packet that has STRATUM_PKT_UNSPEC (==0)
+ * in the packet which is converted to STRATUM_UNSPEC when the packet
+ * is evaluated.
+ */
+#define REFID_ISTEXT(s) (((s) <= 1) || ((s) >= STRATUM_UNSPEC))
+
+
/*
* Event codes. Used for reporting errors/events to the control module
*/
diff --git a/contrib/ntp/include/ntp_calendar.h b/contrib/ntp/include/ntp_calendar.h
index 41c5879..0b1f20d 100644
--- a/contrib/ntp/include/ntp_calendar.h
+++ b/contrib/ntp/include/ntp_calendar.h
@@ -93,6 +93,7 @@ extern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr);
#define SECSPERLEAPYEAR (366 * SECSPERDAY) /* leap year */
#define SECSPERAVGYEAR 31556952 /* mean year length over 400yrs */
+#define GPSWEEKS 1024 /* GPS week cycle */
/*
* Gross hacks. I have illicit knowlege that there won't be overflows
* here, the compiler often can't tell this.
@@ -404,14 +405,21 @@ basedate_get_eracenter(void);
extern time_t
basedate_get_erabase(void);
+extern uint32_t
+basedate_get_gpsweek(void);
+
+extern uint32_t
+basedate_expand_gpsweek(unsigned short weekno);
/*
* Additional support stuff for Ed Rheingold's calendrical calculations
*/
/*
- * Start day of NTP time as days past the imaginary date 12/1/1 BC.
- * (This is the beginning of the Christian Era, or BCE.)
+ * Start day of NTP time as days past 0000-12-31 in the proleptic
+ * Gregorian calendar. (So 0001-01-01 is day number 1; this is the Rata
+ * Die counting scheme used by Ed Rheingold in his book "Calendrical
+ * Calculations".)
*/
#define DAY_NTP_STARTS 693596
@@ -421,14 +429,24 @@ basedate_get_erabase(void);
#define DAY_UNIX_STARTS 719163
/*
+ * Start day of the GPS epoch. This is the Rata Die of 1980-01-06
+ */
+#define DAY_GPS_STARTS 722819
+
+/*
* Difference between UN*X and NTP epoch (25567).
*/
#define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS)
/*
+ * Difference between GPS and NTP epoch (29224)
+ */
+#define NTP_TO_GPS_DAYS (DAY_GPS_STARTS - DAY_NTP_STARTS)
+
+/*
* Days in a normal 4 year leap year calendar cycle (1461).
*/
-#define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS (3 * 365 + 366)
+#define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS (4 * 365 + 1)
/*
* Days in a normal 100 year leap year calendar (36524). We lose a
diff --git a/contrib/ntp/include/ntp_md5.h b/contrib/ntp/include/ntp_md5.h
index 01b417a..06c90b2 100644
--- a/contrib/ntp/include/ntp_md5.h
+++ b/contrib/ntp/include/ntp_md5.h
@@ -7,8 +7,13 @@
#define NTP_MD5_H
#ifdef OPENSSL
-# include "openssl/evp.h"
+# include <openssl/evp.h>
# include "libssl_compat.h"
+# ifdef HAVE_OPENSSL_CMAC_H
+# include <openssl/cmac.h>
+# define CMAC "AES128CMAC"
+# define AES_128_KEY_SIZE 16
+# endif /*HAVE_OPENSSL_CMAC_H*/
#else /* !OPENSSL follows */
/*
* Provide OpenSSL-alike MD5 API if we're not using OpenSSL
diff --git a/contrib/ntp/include/ntp_stdlib.h b/contrib/ntp/include/ntp_stdlib.h
index 889c3b2..c0bc71b 100644
--- a/contrib/ntp/include/ntp_stdlib.h
+++ b/contrib/ntp/include/ntp_stdlib.h
@@ -40,6 +40,9 @@ extern void setup_logfile (const char *);
extern void errno_to_str(int, char *, size_t);
#endif
+extern int xvsbprintf(char**, char* const, char const*, va_list) NTP_PRINTF(3, 0);
+extern int xsbprintf(char**, char* const, char const*, ...) NTP_PRINTF(3, 4);
+
/*
* When building without OpenSSL, use a few macros of theirs to
* minimize source differences in NTP.
diff --git a/contrib/ntp/include/ntpd.h b/contrib/ntp/include/ntpd.h
index 6a5128c..ead0c2c 100644
--- a/contrib/ntp/include/ntpd.h
+++ b/contrib/ntp/include/ntpd.h
@@ -275,8 +275,8 @@ extern u_long orphwait; /* orphan wait time */
extern char *sys_hostname; /* host name */
extern char *sys_groupname; /* group name */
extern char *group_name; /* group name */
-extern u_long sys_revoke; /* keys revoke timeout */
-extern u_long sys_automax; /* session key timeout */
+extern u_char sys_revoke; /* keys revoke timeout */
+extern u_char sys_automax; /* session key timeout */
#endif /* AUTOKEY */
/* ntp_util.c */
diff --git a/contrib/ntp/include/parse.h b/contrib/ntp/include/parse.h
index 02dbb30..e2caa52 100644
--- a/contrib/ntp/include/parse.h
+++ b/contrib/ntp/include/parse.h
@@ -108,7 +108,6 @@ extern unsigned int splclock (void);
* some constants useful for GPS time conversion
*/
#define GPSORIGIN 2524953600UL /* NTP origin - GPS origin in seconds */
-#define GPSWRAP 990 /* assume week count less than this in the previous epoch */
#define GPSWEEKS 1024 /* number of weeks until the GPS epch rolls over */
/*
diff --git a/contrib/ntp/kernel/Makefile.in b/contrib/ntp/kernel/Makefile.in
index 3d1fbe9..e88b256 100644
--- a/contrib/ntp/kernel/Makefile.in
+++ b/contrib/ntp/kernel/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/kernel/sys/Makefile.in b/contrib/ntp/kernel/sys/Makefile.in
index de18d15..684023c 100644
--- a/contrib/ntp/kernel/sys/Makefile.in
+++ b/contrib/ntp/kernel/sys/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/libntp/Makefile.am b/contrib/ntp/libntp/Makefile.am
index 6f3c0ba..04b53b0 100644
--- a/contrib/ntp/libntp/Makefile.am
+++ b/contrib/ntp/libntp/Makefile.am
@@ -110,6 +110,7 @@ libntp_a_SRCS = \
vint64ops.c \
work_fork.c \
work_thread.c \
+ xsbprintf.c \
ymd2yd.c \
$(libisc_SRCS) \
$(NULL)
diff --git a/contrib/ntp/libntp/Makefile.in b/contrib/ntp/libntp/Makefile.in
index 2bef787..fefd9d2 100644
--- a/contrib/ntp/libntp/Makefile.in
+++ b/contrib/ntp/libntp/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -160,7 +160,7 @@ am__libntp_a_SOURCES_DIST = systime.c a_md5encrypt.c adjtime.c \
snprintf.c socket.c socktoa.c socktohost.c ssl_init.c \
statestr.c strdup.c strl_obsd.c syssignal.c timetoa.c \
timevalops.c uglydate.c vint64ops.c work_fork.c work_thread.c \
- ymd2yd.c $(srcdir)/../lib/isc/assertions.c \
+ xsbprintf.c ymd2yd.c $(srcdir)/../lib/isc/assertions.c \
$(srcdir)/../lib/isc/buffer.c \
$(srcdir)/../lib/isc/backtrace-emptytbl.c \
$(srcdir)/../lib/isc/backtrace.c \
@@ -224,8 +224,8 @@ am__objects_4 = a_md5encrypt.$(OBJEXT) adjtime.$(OBJEXT) \
ssl_init.$(OBJEXT) statestr.$(OBJEXT) strdup.$(OBJEXT) \
strl_obsd.$(OBJEXT) syssignal.$(OBJEXT) timetoa.$(OBJEXT) \
timevalops.$(OBJEXT) uglydate.$(OBJEXT) vint64ops.$(OBJEXT) \
- work_fork.$(OBJEXT) work_thread.$(OBJEXT) ymd2yd.$(OBJEXT) \
- $(am__objects_3) $(am__objects_1)
+ work_fork.$(OBJEXT) work_thread.$(OBJEXT) xsbprintf.$(OBJEXT) \
+ ymd2yd.$(OBJEXT) $(am__objects_3) $(am__objects_1)
am_libntp_a_OBJECTS = systime.$(OBJEXT) $(am__objects_4)
libntp_a_OBJECTS = $(am_libntp_a_OBJECTS)
libntpsim_a_AR = $(AR) $(ARFLAGS)
@@ -244,7 +244,7 @@ am__libntpsim_a_SOURCES_DIST = systime_s.c a_md5encrypt.c adjtime.c \
snprintf.c socket.c socktoa.c socktohost.c ssl_init.c \
statestr.c strdup.c strl_obsd.c syssignal.c timetoa.c \
timevalops.c uglydate.c vint64ops.c work_fork.c work_thread.c \
- ymd2yd.c $(srcdir)/../lib/isc/assertions.c \
+ xsbprintf.c ymd2yd.c $(srcdir)/../lib/isc/assertions.c \
$(srcdir)/../lib/isc/buffer.c \
$(srcdir)/../lib/isc/backtrace-emptytbl.c \
$(srcdir)/../lib/isc/backtrace.c \
@@ -704,6 +704,7 @@ libntp_a_SRCS = \
vint64ops.c \
work_fork.c \
work_thread.c \
+ xsbprintf.c \
ymd2yd.c \
$(libisc_SRCS) \
$(NULL)
@@ -876,6 +877,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vint64ops.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/work_fork.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/work_thread.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xsbprintf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ymd2yd.Po@am__quote@
.c.o:
diff --git a/contrib/ntp/libntp/a_md5encrypt.c b/contrib/ntp/libntp/a_md5encrypt.c
index 7dc7e7e..8c046f4 100644
--- a/contrib/ntp/libntp/a_md5encrypt.c
+++ b/contrib/ntp/libntp/a_md5encrypt.c
@@ -12,12 +12,6 @@
#include "ntp_md5.h" /* provides OpenSSL digest API */
#include "isc/string.h"
-#ifdef OPENSSL
-# include "openssl/cmac.h"
-# define CMAC "AES128CMAC"
-# define AES_128_KEY_SIZE 16
-#endif
-
typedef struct {
const void * buf;
size_t len;
@@ -28,7 +22,7 @@ typedef struct {
size_t len;
} rwbuffT;
-#ifdef OPENSSL
+#if defined(OPENSSL) && defined(ENABLE_CMAC)
static size_t
cmac_ctx_size(
CMAC_CTX * ctx)
@@ -42,7 +36,7 @@ cmac_ctx_size(
}
return mlen;
}
-#endif /*OPENSSL*/
+#endif /*OPENSSL && ENABLE_CMAC*/
static size_t
make_mac(
@@ -63,6 +57,7 @@ make_mac(
INIT_SSL();
/* Check if CMAC key type specific code required */
+# ifdef ENABLE_CMAC
if (ktype == NID_cmac) {
CMAC_CTX * ctx = NULL;
void const * keyptr = key->buf;
@@ -100,7 +95,9 @@ make_mac(
if (ctx)
CMAC_CTX_cleanup(ctx);
}
- else { /* generic MAC handling */
+ else
+# endif /*ENABLE_CMAC*/
+ { /* generic MAC handling */
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
u_int uilen = 0;
@@ -153,7 +150,7 @@ make_mac(
if (ktype == NID_md5)
{
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- uint uilen = 0;
+ u_int uilen = 0;
if (digest->len < 16) {
msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
diff --git a/contrib/ntp/libntp/authreadkeys.c b/contrib/ntp/libntp/authreadkeys.c
index bd98ab2..48c5c4d 100644
--- a/contrib/ntp/libntp/authreadkeys.c
+++ b/contrib/ntp/libntp/authreadkeys.c
@@ -221,12 +221,14 @@ authreadkeys(
log_maybe(NULL,
"authreadkeys: invalid type for key %d",
keyno);
+# ifdef ENABLE_CMAC
} else if (NID_cmac != keytype &&
EVP_get_digestbynid(keytype) == NULL) {
log_maybe(NULL,
"authreadkeys: no algorithm for key %d",
keyno);
keytype = 0;
+# endif /* ENABLE_CMAC */
}
#else /* !OPENSSL follows */
/*
diff --git a/contrib/ntp/libntp/calyearstart.c b/contrib/ntp/libntp/calyearstart.c
index 9e3f58f..5616c81 100644
--- a/contrib/ntp/libntp/calyearstart.c
+++ b/contrib/ntp/libntp/calyearstart.c
@@ -54,7 +54,7 @@ calmonthstart(u_int32 ntptime, const time_t *pivot)
}
/*
- * calweekstart - get NTP time at midnight of the last monday on or
+ * calweekstart - get NTP time at midnight of the last Monday on or
* before the current date.
*/
u_int32
diff --git a/contrib/ntp/libntp/ntp_calendar.c b/contrib/ntp/libntp/ntp_calendar.c
index a550d5d..7974268 100644
--- a/contrib/ntp/libntp/ntp_calendar.c
+++ b/contrib/ntp/libntp/ntp_calendar.c
@@ -1832,6 +1832,7 @@ isocal_date_to_ntp(
*/
static int32_t s_baseday = NTP_TO_UNIX_DAYS;
+static int32_t s_gpsweek = 0;
int32_t
basedate_eval_buildstamp(void)
@@ -1873,7 +1874,7 @@ basedate_eval_string(
goto buildstamp;
}
- rc = scanf(str, "%lu%n", &ned, &nc);
+ rc = sscanf(str, "%lu%n", &ned, &nc);
if (rc == 1 && (size_t)nc == sl) {
if (ned <= INT32_MAX)
return (int32_t)ned;
@@ -1901,6 +1902,7 @@ basedate_set_day(
struct calendar jd;
int32_t retv;
+ /* set NTP base date for NTP era unfolding */
if (day < NTP_TO_UNIX_DAYS) {
msyslog(LOG_WARNING,
"baseday_set_day: invalid day (%lu), UNIX epoch substituted",
@@ -1912,6 +1914,17 @@ basedate_set_day(
ntpcal_rd_to_date(&jd, day + DAY_NTP_STARTS);
msyslog(LOG_INFO, "basedate set to %04hu-%02hu-%02hu",
jd.year, (u_short)jd.month, (u_short)jd.monthday);
+
+ /* set GPS base week for GPS week unfolding */
+ day = ntpcal_weekday_ge(day + DAY_NTP_STARTS, CAL_SUNDAY)
+ - DAY_NTP_STARTS;
+ if (day < NTP_TO_GPS_DAYS)
+ day = NTP_TO_GPS_DAYS;
+ s_gpsweek = (day - NTP_TO_GPS_DAYS) / DAYSPERWEEK;
+ ntpcal_rd_to_date(&jd, day + DAY_NTP_STARTS);
+ msyslog(LOG_INFO, "gps base set to %04hu-%02hu-%02hu (week %d)",
+ jd.year, (u_short)jd.month, (u_short)jd.monthday, s_gpsweek);
+
return retv;
}
@@ -1934,4 +1947,29 @@ basedate_get_erabase(void)
return retv;
}
+uint32_t
+basedate_get_gpsweek(void)
+{
+ return s_gpsweek;
+}
+
+uint32_t
+basedate_expand_gpsweek(
+ unsigned short weekno
+ )
+{
+ /* We do a fast modulus expansion here. Since all quantities are
+ * unsigned and we cannot go before the start of the GPS epoch
+ * anyway, and since the truncated GPS week number is 10 bit, the
+ * expansion becomes a simple sub/and/add sequence.
+ */
+ #if GPSWEEKS != 1024
+ # error GPSWEEKS defined wrong -- should be 1024!
+ #endif
+
+ uint32_t diff;
+ diff = ((uint32_t)weekno - s_gpsweek) & (GPSWEEKS - 1);
+ return s_gpsweek + diff;
+}
+
/* -*-EOF-*- */
diff --git a/contrib/ntp/libntp/prettydate.c b/contrib/ntp/libntp/prettydate.c
index 25b085e..deacc26 100644
--- a/contrib/ntp/libntp/prettydate.c
+++ b/contrib/ntp/libntp/prettydate.c
@@ -170,6 +170,11 @@ common_prettydate(
LIB_GETBUF(bp);
+ if (ts->l_ui == 0 && ts->l_uf == 0) {
+ strlcpy (bp, "(no time)", LIB_BUFLENGTH);
+ return (bp);
+ }
+
/* get & fix milliseconds */
ntps = ts->l_ui;
msec = ts->l_uf / 4294967; /* fract / (2 ** 32 / 1000) */
diff --git a/contrib/ntp/libntp/ssl_init.c b/contrib/ntp/libntp/ssl_init.c
index 96d9d08..9258932 100644
--- a/contrib/ntp/libntp/ssl_init.c
+++ b/contrib/ntp/libntp/ssl_init.c
@@ -13,16 +13,16 @@
#include <lib_strbuf.h>
#ifdef OPENSSL
-# include "openssl/cmac.h"
-# include "openssl/crypto.h"
-# include "openssl/err.h"
-# include "openssl/evp.h"
-# include "openssl/opensslv.h"
+# include <openssl/crypto.h>
+# include <openssl/err.h>
+# include <openssl/evp.h>
+# include <openssl/opensslv.h>
# include "libssl_compat.h"
-
-# define CMAC_LENGTH 16
-# define CMAC "AES128CMAC"
-
+# ifdef HAVE_OPENSSL_CMAC_H
+# include <openssl/cmac.h>
+# define CMAC_LENGTH 16
+# define CMAC "AES128CMAC"
+# endif /*HAVE_OPENSSL_CMAC_H*/
int ssl_init_done;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -126,6 +126,7 @@ keytype_from_text(
key_type = OBJ_sn2nid(upcased);
+# ifdef ENABLE_CMAC
if (!key_type && !strncmp(CMAC, upcased, strlen(CMAC) + 1)) {
key_type = NID_cmac;
@@ -134,6 +135,7 @@ keytype_from_text(
__FILE__, __LINE__, __func__, CMAC);
}
}
+# endif /*ENABLE_CMAC*/
#else
key_type = 0;
@@ -153,6 +155,7 @@ keytype_from_text(
digest_len = (md) ? EVP_MD_size(md) : 0;
if (!md || digest_len <= 0) {
+# ifdef ENABLE_CMAC
if (key_type == NID_cmac) {
digest_len = CMAC_LENGTH;
@@ -160,7 +163,9 @@ keytype_from_text(
fprintf(stderr, "%s:%d:%s():%s:len\n",
__FILE__, __LINE__, __func__, CMAC);
}
- } else {
+ } else
+# endif /*ENABLE_CMAC*/
+ {
fprintf(stderr,
"key type %s is not supported by OpenSSL\n",
keytype_name(key_type));
@@ -209,6 +214,7 @@ keytype_name(
INIT_SSL();
name = OBJ_nid2sn(nid);
+# ifdef ENABLE_CMAC
if (NID_cmac == nid) {
name = CMAC;
@@ -217,6 +223,7 @@ keytype_name(
__FILE__, __LINE__, __func__, CMAC);
}
} else
+# endif /*ENABLE_CMAC*/
if (NULL == name) {
name = unknown_type;
}
diff --git a/contrib/ntp/libntp/syssignal.c b/contrib/ntp/libntp/syssignal.c
index 5e496a9..cc87bff 100644
--- a/contrib/ntp/libntp/syssignal.c
+++ b/contrib/ntp/libntp/syssignal.c
@@ -138,12 +138,13 @@ set_ctrl_c_hook(
if (NULL == c_hook) {
handler = SIG_DFL;
- ctrl_c_hook = NULL;
+ signal_no_reset(SIGINT, handler);
+ ctrl_c_hook = c_hook;
} else {
- handler = &sigint_handler;
ctrl_c_hook = c_hook;
+ handler = &sigint_handler;
+ signal_no_reset(SIGINT, handler);
}
- signal_no_reset(SIGINT, handler);
}
#else /* SYS_WINNT follows */
/*
diff --git a/contrib/ntp/libntp/work_fork.c b/contrib/ntp/libntp/work_fork.c
index 2aa2d5c..1dd9e13 100644
--- a/contrib/ntp/libntp/work_fork.c
+++ b/contrib/ntp/libntp/work_fork.c
@@ -89,6 +89,10 @@ netwrite(
}
+#if defined(HAVE_DROPROOT)
+extern int set_user_group_ids(void);
+#endif
+
/* === functions === */
/*
* exit_worker()
@@ -592,6 +596,10 @@ fork_blocking_child(
init_logging("ntp_intres", 0, FALSE);
setup_logfile(NULL);
+#ifdef HAVE_DROPROOT
+ (void) set_user_group_ids();
+#endif
+
/*
* And now back to the portable code
*/
diff --git a/contrib/ntp/libntp/work_thread.c b/contrib/ntp/libntp/work_thread.c
index 433290c..03a5647 100644
--- a/contrib/ntp/libntp/work_thread.c
+++ b/contrib/ntp/libntp/work_thread.c
@@ -56,6 +56,17 @@
# define THREAD_MAXSTACKSIZE THREAD_MINSTACKSIZE
#endif
+/* need a good integer to store a pointer... */
+#ifndef UINTPTR_T
+# if defined(UINTPTR_MAX)
+# define UINTPTR_T uintptr_t
+# elif defined(UINT_PTR)
+# define UINTPTR_T UINT_PTR
+# else
+# define UINTPTR_T size_t
+# endif
+#endif
+
#ifdef SYS_WINNT
@@ -66,7 +77,7 @@ static BOOL same_os_sema(const sem_ref obj, void * osobj);
#else
-# define thread_exit(c) pthread_exit((void*)(size_t)(c))
+# define thread_exit(c) pthread_exit((void*)(UINTPTR_T)(c))
# define tickle_sem sem_post
void * blocking_thread(void *);
static void block_thread_signals(sigset_t *);
@@ -374,7 +385,9 @@ send_blocking_resp_internal(
if (empty)
{
# ifdef WORK_PIPE
- write(c->resp_write_pipe, "", 1);
+ if (1 != write(c->resp_write_pipe, "", 1))
+ msyslog(LOG_WARNING, "async resolver: %s",
+ "failed to notify main thread!");
# else
tickle_sem(c->responses_pending);
# endif
diff --git a/contrib/ntp/libntp/xsbprintf.c b/contrib/ntp/libntp/xsbprintf.c
new file mode 100644
index 0000000..4586758
--- /dev/null
+++ b/contrib/ntp/libntp/xsbprintf.c
@@ -0,0 +1,75 @@
+/*
+ * xsbprintf.c - string buffer formatting helpers
+ *
+ * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ */
+
+#include <config.h>
+#include <sys/types.h>
+
+#include "ntp_stdlib.h"
+
+/* eXtended Varlist String Buffer printf
+ *
+ * Formats via 'vsnprintf' into a string buffer, with some semantic
+ * specialties:
+ *
+ * - The start of the buffer pointer is updated according to the number
+ * of characters written.
+ * - If the buffer is insufficient to format the number of charactes,
+ * the partial result will be be discarded, and zero is returned to
+ * indicate nothing was written to the buffer.
+ * - On successful formatting, the return code is the return value of
+ * the inner call to 'vsnprintf()'.
+ * - If there is any error, the state of the buffer will not be
+ * changed. (Bytes in the buffer might be smashed, but the buffer
+ * position does not change, and the NUL marker stays in place at the
+ * current buffer position.)
+ * - If '(*ppbuf - pend) <= 0' (or ppbuf is NULL), fail with EINVAL.
+ */
+int
+xvsbprintf(
+ char **ppbuf, /* pointer to buffer pointer (I/O) */
+ char * const pend, /* buffer end (I) */
+ char const *pfmt, /* printf-like format string */
+ va_list va /* formatting args for above */
+ )
+{
+ char *pbuf = (ppbuf) ? *ppbuf : NULL;
+ int rc = -1;
+ if (pbuf && (pend - pbuf > 0)) {
+ size_t blen = (size_t)(pend - pbuf);
+ rc = vsnprintf(pbuf, blen, pfmt, va);
+ if (rc > 0) {
+ if ((size_t)rc >= blen)
+ rc = 0;
+ pbuf += rc;
+ }
+ *pbuf = '\0'; /* fear of bad vsnprintf */
+ *ppbuf = pbuf;
+ } else {
+ errno = EINVAL;
+ }
+ return rc;
+}
+
+/* variadic wrapper around the buffer string formatter */
+int
+xsbprintf(
+ char **ppbuf, /* pointer to buffer pointer (I/O) */
+ char * const pend, /* buffer end (I) */
+ char const *pfmt, /* printf-like format string */
+ ... /* formatting args for above */
+ )
+{
+ va_list va;
+ int rc;
+
+ va_start(va, pfmt);
+ rc = xvsbprintf(ppbuf, pend, pfmt, va);
+ va_end(va);
+ return rc;
+}
+
+/* that's all folks! */
diff --git a/contrib/ntp/libparse/Makefile.in b/contrib/ntp/libparse/Makefile.in
index 4ff96bb..b95eb1c 100644
--- a/contrib/ntp/libparse/Makefile.in
+++ b/contrib/ntp/libparse/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/libparse/clk_trimtsip.c b/contrib/ntp/libparse/clk_trimtsip.c
index 64359ef..8cf5660 100644
--- a/contrib/ntp/libparse/clk_trimtsip.c
+++ b/contrib/ntp/libparse/clk_trimtsip.c
@@ -265,9 +265,7 @@ cvt_trimtsip(
clock_time->flags = PARSEB_POWERUP;
return CVT_OK;
}
- if (week < GPSWRAP) {
- week += GPSWEEKS;
- }
+ week = basedate_expand_gpsweek(week);
/* time OK */
@@ -351,14 +349,12 @@ cvt_trimtsip(
int tls = t->t_gpsutc = (u_short) getshort((unsigned char *)&mb(12)); /* current leap correction (GPS-UTC) */
int tlsf = t->t_gpsutcleap = (u_short) getshort((unsigned char *)&mb(24)); /* new leap correction */
- t->t_weekleap = (u_short) getshort((unsigned char *)&mb(20)); /* week no of leap correction */
- if (t->t_weekleap < GPSWRAP)
- t->t_weekleap = (u_short)(t->t_weekleap + GPSWEEKS);
+ t->t_weekleap = basedate_expand_gpsweek(
+ (u_short) getshort((unsigned char *)&mb(20))); /* week no of leap correction */
t->t_dayleap = (u_short) getshort((unsigned char *)&mb(22)); /* day in week of leap correction */
- t->t_week = (u_short) getshort((unsigned char *)&mb(18)); /* current week no */
- if (t->t_week < GPSWRAP)
- t->t_week = (u_short)(t->t_weekleap + GPSWEEKS);
+ t->t_week = basedate_expand_gpsweek(
+ (u_short) getshort((unsigned char *)&mb(18))); /* current week no */
lbp = (unsigned char *)&mb(14); /* last update time */
if (fetch_ieee754(&lbp, IEEE_SINGLE, &t0t, trim_offsets) != IEEE_OK)
diff --git a/contrib/ntp/libparse/gpstolfp.c b/contrib/ntp/libparse/gpstolfp.c
index 8a36075..6a99e88 100644
--- a/contrib/ntp/libparse/gpstolfp.c
+++ b/contrib/ntp/libparse/gpstolfp.c
@@ -45,11 +45,6 @@ gpstolfp(
l_fp * lfp
)
{
- if (weeks < GPSWRAP)
- {
- weeks += GPSWEEKS;
- }
-
lfp->l_ui = (uint32_t)(weeks * SECSPERWEEK + days * SECSPERDAY + seconds + GPSORIGIN); /* convert to NTP time */
lfp->l_uf = 0;
}
diff --git a/contrib/ntp/ntpd/Makefile.in b/contrib/ntp/ntpd/Makefile.in
index fc9bc78..8eab4f9 100644
--- a/contrib/ntp/ntpd/Makefile.in
+++ b/contrib/ntp/ntpd/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/ntpd/complete.conf.in b/contrib/ntp/ntpd/complete.conf.in
index 2747098..66fcbaa 100644
--- a/contrib/ntp/ntpd/complete.conf.in
+++ b/contrib/ntp/ntpd/complete.conf.in
@@ -21,7 +21,7 @@ crypto digest md5 host myhostname ident wedent pw cryptopass randfile /.rnd
revoke 10
keysdir "/etc/ntp/keys"
keys "/etc/ntp.keys"
-trustedkey 1 2 3 4 5 6 7 8 9 10 11 12 (14 ... 16) 18 (32768 ... 65534)
+trustedkey 1 2 3 4 5 6 7 8 9 10 11 12 (14 ... 16) 18 (32768 ... 65535)
controlkey 12
requestkey 12
enable auth ntp monitor stats
diff --git a/contrib/ntp/ntpd/invoke-ntp.conf.texi b/contrib/ntp/ntpd/invoke-ntp.conf.texi
index 7e8a4dc..132709e 100644
--- a/contrib/ntp/ntpd/invoke-ntp.conf.texi
+++ b/contrib/ntp/ntpd/invoke-ntp.conf.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntp.conf.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 05:14:34 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:56:39 AM by AutoGen 5.18.5
# From the definitions ntp.conf.def
# and the template file agtexi-file.tpl
@end ignore
@@ -284,7 +284,7 @@ option.
All packets sent to and received from the server or peer are to
include authentication fields encrypted using the specified
@kbd{key}
-identifier with values from 1 to 65534, inclusive.
+identifier with values from 1 to 65535, inclusive.
The
default is to include no encryption field.
@item @code{minpoll} @kbd{minpoll}
@@ -543,7 +543,7 @@ and reports at the NTP project page linked from
@code{http://www.ntp.org/}.
@subsubsection Symmetric-Key Cryptography
The original RFC-1305 specification allows any one of possibly
-65,534 keys, each distinguished by a 32-bit key identifier, to
+65,535 keys, each distinguished by a 32-bit key identifier, to
authenticate an association.
The servers and clients involved must
agree on the key and key identifier to
@@ -827,7 +827,7 @@ The
@kbd{key}
argument is
the key identifier for a trusted key, where the value can be in the
-range 1 to 65,534, inclusive.
+range 1 to 65,535, inclusive.
@item @code{crypto} @code{[@code{cert} @kbd{file}]} @code{[@code{leap} @kbd{file}]} @code{[@code{randfile} @kbd{file}]} @code{[@code{host} @kbd{file}]} @code{[@code{sign} @kbd{file}]} @code{[@code{gq} @kbd{file}]} @code{[@code{gqpar} @kbd{file}]} @code{[@code{iffpar} @kbd{file}]} @code{[@code{mvpar} @kbd{file}]} @code{[@code{pw} @kbd{password}]}
This command requires the OpenSSL library.
It activates public key
@@ -920,7 +920,7 @@ The
@kbd{key}
argument is a key identifier
for the trusted key, where the value can be in the range 1 to
-65,534, inclusive.
+65,535, inclusive.
@item @code{revoke} @kbd{logsec}
Specifies the interval between re-randomization of certain
cryptographic values used by the Autokey scheme, as a power of 2 in
@@ -947,7 +947,7 @@ servers.
The
@kbd{key}
arguments are 32-bit unsigned
-integers with values from 1 to 65,534.
+integers with values from 1 to 65,535.
@end table
@subsubsection Error Codes
The following error codes are reported via the NTP control
diff --git a/contrib/ntp/ntpd/invoke-ntp.keys.texi b/contrib/ntp/ntpd/invoke-ntp.keys.texi
index d729fc0..9698c54 100644
--- a/contrib/ntp/ntpd/invoke-ntp.keys.texi
+++ b/contrib/ntp/ntpd/invoke-ntp.keys.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntp.keys.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 05:14:37 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:56:41 AM by AutoGen 5.18.5
# From the definitions ntp.keys.def
# and the template file agtexi-file.tpl
@end ignore
@@ -29,7 +29,7 @@ statement in the configuration file.
While key number 0 is fixed by the NTP standard
(as 56 zero bits)
and may not be changed,
-one or more keys numbered between 1 and 65534
+one or more keys numbered between 1 and 65535
may be arbitrarily set in the keys file.
The key file uses the same comment conventions
@@ -42,7 +42,7 @@ Key entries use a fixed format of the form
where
@kbd{keyno}
-is a positive integer (between 1 and 65534),
+is a positive integer (between 1 and 65535),
@kbd{type}
is the message digest algorithm,
@kbd{key}
diff --git a/contrib/ntp/ntpd/invoke-ntpd.texi b/contrib/ntp/ntpd/invoke-ntpd.texi
index 28f132d..16dce21 100644
--- a/contrib/ntp/ntpd/invoke-ntpd.texi
+++ b/contrib/ntp/ntpd/invoke-ntpd.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntpd.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 05:14:39 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:56:42 AM by AutoGen 5.18.5
# From the definitions ntpd-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -142,7 +142,7 @@ with a status code of 0.
@exampleindent 0
@example
-ntpd - NTP daemon program - Ver. 4.2.8p11
+ntpd - NTP daemon program - Ver. 4.2.8p13
Usage: ntpd [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... \
[ <server1> ... <serverN> ]
Flg Arg Option-Name Description
@@ -164,7 +164,7 @@ Usage: ntpd [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... \
-g no panicgate Allow the first adjustment to be Big
- may appear multiple times
-G no force-step-once Step any initial offset correction.
- -i Str jaildir Jail directory
+ -i --- jaildir built without --enable-clockctl or --enable-linuxcaps or --enable-solarisprivs
-I Str interface Listen on an interface name or address
- may appear multiple times
-k Str keyfile path to symmetric keys
@@ -187,7 +187,7 @@ Usage: ntpd [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... \
-s Str statsdir Statistics file location
-t Str trustedkey Trusted key number
- may appear multiple times
- -u Str user Run as userid (or userid:groupid)
+ -u --- user built without --enable-clockctl or --enable-linuxcaps or --enable-solarisprivs
-U Num updateinterval interval in seconds between scans for new or dropped interfaces
Str var make ARG an ntp variable (RW)
- may appear multiple times
diff --git a/contrib/ntp/ntpd/ntp.conf.5man b/contrib/ntp/ntpd/ntp.conf.5man
index 1a50633..50ae14f 100644
--- a/contrib/ntp/ntpd/ntp.conf.5man
+++ b/contrib/ntp/ntpd/ntp.conf.5man
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntp.conf 5man "27 Feb 2018" "4.2.8p11" "File Formats"
+.TH ntp.conf 5man "20 Feb 2019" "4.2.8p13" "File Formats"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-LkaqTP/ag-XkaiSP)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:22 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:43 AM by AutoGen 5.18.5
.\" From the definitions ntp.conf.def
.\" and the template file agman-cmd.tpl
.SH NAME
@@ -326,7 +326,7 @@ option.
All packets sent to and received from the server or peer are to
include authentication fields encrypted using the specified
\f\*[I-Font]key\f[]
-identifier with values from 1 to 65534, inclusive.
+identifier with values from 1 to 65535, inclusive.
The
default is to include no encryption field.
.TP 7
@@ -611,7 +611,7 @@ and reports at the NTP project page linked from
\f[C]http://www.ntp.org/\f[].
.SS Symmetric-Key Cryptography
The original RFC-1305 specification allows any one of possibly
-65,534 keys, each distinguished by a 32-bit key identifier, to
+65,535 keys, each distinguished by a 32-bit key identifier, to
authenticate an association.
The servers and clients involved must
agree on the key and key identifier to
@@ -932,7 +932,7 @@ The
\f\*[I-Font]key\f[]
argument is
the key identifier for a trusted key, where the value can be in the
-range 1 to 65,534, inclusive.
+range 1 to 65,535, inclusive.
.TP 7
.NOP \f\*[B-Font]crypto\f[] [\f\*[B-Font]cert\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]leap\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]randfile\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]host\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]sign\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]gq\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]gqpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]iffpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]mvpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]pw\f[] \f\*[I-Font]password\f[]]
This command requires the OpenSSL library.
@@ -1038,7 +1038,7 @@ The
\f\*[I-Font]key\f[]
argument is a key identifier
for the trusted key, where the value can be in the range 1 to
-65,534, inclusive.
+65,535, inclusive.
.TP 7
.NOP \f\*[B-Font]revoke\f[] \f\*[I-Font]logsec\f[]
Specifies the interval between re-randomization of certain
@@ -1067,7 +1067,7 @@ servers.
The
\f\*[I-Font]key\f[]
arguments are 32-bit unsigned
-integers with values from 1 to 65,534.
+integers with values from 1 to 65,535.
.PP
.SS Error Codes
The following error codes are reported via the NTP control
diff --git a/contrib/ntp/ntpd/ntp.conf.5mdoc b/contrib/ntp/ntpd/ntp.conf.5mdoc
index 7286c81..7d13328 100644
--- a/contrib/ntp/ntpd/ntp.conf.5mdoc
+++ b/contrib/ntp/ntpd/ntp.conf.5mdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTP_CONF 5mdoc File Formats
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:42 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:34 AM by AutoGen 5.18.5
.\" From the definitions ntp.conf.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -325,7 +325,7 @@ option.
All packets sent to and received from the server or peer are to
include authentication fields encrypted using the specified
.Ar key
-identifier with values from 1 to 65534, inclusive.
+identifier with values from 1 to 65535, inclusive.
The
default is to include no encryption field.
.It Cm minpoll Ar minpoll
@@ -583,7 +583,7 @@ and reports at the NTP project page linked from
.Li http://www.ntp.org/ .
.Ss Symmetric\-Key Cryptography
The original RFC\-1305 specification allows any one of possibly
-65,534 keys, each distinguished by a 32\-bit key identifier, to
+65,535 keys, each distinguished by a 32\-bit key identifier, to
authenticate an association.
The servers and clients involved must
agree on the key and key identifier to
@@ -877,7 +877,7 @@ The
.Ar key
argument is
the key identifier for a trusted key, where the value can be in the
-range 1 to 65,534, inclusive.
+range 1 to 65,535, inclusive.
.It Xo Ic crypto
.Op Cm cert Ar file
.Op Cm leap Ar file
@@ -981,7 +981,7 @@ The
.Ar key
argument is a key identifier
for the trusted key, where the value can be in the range 1 to
-65,534, inclusive.
+65,535, inclusive.
.It Ic revoke Ar logsec
Specifies the interval between re\-randomization of certain
cryptographic values used by the Autokey scheme, as a power of 2 in
@@ -1008,7 +1008,7 @@ servers.
The
.Ar key
arguments are 32\-bit unsigned
-integers with values from 1 to 65,534.
+integers with values from 1 to 65,535.
.El
.Ss Error Codes
The following error codes are reported via the NTP control
diff --git a/contrib/ntp/ntpd/ntp.conf.def b/contrib/ntp/ntpd/ntp.conf.def
index 4af7742..9684fb1 100644
--- a/contrib/ntp/ntpd/ntp.conf.def
+++ b/contrib/ntp/ntpd/ntp.conf.def
@@ -327,7 +327,7 @@ option.
All packets sent to and received from the server or peer are to
include authentication fields encrypted using the specified
.Ar key
-identifier with values from 1 to 65534, inclusive.
+identifier with values from 1 to 65535, inclusive.
The
default is to include no encryption field.
.It Cm minpoll Ar minpoll
@@ -585,7 +585,7 @@ and reports at the NTP project page linked from
.Li http://www.ntp.org/ .
.Ss Symmetric-Key Cryptography
The original RFC-1305 specification allows any one of possibly
-65,534 keys, each distinguished by a 32-bit key identifier, to
+65,535 keys, each distinguished by a 32-bit key identifier, to
authenticate an association.
The servers and clients involved must
agree on the key and key identifier to
@@ -879,7 +879,7 @@ The
.Ar key
argument is
the key identifier for a trusted key, where the value can be in the
-range 1 to 65,534, inclusive.
+range 1 to 65,535, inclusive.
.It Xo Ic crypto
.Op Cm cert Ar file
.Op Cm leap Ar file
@@ -983,7 +983,7 @@ The
.Ar key
argument is a key identifier
for the trusted key, where the value can be in the range 1 to
-65,534, inclusive.
+65,535, inclusive.
.It Ic revoke Ar logsec
Specifies the interval between re-randomization of certain
cryptographic values used by the Autokey scheme, as a power of 2 in
@@ -1010,7 +1010,7 @@ servers.
The
.Ar key
arguments are 32-bit unsigned
-integers with values from 1 to 65,534.
+integers with values from 1 to 65,535.
.El
.Ss Error Codes
The following error codes are reported via the NTP control
diff --git a/contrib/ntp/ntpd/ntp.conf.html b/contrib/ntp/ntpd/ntp.conf.html
index 2d477e2..e19e326 100644
--- a/contrib/ntp/ntpd/ntp.conf.html
+++ b/contrib/ntp/ntpd/ntp.conf.html
@@ -1,128 +1,168 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>NTP Configuration File User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="NTP Configuration File User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>NTP Configuration File User&rsquo;s Manual</title>
+
+<meta name="description" content="NTP Configuration File User&rsquo;s Manual">
+<meta name="keywords" content="NTP Configuration File User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">NTP Configuration File User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002econf-Description">ntp.conf Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">NTP's Configuration File User Manual</h2>
+<body lang="en">
+<h1 class="settitle" align="center">NTP Configuration File User&rsquo;s Manual</h1>
-<p>This document describes the configuration file for the NTP Project's
-<code>ntpd</code> program.
- <p>This document applies to version 4.2.8p11 of <code>ntp.conf</code>.
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">NTP's Configuration File User Manual</a>
-</ul>
+
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002econf-Description" accesskey="n" rel="next">ntp.conf Description</a>, Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
</div>
+<a name="NTP_0027s-Configuration-File-User-Manual"></a>
+<h1 class="top">NTP&rsquo;s Configuration File User Manual</h1>
-<ul class="menu">
-<li><a accesskey="1" href="#ntp_002econf-Description">ntp.conf Description</a>
-<li><a accesskey="2" href="#ntp_002econf-Notes">ntp.conf Notes</a>
+<p>This document describes the configuration file for the NTP Project&rsquo;s
+<code>ntpd</code> program.
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntp.conf</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
+
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Description" href="#toc-Description">1 Description</a></li>
</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntp_002econf-Description"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
</div>
-<!-- node-name, next, previous, up -->
-<h3 class="section">Description</h3>
+
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-Description" accesskey="1">ntp.conf Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-Notes" accesskey="2">ntp.conf Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="ntp_002econf-Description"></a>
+<div class="header">
+<p>
+Previous: <a href="#Top" accesskey="p" rel="prev">Top</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
+</div>
+<a name="Description"></a>
+<h2 class="chapter">1 Description</h2>
<p>The behavior of <code>ntpd</code> can be changed by a configuration file,
by default <code>ntp.conf</code>.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-Notes" accesskey="1">ntp.conf Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
-<div class="node">
-<p><hr>
+<hr>
<a name="ntp_002econf-Notes"></a>
-<br>
+<div class="header">
+<p>
+Previous: <a href="#ntp_002econf-Bugs" accesskey="p" rel="prev">ntp.conf Bugs</a>, Up: <a href="#ntp_002econf-Description" accesskey="u" rel="up">ntp.conf Description</a> &nbsp; </p>
</div>
+<a name="Notes-about-ntp_002econf"></a>
+<h3 class="section">1.1 Notes about ntp.conf</h3>
+<a name="index-ntp_002econf"></a>
+<a name="index-Network-Time-Protocol-_0028NTP_0029-daemon-configuration-file-format"></a>
-<h3 class="section">Notes about ntp.conf</h3>
-<p><a name="index-ntp_002econf-1"></a><a name="index-Network-Time-Protocol-_0028NTP_0029-daemon-configuration-file-format-2"></a>
- <p>The
+<p>The
<code>ntp.conf</code>
configuration file is read at initial startup by the
<code>ntpd(1ntpdmdoc)</code>
daemon in order to specify the synchronization sources,
-modes and other related information.
+modes and other related information.
Usually, it is installed in the
-<span class="file">/etc</span>
+<samp>/etc</samp>
directory,
but could be installed elsewhere
-(see the daemon's
+(see the daemon&rsquo;s
<code>-c</code>
command line option).
-
- <p>The file format is similar to other
-<span class="sc">unix</span>
-configuration files.
+</p>
+<p>The file format is similar to other
+<small>UNIX</small>
+configuration files.
Comments begin with a
-#
+&lsquo;#&rsquo;
character and extend to the end of the line;
-blank lines are ignored.
+blank lines are ignored.
Configuration commands consist of an initial keyword
followed by a list of arguments,
-some of which may be optional, separated by whitespace.
-Commands may not be continued over multiple lines.
+some of which may be optional, separated by whitespace.
+Commands may not be continued over multiple lines.
Arguments may be host names,
host addresses written in numeric, dotted-quad form,
integers, floating point numbers (when specifying times in seconds)
and text strings.
-
- <p>The rest of this page describes the configuration and control options.
+</p>
+<p>The rest of this page describes the configuration and control options.
The
-"Notes on Configuring NTP and Setting up an NTP Subnet"
+&quot;Notes on Configuring NTP and Setting up an NTP Subnet&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>)
-contains an extended discussion of these options.
+<samp>/usr/share/doc/ntp</samp>)
+contains an extended discussion of these options.
In addition to the discussion of general
-<a href="#Configuration-Options">Configuration Options</a>,
+&lsquo;Configuration Options&rsquo;,
there are sections describing the following supported functionality
and the options used to control it:
- <ul>
-<li><a href="#Authentication-Support">Authentication Support</a>
-<li><a href="#Monitoring-Support">Monitoring Support</a>
-<li><a href="#Access-Control-Support">Access Control Support</a>
-<li><a href="#Automatic-NTP-Configuration-Options">Automatic NTP Configuration Options</a>
-<li><a href="#Reference-Clock-Support">Reference Clock Support</a>
-<li><a href="#Miscellaneous-Options">Miscellaneous Options</a>
-</ul>
-
- <p>Following these is a section describing
-<a href="#Miscellaneous-Options">Miscellaneous Options</a>.
+</p><ul>
+<li> <a href="#Authentication-Support">Authentication Support</a>
+</li><li> <a href="#Monitoring-Support">Monitoring Support</a>
+</li><li> <a href="#Access-Control-Support">Access Control Support</a>
+</li><li> <a href="#Automatic-NTP-Configuration-Options">Automatic NTP Configuration Options</a>
+</li><li> <a href="#Reference-Clock-Support">Reference Clock Support</a>
+</li><li> <a href="#Miscellaneous-Options">Miscellaneous Options</a>
+</li></ul>
+
+<p>Following these is a section describing
+<a href="#Miscellaneous-Options">Miscellaneous Options</a>.
While there is a rich set of options available,
the only required option is one or more
<code>pool</code>,
@@ -131,42 +171,66 @@ the only required option is one or more
<code>broadcast</code>
or
<code>manycastclient</code>
-commands.
-<div class="node">
-<p><hr>
+commands.
+</p><table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#Configuration-Support" accesskey="1">Configuration Support</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Authentication-Support" accesskey="2">Authentication Support</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Monitoring-Support" accesskey="3">Monitoring Support</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Access-Control-Support" accesskey="4">Access Control Support</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Automatic-NTP-Configuration-Options" accesskey="5">Automatic NTP Configuration Options</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Reference-Clock-Support" accesskey="6">Reference Clock Support</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Miscellaneous-Options" accesskey="7">Miscellaneous Options</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-Files" accesskey="8">ntp.conf Files</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-See-Also" accesskey="9">ntp.conf See Also</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-Bugs">ntp.conf Bugs</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; :</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
<a name="Configuration-Support"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Authentication-Support" accesskey="n" rel="next">Authentication Support</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">Configuration Support</h4>
-
+<a name="Configuration-Support-1"></a>
+<h4 class="subsection">1.1.1 Configuration Support</h4>
<p>Following is a description of the configuration commands in
-NTPv4.
+NTPv4.
These commands have the same basic functions as in NTPv3 and
-in some cases new functions and new arguments.
+in some cases new functions and new arguments.
There are two
classes of commands, configuration commands that configure a
persistent association with a remote server or peer or reference
clock, and auxiliary commands that specify environmental variables
that control various related operations.
-
-<h5 class="subsubsection">Configuration Commands</h5>
-
+</p><a name="Configuration-Commands"></a>
+<h4 class="subsubsection">1.1.1.1 Configuration Commands</h4>
<p>The various modes are determined by the command keyword and the
-type of the required IP address.
+type of the required IP address.
Addresses are classed by type as
(s) a remote server or peer (IPv4 class A, B and C), (b) the
broadcast address of a local interface, (m) a multicast address (IPv4
-class D), or (r) a reference clock address (127.127.x.x).
+class D), or (r) a reference clock address (127.127.x.x).
Note that
-only those options applicable to each command are listed below.
+only those options applicable to each command are listed below.
Use
of options not listed may not be caught as an error, but may result
in some weird and even destructive behavior.
-
- <p>If the Basic Socket Interface Extensions for IPv6 (RFC-2553)
+</p>
+<p>If the Basic Socket Interface Extensions for IPv6 (RFC-2553)
is detected, support for the IPv6 address family is generated
-in addition to the default support of the IPv4 address family.
+in addition to the default support of the IPv4 address family.
In a few cases, including the
<code>reslist</code>
billboard generated
@@ -174,84 +238,96 @@ by
<code>ntpq(1ntpqmdoc)</code>
or
<code>ntpdc(1ntpdcmdoc)</code>,
-IPv6 addresses are automatically generated.
+IPv6 addresses are automatically generated.
IPv6 addresses can be identified by the presence of colons
-:
-in the address field.
+&ldquo;:&rdquo;
+in the address field.
IPv6 addresses can be used almost everywhere where
IPv4 addresses can be used,
with the exception of reference clock addresses,
which are always IPv4.
-
- <p>Note that in contexts where a host name is expected, a
+</p>
+<p>Note that in contexts where a host name is expected, a
<code>-4</code>
qualifier preceding
the host name forces DNS resolution to the IPv4 namespace,
while a
<code>-6</code>
-qualifier forces DNS resolution to the IPv6 namespace.
+qualifier forces DNS resolution to the IPv6 namespace.
See IPv6 references for the
equivalent classes for that address family.
- <dl>
-<dt><code>pool</code> <kbd>address</kbd> <code>[burst]</code> <code>[iburst]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[maxpoll </code><kbd>maxpoll</kbd><code>]</code><br><dt><code>server</code> <kbd>address</kbd> <code>[key </code><kbd>key</kbd> <kbd>|</kbd><code> autokey]</code> <code>[burst]</code> <code>[iburst]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[maxpoll </code><kbd>maxpoll</kbd><code>]</code> <code>[true]</code><br><dt><code>peer</code> <kbd>address</kbd> <code>[key </code><kbd>key</kbd> <kbd>|</kbd><code> autokey]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[maxpoll </code><kbd>maxpoll</kbd><code>]</code> <code>[true]</code> <code>[xleave]</code><br><dt><code>broadcast</code> <kbd>address</kbd> <code>[key </code><kbd>key</kbd> <kbd>|</kbd><code> autokey]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[ttl </code><kbd>ttl</kbd><code>]</code> <code>[xleave]</code><br><dt><code>manycastclient</code> <kbd>address</kbd> <code>[key </code><kbd>key</kbd> <kbd>|</kbd><code> autokey]</code> <code>[version </code><kbd>version</kbd><code>]</code> <code>[prefer]</code> <code>[minpoll </code><kbd>minpoll</kbd><code>]</code> <code>[maxpoll </code><kbd>maxpoll</kbd><code>]</code> <code>[ttl </code><kbd>ttl</kbd><code>]</code><dd></dl>
+</p><dl compact="compact">
+<dt><code>pool</code> <kbd>address</kbd> <code>[<code>burst</code>]</code> <code>[<code>iburst</code>]</code> <code>[<code>version</code> <kbd>version</kbd>]</code> <code>[<code>prefer</code>]</code> <code>[<code>minpoll</code> <kbd>minpoll</kbd>]</code> <code>[<code>maxpoll</code> <kbd>maxpoll</kbd>]</code></dt>
+<dt><code>server</code> <kbd>address</kbd> <code>[<code>key</code> <kbd>key</kbd> <kbd>|</kbd> <code>autokey</code>]</code> <code>[<code>burst</code>]</code> <code>[<code>iburst</code>]</code> <code>[<code>version</code> <kbd>version</kbd>]</code> <code>[<code>prefer</code>]</code> <code>[<code>minpoll</code> <kbd>minpoll</kbd>]</code> <code>[<code>maxpoll</code> <kbd>maxpoll</kbd>]</code> <code>[<code>true</code>]</code></dt>
+<dt><code>peer</code> <kbd>address</kbd> <code>[<code>key</code> <kbd>key</kbd> <kbd>|</kbd> <code>autokey</code>]</code> <code>[<code>version</code> <kbd>version</kbd>]</code> <code>[<code>prefer</code>]</code> <code>[<code>minpoll</code> <kbd>minpoll</kbd>]</code> <code>[<code>maxpoll</code> <kbd>maxpoll</kbd>]</code> <code>[<code>true</code>]</code> <code>[<code>xleave</code>]</code></dt>
+<dt><code>broadcast</code> <kbd>address</kbd> <code>[<code>key</code> <kbd>key</kbd> <kbd>|</kbd> <code>autokey</code>]</code> <code>[<code>version</code> <kbd>version</kbd>]</code> <code>[<code>prefer</code>]</code> <code>[<code>minpoll</code> <kbd>minpoll</kbd>]</code> <code>[<code>ttl</code> <kbd>ttl</kbd>]</code> <code>[<code>xleave</code>]</code></dt>
+<dt><code>manycastclient</code> <kbd>address</kbd> <code>[<code>key</code> <kbd>key</kbd> <kbd>|</kbd> <code>autokey</code>]</code> <code>[<code>version</code> <kbd>version</kbd>]</code> <code>[<code>prefer</code>]</code> <code>[<code>minpoll</code> <kbd>minpoll</kbd>]</code> <code>[<code>maxpoll</code> <kbd>maxpoll</kbd>]</code> <code>[<code>ttl</code> <kbd>ttl</kbd>]</code></dt>
+</dl>
- <p>These five commands specify the time server name or address to
-be used and the mode in which to operate.
+<p>These five commands specify the time server name or address to
+be used and the mode in which to operate.
The
<kbd>address</kbd>
can be
-either a DNS name or an IP address in dotted-quad notation.
+either a DNS name or an IP address in dotted-quad notation.
Additional information on association behavior can be found in the
-"Association Management"
+&quot;Association Management&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>).
- <dl>
-<dt><code>pool</code><dd>For type s addresses, this command mobilizes a persistent
-client mode association with a number of remote servers.
+<samp>/usr/share/doc/ntp</samp>).
+</p><dl compact="compact">
+<dt><code>pool</code></dt>
+<dd><p>For type s addresses, this command mobilizes a persistent
+client mode association with a number of remote servers.
In this mode the local clock can synchronized to the
remote server, but the remote server can never be synchronized to
-the local clock.
-<br><dt><code>server</code><dd>For type s and r addresses, this command mobilizes a persistent
+the local clock.
+</p></dd>
+<dt><code>server</code></dt>
+<dd><p>For type s and r addresses, this command mobilizes a persistent
client mode association with the specified remote server or local
-radio clock.
+radio clock.
In this mode the local clock can synchronized to the
remote server, but the remote server can never be synchronized to
-the local clock.
+the local clock.
This command should
<em>not</em>
be used for type
-b or m addresses.
-<br><dt><code>peer</code><dd>For type s addresses (only), this command mobilizes a
+b or m addresses.
+</p></dd>
+<dt><code>peer</code></dt>
+<dd><p>For type s addresses (only), this command mobilizes a
persistent symmetric-active mode association with the specified
-remote peer.
+remote peer.
In this mode the local clock can be synchronized to
the remote peer or the remote peer can be synchronized to the local
-clock.
+clock.
This is useful in a network of servers where, depending on
various failure scenarios, either the local or remote peer may be
-the better source of time.
+the better source of time.
This command should NOT be used for type
-b, m or r addresses.
-<br><dt><code>broadcast</code><dd>For type b and m addresses (only), this
-command mobilizes a persistent broadcast mode association.
+b, m or r addresses.
+</p></dd>
+<dt><code>broadcast</code></dt>
+<dd><p>For type b and m addresses (only), this
+command mobilizes a persistent broadcast mode association.
Multiple
commands can be used to specify multiple local broadcast interfaces
-(subnets) and/or multiple multicast groups.
+(subnets) and/or multiple multicast groups.
Note that local
broadcast messages go only to the interface associated with the
-subnet specified, but multicast messages go to all interfaces.
+subnet specified, but multicast messages go to all interfaces.
In broadcast mode the local server sends periodic broadcast
messages to a client population at the
<kbd>address</kbd>
specified, which is usually the broadcast address on (one of) the
-local network(s) or a multicast address assigned to NTP.
+local network(s) or a multicast address assigned to NTP.
The IANA
has assigned the multicast group address IPv4 224.0.1.1 and
IPv6 ff05::101 (site local) exclusively to
NTP, but other nonconflicting addresses can be used to contain the
-messages within administrative boundaries.
+messages within administrative boundaries.
Ordinarily, this
specification applies only to the local server operating as a
sender; for operation as a broadcast client, see the
@@ -259,65 +335,73 @@ sender; for operation as a broadcast client, see the
or
<code>multicastclient</code>
commands
-below.
-<br><dt><code>manycastclient</code><dd>For type m addresses (only), this command mobilizes a
+below.
+</p></dd>
+<dt><code>manycastclient</code></dt>
+<dd><p>For type m addresses (only), this command mobilizes a
manycast client mode association for the multicast address
-specified.
+specified.
In this case a specific address must be supplied which
matches the address used on the
<code>manycastserver</code>
command for
-the designated manycast servers.
+the designated manycast servers.
The NTP multicast address
224.0.1.1 assigned by the IANA should NOT be used, unless specific
means are taken to avoid spraying large areas of the Internet with
these messages and causing a possibly massive implosion of replies
-at the sender.
+at the sender.
The
<code>manycastserver</code>
command specifies that the local server
is to operate in client mode with the remote servers that are
-discovered as the result of broadcast/multicast messages.
+discovered as the result of broadcast/multicast messages.
The
client broadcasts a request message to the group address associated
with the specified
<kbd>address</kbd>
and specifically enabled
-servers respond to these messages.
+servers respond to these messages.
The client selects the servers
providing the best time and continues as with the
<code>server</code>
-command.
+command.
The remaining servers are discarded as if never
-heard.
+heard.
+</p></dd>
</dl>
- <p>Options:
- <dl>
-<dt><code>autokey</code><dd>All packets sent to and received from the server or peer are to
+<p>Options:
+</p><dl compact="compact">
+<dt><code>autokey</code></dt>
+<dd><p>All packets sent to and received from the server or peer are to
include authentication fields encrypted using the autokey scheme
described in
-<a href="#Authentication-Options">Authentication Options</a>.
-<br><dt><code>burst</code><dd>when the server is reachable, send a burst of eight packets
-instead of the usual one.
+&lsquo;Authentication Options&rsquo;.
+</p></dd>
+<dt><code>burst</code></dt>
+<dd><p>when the server is reachable, send a burst of eight packets
+instead of the usual one.
The packet spacing is normally 2 s;
however, the spacing between the first and second packets
can be changed with the
<code>calldelay</code>
command to allow
-additional time for a modem or ISDN call to complete.
+additional time for a modem or ISDN call to complete.
This is designed to improve timekeeping quality
with the
<code>server</code>
-command and s addresses.
-<br><dt><code>iburst</code><dd>When the server is unreachable, send a burst of eight packets
-instead of the usual one.
+command and s addresses.
+</p></dd>
+<dt><code>iburst</code></dt>
+<dd><p>When the server is unreachable, send a burst of eight packets
+instead of the usual one.
The packet spacing is normally 2 s;
however, the spacing between the first two packets can be
changed with the
<code>calldelay</code>
command to allow
-additional time for a modem or ISDN call to complete.
+additional time for a modem or ISDN call to complete.
This is designed to speed the initial synchronization
acquisition with the
<code>server</code>
@@ -325,167 +409,196 @@ command and s addresses and when
<code>ntpd(1ntpdmdoc)</code>
is started with the
<code>-q</code>
-option.
-<br><dt><code>key</code> <kbd>key</kbd><dd>All packets sent to and received from the server or peer are to
+option.
+</p></dd>
+<dt><code>key</code> <kbd>key</kbd></dt>
+<dd><p>All packets sent to and received from the server or peer are to
include authentication fields encrypted using the specified
<kbd>key</kbd>
-identifier with values from 1 to 65534, inclusive.
+identifier with values from 1 to 65535, inclusive.
The
-default is to include no encryption field.
-<br><dt><code>minpoll</code> <kbd>minpoll</kbd><br><dt><code>maxpoll</code> <kbd>maxpoll</kbd><dd>These options specify the minimum and maximum poll intervals
+default is to include no encryption field.
+</p></dd>
+<dt><code>minpoll</code> <kbd>minpoll</kbd></dt>
+<dt><code>maxpoll</code> <kbd>maxpoll</kbd></dt>
+<dd><p>These options specify the minimum and maximum poll intervals
for NTP messages, as a power of 2 in seconds
The maximum poll
interval defaults to 10 (1,024 s), but can be increased by the
<code>maxpoll</code>
-option to an upper limit of 17 (36.4 h).
+option to an upper limit of 17 (36.4 h).
The
minimum poll interval defaults to 6 (64 s), but can be decreased by
the
<code>minpoll</code>
-option to a lower limit of 4 (16 s).
-<br><dt><code>noselect</code><dd>Marks the server as unused, except for display purposes.
-The server is discarded by the selection algroithm.
-<br><dt><code>preempt</code><dd>Says the association can be preempted.
-<br><dt><code>true</code><dd>Marks the server as a truechimer.
-Use this option only for testing.
-<br><dt><code>prefer</code><dd>Marks the server as preferred.
+option to a lower limit of 4 (16 s).
+</p></dd>
+<dt><code>noselect</code></dt>
+<dd><p>Marks the server as unused, except for display purposes.
+The server is discarded by the selection algroithm.
+</p></dd>
+<dt><code>preempt</code></dt>
+<dd><p>Says the association can be preempted.
+</p></dd>
+<dt><code>true</code></dt>
+<dd><p>Marks the server as a truechimer.
+Use this option only for testing.
+</p></dd>
+<dt><code>prefer</code></dt>
+<dd><p>Marks the server as preferred.
All other things being equal,
this host will be chosen for synchronization among a set of
-correctly operating hosts.
+correctly operating hosts.
See the
-"Mitigation Rules and the prefer Keyword"
+&quot;Mitigation Rules and the prefer Keyword&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>)
-for further information.
-<br><dt><code>true</code><dd>Forces the association to always survive the selection and clustering algorithms.
+<samp>/usr/share/doc/ntp</samp>)
+for further information.
+</p></dd>
+<dt><code>true</code></dt>
+<dd><p>Forces the association to always survive the selection and clustering algorithms.
This option should almost certainly
<em>only</em>
-be used while testing an association.
-<br><dt><code>ttl</code> <kbd>ttl</kbd><dd>This option is used only with broadcast server and manycast
-client modes.
+be used while testing an association.
+</p></dd>
+<dt><code>ttl</code> <kbd>ttl</kbd></dt>
+<dd><p>This option is used only with broadcast server and manycast
+client modes.
It specifies the time-to-live
<kbd>ttl</kbd>
to
use on broadcast server and multicast server and the maximum
<kbd>ttl</kbd>
for the expanding ring search with manycast
-client packets.
+client packets.
Selection of the proper value, which defaults to
127, is something of a black art and should be coordinated with the
-network administrator.
-<br><dt><code>version</code> <kbd>version</kbd><dd>Specifies the version number to be used for outgoing NTP
-packets.
+network administrator.
+</p></dd>
+<dt><code>version</code> <kbd>version</kbd></dt>
+<dd><p>Specifies the version number to be used for outgoing NTP
+packets.
Versions 1-4 are the choices, with version 4 the
-default.
-<br><dt><code>xleave</code><dd>Valid in
+default.
+</p></dd>
+<dt><code>xleave</code></dt>
+<dd><p>Valid in
<code>peer</code>
and
<code>broadcast</code>
-modes only, this flag enables interleave mode.
+modes only, this flag enables interleave mode.
+</p></dd>
</dl>
-
-<h5 class="subsubsection">Auxiliary Commands</h5>
-
- <dl>
-<dt><code>broadcastclient</code><dd>This command enables reception of broadcast server messages to
-any local interface (type b) address.
+<a name="Auxiliary-Commands"></a>
+<h4 class="subsubsection">1.1.1.2 Auxiliary Commands</h4>
+<dl compact="compact">
+<dt><code>broadcastclient</code></dt>
+<dd><p>This command enables reception of broadcast server messages to
+any local interface (type b) address.
Upon receiving a message for
the first time, the broadcast client measures the nominal server
propagation delay using a brief client/server exchange with the
server, then enters the broadcast client mode, in which it
-synchronizes to succeeding broadcast messages.
+synchronizes to succeeding broadcast messages.
Note that, in order
to avoid accidental or malicious disruption in this mode, both the
server and client should operate using symmetric-key or public-key
authentication as described in
-<a href="#Authentication-Options">Authentication Options</a>.
-<br><dt><code>manycastserver</code> <kbd>address</kbd> <kbd>...</kbd><dd>This command enables reception of manycast client messages to
-the multicast group address(es) (type m) specified.
+&lsquo;Authentication Options&rsquo;.
+</p></dd>
+<dt><code>manycastserver</code> <kbd>address</kbd> <kbd>...</kbd></dt>
+<dd><p>This command enables reception of manycast client messages to
+the multicast group address(es) (type m) specified.
At least one
address is required, but the NTP multicast address 224.0.1.1
assigned by the IANA should NOT be used, unless specific means are
taken to limit the span of the reply and avoid a possibly massive
-implosion at the original sender.
+implosion at the original sender.
Note that, in order to avoid
accidental or malicious disruption in this mode, both the server
and client should operate using symmetric-key or public-key
authentication as described in
-<a href="#Authentication-Options">Authentication Options</a>.
-<br><dt><code>multicastclient</code> <kbd>address</kbd> <kbd>...</kbd><dd>This command enables reception of multicast server messages to
-the multicast group address(es) (type m) specified.
+&lsquo;Authentication Options&rsquo;.
+</p></dd>
+<dt><code>multicastclient</code> <kbd>address</kbd> <kbd>...</kbd></dt>
+<dd><p>This command enables reception of multicast server messages to
+the multicast group address(es) (type m) specified.
Upon receiving
a message for the first time, the multicast client measures the
nominal server propagation delay using a brief client/server
exchange with the server, then enters the broadcast client mode, in
-which it synchronizes to succeeding multicast messages.
+which it synchronizes to succeeding multicast messages.
Note that,
in order to avoid accidental or malicious disruption in this mode,
both the server and client should operate using symmetric-key or
public-key authentication as described in
-<a href="#Authentication-Options">Authentication Options</a>.
-<br><dt><code>mdnstries</code> <kbd>number</kbd><dd>If we are participating in mDNS,
+&lsquo;Authentication Options&rsquo;.
+</p></dd>
+<dt><code>mdnstries</code> <kbd>number</kbd></dt>
+<dd><p>If we are participating in mDNS,
after we have synched for the first time
-we attempt to register with the mDNS system.
+we attempt to register with the mDNS system.
If that registration attempt fails,
we try again at one minute intervals for up to
<code>mdnstries</code>
-times.
+times.
After all,
<code>ntpd</code>
-may be starting before mDNS.
+may be starting before mDNS.
The default value for
<code>mdnstries</code>
-is 5.
+is 5.
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
+<hr>
<a name="Authentication-Support"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Monitoring-Support" accesskey="n" rel="next">Monitoring Support</a>, Previous: <a href="#Configuration-Support" accesskey="p" rel="prev">Configuration Support</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">Authentication Support</h4>
-
+<a name="Authentication-Support-1"></a>
+<h4 class="subsection">1.1.2 Authentication Support</h4>
<p>Authentication support allows the NTP client to verify that the
server is in fact known and trusted and not an intruder intending
-accidentally or on purpose to masquerade as that server.
+accidentally or on purpose to masquerade as that server.
The NTPv3
specification RFC-1305 defines a scheme which provides
-cryptographic authentication of received NTP packets.
+cryptographic authentication of received NTP packets.
Originally,
this was done using the Data Encryption Standard (DES) algorithm
operating in Cipher Block Chaining (CBC) mode, commonly called
-DES-CBC.
+DES-CBC.
Subsequently, this was replaced by the RSA Message Digest
-5 (MD5) algorithm using a private key, commonly called keyed-MD5.
+5 (MD5) algorithm using a private key, commonly called keyed-MD5.
Either algorithm computes a message digest, or one-way hash, which
can be used to verify the server has the correct private key and
key identifier.
-
- <p>NTPv4 retains the NTPv3 scheme, properly described as symmetric key
+</p>
+<p>NTPv4 retains the NTPv3 scheme, properly described as symmetric key
cryptography and, in addition, provides a new Autokey scheme
-based on public key cryptography.
+based on public key cryptography.
Public key cryptography is generally considered more secure
than symmetric key cryptography, since the security is based
on a private value which is generated by each server and
-never revealed.
+never revealed.
With Autokey all key distribution and
management functions involve only public values, which
-considerably simplifies key distribution and storage.
+considerably simplifies key distribution and storage.
Public key management is based on X.509 certificates,
which can be provided by commercial services or
produced by utility programs in the OpenSSL software library
or the NTPv4 distribution.
-
- <p>While the algorithms for symmetric key cryptography are
+</p>
+<p>While the algorithms for symmetric key cryptography are
included in the NTPv4 distribution, public key cryptography
requires the OpenSSL software library to be installed
-before building the NTP distribution.
+before building the NTP distribution.
Directions for doing that
are on the Building and Installing the Distribution page.
-
- <p>Authentication is configured separately for each association
+</p>
+<p>Authentication is configured separately for each association
using the
<code>key</code>
or
@@ -497,36 +610,36 @@ subcommand on the
and
<code>manycastclient</code>
configuration commands as described in
-<a href="#Configuration-Options">Configuration Options</a>
-page.
+&lsquo;Configuration Options&rsquo;
+page.
The authentication
options described below specify the locations of the key files,
if other than default, which symmetric keys are trusted
and the interval between various operations, if other than default.
-
- <p>Authentication is always enabled,
+</p>
+<p>Authentication is always enabled,
although ineffective if not configured as
-described below.
+described below.
If a NTP packet arrives
including a message authentication
code (MAC), it is accepted only if it
-passes all cryptographic checks.
+passes all cryptographic checks.
The
checks require correct key ID, key value
-and message digest.
+and message digest.
If the packet has
been modified in any way or replayed
by an intruder, it will fail one or more
-of these checks and be discarded.
+of these checks and be discarded.
Furthermore, the Autokey scheme requires a
preliminary protocol exchange to obtain
the server certificate, verify its
credentials and initialize the protocol
-
- <p>The
+</p>
+<p>The
<code>auth</code>
flag controls whether new associations or
-remote configuration commands require cryptographic authentication.
+remote configuration commands require cryptographic authentication.
This flag can be set or reset by the
<code>enable</code>
and
@@ -535,22 +648,22 @@ commands and also by remote
configuration commands sent by a
<code>ntpdc(1ntpdcmdoc)</code>
program running on
-another machine.
+another machine.
If this flag is enabled, which is the default
case, new broadcast client and symmetric passive associations and
remote configuration commands must be cryptographically
-authenticated using either symmetric key or public key cryptography.
+authenticated using either symmetric key or public key cryptography.
If this
flag is disabled, these operations are effective
even if not cryptographic
-authenticated.
+authenticated.
It should be understood
that operating with the
<code>auth</code>
flag disabled invites a significant vulnerability
where a rogue hacker can
masquerade as a falseticker and seriously
-disrupt system timekeeping.
+disrupt system timekeeping.
It is
important to note that this flag has no purpose
other than to allow or disallow
@@ -559,42 +672,41 @@ and symmetric active messages
and remote configuration commands and, in particular,
the flag has no effect on
the authentication process itself.
-
- <p>An attractive alternative where multicast support is available
+</p>
+<p>An attractive alternative where multicast support is available
is manycast mode, in which clients periodically troll
for servers as described in the
<a href="#Automatic-NTP-Configuration-Options">Automatic NTP Configuration Options</a>
-page.
+page.
Either symmetric key or public key
-cryptographic authentication can be used in this mode.
+cryptographic authentication can be used in this mode.
The principle advantage
of manycast mode is that potential servers need not be
configured in advance,
since the client finds them during regular operation,
and the configuration
files for all clients can be identical.
-
- <p>The security model and protocol schemes for
+</p>
+<p>The security model and protocol schemes for
both symmetric key and public key
cryptography are summarized below;
further details are in the briefings, papers
and reports at the NTP project page linked from
<code>http://www.ntp.org/</code>.
-
-<h5 class="subsubsection">Symmetric-Key Cryptography</h5>
-
+</p><a name="Symmetric_002dKey-Cryptography"></a>
+<h4 class="subsubsection">1.1.2.1 Symmetric-Key Cryptography</h4>
<p>The original RFC-1305 specification allows any one of possibly
-65,534 keys, each distinguished by a 32-bit key identifier, to
-authenticate an association.
+65,535 keys, each distinguished by a 32-bit key identifier, to
+authenticate an association.
The servers and clients involved must
agree on the key and key identifier to
-authenticate NTP packets.
+authenticate NTP packets.
Keys and
related information are specified in a key
file, usually called
-<span class="file">ntp.keys</span>,
+<samp>ntp.keys</samp>,
which must be distributed and stored using
-secure means beyond the scope of the NTP protocol itself.
+secure means beyond the scope of the NTP protocol itself.
Besides the keys used
for ordinary NTP associations,
additional keys can be used as passwords for the
@@ -602,25 +714,25 @@ additional keys can be used as passwords for the
and
<code>ntpdc(1ntpdcmdoc)</code>
utility programs.
-
- <p>When
+</p>
+<p>When
<code>ntpd(1ntpdmdoc)</code>
is first started, it reads the key file specified in the
<code>keys</code>
configuration command and installs the keys
-in the key cache.
+in the key cache.
However,
individual keys must be activated with the
<code>trusted</code>
-command before use.
+command before use.
This
allows, for instance, the installation of possibly
several batches of keys and
then activating or deactivating each batch
remotely using
-<code>ntpdc(1ntpdcmdoc)</code>.
+<code>ntpdc(1ntpdcmdoc)</code>.
This also provides a revocation capability that can be used
-if a key becomes compromised.
+if a key becomes compromised.
The
<code>requestkey</code>
command selects the key used as the password for the
@@ -630,121 +742,118 @@ utility, while the
command selects the key used as the password for the
<code>ntpq(1ntpqmdoc)</code>
utility.
-
-<h5 class="subsubsection">Public Key Cryptography</h5>
-
+</p><a name="Public-Key-Cryptography"></a>
+<h4 class="subsubsection">1.1.2.2 Public Key Cryptography</h4>
<p>NTPv4 supports the original NTPv3 symmetric key scheme
described in RFC-1305 and in addition the Autokey protocol,
-which is based on public key cryptography.
+which is based on public key cryptography.
The Autokey Version 2 protocol described on the Autokey Protocol
page verifies packet integrity using MD5 message digests
and verifies the source with digital signatures and any of several
-digest/signature schemes.
+digest/signature schemes.
Optional identity schemes described on the Identity Schemes
page and based on cryptographic challenge/response algorithms
-are also available.
+are also available.
Using all of these schemes provides strong security against
replay with or without modification, spoofing, masquerade
and most forms of clogging attacks.
-
- <p>The Autokey protocol has several modes of operation
-corresponding to the various NTP modes supported.
+</p>
+<p>The Autokey protocol has several modes of operation
+corresponding to the various NTP modes supported.
Most modes use a special cookie which can be
computed independently by the client and server,
-but encrypted in transmission.
+but encrypted in transmission.
All modes use in addition a variant of the S-KEY scheme,
in which a pseudo-random key list is generated and used
-in reverse order.
+in reverse order.
These schemes are described along with an executive summary,
current status, briefing slides and reading list on the
-<a href="#Autonomous-Authentication">Autonomous Authentication</a>
+&lsquo;Autonomous Authentication&rsquo;
page.
-
- <p>The specific cryptographic environment used by Autokey servers
+</p>
+<p>The specific cryptographic environment used by Autokey servers
and clients is determined by a set of files
and soft links generated by the
<code>ntp-keygen(1ntpkeygenmdoc)</code>
-program.
+program.
This includes a required host key file,
required certificate file and optional sign key file,
-leapsecond file and identity scheme files.
+leapsecond file and identity scheme files.
The
digest/signature scheme is specified in the X.509 certificate
-along with the matching sign key.
+along with the matching sign key.
There are several schemes
available in the OpenSSL software library, each identified
by a specific string such as
<code>md5WithRSAEncryption</code>,
which stands for the MD5 message digest with RSA
-encryption scheme.
+encryption scheme.
The current NTP distribution supports
all the schemes in the OpenSSL library, including
those based on RSA and DSA digital signatures.
-
- <p>NTP secure groups can be used to define cryptographic compartments
-and security hierarchies.
+</p>
+<p>NTP secure groups can be used to define cryptographic compartments
+and security hierarchies.
It is important that every host
in the group be able to construct a certificate trail to one
-or more trusted hosts in the same group.
+or more trusted hosts in the same group.
Each group
host runs the Autokey protocol to obtain the certificates
-for all hosts along the trail to one or more trusted hosts.
+for all hosts along the trail to one or more trusted hosts.
This requires the configuration file in all hosts to be
engineered so that, even under anticipated failure conditions,
the NTP subnet will form such that every group host can find
a trail to at least one trusted host.
-
-<h5 class="subsubsection">Naming and Addressing</h5>
-
+</p><a name="Naming-and-Addressing"></a>
+<h4 class="subsubsection">1.1.2.3 Naming and Addressing</h4>
<p>It is important to note that Autokey does not use DNS to
-resolve addresses, since DNS can't be completely trusted
-until the name servers have synchronized clocks.
+resolve addresses, since DNS can&rsquo;t be completely trusted
+until the name servers have synchronized clocks.
The cryptographic name used by Autokey to bind the host identity
credentials and cryptographic values must be independent
-of interface, network and any other naming convention.
+of interface, network and any other naming convention.
The name appears in the host certificate in either or both
the subject and issuer fields, so protection against
DNS compromise is essential.
-
- <p>By convention, the name of an Autokey host is the name returned
+</p>
+<p>By convention, the name of an Autokey host is the name returned
by the Unix
<code>gethostname(2)</code>
-system call or equivalent in other systems.
+system call or equivalent in other systems.
By the system design
-model, there are no provisions to allow alternate names or aliases.
+model, there are no provisions to allow alternate names or aliases.
However, this is not to say that DNS aliases, different names
for each interface, etc., are constrained in any way.
-
- <p>It is also important to note that Autokey verifies authenticity
+</p>
+<p>It is also important to note that Autokey verifies authenticity
using the host name, network address and public keys,
all of which are bound together by the protocol specifically
-to deflect masquerade attacks.
+to deflect masquerade attacks.
For this reason Autokey
includes the source and destination IP addresses in message digest
computations and so the same addresses must be available
-at both the server and client.
+at both the server and client.
For this reason operation
-with network address translation schemes is not possible.
+with network address translation schemes is not possible.
This reflects the intended robust security model where government
and corporate NTP servers are operated outside firewall perimeters.
-
-<h5 class="subsubsection">Operation</h5>
-
+</p><a name="Operation"></a>
+<h4 class="subsubsection">1.1.2.4 Operation</h4>
<p>A specific combination of authentication scheme (none,
symmetric key, public key) and identity scheme is called
-a cryptotype, although not all combinations are compatible.
+a cryptotype, although not all combinations are compatible.
There may be management configurations where the clients,
-servers and peers may not all support the same cryptotypes.
+servers and peers may not all support the same cryptotypes.
A secure NTPv4 subnet can be configured in many ways while
keeping in mind the principles explained above and
-in this section.
+in this section.
Note however that some cryptotype
combinations may successfully interoperate with each other,
but may not represent good security practice.
-
- <p>The cryptotype of an association is determined at the time
+</p>
+<p>The cryptotype of an association is determined at the time
of mobilization, either at configuration time or some time
-later when a message of appropriate cryptotype arrives.
+later when a message of appropriate cryptotype arrives.
When mobilized by a
<code>server</code>
or
@@ -761,513 +870,609 @@ using the symmetric key ID specified; if the
<code>autokey</code>
subcommand is present, the association is authenticated
using Autokey.
-
- <p>When multiple identity schemes are supported in the Autokey
-protocol, the first message exchange determines which one is used.
+</p>
+<p>When multiple identity schemes are supported in the Autokey
+protocol, the first message exchange determines which one is used.
The client request message contains bits corresponding
-to which schemes it has available.
+to which schemes it has available.
The server response message
-contains bits corresponding to which schemes it has available.
+contains bits corresponding to which schemes it has available.
Both server and client match the received bits with their own
and select a common scheme.
-
- <p>Following the principle that time is a public value,
+</p>
+<p>Following the principle that time is a public value,
a server responds to any client packet that matches
-its cryptotype capabilities.
+its cryptotype capabilities.
Thus, a server receiving
an unauthenticated packet will respond with an unauthenticated
packet, while the same server receiving a packet of a cryptotype
-it supports will respond with packets of that cryptotype.
+it supports will respond with packets of that cryptotype.
However, unconfigured broadcast or manycast client
associations or symmetric passive associations will not be
mobilized unless the server supports a cryptotype compatible
-with the first packet received.
+with the first packet received.
By default, unauthenticated associations will not be mobilized
unless overridden in a decidedly dangerous way.
-
- <p>Some examples may help to reduce confusion.
-Client Alice has no specific cryptotype selected.
-Server Bob has both a symmetric key file and minimal Autokey files.
-Alice's unauthenticated messages arrive at Bob, who replies with
-unauthenticated messages.
-Cathy has a copy of Bob's symmetric
-key file and has selected key ID 4 in messages to Bob.
-Bob verifies the message with his key ID 4.
-If it's the
+</p>
+<p>Some examples may help to reduce confusion.
+Client Alice has no specific cryptotype selected.
+Server Bob has both a symmetric key file and minimal Autokey files.
+Alice&rsquo;s unauthenticated messages arrive at Bob, who replies with
+unauthenticated messages.
+Cathy has a copy of Bob&rsquo;s symmetric
+key file and has selected key ID 4 in messages to Bob.
+Bob verifies the message with his key ID 4.
+If it&rsquo;s the
same key and the message is verified, Bob sends Cathy a reply
-authenticated with that key.
+authenticated with that key.
If verification fails,
Bob sends Cathy a thing called a crypto-NAK, which tells her
-something broke.
+something broke.
She can see the evidence using the
<code>ntpq(1ntpqmdoc)</code>
program.
-
- <p>Denise has rolled her own host key and certificate.
-She also uses one of the identity schemes as Bob.
+</p>
+<p>Denise has rolled her own host key and certificate.
+She also uses one of the identity schemes as Bob.
She sends the first Autokey message to Bob and they
-both dance the protocol authentication and identity steps.
+both dance the protocol authentication and identity steps.
If all comes out okay, Denise and Bob continue as described above.
-
- <p>It should be clear from the above that Bob can support
+</p>
+<p>It should be clear from the above that Bob can support
all the girls at the same time, as long as he has compatible
-authentication and identity credentials.
+authentication and identity credentials.
Now, Bob can act just like the girls in his own choice of servers;
he can run multiple configured associations with multiple different
-servers (or the same server, although that might not be useful).
+servers (or the same server, although that might not be useful).
But, wise security policy might preclude some cryptotype
combinations; for instance, running an identity scheme
with one server and no authentication with another might not be wise.
-
-<h5 class="subsubsection">Key Management</h5>
-
+</p><a name="Key-Management"></a>
+<h4 class="subsubsection">1.1.2.5 Key Management</h4>
<p>The cryptographic values used by the Autokey protocol are
incorporated as a set of files generated by the
<code>ntp-keygen(1ntpkeygenmdoc)</code>
utility program, including symmetric key, host key and
public certificate files, as well as sign key, identity parameters
-and leapseconds files.
+and leapseconds files.
Alternatively, host and sign keys and
certificate files can be generated by the OpenSSL utilities
and certificates can be imported from public certificate
-authorities.
+authorities.
Note that symmetric keys are necessary for the
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
-utility programs.
+utility programs.
The remaining files are necessary only for the
Autokey protocol.
-
- <p>Certificates imported from OpenSSL or public certificate
-authorities have certian limitations.
+</p>
+<p>Certificates imported from OpenSSL or public certificate
+authorities have certian limitations.
The certificate should be in ASN.1 syntax, X.509 Version 3
format and encoded in PEM, which is the same format
-used by OpenSSL.
+used by OpenSSL.
The overall length of the certificate encoded
-in ASN.1 must not exceed 1024 bytes.
+in ASN.1 must not exceed 1024 bytes.
The subject distinguished
name field (CN) is the fully qualified name of the host
-on which it is used; the remaining subject fields are ignored.
+on which it is used; the remaining subject fields are ignored.
The certificate extension fields must not contain either
a subject key identifier or a issuer key identifier field;
however, an extended key usage field for a trusted host must
contain the value
-<code>trustRoot</code>;.
+<code>trustRoot</code>;.
Other extension fields are ignored.
-
-<h5 class="subsubsection">Authentication Commands</h5>
-
- <dl>
-<dt><code>autokey</code> <code>[</code><kbd>logsec</kbd><code>]</code><dd>Specifies the interval between regenerations of the session key
-list used with the Autokey protocol.
+</p><a name="Authentication-Commands"></a>
+<h4 class="subsubsection">1.1.2.6 Authentication Commands</h4>
+<dl compact="compact">
+<dt><code>autokey</code> <code>[<kbd>logsec</kbd>]</code></dt>
+<dd><p>Specifies the interval between regenerations of the session key
+list used with the Autokey protocol.
Note that the size of the key
list for each association depends on this interval and the current
-poll interval.
-The default value is 12 (4096 s or about 1.1 hours).
+poll interval.
+The default value is 12 (4096 s or about 1.1 hours).
For poll intervals above the specified interval, a session key list
with a single entry will be regenerated for every message
-sent.
-<br><dt><code>controlkey</code> <kbd>key</kbd><dd>Specifies the key identifier to use with the
+sent.
+</p></dd>
+<dt><code>controlkey</code> <kbd>key</kbd></dt>
+<dd><p>Specifies the key identifier to use with the
<code>ntpq(1ntpqmdoc)</code>
utility, which uses the standard
-protocol defined in RFC-1305.
+protocol defined in RFC-1305.
The
<kbd>key</kbd>
argument is
the key identifier for a trusted key, where the value can be in the
-range 1 to 65,534, inclusive.
-<br><dt><code>crypto</code> <code>[cert </code><kbd>file</kbd><code>]</code> <code>[leap </code><kbd>file</kbd><code>]</code> <code>[randfile </code><kbd>file</kbd><code>]</code> <code>[host </code><kbd>file</kbd><code>]</code> <code>[sign </code><kbd>file</kbd><code>]</code> <code>[gq </code><kbd>file</kbd><code>]</code> <code>[gqpar </code><kbd>file</kbd><code>]</code> <code>[iffpar </code><kbd>file</kbd><code>]</code> <code>[mvpar </code><kbd>file</kbd><code>]</code> <code>[pw </code><kbd>password</kbd><code>]</code><dd>This command requires the OpenSSL library.
+range 1 to 65,535, inclusive.
+</p></dd>
+<dt><code>crypto</code> <code>[<code>cert</code> <kbd>file</kbd>]</code> <code>[<code>leap</code> <kbd>file</kbd>]</code> <code>[<code>randfile</code> <kbd>file</kbd>]</code> <code>[<code>host</code> <kbd>file</kbd>]</code> <code>[<code>sign</code> <kbd>file</kbd>]</code> <code>[<code>gq</code> <kbd>file</kbd>]</code> <code>[<code>gqpar</code> <kbd>file</kbd>]</code> <code>[<code>iffpar</code> <kbd>file</kbd>]</code> <code>[<code>mvpar</code> <kbd>file</kbd>]</code> <code>[<code>pw</code> <kbd>password</kbd>]</code></dt>
+<dd><p>This command requires the OpenSSL library.
It activates public key
cryptography, selects the message digest and signature
encryption scheme and loads the required private and public
-values described above.
+values described above.
If one or more files are left unspecified,
-the default names are used as described above.
+the default names are used as described above.
Unless the complete path and name of the file are specified, the
location of a file is relative to the keys directory specified
in the
<code>keysdir</code>
command or default
-<span class="file">/usr/local/etc</span>.
+<samp>/usr/local/etc</samp>.
Following are the subcommands:
- <dl>
-<dt><code>cert</code> <kbd>file</kbd><dd>Specifies the location of the required host public certificate file.
+</p><dl compact="compact">
+<dt><code>cert</code> <kbd>file</kbd></dt>
+<dd><p>Specifies the location of the required host public certificate file.
This overrides the link
-<span class="file">ntpkey_cert_</span><kbd>hostname</kbd>
-in the keys directory.
-<br><dt><code>gqpar</code> <kbd>file</kbd><dd>Specifies the location of the optional GQ parameters file.
+<samp>ntpkey_cert_</samp><kbd>hostname</kbd>
+in the keys directory.
+</p></dd>
+<dt><code>gqpar</code> <kbd>file</kbd></dt>
+<dd><p>Specifies the location of the optional GQ parameters file.
This
overrides the link
-<span class="file">ntpkey_gq_</span><kbd>hostname</kbd>
-in the keys directory.
-<br><dt><code>host</code> <kbd>file</kbd><dd>Specifies the location of the required host key file.
+<samp>ntpkey_gq_</samp><kbd>hostname</kbd>
+in the keys directory.
+</p></dd>
+<dt><code>host</code> <kbd>file</kbd></dt>
+<dd><p>Specifies the location of the required host key file.
This overrides
the link
-<span class="file">ntpkey_key_</span><kbd>hostname</kbd>
-in the keys directory.
-<br><dt><code>iffpar</code> <kbd>file</kbd><dd>Specifies the location of the optional IFF parameters file.
+<samp>ntpkey_key_</samp><kbd>hostname</kbd>
+in the keys directory.
+</p></dd>
+<dt><code>iffpar</code> <kbd>file</kbd></dt>
+<dd><p>Specifies the location of the optional IFF parameters file.
This overrides the link
-<span class="file">ntpkey_iff_</span><kbd>hostname</kbd>
-in the keys directory.
-<br><dt><code>leap</code> <kbd>file</kbd><dd>Specifies the location of the optional leapsecond file.
+<samp>ntpkey_iff_</samp><kbd>hostname</kbd>
+in the keys directory.
+</p></dd>
+<dt><code>leap</code> <kbd>file</kbd></dt>
+<dd><p>Specifies the location of the optional leapsecond file.
This overrides the link
-<span class="file">ntpkey_leap</span>
-in the keys directory.
-<br><dt><code>mvpar</code> <kbd>file</kbd><dd>Specifies the location of the optional MV parameters file.
+<samp>ntpkey_leap</samp>
+in the keys directory.
+</p></dd>
+<dt><code>mvpar</code> <kbd>file</kbd></dt>
+<dd><p>Specifies the location of the optional MV parameters file.
This overrides the link
-<span class="file">ntpkey_mv_</span><kbd>hostname</kbd>
-in the keys directory.
-<br><dt><code>pw</code> <kbd>password</kbd><dd>Specifies the password to decrypt files containing private keys and
-identity parameters.
+<samp>ntpkey_mv_</samp><kbd>hostname</kbd>
+in the keys directory.
+</p></dd>
+<dt><code>pw</code> <kbd>password</kbd></dt>
+<dd><p>Specifies the password to decrypt files containing private keys and
+identity parameters.
This is required only if these files have been
-encrypted.
-<br><dt><code>randfile</code> <kbd>file</kbd><dd>Specifies the location of the random seed file used by the OpenSSL
-library.
-The defaults are described in the main text above.
-<br><dt><code>sign</code> <kbd>file</kbd><dd>Specifies the location of the optional sign key file.
+encrypted.
+</p></dd>
+<dt><code>randfile</code> <kbd>file</kbd></dt>
+<dd><p>Specifies the location of the random seed file used by the OpenSSL
+library.
+The defaults are described in the main text above.
+</p></dd>
+<dt><code>sign</code> <kbd>file</kbd></dt>
+<dd><p>Specifies the location of the optional sign key file.
This overrides
the link
-<span class="file">ntpkey_sign_</span><kbd>hostname</kbd>
-in the keys directory.
+<samp>ntpkey_sign_</samp><kbd>hostname</kbd>
+in the keys directory.
If this file is
-not found, the host key is also the sign key.
+not found, the host key is also the sign key.
+</p></dd>
</dl>
- <br><dt><code>keys</code> <kbd>keyfile</kbd><dd>Specifies the complete path and location of the MD5 key file
+</dd>
+<dt><code>keys</code> <kbd>keyfile</kbd></dt>
+<dd><p>Specifies the complete path and location of the MD5 key file
containing the keys and key identifiers used by
<code>ntpd(1ntpdmdoc)</code>,
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
-when operating with symmetric key cryptography.
+when operating with symmetric key cryptography.
This is the same operation as the
<code>-k</code>
-command line option.
-<br><dt><code>keysdir</code> <kbd>path</kbd><dd>This command specifies the default directory path for
-cryptographic keys, parameters and certificates.
+command line option.
+</p></dd>
+<dt><code>keysdir</code> <kbd>path</kbd></dt>
+<dd><p>This command specifies the default directory path for
+cryptographic keys, parameters and certificates.
The default is
-<span class="file">/usr/local/etc/</span>.
-<br><dt><code>requestkey</code> <kbd>key</kbd><dd>Specifies the key identifier to use with the
+<samp>/usr/local/etc/</samp>.
+</p></dd>
+<dt><code>requestkey</code> <kbd>key</kbd></dt>
+<dd><p>Specifies the key identifier to use with the
<code>ntpdc(1ntpdcmdoc)</code>
utility program, which uses a
proprietary protocol specific to this implementation of
-<code>ntpd(1ntpdmdoc)</code>.
+<code>ntpd(1ntpdmdoc)</code>.
The
<kbd>key</kbd>
argument is a key identifier
for the trusted key, where the value can be in the range 1 to
-65,534, inclusive.
-<br><dt><code>revoke</code> <kbd>logsec</kbd><dd>Specifies the interval between re-randomization of certain
+65,535, inclusive.
+</p></dd>
+<dt><code>revoke</code> <kbd>logsec</kbd></dt>
+<dd><p>Specifies the interval between re-randomization of certain
cryptographic values used by the Autokey scheme, as a power of 2 in
-seconds.
+seconds.
These values need to be updated frequently in order to
deflect brute-force attacks on the algorithms of the scheme;
-however, updating some values is a relatively expensive operation.
-The default interval is 16 (65,536 s or about 18 hours).
+however, updating some values is a relatively expensive operation.
+The default interval is 16 (65,536 s or about 18 hours).
For poll
intervals above the specified interval, the values will be updated
-for every message sent.
-<br><dt><code>trustedkey</code> <kbd>key</kbd> <kbd>...</kbd><dd>Specifies the key identifiers which are trusted for the
+for every message sent.
+</p></dd>
+<dt><code>trustedkey</code> <kbd>key</kbd> <kbd>...</kbd></dt>
+<dd><p>Specifies the key identifiers which are trusted for the
purposes of authenticating peers with symmetric key cryptography,
as well as keys used by the
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
-programs.
+programs.
The authentication procedures require that both the local
and remote servers share the same key and key identifier for this
purpose, although different keys can be used with different
-servers.
+servers.
The
<kbd>key</kbd>
arguments are 32-bit unsigned
-integers with values from 1 to 65,534.
+integers with values from 1 to 65,535.
+</p></dd>
</dl>
-
-<h5 class="subsubsection">Error Codes</h5>
-
+<a name="Error-Codes"></a>
+<h4 class="subsubsection">1.1.2.7 Error Codes</h4>
<p>The following error codes are reported via the NTP control
and monitoring protocol trap mechanism.
- <dl>
-<dt>101<dd>(bad field format or length)
-The packet has invalid version, length or format.
-<br><dt>102<dd>(bad timestamp)
-The packet timestamp is the same or older than the most recent received.
-This could be due to a replay or a server clock time step.
-<br><dt>103<dd>(bad filestamp)
-The packet filestamp is the same or older than the most recent received.
-This could be due to a replay or a key file generation error.
-<br><dt>104<dd>(bad or missing public key)
-The public key is missing, has incorrect format or is an unsupported type.
-<br><dt>105<dd>(unsupported digest type)
-The server requires an unsupported digest/signature scheme.
-<br><dt>106<dd>(mismatched digest types)
-Not used.
-<br><dt>107<dd>(bad signature length)
-The signature length does not match the current public key.
-<br><dt>108<dd>(signature not verified)
-The message fails the signature check.
+</p><dl compact="compact">
+<dt>101</dt>
+<dd><p>(bad field format or length)
+The packet has invalid version, length or format.
+</p></dd>
+<dt>102</dt>
+<dd><p>(bad timestamp)
+The packet timestamp is the same or older than the most recent received.
+This could be due to a replay or a server clock time step.
+</p></dd>
+<dt>103</dt>
+<dd><p>(bad filestamp)
+The packet filestamp is the same or older than the most recent received.
+This could be due to a replay or a key file generation error.
+</p></dd>
+<dt>104</dt>
+<dd><p>(bad or missing public key)
+The public key is missing, has incorrect format or is an unsupported type.
+</p></dd>
+<dt>105</dt>
+<dd><p>(unsupported digest type)
+The server requires an unsupported digest/signature scheme.
+</p></dd>
+<dt>106</dt>
+<dd><p>(mismatched digest types)
+Not used.
+</p></dd>
+<dt>107</dt>
+<dd><p>(bad signature length)
+The signature length does not match the current public key.
+</p></dd>
+<dt>108</dt>
+<dd><p>(signature not verified)
+The message fails the signature check.
It could be bogus or signed by a
-different private key.
-<br><dt>109<dd>(certificate not verified)
-The certificate is invalid or signed with the wrong key.
-<br><dt>110<dd>(certificate not verified)
+different private key.
+</p></dd>
+<dt>109</dt>
+<dd><p>(certificate not verified)
+The certificate is invalid or signed with the wrong key.
+</p></dd>
+<dt>110</dt>
+<dd><p>(certificate not verified)
The certificate is not yet valid or has expired or the signature could not
-be verified.
-<br><dt>111<dd>(bad or missing cookie)
-The cookie is missing, corrupted or bogus.
-<br><dt>112<dd>(bad or missing leapseconds table)
-The leapseconds table is missing, corrupted or bogus.
-<br><dt>113<dd>(bad or missing certificate)
-The certificate is missing, corrupted or bogus.
-<br><dt>114<dd>(bad or missing identity)
-The identity key is missing, corrupt or bogus.
+be verified.
+</p></dd>
+<dt>111</dt>
+<dd><p>(bad or missing cookie)
+The cookie is missing, corrupted or bogus.
+</p></dd>
+<dt>112</dt>
+<dd><p>(bad or missing leapseconds table)
+The leapseconds table is missing, corrupted or bogus.
+</p></dd>
+<dt>113</dt>
+<dd><p>(bad or missing certificate)
+The certificate is missing, corrupted or bogus.
+</p></dd>
+<dt>114</dt>
+<dd><p>(bad or missing identity)
+The identity key is missing, corrupt or bogus.
+</p></dd>
</dl>
- <div class="node">
-<p><hr>
+<hr>
<a name="Monitoring-Support"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Access-Control-Support" accesskey="n" rel="next">Access Control Support</a>, Previous: <a href="#Authentication-Support" accesskey="p" rel="prev">Authentication Support</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">Monitoring Support</h4>
-
+<a name="Monitoring-Support-1"></a>
+<h4 class="subsection">1.1.3 Monitoring Support</h4>
<p><code>ntpd(1ntpdmdoc)</code>
includes a comprehensive monitoring facility suitable
for continuous, long term recording of server and client
-timekeeping performance.
+timekeeping performance.
See the
<code>statistics</code>
command below
for a listing and example of each type of statistics currently
-supported.
+supported.
Statistic files are managed using file generation sets
and scripts in the
-<span class="file">./scripts</span>
-directory of the source code distribution.
+<samp>./scripts</samp>
+directory of the source code distribution.
Using
these facilities and
-<span class="sc">unix</span>
+<small>UNIX</small>
<code>cron(8)</code>
jobs, the data can be
automatically summarized and archived for retrospective analysis.
-
-<h5 class="subsubsection">Monitoring Commands</h5>
-
- <dl>
-<dt><code>statistics</code> <kbd>name</kbd> <kbd>...</kbd><dd>Enables writing of statistics records.
+</p><a name="Monitoring-Commands"></a>
+<h4 class="subsubsection">1.1.3.1 Monitoring Commands</h4>
+<dl compact="compact">
+<dt><code>statistics</code> <kbd>name</kbd> <kbd>...</kbd></dt>
+<dd><p>Enables writing of statistics records.
Currently, eight kinds of
<kbd>name</kbd>
statistics are supported.
- <dl>
-<dt><code>clockstats</code><dd>Enables recording of clock driver statistics information.
+</p><dl compact="compact">
+<dt><code>clockstats</code></dt>
+<dd><p>Enables recording of clock driver statistics information.
Each update
received from a clock driver appends a line of the following form to
the file generation set named
<code>clockstats</code>:
-<pre class="verbatim">
- 49213 525.624 127.127.4.1 93 226 00:08:29.606 D
- </pre>
-
- <p>The first two fields show the date (Modified Julian Day) and time
-(seconds and fraction past UTC midnight).
+</p><pre class="verbatim">49213 525.624 127.127.4.1 93 226 00:08:29.606 D
+</pre>
+<p>The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
The next field shows the
-clock address in dotted-quad notation.
+clock address in dotted-quad notation.
The final field shows the last
timecode received from the clock in decoded ASCII format, where
-meaningful.
+meaningful.
In some clock drivers a good deal of additional information
-can be gathered and displayed as well.
+can be gathered and displayed as well.
See information specific to each
-clock for further details.
-<br><dt><code>cryptostats</code><dd>This option requires the OpenSSL cryptographic software library.
+clock for further details.
+</p></dd>
+<dt><code>cryptostats</code></dt>
+<dd><p>This option requires the OpenSSL cryptographic software library.
It
-enables recording of cryptographic public key protocol information.
+enables recording of cryptographic public key protocol information.
Each message received by the protocol module appends a line of the
following form to the file generation set named
<code>cryptostats</code>:
-<pre class="verbatim">
- 49213 525.624 127.127.4.1 message
- </pre>
-
- <p>The first two fields show the date (Modified Julian Day) and time
-(seconds and fraction past UTC midnight).
+</p><pre class="verbatim">49213 525.624 127.127.4.1 message
+</pre>
+<p>The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
The next field shows the peer
address in dotted-quad notation, The final message field includes the
-message type and certain ancillary information.
+message type and certain ancillary information.
See the
-<a href="#Authentication-Options">Authentication Options</a>
-section for further information.
-<br><dt><code>loopstats</code><dd>Enables recording of loop filter statistics information.
+&lsquo;Authentication Options&rsquo;
+section for further information.
+</p></dd>
+<dt><code>loopstats</code></dt>
+<dd><p>Enables recording of loop filter statistics information.
Each
update of the local clock outputs a line of the following form to
the file generation set named
<code>loopstats</code>:
-<pre class="verbatim">
- 50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
- </pre>
-
- <p>The first two fields show the date (Modified Julian Day) and
-time (seconds and fraction past UTC midnight).
+</p><pre class="verbatim">50935 75440.031 0.000006019 13.778190 0.000351733 0.0133806
+</pre>
+<p>The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
The next five fields
show time offset (seconds), frequency offset (parts per million -
PPM), RMS jitter (seconds), Allan deviation (PPM) and clock
-discipline time constant.
-<br><dt><code>peerstats</code><dd>Enables recording of peer statistics information.
+discipline time constant.
+</p></dd>
+<dt><code>peerstats</code></dt>
+<dd><p>Enables recording of peer statistics information.
This includes
statistics records of all peers of a NTP server and of special
-signals, where present and configured.
+signals, where present and configured.
Each valid update appends a
line of the following form to the current element of a file
generation set named
<code>peerstats</code>:
-<pre class="verbatim">
- 48773 10847.650 127.127.4.1 9714 -0.001605376 0.000000000 0.001424877 0.000958674
- </pre>
-
- <p>The first two fields show the date (Modified Julian Day) and
-time (seconds and fraction past UTC midnight).
+</p><pre class="verbatim">48773 10847.650 127.127.4.1 9714 -0.001605376 0.000000000 0.001424877 0.000958674
+</pre>
+<p>The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
The next two fields
show the peer address in dotted-quad notation and status,
-respectively.
+respectively.
The status field is encoded in hex in the format
-described in Appendix A of the NTP specification RFC 1305.
+described in Appendix A of the NTP specification RFC 1305.
The final four fields show the offset,
-delay, dispersion and RMS jitter, all in seconds.
-<br><dt><code>rawstats</code><dd>Enables recording of raw-timestamp statistics information.
+delay, dispersion and RMS jitter, all in seconds.
+</p></dd>
+<dt><code>rawstats</code></dt>
+<dd><p>Enables recording of raw-timestamp statistics information.
This
includes statistics records of all peers of a NTP server and of
-special signals, where present and configured.
+special signals, where present and configured.
Each NTP message
received from a peer or clock driver appends a line of the
following form to the file generation set named
<code>rawstats</code>:
-<pre class="verbatim">
- 50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
- </pre>
-
- <p>The first two fields show the date (Modified Julian Day) and
-time (seconds and fraction past UTC midnight).
+</p><pre class="verbatim">50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 02453332.540806000 3102453332.541458000
+</pre>
+<p>The first two fields show the date (Modified Julian Day) and
+time (seconds and fraction past UTC midnight).
The next two fields
show the remote peer or clock address followed by the local address
-in dotted-quad notation.
+in dotted-quad notation.
The final four fields show the originate,
-receive, transmit and final NTP timestamps in order.
+receive, transmit and final NTP timestamps in order.
The timestamp
values are as received and before processing by the various data
-smoothing and mitigation algorithms.
-<br><dt><code>sysstats</code><dd>Enables recording of ntpd statistics counters on a periodic basis.
+smoothing and mitigation algorithms.
+</p></dd>
+<dt><code>sysstats</code></dt>
+<dd><p>Enables recording of ntpd statistics counters on a periodic basis.
Each
hour a line of the following form is appended to the file generation
set named
<code>sysstats</code>:
-<pre class="verbatim">
- 50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
- </pre>
-
- <p>The first two fields show the date (Modified Julian Day) and time
-(seconds and fraction past UTC midnight).
+</p><pre class="verbatim">50928 2132.543 36000 81965 0 9546 56 71793 512 540 10 147
+</pre>
+<p>The first two fields show the date (Modified Julian Day) and time
+(seconds and fraction past UTC midnight).
The remaining ten fields show
the statistics counter values accumulated since the last generated
line.
- <dl>
-<dt>Time since restart <code>36000</code><dd>Time in hours since the system was last rebooted.
-<br><dt>Packets received <code>81965</code><dd>Total number of packets received.
-<br><dt>Packets processed <code>0</code><dd>Number of packets received in response to previous packets sent
-<br><dt>Current version <code>9546</code><dd>Number of packets matching the current NTP version.
-<br><dt>Previous version <code>56</code><dd>Number of packets matching the previous NTP version.
-<br><dt>Bad version <code>71793</code><dd>Number of packets matching neither NTP version.
-<br><dt>Access denied <code>512</code><dd>Number of packets denied access for any reason.
-<br><dt>Bad length or format <code>540</code><dd>Number of packets with invalid length, format or port number.
-<br><dt>Bad authentication <code>10</code><dd>Number of packets not verified as authentic.
-<br><dt>Rate exceeded <code>147</code><dd>Number of packets discarded due to rate limitation.
+</p><dl compact="compact">
+<dt>Time since restart <code>36000</code></dt>
+<dd><p>Time in hours since the system was last rebooted.
+</p></dd>
+<dt>Packets received <code>81965</code></dt>
+<dd><p>Total number of packets received.
+</p></dd>
+<dt>Packets processed <code>0</code></dt>
+<dd><p>Number of packets received in response to previous packets sent
+</p></dd>
+<dt>Current version <code>9546</code></dt>
+<dd><p>Number of packets matching the current NTP version.
+</p></dd>
+<dt>Previous version <code>56</code></dt>
+<dd><p>Number of packets matching the previous NTP version.
+</p></dd>
+<dt>Bad version <code>71793</code></dt>
+<dd><p>Number of packets matching neither NTP version.
+</p></dd>
+<dt>Access denied <code>512</code></dt>
+<dd><p>Number of packets denied access for any reason.
+</p></dd>
+<dt>Bad length or format <code>540</code></dt>
+<dd><p>Number of packets with invalid length, format or port number.
+</p></dd>
+<dt>Bad authentication <code>10</code></dt>
+<dd><p>Number of packets not verified as authentic.
+</p></dd>
+<dt>Rate exceeded <code>147</code></dt>
+<dd><p>Number of packets discarded due to rate limitation.
+</p></dd>
</dl>
- <br><dt><code>statsdir</code> <kbd>directory_path</kbd><dd>Indicates the full path of a directory where statistics files
-should be created (see below).
+</dd>
+<dt><code>statsdir</code> <kbd>directory_path</kbd></dt>
+<dd><p>Indicates the full path of a directory where statistics files
+should be created (see below).
This keyword allows
the (otherwise constant)
<code>filegen</code>
filename prefix to be modified for file generation sets, which
-is useful for handling statistics logs.
-<br><dt><code>filegen</code> <kbd>name</kbd> <code>[file </code><kbd>filename</kbd><code>]</code> <code>[type </code><kbd>typename</kbd><code>]</code> <code>[link | nolink]</code> <code>[enable | disable]</code><dd>Configures setting of generation file set name.
+is useful for handling statistics logs.
+</p></dd>
+<dt><code>filegen</code> <kbd>name</kbd> <code>[<code>file</code> <kbd>filename</kbd>]</code> <code>[<code>type</code> <kbd>typename</kbd>]</code> <code>[<code>link</code> | <code>nolink</code>]</code> <code>[<code>enable</code> | <code>disable</code>]</code></dt>
+<dd><p>Configures setting of generation file set name.
Generation
file sets provide a means for handling files that are
-continuously growing during the lifetime of a server.
-Server statistics are a typical example for such files.
+continuously growing during the lifetime of a server.
+Server statistics are a typical example for such files.
Generation file sets provide access to a set of files used
-to store the actual data.
+to store the actual data.
At any time at most one element
-of the set is being written to.
+of the set is being written to.
The type given specifies
-when and how data will be directed to a new element of the set.
+when and how data will be directed to a new element of the set.
This way, information stored in elements of a file set
that are currently unused are available for administrational
-operations without the risk of disturbing the operation of ntpd.
+operations without the risk of disturbing the operation of ntpd.
(Most important: they can be removed to free space for new data
produced.)
-
- <p>Note that this command can be sent from the
+</p>
+<p>Note that this command can be sent from the
<code>ntpdc(1ntpdcmdoc)</code>
program running at a remote location.
- <dl>
-<dt><code>name</code><dd>This is the type of the statistics records, as shown in the
+</p><dl compact="compact">
+<dt><code>name</code></dt>
+<dd><p>This is the type of the statistics records, as shown in the
<code>statistics</code>
-command.
-<br><dt><code>file</code> <kbd>filename</kbd><dd>This is the file name for the statistics records.
+command.
+</p></dd>
+<dt><code>file</code> <kbd>filename</kbd></dt>
+<dd><p>This is the file name for the statistics records.
Filenames of set
members are built from three concatenated elements
<code>prefix</code>,
<code>filename</code>
and
<code>suffix</code>:
- <dl>
-<dt><code>prefix</code><dd>This is a constant filename path.
+</p><dl compact="compact">
+<dt><code>prefix</code></dt>
+<dd><p>This is a constant filename path.
It is not subject to
modifications via the
<kbd>filegen</kbd>
-option.
+option.
It is defined by the
-server, usually specified as a compile-time constant.
+server, usually specified as a compile-time constant.
It may,
however, be configurable for individual file generation sets
-via other commands.
+via other commands.
For example, the prefix used with
<kbd>loopstats</kbd>
and
<kbd>peerstats</kbd>
generation can be configured using the
<kbd>statsdir</kbd>
-option explained above.
-<br><dt><code>filename</code><dd>This string is directly concatenated to the prefix mentioned
+option explained above.
+</p></dd>
+<dt><code>filename</code></dt>
+<dd><p>This string is directly concatenated to the prefix mentioned
above (no intervening
-/).
+&lsquo;/&rsquo;).
This can be modified using
the file argument to the
<kbd>filegen</kbd>
-statement.
+statement.
No
-<span class="file">..</span>
+<samp>..</samp>
elements are
allowed in this component to prevent filenames referring to
parts outside the filesystem hierarchy denoted by
-<kbd>prefix</kbd>.
-<br><dt><code>suffix</code><dd>This part is reflects individual elements of a file set.
+<kbd>prefix</kbd>.
+</p></dd>
+<dt><code>suffix</code></dt>
+<dd><p>This part is reflects individual elements of a file set.
It is
-generated according to the type of a file set.
+generated according to the type of a file set.
+</p></dd>
</dl>
- <br><dt><code>type</code> <kbd>typename</kbd><dd>A file generation set is characterized by its type.
+</dd>
+<dt><code>type</code> <kbd>typename</kbd></dt>
+<dd><p>A file generation set is characterized by its type.
The following
types are supported:
- <dl>
-<dt><code>none</code><dd>The file set is actually a single plain file.
-<br><dt><code>pid</code><dd>One element of file set is used per incarnation of a ntpd
-server.
+</p><dl compact="compact">
+<dt><code>none</code></dt>
+<dd><p>The file set is actually a single plain file.
+</p></dd>
+<dt><code>pid</code></dt>
+<dd><p>One element of file set is used per incarnation of a ntpd
+server.
This type does not perform any changes to file set
members during runtime, however it provides an easy way of
separating files belonging to different
<code>ntpd(1ntpdmdoc)</code>
-server incarnations.
+server incarnations.
The set member filename is built by appending a
-.
+&lsquo;.&rsquo;
to concatenated
<kbd>prefix</kbd>
and
@@ -1275,399 +1480,445 @@ and
strings, and
appending the decimal representation of the process ID of the
<code>ntpd(1ntpdmdoc)</code>
-server process.
-<br><dt><code>day</code><dd>One file generation set element is created per day.
+server process.
+</p></dd>
+<dt><code>day</code></dt>
+<dd><p>One file generation set element is created per day.
A day is
-defined as the period between 00:00 and 24:00 UTC.
+defined as the period between 00:00 and 24:00 UTC.
The file set
member suffix consists of a
-.
+&lsquo;.&rsquo;
and a day specification in
the form
-<code>YYYYMMdd</code>.
+<code>YYYYMMdd</code>.
<code>YYYY</code>
-is a 4-digit year number (e.g., 1992).
+is a 4-digit year number (e.g., 1992).
<code>MM</code>
-is a two digit month number.
+is a two digit month number.
<code>dd</code>
-is a two digit day number.
+is a two digit day number.
Thus, all information written at 10 December 1992 would end up
in a file named
<kbd>prefix</kbd>
-<kbd>filename</kbd>.19921210.
-<br><dt><code>week</code><dd>Any file set member contains data related to a certain week of
-a year.
+<kbd>filename</kbd>.19921210.
+</p></dd>
+<dt><code>week</code></dt>
+<dd><p>Any file set member contains data related to a certain week of
+a year.
The term week is defined by computing day-of-year
-modulo 7.
+modulo 7.
Elements of such a file generation set are
distinguished by appending the following suffix to the file set
filename base: A dot, a 4-digit year number, the letter
<code>W</code>,
-and a 2-digit week number.
+and a 2-digit week number.
For example, information from January,
10th 1992 would end up in a file with suffix
-.No . Ns Ar 1992W1 .
-<br><dt><code>month</code><dd>One generation file set element is generated per month.
+.No . Ns Ar 1992W1 .
+</p></dd>
+<dt><code>month</code></dt>
+<dd><p>One generation file set element is generated per month.
The
file name suffix consists of a dot, a 4-digit year number, and
-a 2-digit month.
-<br><dt><code>year</code><dd>One generation file element is generated per year.
+a 2-digit month.
+</p></dd>
+<dt><code>year</code></dt>
+<dd><p>One generation file element is generated per year.
The filename
-suffix consists of a dot and a 4 digit year number.
-<br><dt><code>age</code><dd>This type of file generation sets changes to a new element of
-the file set every 24 hours of server operation.
+suffix consists of a dot and a 4 digit year number.
+</p></dd>
+<dt><code>age</code></dt>
+<dd><p>This type of file generation sets changes to a new element of
+the file set every 24 hours of server operation.
The filename
suffix consists of a dot, the letter
<code>a</code>,
-and an 8-digit number.
+and an 8-digit number.
This number is taken to be the number of seconds the server is
-running at the start of the corresponding 24-hour period.
+running at the start of the corresponding 24-hour period.
Information is only written to a file generation by specifying
<code>enable</code>;
output is prevented by specifying
-<code>disable</code>.
+<code>disable</code>.
+</p></dd>
</dl>
- <br><dt><code>link</code> | <code>nolink</code><dd>It is convenient to be able to access the current element of a file
-generation set by a fixed name.
+</dd>
+<dt><code>link</code> | <code>nolink</code></dt>
+<dd><p>It is convenient to be able to access the current element of a file
+generation set by a fixed name.
This feature is enabled by
specifying
<code>link</code>
and disabled using
-<code>nolink</code>.
+<code>nolink</code>.
If link is specified, a
hard link from the current file set element to a file without
-suffix is created.
+suffix is created.
When there is already a file with this name and
the number of links of this file is one, it is renamed appending a
dot, the letter
<code>C</code>,
and the pid of the
<code>ntpd(1ntpdmdoc)</code>
-server process.
+server process.
When the
-number of links is greater than one, the file is unlinked.
+number of links is greater than one, the file is unlinked.
This
-allows the current file to be accessed by a constant name.
-<br><dt><code>enable</code> <code>|</code> <code>disable</code><dd>Enables or disables the recording function.
+allows the current file to be accessed by a constant name.
+</p></dd>
+<dt><code>enable</code> <code>|</code> <code>disable</code></dt>
+<dd><p>Enables or disables the recording function.
+</p></dd>
+</dl>
+</dd>
+</dl>
+</dd>
</dl>
- </dl>
- </dl>
-<div class="node">
-<p><hr>
+<hr>
<a name="Access-Control-Support"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Automatic-NTP-Configuration-Options" accesskey="n" rel="next">Automatic NTP Configuration Options</a>, Previous: <a href="#Monitoring-Support" accesskey="p" rel="prev">Monitoring Support</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">Access Control Support</h4>
-
+<a name="Access-Control-Support-1"></a>
+<h4 class="subsection">1.1.4 Access Control Support</h4>
<p>The
<code>ntpd(1ntpdmdoc)</code>
daemon implements a general purpose address/mask based restriction
-list.
+list.
The list contains address/match entries sorted first
-by increasing address values and and then by increasing mask values.
+by increasing address values and and then by increasing mask values.
A match occurs when the bitwise AND of the mask and the packet
source address is equal to the bitwise AND of the mask and
-address in the list.
+address in the list.
The list is searched in order with the
last match found defining the restriction flags associated
-with the entry.
+with the entry.
Additional information and examples can be found in the
-"Notes on Configuring NTP and Setting up a NTP Subnet"
+&quot;Notes on Configuring NTP and Setting up a NTP Subnet&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>).
-
- <p>The restriction facility was implemented in conformance
+<samp>/usr/share/doc/ntp</samp>).
+</p>
+<p>The restriction facility was implemented in conformance
with the access policies for the original NSFnet backbone
-time servers.
+time servers.
Later the facility was expanded to deflect
-cryptographic and clogging attacks.
+cryptographic and clogging attacks.
While this facility may
be useful for keeping unwanted or broken or malicious clients
from congesting innocent servers, it should not be considered
-an alternative to the NTP authentication facilities.
+an alternative to the NTP authentication facilities.
Source address based restrictions are easily circumvented
by a determined cracker.
-
- <p>Clients can be denied service because they are explicitly
+</p>
+<p>Clients can be denied service because they are explicitly
included in the restrict list created by the
<code>restrict</code>
command
or implicitly as the result of cryptographic or rate limit
-violations.
+violations.
Cryptographic violations include certificate
or identity verification failure; rate limit violations generally
result from defective NTP implementations that send packets
-at abusive rates.
+at abusive rates.
Some violations cause denied service
only for the offending packet, others cause denied service
for a timed period and others cause the denied service for
-an indefinite period.
+an indefinite period.
When a client or network is denied access
for an indefinite period, the only way at present to remove
the restrictions is by restarting the server.
-
-<h5 class="subsubsection">The Kiss-of-Death Packet</h5>
-
+</p><a name="The-Kiss_002dof_002dDeath-Packet"></a>
+<h4 class="subsubsection">1.1.4.1 The Kiss-of-Death Packet</h4>
<p>Ordinarily, packets denied service are simply dropped with no
-further action except incrementing statistics counters.
+further action except incrementing statistics counters.
Sometimes a
more proactive response is needed, such as a server message that
explicitly requests the client to stop sending and leave a message
-for the system operator.
+for the system operator.
A special packet format has been created
-for this purpose called the "kiss-of-death" (KoD) packet.
+for this purpose called the &quot;kiss-of-death&quot; (KoD) packet.
KoD packets have the leap bits set unsynchronized and stratum set
to zero and the reference identifier field set to a four-byte
-ASCII code.
+ASCII code.
If the
<code>noserve</code>
or
<code>notrust</code>
flag of the matching restrict list entry is set,
-the code is "DENY"; if the
+the code is &quot;DENY&quot;; if the
<code>limited</code>
flag is set and the rate limit
-is exceeded, the code is "RATE".
-Finally, if a cryptographic violation occurs, the code is "CRYP".
-
- <p>A client receiving a KoD performs a set of sanity checks to
+is exceeded, the code is &quot;RATE&quot;.
+Finally, if a cryptographic violation occurs, the code is &quot;CRYP&quot;.
+</p>
+<p>A client receiving a KoD performs a set of sanity checks to
minimize security exposure, then updates the stratum and
reference identifier peer variables, sets the access
denied (TEST4) bit in the peer flash variable and sends
-a message to the log.
+a message to the log.
As long as the TEST4 bit is set,
-the client will send no further packets to the server.
+the client will send no further packets to the server.
The only way at present to recover from this condition is
-to restart the protocol at both the client and server.
+to restart the protocol at both the client and server.
This
-happens automatically at the client when the association times out.
+happens automatically at the client when the association times out.
It will happen at the server only if the server operator cooperates.
-
-<h5 class="subsubsection">Access Control Commands</h5>
-
- <dl>
-<dt><code>discard</code> <code>[average </code><kbd>avg</kbd><code>]</code> <code>[minimum </code><kbd>min</kbd><code>]</code> <code>[monitor </code><kbd>prob</kbd><code>]</code><dd>Set the parameters of the
+</p><a name="Access-Control-Commands"></a>
+<h4 class="subsubsection">1.1.4.2 Access Control Commands</h4>
+<dl compact="compact">
+<dt><code>discard</code> <code>[<code>average</code> <kbd>avg</kbd>]</code> <code>[<code>minimum</code> <kbd>min</kbd>]</code> <code>[<code>monitor</code> <kbd>prob</kbd>]</code></dt>
+<dd><p>Set the parameters of the
<code>limited</code>
facility which protects the server from
-client abuse.
+client abuse.
The
<code>average</code>
subcommand specifies the minimum average packet
spacing, while the
<code>minimum</code>
-subcommand specifies the minimum packet spacing.
+subcommand specifies the minimum packet spacing.
Packets that violate these minima are discarded
-and a kiss-o'-death packet returned if enabled.
+and a kiss-o&rsquo;-death packet returned if enabled.
The default
-minimum average and minimum are 5 and 2, respectively.
+minimum average and minimum are 5 and 2, respectively.
The
<code>monitor</code>
subcommand specifies the probability of discard
-for packets that overflow the rate-control window.
-<br><dt><code>restrict</code> <code>address</code> <code>[mask </code><kbd>mask</kbd><code>]</code> <code>[ippeerlimit </code><kbd>int</kbd><code>]</code> <code>[</code><kbd>flag</kbd> <kbd>...</kbd><code>]</code><dd>The
+for packets that overflow the rate-control window.
+</p></dd>
+<dt><code>restrict</code> <code>address</code> <code>[<code>mask</code> <kbd>mask</kbd>]</code> <code>[<code>ippeerlimit</code> <kbd>int</kbd>]</code> <code>[<kbd>flag</kbd> <kbd>...</kbd>]</code></dt>
+<dd><p>The
<kbd>address</kbd>
argument expressed in
-dotted-quad form is the address of a host or network.
+dotted-quad form is the address of a host or network.
Alternatively, the
<kbd>address</kbd>
-argument can be a valid host DNS name.
+argument can be a valid host DNS name.
The
<kbd>mask</kbd>
argument expressed in dotted-quad form defaults to
<code>255.255.255.255</code>,
meaning that the
<kbd>address</kbd>
-is treated as the address of an individual host.
+is treated as the address of an individual host.
A default entry (address
<code>0.0.0.0</code>,
mask
<code>0.0.0.0</code>)
-is always included and is always the first entry in the list.
+is always included and is always the first entry in the list.
Note that text string
<code>default</code>,
with no mask option, may
-be used to indicate the default entry.
+be used to indicate the default entry.
The
<code>ippeerlimit</code>
directive limits the number of peer requests for each IP to
<kbd>int</kbd>,
-where a value of -1 means "unlimited", the current default.
-A value of 0 means "none".
+where a value of -1 means &quot;unlimited&quot;, the current default.
+A value of 0 means &quot;none&quot;.
There would usually be at most 1 peering request per IP,
but if the remote peering requests are behind a proxy
-there could well be more than 1 per IP.
+there could well be more than 1 per IP.
In the current implementation,
<code>flag</code>
always
restricts access, i.e., an entry with no flags indicates that free
-access to the server is to be given.
+access to the server is to be given.
The flags are not orthogonal,
in that more restrictive flags will often make less restrictive
-ones redundant.
+ones redundant.
The flags can generally be classed into two
categories, those which restrict time service and those which
restrict informational queries and attempts to do run-time
-reconfiguration of the server.
+reconfiguration of the server.
One or more of the following flags
may be specified:
- <dl>
-<dt><code>ignore</code><dd>Deny packets of all kinds, including
+</p><dl compact="compact">
+<dt><code>ignore</code></dt>
+<dd><p>Deny packets of all kinds, including
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
-queries.
-<br><dt><code>kod</code><dd>If this flag is set when an access violation occurs, a kiss-o'-death
-(KoD) packet is sent.
+queries.
+</p></dd>
+<dt><code>kod</code></dt>
+<dd><p>If this flag is set when an access violation occurs, a kiss-o&rsquo;-death
+(KoD) packet is sent.
KoD packets are rate limited to no more than one
-per second.
+per second.
If another KoD packet occurs within one second after the
-last one, the packet is dropped.
-<br><dt><code>limited</code><dd>Deny service if the packet spacing violates the lower limits specified
+last one, the packet is dropped.
+</p></dd>
+<dt><code>limited</code></dt>
+<dd><p>Deny service if the packet spacing violates the lower limits specified
in the
<code>discard</code>
-command.
+command.
A history of clients is kept using the
monitoring capability of
-<code>ntpd(1ntpdmdoc)</code>.
+<code>ntpd(1ntpdmdoc)</code>.
Thus, monitoring is always active as
long as there is a restriction entry with the
<code>limited</code>
-flag.
-<br><dt><code>lowpriotrap</code><dd>Declare traps set by matching hosts to be low priority.
+flag.
+</p></dd>
+<dt><code>lowpriotrap</code></dt>
+<dd><p>Declare traps set by matching hosts to be low priority.
The
number of traps a server can maintain is limited (the current limit
-is 3).
+is 3).
Traps are usually assigned on a first come, first served
-basis, with later trap requestors being denied service.
+basis, with later trap requestors being denied service.
This flag
modifies the assignment algorithm by allowing low priority traps to
-be overridden by later requests for normal priority traps.
-<br><dt><code>noepeer</code><dd>Deny ephemeral peer requests,
-even if they come from an authenticated source.
+be overridden by later requests for normal priority traps.
+</p></dd>
+<dt><code>noepeer</code></dt>
+<dd><p>Deny ephemeral peer requests,
+even if they come from an authenticated source.
Note that the ability to use a symmetric key for authentication may be restricted to
one or more IPs or subnets via the third field of the
-<span class="file">ntp.keys</span>
-file.
+<samp>ntp.keys</samp>
+file.
This restriction is not enabled by default,
-to maintain backward compatability.
+to maintain backward compatability.
Expect
<code>noepeer</code>
-to become the default in ntp-4.4.
-<br><dt><code>nomodify</code><dd>Deny
+to become the default in ntp-4.4.
+</p></dd>
+<dt><code>nomodify</code></dt>
+<dd><p>Deny
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
queries which attempt to modify the state of the
-server (i.e., run time reconfiguration).
+server (i.e., run time reconfiguration).
Queries which return
-information are permitted.
-<br><dt><code>noquery</code><dd>Deny
+information are permitted.
+</p></dd>
+<dt><code>noquery</code></dt>
+<dd><p>Deny
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
-queries.
-Time service is not affected.
-<br><dt><code>nopeer</code><dd>Deny unauthenticated packets which would result in mobilizing a new association.
+queries.
+Time service is not affected.
+</p></dd>
+<dt><code>nopeer</code></dt>
+<dd><p>Deny unauthenticated packets which would result in mobilizing a new association.
This includes
broadcast and symmetric active packets
-when a configured association does not exist.
+when a configured association does not exist.
It also includes
<code>pool</code>
-associations, so if you want to use servers from a
+associations, so if you want to use servers from a
<code>pool</code>
directive and also want to use
<code>nopeer</code>
-by default, you'll want a
+by default, you&rsquo;ll want a
<code>restrict source ...</code>
line as well that does
<em>not</em>
include the
<code>nopeer</code>
-directive.
-<br><dt><code>noserve</code><dd>Deny all packets except
+directive.
+</p></dd>
+<dt><code>noserve</code></dt>
+<dd><p>Deny all packets except
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
-queries.
-<br><dt><code>notrap</code><dd>Decline to provide mode 6 control message trap service to matching
-hosts.
+queries.
+</p></dd>
+<dt><code>notrap</code></dt>
+<dd><p>Decline to provide mode 6 control message trap service to matching
+hosts.
The trap service is a subsystem of the
<code>ntpq(1ntpqmdoc)</code>
control message
-protocol which is intended for use by remote event logging programs.
-<br><dt><code>notrust</code><dd>Deny service unless the packet is cryptographically authenticated.
-<br><dt><code>ntpport</code><dd>This is actually a match algorithm modifier, rather than a
-restriction flag.
+protocol which is intended for use by remote event logging programs.
+</p></dd>
+<dt><code>notrust</code></dt>
+<dd><p>Deny service unless the packet is cryptographically authenticated.
+</p></dd>
+<dt><code>ntpport</code></dt>
+<dd><p>This is actually a match algorithm modifier, rather than a
+restriction flag.
Its presence causes the restriction entry to be
matched only if the source port in the packet is the standard NTP
-UDP port (123).
+UDP port (123).
Both
<code>ntpport</code>
and
<code>non-ntpport</code>
may
-be specified.
+be specified.
The
<code>ntpport</code>
is considered more specific and
-is sorted later in the list.
-<br><dt><code>version</code><dd>Deny packets that do not match the current NTP version.
+is sorted later in the list.
+</p></dd>
+<dt><code>version</code></dt>
+<dd><p>Deny packets that do not match the current NTP version.
+</p></dd>
</dl>
- <p>Default restriction list entries with the flags ignore, interface,
-ntpport, for each of the local host's interface addresses are
+<p>Default restriction list entries with the flags ignore, interface,
+ntpport, for each of the local host&rsquo;s interface addresses are
inserted into the table at startup to prevent the server
-from attempting to synchronize to its own time.
+from attempting to synchronize to its own time.
A default entry is also always present, though if it is
otherwise unconfigured; no flags are associated
with the default entry (i.e., everything besides your own
-NTP server is unrestricted).
+NTP server is unrestricted).
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
+<hr>
<a name="Automatic-NTP-Configuration-Options"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Reference-Clock-Support" accesskey="n" rel="next">Reference Clock Support</a>, Previous: <a href="#Access-Control-Support" accesskey="p" rel="prev">Access Control Support</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">Automatic NTP Configuration Options</h4>
-
-<h5 class="subsubsection">Manycasting</h5>
-
+<a name="Automatic-NTP-Configuration-Options-1"></a>
+<h4 class="subsection">1.1.5 Automatic NTP Configuration Options</h4>
+<a name="Manycasting"></a>
+<h4 class="subsubsection">1.1.5.1 Manycasting</h4>
<p>Manycasting is a automatic discovery and configuration paradigm
-new to NTPv4.
+new to NTPv4.
It is intended as a means for a multicast client
to troll the nearby network neighborhood to find cooperating
manycast servers, validate them using cryptographic means
and evaluate their time values with respect to other servers
-that might be lurking in the vicinity.
+that might be lurking in the vicinity.
The intended result is that each manycast client mobilizes
-client associations with some number of the "best"
+client associations with some number of the &quot;best&quot;
of the nearby manycast servers, yet automatically reconfigures
to sustain this number of servers should one or another fail.
-
- <p>Note that the manycasting paradigm does not coincide
+</p>
+<p>Note that the manycasting paradigm does not coincide
with the anycast paradigm described in RFC-1546,
which is designed to find a single server from a clique
-of servers providing the same service.
+of servers providing the same service.
The manycast paradigm is designed to find a plurality
of redundant servers satisfying defined optimality criteria.
-
- <p>Manycasting can be used with either symmetric key
-or public key cryptography.
+</p>
+<p>Manycasting can be used with either symmetric key
+or public key cryptography.
The public key infrastructure (PKI)
offers the best protection against compromised keys
and is generally considered stronger, at least with relatively
-large key sizes.
+large key sizes.
It is implemented using the Autokey protocol and
the OpenSSL cryptographic library available from
-<code>http://www.openssl.org/</code>.
+<code>http://www.openssl.org/</code>.
The library can also be used with other NTPv4 modes
as well and is highly recommended, especially for broadcast modes.
-
- <p>A persistent manycast client association is configured
+</p>
+<p>A persistent manycast client association is configured
using the
<code>manycastclient</code>
command, which is similar to the
@@ -1676,62 +1927,62 @@ command but with a multicast (IPv4 class
<code>D</code>
or IPv6 prefix
<code>FF</code>)
-group address.
+group address.
The IANA has designated IPv4 address 224.1.1.1
-and IPv6 address FF05::101 (site local) for NTP.
+and IPv6 address FF05::101 (site local) for NTP.
When more servers are needed, it broadcasts manycast
client messages to this address at the minimum feasible rate
and minimum feasible time-to-live (TTL) hops, depending
-on how many servers have already been found.
+on how many servers have already been found.
There can be as many manycast client associations
as different group address, each one serving as a template
for a future ephemeral unicast client/server association.
-
- <p>Manycast servers configured with the
+</p>
+<p>Manycast servers configured with the
<code>manycastserver</code>
command listen on the specified group address for manycast
-client messages.
+client messages.
Note the distinction between manycast client,
which actively broadcasts messages, and manycast server,
-which passively responds to them.
+which passively responds to them.
If a manycast server is
in scope of the current TTL and is itself synchronized
to a valid source and operating at a stratum level equal
to or lower than the manycast client, it replies to the
manycast client message with an ordinary unicast server message.
-
- <p>The manycast client receiving this message mobilizes
+</p>
+<p>The manycast client receiving this message mobilizes
an ephemeral client/server association according to the
matching manycast client template, but only if cryptographically
authenticated and the server stratum is less than or equal
-to the client stratum.
+to the client stratum.
Authentication is explicitly required
-and either symmetric key or public key (Autokey) can be used.
+and either symmetric key or public key (Autokey) can be used.
Then, the client polls the server at its unicast address
in burst mode in order to reliably set the host clock
-and validate the source.
+and validate the source.
This normally results
in a volley of eight client/server at 2-s intervals
during which both the synchronization and cryptographic
-protocols run concurrently.
+protocols run concurrently.
Following the volley,
the client runs the NTP intersection and clustering
-algorithms, which act to discard all but the "best"
+algorithms, which act to discard all but the &quot;best&quot;
associations according to stratum and synchronization
-distance.
+distance.
The surviving associations then continue
in ordinary client/server mode.
-
- <p>The manycast client polling strategy is designed to reduce
+</p>
+<p>The manycast client polling strategy is designed to reduce
as much as possible the volume of manycast client messages
and the effects of implosion due to near-simultaneous
-arrival of manycast server messages.
+arrival of manycast server messages.
The strategy is determined by the
<code>manycastclient</code>,
<code>tos</code>
and
<code>ttl</code>
-configuration commands.
+configuration commands.
The manycast poll interval is
normally eight times the system poll interval,
which starts out at the
@@ -1740,17 +1991,17 @@ value specified in the
<code>manycastclient</code>,
command and, under normal circumstances, increments to the
<code>maxpolll</code>
-value specified in this command.
+value specified in this command.
Initially, the TTL is
set at the minimum hops specified by the
<code>ttl</code>
-command.
+command.
At each retransmission the TTL is increased until reaching
the maximum hops specified by this command or a sufficient
-number client associations have been found.
+number client associations have been found.
Further retransmissions use the same TTL.
-
- <p>The quality and reliability of the suite of associations
+</p>
+<p>The quality and reliability of the suite of associations
discovered by the manycast client is determined by the NTP
mitigation algorithms and the
<code>minclock</code>
@@ -1758,66 +2009,66 @@ and
<code>minsane</code>
values specified in the
<code>tos</code>
-configuration command.
+configuration command.
At least
<code>minsane</code>
candidate servers must be available and the mitigation
algorithms produce at least
<code>minclock</code>
-survivors in order to synchronize the clock.
+survivors in order to synchronize the clock.
Byzantine agreement principles require at least four
-candidates in order to correctly discard a single falseticker.
+candidates in order to correctly discard a single falseticker.
For legacy purposes,
<code>minsane</code>
defaults to 1 and
<code>minclock</code>
-defaults to 3.
+defaults to 3.
For manycast service
<code>minsane</code>
should be explicitly set to 4, assuming at least that
number of servers are available.
-
- <p>If at least
+</p>
+<p>If at least
<code>minclock</code>
servers are found, the manycast poll interval is immediately
set to eight times
-<code>maxpoll</code>.
+<code>maxpoll</code>.
If less than
<code>minclock</code>
servers are found when the TTL has reached the maximum hops,
-the manycast poll interval is doubled.
+the manycast poll interval is doubled.
For each transmission
after that, the poll interval is doubled again until
reaching the maximum of eight times
-<code>maxpoll</code>.
+<code>maxpoll</code>.
Further transmissions use the same poll interval and
-TTL values.
+TTL values.
Note that while all this is going on,
each client/server association found is operating normally
it the system poll interval.
-
- <p>Administratively scoped multicast boundaries are normally
+</p>
+<p>Administratively scoped multicast boundaries are normally
specified by the network router configuration and,
-in the case of IPv6, the link/site scope prefix.
+in the case of IPv6, the link/site scope prefix.
By default, the increment for TTL hops is 32 starting
from 31; however, the
<code>ttl</code>
configuration command can be
used to modify the values to match the scope rules.
-
- <p>It is often useful to narrow the range of acceptable
-servers which can be found by manycast client associations.
+</p>
+<p>It is often useful to narrow the range of acceptable
+servers which can be found by manycast client associations.
Because manycast servers respond only when the client
stratum is equal to or greater than the server stratum,
primary (stratum 1) servers fill find only primary servers
-in TTL range, which is probably the most common objective.
+in TTL range, which is probably the most common objective.
However, unless configured otherwise, all manycast clients
in TTL range will eventually find all primary servers
in TTL range, which is probably not the most common
-objective in large networks.
+objective in large networks.
The
<code>tos</code>
-command can be used to modify this behavior.
+command can be used to modify this behavior.
Servers with stratum below
<code>floor</code>
or above
@@ -1829,270 +2080,283 @@ process; however, these servers may be temporally
accepted if the number of servers within TTL range is
less than
<code>minclock</code>.
-
- <p>The above actions occur for each manycast client message,
-which repeats at the designated poll interval.
+</p>
+<p>The above actions occur for each manycast client message,
+which repeats at the designated poll interval.
However, once the ephemeral client association is mobilized,
subsequent manycast server replies are discarded,
-since that would result in a duplicate association.
+since that would result in a duplicate association.
If during a poll interval the number of client associations
falls below
<code>minclock</code>,
all manycast client prototype associations are reset
to the initial poll interval and TTL hops and operation
-resumes from the beginning.
+resumes from the beginning.
It is important to avoid
frequent manycast client messages, since each one requires
-all manycast servers in TTL range to respond.
+all manycast servers in TTL range to respond.
The result could well be an implosion, either minor or major,
-depending on the number of servers in range.
+depending on the number of servers in range.
The recommended value for
<code>maxpoll</code>
is 12 (4,096 s).
-
- <p>It is possible and frequently useful to configure a host
-as both manycast client and manycast server.
+</p>
+<p>It is possible and frequently useful to configure a host
+as both manycast client and manycast server.
A number of hosts configured this way and sharing a common
group address will automatically organize themselves
in an optimum configuration based on stratum and
-synchronization distance.
+synchronization distance.
For example, consider an NTP
subnet of two primary servers and a hundred or more
-dependent clients.
+dependent clients.
With two exceptions, all servers
and clients have identical configuration files including both
<code>multicastclient</code>
and
<code>multicastserver</code>
commands using, for instance, multicast group address
-239.1.1.1.
+239.1.1.1.
The only exception is that each primary server
configuration file must include commands for the primary
reference source such as a GPS receiver.
-
- <p>The remaining configuration files for all secondary
+</p>
+<p>The remaining configuration files for all secondary
servers and clients have the same contents, except for the
<code>tos</code>
-command, which is specific for each stratum level.
+command, which is specific for each stratum level.
For stratum 1 and stratum 2 servers, that command is
-not necessary.
+not necessary.
For stratum 3 and above servers the
<code>floor</code>
-value is set to the intended stratum number.
+value is set to the intended stratum number.
Thus, all stratum 3 configuration files are identical,
all stratum 4 files are identical and so forth.
-
- <p>Once operations have stabilized in this scenario,
+</p>
+<p>Once operations have stabilized in this scenario,
the primary servers will find the primary reference source
and each other, since they both operate at the same
stratum (1), but not with any secondary server or client,
-since these operate at a higher stratum.
+since these operate at a higher stratum.
The secondary
-servers will find the servers at the same stratum level.
+servers will find the servers at the same stratum level.
If one of the primary servers loses its GPS receiver,
it will continue to operate as a client and other clients
will time out the corresponding association and
re-associate accordingly.
-
- <p>Some administrators prefer to avoid running
+</p>
+<p>Some administrators prefer to avoid running
<code>ntpd(1ntpdmdoc)</code>
continuously and run either
<code>sntp(1sntpmdoc)</code>
or
<code>ntpd(1ntpdmdoc)</code>
<code>-q</code>
-as a cron job.
+as a cron job.
In either case the servers must be
configured in advance and the program fails if none are
-available when the cron job runs.
+available when the cron job runs.
A really slick
application of manycast is with
<code>ntpd(1ntpdmdoc)</code>
-<code>-q</code>.
+<code>-q</code>.
The program wakes up, scans the local landscape looking
for the usual suspects, selects the best from among
-the rascals, sets the clock and then departs.
+the rascals, sets the clock and then departs.
Servers do not have to be configured in advance and
all clients throughout the network can have the same
configuration file.
-
-<h5 class="subsubsection">Manycast Interactions with Autokey</h5>
-
+</p><a name="Manycast-Interactions-with-Autokey"></a>
+<h4 class="subsubsection">1.1.5.2 Manycast Interactions with Autokey</h4>
<p>Each time a manycast client sends a client mode packet
to a multicast group address, all manycast servers
in scope generate a reply including the host name
-and status word.
+and status word.
The manycast clients then run
the Autokey protocol, which collects and verifies
-all certificates involved.
+all certificates involved.
Following the burst interval
all but three survivors are cast off,
-but the certificates remain in the local cache.
+but the certificates remain in the local cache.
It often happens that several complete signing trails
from the client to the primary servers are collected in this way.
-
- <p>About once an hour or less often if the poll interval
-exceeds this, the client regenerates the Autokey key list.
-This is in general transparent in client/server mode.
+</p>
+<p>About once an hour or less often if the poll interval
+exceeds this, the client regenerates the Autokey key list.
+This is in general transparent in client/server mode.
However, about once per day the server private value
used to generate cookies is refreshed along with all
-manycast client associations.
+manycast client associations.
In this case all
-cryptographic values including certificates is refreshed.
+cryptographic values including certificates is refreshed.
If a new certificate has been generated since
the last refresh epoch, it will automatically revoke
all prior certificates that happen to be in the
-certificate cache.
+certificate cache.
At the same time, the manycast
scheme starts all over from the beginning and
the expanding ring shrinks to the minimum and increments
from there while collecting all servers in scope.
-
-<h5 class="subsubsection">Broadcast Options</h5>
-
- <dl>
-<dt><code>tos</code> <code>[bcpollbstep </code><kbd>gate</kbd><code>]</code><dd>This command provides a way to delay,
+</p><a name="Broadcast-Options"></a>
+<h4 class="subsubsection">1.1.5.3 Broadcast Options</h4>
+<dl compact="compact">
+<dt><code>tos</code> <code>[<code>bcpollbstep</code> <kbd>gate</kbd>]</code></dt>
+<dd><p>This command provides a way to delay,
by the specified number of broadcast poll intervals,
-believing backward time steps from a broadcast server.
-Broadcast time networks are expected to be trusted.
-In the event a broadcast server's time is stepped backwards,
+believing backward time steps from a broadcast server.
+Broadcast time networks are expected to be trusted.
+In the event a broadcast server&rsquo;s time is stepped backwards,
there is clear benefit to having the clients notice this change
-as soon as possible.
+as soon as possible.
Attacks such as replay attacks can happen, however,
and even though there are a number of protections built in to
-broadcast mode, attempts to perform a replay attack are possible.
+broadcast mode, attempts to perform a replay attack are possible.
This value defaults to 0, but can be changed
-to any number of poll intervals between 0 and 4.
+to any number of poll intervals between 0 and 4.
+</p></dd>
</dl>
-
-<h5 class="subsubsection">Manycast Options</h5>
-
- <dl>
-<dt><code>tos</code> <code>[ceiling </code><kbd>ceiling</kbd><code> | cohort { 0 | 1 } | floor </code><kbd>floor</kbd><code> | minclock </code><kbd>minclock</kbd><code> | minsane </code><kbd>minsane</kbd><code>]</code><dd>This command affects the clock selection and clustering
-algorithms.
+<a name="Manycast-Options"></a>
+<h4 class="subsubsection">1.1.5.4 Manycast Options</h4>
+<dl compact="compact">
+<dt><code>tos</code> <code>[<code>ceiling</code> <kbd>ceiling</kbd> | <code>cohort</code> <code>{</code> <code>0</code> | <code>1</code> <code>}</code> | <code>floor</code> <kbd>floor</kbd> | <code>minclock</code> <kbd>minclock</kbd> | <code>minsane</code> <kbd>minsane</kbd>]</code></dt>
+<dd><p>This command affects the clock selection and clustering
+algorithms.
It can be used to select the quality and
quantity of peers used to synchronize the system clock
-and is most useful in manycast mode.
+and is most useful in manycast mode.
The variables operate
as follows:
- <dl>
-<dt><code>ceiling</code> <kbd>ceiling</kbd><dd>Peers with strata above
+</p><dl compact="compact">
+<dt><code>ceiling</code> <kbd>ceiling</kbd></dt>
+<dd><p>Peers with strata above
<code>ceiling</code>
will be discarded if there are at least
<code>minclock</code>
-peers remaining.
+peers remaining.
This value defaults to 15, but can be changed
-to any number from 1 to 15.
-<br><dt><code>cohort</code> <code>{0 | 1}</code><dd>This is a binary flag which enables (0) or disables (1)
+to any number from 1 to 15.
+</p></dd>
+<dt><code>cohort</code> <code>{0 | 1}</code></dt>
+<dd><p>This is a binary flag which enables (0) or disables (1)
manycast server replies to manycast clients with the same
-stratum level.
+stratum level.
This is useful to reduce implosions where
large numbers of clients with the same stratum level
-are present.
-The default is to enable these replies.
-<br><dt><code>floor</code> <kbd>floor</kbd><dd>Peers with strata below
+are present.
+The default is to enable these replies.
+</p></dd>
+<dt><code>floor</code> <kbd>floor</kbd></dt>
+<dd><p>Peers with strata below
<code>floor</code>
will be discarded if there are at least
<code>minclock</code>
-peers remaining.
+peers remaining.
This value defaults to 1, but can be changed
-to any number from 1 to 15.
-<br><dt><code>minclock</code> <kbd>minclock</kbd><dd>The clustering algorithm repeatedly casts out outlier
+to any number from 1 to 15.
+</p></dd>
+<dt><code>minclock</code> <kbd>minclock</kbd></dt>
+<dd><p>The clustering algorithm repeatedly casts out outlier
associations until no more than
<code>minclock</code>
-associations remain.
+associations remain.
This value defaults to 3,
but can be changed to any number from 1 to the number of
-configured sources.
-<br><dt><code>minsane</code> <kbd>minsane</kbd><dd>This is the minimum number of candidates available
+configured sources.
+</p></dd>
+<dt><code>minsane</code> <kbd>minsane</kbd></dt>
+<dd><p>This is the minimum number of candidates available
to the clock selection algorithm in order to produce
-one or more truechimers for the clustering algorithm.
+one or more truechimers for the clustering algorithm.
If fewer than this number are available, the clock is
-undisciplined and allowed to run free.
+undisciplined and allowed to run free.
The default is 1
-for legacy purposes.
+for legacy purposes.
However, according to principles of
Byzantine agreement,
<code>minsane</code>
should be at least 4 in order to detect and discard
-a single falseticker.
+a single falseticker.
+</p></dd>
</dl>
- <br><dt><code>ttl</code> <kbd>hop</kbd> <kbd>...</kbd><dd>This command specifies a list of TTL values in increasing
-order, up to 8 values can be specified.
+</dd>
+<dt><code>ttl</code> <kbd>hop</kbd> <kbd>...</kbd></dt>
+<dd><p>This command specifies a list of TTL values in increasing
+order, up to 8 values can be specified.
In manycast mode these values are used in turn
-in an expanding-ring search.
+in an expanding-ring search.
The default is eight
-multiples of 32 starting at 31.
+multiples of 32 starting at 31.
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
+<hr>
<a name="Reference-Clock-Support"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Miscellaneous-Options" accesskey="n" rel="next">Miscellaneous Options</a>, Previous: <a href="#Automatic-NTP-Configuration-Options" accesskey="p" rel="prev">Automatic NTP Configuration Options</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">Reference Clock Support</h4>
-
+<a name="Reference-Clock-Support-1"></a>
+<h4 class="subsection">1.1.6 Reference Clock Support</h4>
<p>The NTP Version 4 daemon supports some three dozen different radio,
satellite and modem reference clocks plus a special pseudo-clock
-used for backup or when no other clock source is available.
+used for backup or when no other clock source is available.
Detailed descriptions of individual device drivers and options can
be found in the
-"Reference Clock Drivers"
+&quot;Reference Clock Drivers&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>).
+<samp>/usr/share/doc/ntp</samp>).
Additional information can be found in the pages linked
there, including the
-"Debugging Hints for Reference Clock Drivers"
+&quot;Debugging Hints for Reference Clock Drivers&quot;
and
-"How To Write a Reference Clock Driver"
+&quot;How To Write a Reference Clock Driver&quot;
pages
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>).
+<samp>/usr/share/doc/ntp</samp>).
In addition, support for a PPS
signal is available as described in the
-"Pulse-per-second (PPS) Signal Interfacing"
+&quot;Pulse-per-second (PPS) Signal Interfacing&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>).
+<samp>/usr/share/doc/ntp</samp>).
Many
drivers support special line discipline/streams modules which can
-significantly improve the accuracy using the driver.
+significantly improve the accuracy using the driver.
These are
described in the
-"Line Disciplines and Streams Drivers"
+&quot;Line Disciplines and Streams Drivers&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>).
-
- <p>A reference clock will generally (though not always) be a radio
+<samp>/usr/share/doc/ntp</samp>).
+</p>
+<p>A reference clock will generally (though not always) be a radio
timecode receiver which is synchronized to a source of standard
time such as the services offered by the NRC in Canada and NIST and
-USNO in the US.
+USNO in the US.
The interface between the computer and the timecode
-receiver is device dependent, but is usually a serial port.
+receiver is device dependent, but is usually a serial port.
A
device driver specific to each reference clock must be selected and
compiled in the distribution; however, most common radio, satellite
-and modem clocks are included by default.
+and modem clocks are included by default.
Note that an attempt to
configure a reference clock when the driver has not been compiled
or the hardware port has not been appropriately configured results
in a scalding remark to the system log file, but is otherwise non
hazardous.
-
- <p>For the purposes of configuration,
+</p>
+<p>For the purposes of configuration,
<code>ntpd(1ntpdmdoc)</code>
treats
reference clocks in a manner analogous to normal NTP peers as much
-as possible.
+as possible.
Reference clocks are identified by a syntactically
correct but invalid IP address, in order to distinguish them from
-normal NTP peers.
+normal NTP peers.
Reference clock addresses are of the form
<code>127.127.</code><kbd>t</kbd>.<kbd>u</kbd>,
where
@@ -2101,199 +2365,222 @@ is an integer
denoting the clock type and
<kbd>u</kbd>
indicates the unit
-number in the range 0-3.
+number in the range 0-3.
While it may seem overkill, it is in fact
sometimes useful to configure multiple reference clocks of the same
type, in which case the unit numbers must be unique.
-
- <p>The
+</p>
+<p>The
<code>server</code>
command is used to configure a reference
clock, where the
<kbd>address</kbd>
argument in that command
-is the clock address.
+is the clock address.
The
<code>key</code>,
<code>version</code>
and
<code>ttl</code>
-options are not used for reference clock support.
+options are not used for reference clock support.
The
<code>mode</code>
option is added for reference clock support, as
-described below.
+described below.
The
<code>prefer</code>
option can be useful to
persuade the server to cherish a reference clock with somewhat more
-enthusiasm than other reference clocks or peers.
+enthusiasm than other reference clocks or peers.
Further
information on this option can be found in the
-"Mitigation Rules and the prefer Keyword"
+&quot;Mitigation Rules and the prefer Keyword&quot;
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>)
-page.
+<samp>/usr/share/doc/ntp</samp>)
+page.
The
<code>minpoll</code>
and
<code>maxpoll</code>
options have
-meaning only for selected clock drivers.
+meaning only for selected clock drivers.
See the individual clock
driver document pages for additional information.
-
- <p>The
+</p>
+<p>The
<code>fudge</code>
command is used to provide additional
information for individual clock drivers and normally follows
immediately after the
<code>server</code>
-command.
+command.
The
<kbd>address</kbd>
-argument specifies the clock address.
+argument specifies the clock address.
The
<code>refid</code>
and
<code>stratum</code>
options can be used to
-override the defaults for the device.
+override the defaults for the device.
There are two optional
device-dependent time offsets and four flags that can be included
in the
<code>fudge</code>
command as well.
-
- <p>The stratum number of a reference clock is by default zero.
+</p>
+<p>The stratum number of a reference clock is by default zero.
Since the
<code>ntpd(1ntpdmdoc)</code>
daemon adds one to the stratum of each
peer, a primary server ordinarily displays an external stratum of
-one.
+one.
In order to provide engineered backups, it is often useful to
-specify the reference clock stratum as greater than zero.
+specify the reference clock stratum as greater than zero.
The
<code>stratum</code>
-option is used for this purpose.
+option is used for this purpose.
Also, in cases
involving both a reference clock and a pulse-per-second (PPS)
discipline signal, it is useful to specify the reference clock
-identifier as other than the default, depending on the driver.
+identifier as other than the default, depending on the driver.
The
<code>refid</code>
-option is used for this purpose.
+option is used for this purpose.
Except where noted,
these options apply to all clock drivers.
-
-<h5 class="subsubsection">Reference Clock Commands</h5>
-
- <dl>
-<dt><code>server</code> <code>127.127.</code><kbd>t</kbd>.<kbd>u</kbd> <code>[prefer]</code> <code>[mode </code><kbd>int</kbd><code>]</code> <code>[minpoll </code><kbd>int</kbd><code>]</code> <code>[maxpoll </code><kbd>int</kbd><code>]</code><dd>This command can be used to configure reference clocks in
-special ways.
+</p><a name="Reference-Clock-Commands"></a>
+<h4 class="subsubsection">1.1.6.1 Reference Clock Commands</h4>
+<dl compact="compact">
+<dt><code>server</code> <code>127.127.</code><kbd>t</kbd>.<kbd>u</kbd> <code>[<code>prefer</code>]</code> <code>[<code>mode</code> <kbd>int</kbd>]</code> <code>[<code>minpoll</code> <kbd>int</kbd>]</code> <code>[<code>maxpoll</code> <kbd>int</kbd>]</code></dt>
+<dd><p>This command can be used to configure reference clocks in
+special ways.
The options are interpreted as follows:
- <dl>
-<dt><code>prefer</code><dd>Marks the reference clock as preferred.
+</p><dl compact="compact">
+<dt><code>prefer</code></dt>
+<dd><p>Marks the reference clock as preferred.
All other things being
equal, this host will be chosen for synchronization among a set of
-correctly operating hosts.
+correctly operating hosts.
See the
-"Mitigation Rules and the prefer Keyword"
+&quot;Mitigation Rules and the prefer Keyword&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>)
-for further information.
-<br><dt><code>mode</code> <kbd>int</kbd><dd>Specifies a mode number which is interpreted in a
-device-specific fashion.
+<samp>/usr/share/doc/ntp</samp>)
+for further information.
+</p></dd>
+<dt><code>mode</code> <kbd>int</kbd></dt>
+<dd><p>Specifies a mode number which is interpreted in a
+device-specific fashion.
For instance, it selects a dialing
protocol in the ACTS driver and a device subtype in the
parse
-drivers.
-<br><dt><code>minpoll</code> <kbd>int</kbd><br><dt><code>maxpoll</code> <kbd>int</kbd><dd>These options specify the minimum and maximum polling interval
+drivers.
+</p></dd>
+<dt><code>minpoll</code> <kbd>int</kbd></dt>
+<dt><code>maxpoll</code> <kbd>int</kbd></dt>
+<dd><p>These options specify the minimum and maximum polling interval
for reference clock messages, as a power of 2 in seconds
For
most directly connected reference clocks, both
<code>minpoll</code>
and
<code>maxpoll</code>
-default to 6 (64 s).
+default to 6 (64 s).
For modem reference clocks,
<code>minpoll</code>
defaults to 10 (17.1 m) and
<code>maxpoll</code>
-defaults to 14 (4.5 h).
-The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+defaults to 14 (4.5 h).
+The allowable range is 4 (16 s) to 17 (36.4 h) inclusive.
+</p></dd>
</dl>
- <br><dt><code>fudge</code> <code>127.127.</code><kbd>t</kbd>.<kbd>u</kbd> <code>[time1 </code><kbd>sec</kbd><code>]</code> <code>[time2 </code><kbd>sec</kbd><code>]</code> <code>[stratum </code><kbd>int</kbd><code>]</code> <code>[refid </code><kbd>string</kbd><code>]</code> <code>[mode </code><kbd>int</kbd><code>]</code> <code>[flag1 0 | 1]</code> <code>[flag2 0 | 1]</code> <code>[flag3 0 | 1]</code> <code>[flag4 0 | 1]</code><dd>This command can be used to configure reference clocks in
-special ways.
+</dd>
+<dt><code>fudge</code> <code>127.127.</code><kbd>t</kbd>.<kbd>u</kbd> <code>[<code>time1</code> <kbd>sec</kbd>]</code> <code>[<code>time2</code> <kbd>sec</kbd>]</code> <code>[<code>stratum</code> <kbd>int</kbd>]</code> <code>[<code>refid</code> <kbd>string</kbd>]</code> <code>[<code>mode</code> <kbd>int</kbd>]</code> <code>[<code>flag1</code> <code>0</code> <code>|</code> <code>1</code>]</code> <code>[<code>flag2</code> <code>0</code> <code>|</code> <code>1</code>]</code> <code>[<code>flag3</code> <code>0</code> <code>|</code> <code>1</code>]</code> <code>[<code>flag4</code> <code>0</code> <code>|</code> <code>1</code>]</code></dt>
+<dd><p>This command can be used to configure reference clocks in
+special ways.
It must immediately follow the
<code>server</code>
-command which configures the driver.
+command which configures the driver.
Note that the same capability
is possible at run time using the
<code>ntpdc(1ntpdcmdoc)</code>
-program.
+program.
The options are interpreted as
follows:
- <dl>
-<dt><code>time1</code> <kbd>sec</kbd><dd>Specifies a constant to be added to the time offset produced by
-the driver, a fixed-point decimal number in seconds.
+</p><dl compact="compact">
+<dt><code>time1</code> <kbd>sec</kbd></dt>
+<dd><p>Specifies a constant to be added to the time offset produced by
+the driver, a fixed-point decimal number in seconds.
This is used
as a calibration constant to adjust the nominal time offset of a
particular clock to agree with an external standard, such as a
-precision PPS signal.
+precision PPS signal.
It also provides a way to correct a
systematic error or bias due to serial port or operating system
-latencies, different cable lengths or receiver internal delay.
+latencies, different cable lengths or receiver internal delay.
The
specified offset is in addition to the propagation delay provided
-by other means, such as internal DIPswitches.
+by other means, such as internal DIPswitches.
Where a calibration
for an individual system and driver is available, an approximate
-correction is noted in the driver documentation pages.
+correction is noted in the driver documentation pages.
Note: in order to facilitate calibration when more than one
radio clock or PPS signal is supported, a special calibration
-feature is available.
+feature is available.
It takes the form of an argument to the
<code>enable</code>
command described in
<a href="#Miscellaneous-Options">Miscellaneous Options</a>
page and operates as described in the
-"Reference Clock Drivers"
+&quot;Reference Clock Drivers&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span>).
-<br><dt><code>time2</code> <kbd>secs</kbd><dd>Specifies a fixed-point decimal number in seconds, which is
-interpreted in a driver-dependent way.
+<samp>/usr/share/doc/ntp</samp>).
+</p></dd>
+<dt><code>time2</code> <kbd>secs</kbd></dt>
+<dd><p>Specifies a fixed-point decimal number in seconds, which is
+interpreted in a driver-dependent way.
See the descriptions of
specific drivers in the
-"Reference Clock Drivers"
+&quot;Reference Clock Drivers&quot;
page
(available as part of the HTML documentation
provided in
-<span class="file">/usr/share/doc/ntp</span> <span class="file">).</span>
-<br><dt><code>stratum</code> <kbd>int</kbd><dd>Specifies the stratum number assigned to the driver, an integer
-between 0 and 15.
+<samp>/usr/share/doc/ntp</samp> <samp>).</samp>
+</p></dd>
+<dt><code>stratum</code> <kbd>int</kbd></dt>
+<dd><p>Specifies the stratum number assigned to the driver, an integer
+between 0 and 15.
This number overrides the default stratum number
-ordinarily assigned by the driver itself, usually zero.
-<br><dt><code>refid</code> <kbd>string</kbd><dd>Specifies an ASCII string of from one to four characters which
-defines the reference identifier used by the driver.
+ordinarily assigned by the driver itself, usually zero.
+</p></dd>
+<dt><code>refid</code> <kbd>string</kbd></dt>
+<dd><p>Specifies an ASCII string of from one to four characters which
+defines the reference identifier used by the driver.
This string
overrides the default identifier ordinarily assigned by the driver
-itself.
-<br><dt><code>mode</code> <kbd>int</kbd><dd>Specifies a mode number which is interpreted in a
-device-specific fashion.
+itself.
+</p></dd>
+<dt><code>mode</code> <kbd>int</kbd></dt>
+<dd><p>Specifies a mode number which is interpreted in a
+device-specific fashion.
For instance, it selects a dialing
protocol in the ACTS driver and a device subtype in the
parse
-drivers.
-<br><dt><code>flag1</code> <code>0</code> <code>|</code> <code>1</code><br><dt><code>flag2</code> <code>0</code> <code>|</code> <code>1</code><br><dt><code>flag3</code> <code>0</code> <code>|</code> <code>1</code><br><dt><code>flag4</code> <code>0</code> <code>|</code> <code>1</code><dd>These four flags are used for customizing the clock driver.
+drivers.
+</p></dd>
+<dt><code>flag1</code> <code>0</code> <code>|</code> <code>1</code></dt>
+<dt><code>flag2</code> <code>0</code> <code>|</code> <code>1</code></dt>
+<dt><code>flag3</code> <code>0</code> <code>|</code> <code>1</code></dt>
+<dt><code>flag4</code> <code>0</code> <code>|</code> <code>1</code></dt>
+<dd><p>These four flags are used for customizing the clock driver.
The
interpretation of these values, and whether they are used at all,
-is a function of the particular clock driver.
+is a function of the particular clock driver.
However, by
convention
<code>flag4</code>
@@ -2302,155 +2589,186 @@ data to the
<code>clockstats</code>
file configured with the
<code>filegen</code>
-command.
+command.
Further information on the
<code>filegen</code>
command can be found in
-<a href="#Monitoring-Options">Monitoring Options</a>.
+&lsquo;Monitoring Options&rsquo;.
+</p></dd>
+</dl>
+</dd>
</dl>
- </dl>
-<div class="node">
-<p><hr>
+<hr>
<a name="Miscellaneous-Options"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#ntp_002econf-Files" accesskey="n" rel="next">ntp.conf Files</a>, Previous: <a href="#Reference-Clock-Support" accesskey="p" rel="prev">Reference Clock Support</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">Miscellaneous Options</h4>
-
- <dl>
-<dt><code>broadcastdelay</code> <kbd>seconds</kbd><dd>The broadcast and multicast modes require a special calibration
+<a name="Miscellaneous-Options-1"></a>
+<h4 class="subsection">1.1.7 Miscellaneous Options</h4>
+<dl compact="compact">
+<dt><code>broadcastdelay</code> <kbd>seconds</kbd></dt>
+<dd><p>The broadcast and multicast modes require a special calibration
to determine the network delay between the local and remote
-servers.
+servers.
Ordinarily, this is done automatically by the initial
-protocol exchanges between the client and server.
+protocol exchanges between the client and server.
In some cases,
the calibration procedure may fail due to network or server access
-controls, for example.
+controls, for example.
This command specifies the default delay to
-be used under these circumstances.
+be used under these circumstances.
Typically (for Ethernet), a
-number between 0.003 and 0.007 seconds is appropriate.
+number between 0.003 and 0.007 seconds is appropriate.
The default
-when this command is not used is 0.004 seconds.
-<br><dt><code>calldelay</code> <kbd>delay</kbd><dd>This option controls the delay in seconds between the first and second
+when this command is not used is 0.004 seconds.
+</p></dd>
+<dt><code>calldelay</code> <kbd>delay</kbd></dt>
+<dd><p>This option controls the delay in seconds between the first and second
packets sent in burst or iburst mode to allow additional time for a modem
-or ISDN call to complete.
-<br><dt><code>driftfile</code> <kbd>driftfile</kbd><dd>This command specifies the complete path and name of the file used to
-record the frequency of the local clock oscillator.
+or ISDN call to complete.
+</p></dd>
+<dt><code>driftfile</code> <kbd>driftfile</kbd></dt>
+<dd><p>This command specifies the complete path and name of the file used to
+record the frequency of the local clock oscillator.
This is the same
operation as the
<code>-f</code>
-command line option.
+command line option.
If the file exists, it is read at
startup in order to set the initial frequency and then updated once per
-hour with the current frequency computed by the daemon.
+hour with the current frequency computed by the daemon.
If the file name is
specified, but the file itself does not exist, the starts with an initial
-frequency of zero and creates the file when writing it for the first time.
+frequency of zero and creates the file when writing it for the first time.
If this command is not given, the daemon will always start with an initial
frequency of zero.
-
- <p>The file format consists of a single line containing a single
+</p>
+<p>The file format consists of a single line containing a single
floating point number, which records the frequency offset measured
-in parts-per-million (PPM).
+in parts-per-million (PPM).
The file is updated by first writing
the current drift value into a temporary file and then renaming
-this file to replace the old version.
+this file to replace the old version.
This implies that
<code>ntpd(1ntpdmdoc)</code>
must have write permission for the directory the
drift file is located in, and that file system links, symbolic or
-otherwise, should be avoided.
-<br><dt><code>dscp</code> <kbd>value</kbd><dd>This option specifies the Differentiated Services Control Point (DSCP) value,
-a 6-bit code.
-The default value is 46, signifying Expedited Forwarding.
-<br><dt><code>enable</code> <code>[auth | bclient | calibrate | kernel | mode7 | monitor | ntp | stats | peer_clear_digest_early | unpeer_crypto_early | unpeer_crypto_nak_early | unpeer_digest_early]</code><br><dt><code>disable</code> <code>[auth | bclient | calibrate | kernel | mode7 | monitor | ntp | stats | peer_clear_digest_early | unpeer_crypto_early | unpeer_crypto_nak_early | unpeer_digest_early]</code><dd>Provides a way to enable or disable various server options.
-Flags not mentioned are unaffected.
+otherwise, should be avoided.
+</p></dd>
+<dt><code>dscp</code> <kbd>value</kbd></dt>
+<dd><p>This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6-bit code.
+The default value is 46, signifying Expedited Forwarding.
+</p></dd>
+<dt><code>enable</code> <code>[<code>auth</code> | <code>bclient</code> | <code>calibrate</code> | <code>kernel</code> | <code>mode7</code> | <code>monitor</code> | <code>ntp</code> | <code>stats</code> | <code>peer_clear_digest_early</code> | <code>unpeer_crypto_early</code> | <code>unpeer_crypto_nak_early</code> | <code>unpeer_digest_early</code>]</code></dt>
+<dt><code>disable</code> <code>[<code>auth</code> | <code>bclient</code> | <code>calibrate</code> | <code>kernel</code> | <code>mode7</code> | <code>monitor</code> | <code>ntp</code> | <code>stats</code> | <code>peer_clear_digest_early</code> | <code>unpeer_crypto_early</code> | <code>unpeer_crypto_nak_early</code> | <code>unpeer_digest_early</code>]</code></dt>
+<dd><p>Provides a way to enable or disable various server options.
+Flags not mentioned are unaffected.
Note that all of these flags
can be controlled remotely using the
<code>ntpdc(1ntpdcmdoc)</code>
utility program.
- <dl>
-<dt><code>auth</code><dd>Enables the server to synchronize with unconfigured peers only if the
+</p><dl compact="compact">
+<dt><code>auth</code></dt>
+<dd><p>Enables the server to synchronize with unconfigured peers only if the
peer has been correctly authenticated using either public key or
-private key cryptography.
+private key cryptography.
The default for this flag is
-<code>enable</code>.
-<br><dt><code>bclient</code><dd>Enables the server to listen for a message from a broadcast or
+<code>enable</code>.
+</p></dd>
+<dt><code>bclient</code></dt>
+<dd><p>Enables the server to listen for a message from a broadcast or
multicast server, as in the
<code>multicastclient</code>
command with default
-address.
+address.
The default for this flag is
-<code>disable</code>.
-<br><dt><code>calibrate</code><dd>Enables the calibrate feature for reference clocks.
+<code>disable</code>.
+</p></dd>
+<dt><code>calibrate</code></dt>
+<dd><p>Enables the calibrate feature for reference clocks.
The default for
this flag is
-<code>disable</code>.
-<br><dt><code>kernel</code><dd>Enables the kernel time discipline, if available.
+<code>disable</code>.
+</p></dd>
+<dt><code>kernel</code></dt>
+<dd><p>Enables the kernel time discipline, if available.
The default for this
flag is
<code>enable</code>
if support is available, otherwise
-<code>disable</code>.
-<br><dt><code>mode7</code><dd>Enables processing of NTP mode 7 implementation-specific requests
+<code>disable</code>.
+</p></dd>
+<dt><code>mode7</code></dt>
+<dd><p>Enables processing of NTP mode 7 implementation-specific requests
which are used by the deprecated
<code>ntpdc(1ntpdcmdoc)</code>
-program.
-The default for this flag is disable.
+program.
+The default for this flag is disable.
This flag is excluded from runtime configuration using
-<code>ntpq(1ntpqmdoc)</code>.
+<code>ntpq(1ntpqmdoc)</code>.
The
<code>ntpq(1ntpqmdoc)</code>
program provides the same capabilities as
<code>ntpdc(1ntpdcmdoc)</code>
-using standard mode 6 requests.
-<br><dt><code>monitor</code><dd>Enables the monitoring facility.
+using standard mode 6 requests.
+</p></dd>
+<dt><code>monitor</code></dt>
+<dd><p>Enables the monitoring facility.
See the
<code>ntpdc(1ntpdcmdoc)</code>
program
and the
<code>monlist</code>
-command or further information.
+command or further information.
The
default for this flag is
-<code>enable</code>.
-<br><dt><code>ntp</code><dd>Enables time and frequency discipline.
+<code>enable</code>.
+</p></dd>
+<dt><code>ntp</code></dt>
+<dd><p>Enables time and frequency discipline.
In effect, this switch opens and
-closes the feedback loop, which is useful for testing.
+closes the feedback loop, which is useful for testing.
The default for
this flag is
-<code>enable</code>.
-<br><dt><code>peer_clear_digest_early</code><dd>By default, if
+<code>enable</code>.
+</p></dd>
+<dt><code>peer_clear_digest_early</code></dt>
+<dd><p>By default, if
<code>ntpd(1ntpdmdoc)</code>
is using autokey and it
receives a crypto-NAK packet that
passes the duplicate packet and origin timestamp checks
-the peer variables are immediately cleared.
+the peer variables are immediately cleared.
While this is generally a feature
as it allows for quick recovery if a server key has changed,
a properly forged and appropriately delivered crypto-NAK packet
-can be used in a DoS attack.
+can be used in a DoS attack.
If you have active noticable problems with this type of DoS attack
then you should consider
-disabling this option.
+disabling this option.
You can check your
<code>peerstats</code>
-file for evidence of any of these attacks.
+file for evidence of any of these attacks.
The
default for this flag is
-<code>enable</code>.
-<br><dt><code>stats</code><dd>Enables the statistics facility.
+<code>enable</code>.
+</p></dd>
+<dt><code>stats</code></dt>
+<dd><p>Enables the statistics facility.
See the
-<a href="#Monitoring-Options">Monitoring Options</a>
-section for further information.
+&lsquo;Monitoring Options&rsquo;
+section for further information.
The default for this flag is
-<code>disable</code>.
-<br><dt><code>unpeer_crypto_early</code><dd>By default, if
+<code>disable</code>.
+</p></dd>
+<dt><code>unpeer_crypto_early</code></dt>
+<dd><p>By default, if
<code>ntpd(1ntpdmdoc)</code>
receives an autokey packet that fails TEST9,
a crypto failure,
-the association is immediately cleared.
+the association is immediately cleared.
This is almost certainly a feature,
but if, in spite of the current recommendation of not using autokey,
you are
@@ -2460,84 +2778,93 @@ using autokey
you are seeing this sort of DoS attack
disabling this flag will delay
tearing down the association until the reachability counter
-becomes zero.
+becomes zero.
You can check your
<code>peerstats</code>
-file for evidence of any of these attacks.
+file for evidence of any of these attacks.
The
default for this flag is
-<code>enable</code>.
-<br><dt><code>unpeer_crypto_nak_early</code><dd>By default, if
+<code>enable</code>.
+</p></dd>
+<dt><code>unpeer_crypto_nak_early</code></dt>
+<dd><p>By default, if
<code>ntpd(1ntpdmdoc)</code>
receives a crypto-NAK packet that
passes the duplicate packet and origin timestamp checks
-the association is immediately cleared.
+the association is immediately cleared.
While this is generally a feature
as it allows for quick recovery if a server key has changed,
a properly forged and appropriately delivered crypto-NAK packet
-can be used in a DoS attack.
+can be used in a DoS attack.
If you have active noticable problems with this type of DoS attack
then you should consider
-disabling this option.
+disabling this option.
You can check your
<code>peerstats</code>
-file for evidence of any of these attacks.
+file for evidence of any of these attacks.
The
default for this flag is
-<code>enable</code>.
-<br><dt><code>unpeer_digest_early</code><dd>By default, if
+<code>enable</code>.
+</p></dd>
+<dt><code>unpeer_digest_early</code></dt>
+<dd><p>By default, if
<code>ntpd(1ntpdmdoc)</code>
receives what should be an authenticated packet
that passes other packet sanity checks but
contains an invalid digest
-the association is immediately cleared.
+the association is immediately cleared.
While this is generally a feature
as it allows for quick recovery,
if this type of packet is carefully forged and sent
-during an appropriate window it can be used for a DoS attack.
+during an appropriate window it can be used for a DoS attack.
If you have active noticable problems with this type of DoS attack
then you should consider
-disabling this option.
+disabling this option.
You can check your
<code>peerstats</code>
-file for evidence of any of these attacks.
+file for evidence of any of these attacks.
The
default for this flag is
-<code>enable</code>.
+<code>enable</code>.
+</p></dd>
</dl>
- <br><dt><code>includefile</code> <kbd>includefile</kbd><dd>This command allows additional configuration commands
-to be included from a separate file.
+</dd>
+<dt><code>includefile</code> <kbd>includefile</kbd></dt>
+<dd><p>This command allows additional configuration commands
+to be included from a separate file.
Include files may
be nested to a depth of five; upon reaching the end of any
include file, command processing resumes in the previous
-configuration file.
+configuration file.
This option is useful for sites that run
<code>ntpd(1ntpdmdoc)</code>
on multiple hosts, with (mostly) common options (e.g., a
-restriction list).
-<br><dt><code>interface</code> <code>[listen | ignore | drop]</code> <code>[all | ipv4 | ipv6 | wildcard </code><kbd>name</kbd><code> | </code><kbd>address</kbd><code> [/ </code><kbd>prefixlen</kbd><code>]]</code><dd>The
+restriction list).
+</p></dd>
+<dt><code>interface</code> <code>[<code>listen</code> | <code>ignore</code> | <code>drop</code>]</code> <code>[<code>all</code> | <code>ipv4</code> | <code>ipv6</code> | <code>wildcard</code> <kbd>name</kbd> | <kbd>address</kbd> <code>[<code>/</code> <kbd>prefixlen</kbd>]</code>]</code></dt>
+<dd><p>The
<code>interface</code>
directive controls which network addresses
<code>ntpd(1ntpdmdoc)</code>
-opens, and whether input is dropped without processing.
+opens, and whether input is dropped without processing.
The first parameter determines the action for addresses
-which match the second parameter.
+which match the second parameter.
The second parameter specifies a class of addresses,
or a specific interface name,
-or an address.
+or an address.
In the address case,
<kbd>prefixlen</kbd>
-determines how many bits must match for this rule to apply.
+determines how many bits must match for this rule to apply.
<code>ignore</code>
prevents opening matching addresses,
<code>drop</code>
causes
<code>ntpd(1ntpdmdoc)</code>
-to open the address and drop all received packets without examination.
+to open the address and drop all received packets without examination.
Multiple
<code>interface</code>
-directives can be used.
-The last rule which matches a particular address determines the action for it.
+directives can be used.
+The last rule which matches a particular address determines the action for it.
<code>interface</code>
directives are disabled if any
<code>-I</code>,
@@ -2546,18 +2873,20 @@ directives are disabled if any
or
<code>--novirtualips</code>
command-line options are specified in the configuration file,
-all available network addresses are opened.
+all available network addresses are opened.
The
<code>nic</code>
directive is an alias for
-<code>interface</code>.
-<br><dt><code>leapfile</code> <kbd>leapfile</kbd><dd>This command loads the IERS leapseconds file and initializes the
+<code>interface</code>.
+</p></dd>
+<dt><code>leapfile</code> <kbd>leapfile</kbd></dt>
+<dd><p>This command loads the IERS leapseconds file and initializes the
leapsecond values for the next leapsecond event, leapfile expiration
-time, and TAI offset.
+time, and TAI offset.
The file can be obtained directly from the IERS at
<code>https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list</code>
or
-<code>ftp://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list</code>.
+<code>ftp://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list</code>.
The
<code>leapfile</code>
is scanned when
@@ -2566,56 +2895,60 @@ processes the
<code>leapfile</code> <code>directive</code> <code>or</code> <code>when</code>
<code>ntpd</code> <code>detects</code> <code>that</code> <code>the</code>
<kbd>leapfile</kbd>
-has changed.
+has changed.
<code>ntpd</code>
checks once a day to see if the
<kbd>leapfile</kbd>
-has changed.
+has changed.
The
<code>update-leap(1update_leapmdoc)</code>
script can be run to see if the
<kbd>leapfile</kbd>
-should be updated.
-<br><dt><code>leapsmearinterval</code> <kbd>seconds</kbd><dd>This EXPERIMENTAL option is only available if
+should be updated.
+</p></dd>
+<dt><code>leapsmearinterval</code> <kbd>seconds</kbd></dt>
+<dd><p>This EXPERIMENTAL option is only available if
<code>ntpd(1ntpdmdoc)</code>
was built with the
<code>--enable-leap-smear</code>
option to the
<code>configure</code>
-script.
-It specifies the interval over which a leap second correction will be applied.
+script.
+It specifies the interval over which a leap second correction will be applied.
Recommended values for this option are between
-7200 (2 hours) and 86400 (24 hours).
-.Sy DO NOT USE THIS OPTION ON PUBLIC-ACCESS SERVERS!
-See http://bugs.ntp.org/2855 for more information.
-<br><dt><code>logconfig</code> <kbd>configkeyword</kbd><dd>This command controls the amount and type of output written to
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
+</p></dd>
+<dt><code>logconfig</code> <kbd>configkeyword</kbd></dt>
+<dd><p>This command controls the amount and type of output written to
the system
<code>syslog(3)</code>
facility or the alternate
<code>logfile</code>
-log file.
-By default, all output is turned on.
+log file.
+By default, all output is turned on.
All
<kbd>configkeyword</kbd>
keywords can be prefixed with
-=,
-+
+&lsquo;=&rsquo;,
+&lsquo;+&rsquo;
and
--,
+&lsquo;-&rsquo;,
where
-=
+&lsquo;=&rsquo;
sets the
<code>syslog(3)</code>
priority mask,
-+
+&lsquo;+&rsquo;
adds and
--
+&lsquo;-&rsquo;
removes
-messages.
+messages.
<code>syslog(3)</code>
messages can be controlled in four
classes
-(<code>clock</code>, <code>peer</code>, <code>sys</code> and <code>sync</code>).
+(<code>clock</code>, <code>peer</code>, <code>sys</code> and <code>sync</code>).
Within these classes four types of messages can be
controlled: informational messages
(<code>info</code>),
@@ -2626,383 +2959,464 @@ statistics messages
and
status messages
(<code>status</code>).
-
- <p>Configuration keywords are formed by concatenating the message class with
-the event class.
+</p>
+<p>Configuration keywords are formed by concatenating the message class with
+the event class.
The
<code>all</code>
-prefix can be used instead of a message class.
+prefix can be used instead of a message class.
A
message class may also be followed by the
<code>all</code>
keyword to enable/disable all
-messages of the respective message class.
+messages of the respective message class.
Thus, a minimal log configuration
could look like this:
-<pre class="verbatim">
- logconfig =syncstatus +sysevents
+</p><pre class="verbatim">logconfig =syncstatus +sysevents
</pre>
-
- <p>This would just list the synchronizations state of
+<p>This would just list the synchronizations state of
<code>ntpd(1ntpdmdoc)</code>
-and the major system events.
+and the major system events.
For a simple reference server, the
following minimum message configuration could be useful:
-<pre class="verbatim">
- logconfig =syncall +clockall
+</p><pre class="verbatim">logconfig =syncall +clockall
</pre>
-
- <p>This configuration will list all clock information and
-synchronization information.
+<p>This configuration will list all clock information and
+synchronization information.
All other events and messages about
-peers, system events and so on is suppressed.
-<br><dt><code>logfile</code> <kbd>logfile</kbd><dd>This command specifies the location of an alternate log file to
+peers, system events and so on is suppressed.
+</p></dd>
+<dt><code>logfile</code> <kbd>logfile</kbd></dt>
+<dd><p>This command specifies the location of an alternate log file to
be used instead of the default system
<code>syslog(3)</code>
-facility.
+facility.
This is the same operation as the
<code>-l</code>
-command line option.
-<br><dt><code>mru</code> <code>[maxdepth </code><kbd>count</kbd><code> | maxmem </code><kbd>kilobytes</kbd><code> | mindepth </code><kbd>count</kbd><code> | maxage </code><kbd>seconds</kbd><code> | initialloc </code><kbd>count</kbd><code> | initmem </code><kbd>kilobytes</kbd><code> | incalloc </code><kbd>count</kbd><code> | incmem </code><kbd>kilobytes</kbd><code>]</code><dd>Controls size limite of the monitoring facility's Most Recently Used
+command line option.
+</p></dd>
+<dt><code>mru</code> <code>[<code>maxdepth</code> <kbd>count</kbd> | <code>maxmem</code> <kbd>kilobytes</kbd> | <code>mindepth</code> <kbd>count</kbd> | <code>maxage</code> <kbd>seconds</kbd> | <code>initialloc</code> <kbd>count</kbd> | <code>initmem</code> <kbd>kilobytes</kbd> | <code>incalloc</code> <kbd>count</kbd> | <code>incmem</code> <kbd>kilobytes</kbd>]</code></dt>
+<dd><p>Controls size limite of the monitoring facility&rsquo;s Most Recently Used
(MRU) list
of client addresses, which is also used by the
rate control facility.
- <dl>
-<dt><code>maxdepth</code> <kbd>count</kbd><br><dt><code>maxmem</code> <kbd>kilobytes</kbd><dd>Equivalent upper limits on the size of the MRU list, in terms of entries or kilobytes.
+</p><dl compact="compact">
+<dt><code>maxdepth</code> <kbd>count</kbd></dt>
+<dt><code>maxmem</code> <kbd>kilobytes</kbd></dt>
+<dd><p>Equivalent upper limits on the size of the MRU list, in terms of entries or kilobytes.
The acutal limit will be up to
<code>incalloc</code>
entries or
<code>incmem</code>
-kilobytes larger.
+kilobytes larger.
As with all of the
<code>mru</code>
options offered in units of entries or kilobytes, if both
<code>maxdepth</code>
and
<code>maxmem</code> <code>are</code> <code>used,</code> <code>the</code> <code>last</code> <code>one</code> <code>used</code> <code>controls.</code>
-The default is 1024 kilobytes.
-<br><dt><code>mindepth</code> <kbd>count</kbd><dd>Lower limit on the MRU list size.
+The default is 1024 kilobytes.
+</p></dd>
+<dt><code>mindepth</code> <kbd>count</kbd></dt>
+<dd><p>Lower limit on the MRU list size.
When the MRU list has fewer than
<code>mindepth</code>
entries, existing entries are never removed to make room for newer ones,
-regardless of their age.
-The default is 600 entries.
-<br><dt><code>maxage</code> <kbd>seconds</kbd><dd>Once the MRU list has
+regardless of their age.
+The default is 600 entries.
+</p></dd>
+<dt><code>maxage</code> <kbd>seconds</kbd></dt>
+<dd><p>Once the MRU list has
<code>mindepth</code>
entries and an additional client is to ba added to the list,
if the oldest entry was updated more than
<code>maxage</code>
-seconds ago, that entry is removed and its storage is reused.
+seconds ago, that entry is removed and its storage is reused.
If the oldest entry was updated more recently the MRU list is grown,
-subject to
-<code>maxdepth</code> <code>/</code> <code>moxmem</code>.
-The default is 64 seconds.
-<br><dt><code>initalloc</code> <kbd>count</kbd><br><dt><code>initmem</code> <kbd>kilobytes</kbd><dd>Initial memory allocation at the time the monitoringfacility is first enabled,
-in terms of the number of entries or kilobytes.
-The default is 4 kilobytes.
-<br><dt><code>incalloc</code> <kbd>count</kbd><br><dt><code>incmem</code> <kbd>kilobytes</kbd><dd>Size of additional memory allocations when growing the MRU list, in entries or kilobytes.
-The default is 4 kilobytes.
+subject to
+<code>maxdepth</code> <code>/</code> <code>moxmem</code>.
+The default is 64 seconds.
+</p></dd>
+<dt><code>initalloc</code> <kbd>count</kbd></dt>
+<dt><code>initmem</code> <kbd>kilobytes</kbd></dt>
+<dd><p>Initial memory allocation at the time the monitoringfacility is first enabled,
+in terms of the number of entries or kilobytes.
+The default is 4 kilobytes.
+</p></dd>
+<dt><code>incalloc</code> <kbd>count</kbd></dt>
+<dt><code>incmem</code> <kbd>kilobytes</kbd></dt>
+<dd><p>Size of additional memory allocations when growing the MRU list, in entries or kilobytes.
+The default is 4 kilobytes.
+</p></dd>
</dl>
- <br><dt><code>nonvolatile</code> <kbd>threshold</kbd><dd>Specify the
+</dd>
+<dt><code>nonvolatile</code> <kbd>threshold</kbd></dt>
+<dd><p>Specify the
<kbd>threshold</kbd>
delta in seconds before an hourly change to the
<code>driftfile</code>
-(frequency file) will be written, with a default value of 1e-7 (0.1 PPM).
-The frequency file is inspected each hour.
+(frequency file) will be written, with a default value of 1e-7 (0.1 PPM).
+The frequency file is inspected each hour.
If the difference between the current frequency and the last value written
exceeds the threshold, the file is written and the
<code>threshold</code>
-becomes the new threshold value.
-If the threshold is not exceeeded, it is reduced by half.
-This is intended to reduce the number of file writes
-for embedded systems with nonvolatile memory.
-<br><dt><code>phone</code> <kbd>dial</kbd> <kbd>...</kbd><dd>This command is used in conjunction with
+becomes the new threshold value.
+If the threshold is not exceeeded, it is reduced by half.
+This is intended to reduce the number of file writes
+for embedded systems with nonvolatile memory.
+</p></dd>
+<dt><code>phone</code> <kbd>dial</kbd> <kbd>...</kbd></dt>
+<dd><p>This command is used in conjunction with
the ACTS modem driver (type 18)
-or the JJY driver (type 40, mode 100 - 180).
+or the JJY driver (type 40, mode 100 - 180).
For the ACTS modem driver (type 18), the arguments consist of
a maximum of 10 telephone numbers used to dial USNO, NIST, or European
-time service.
-For the JJY driver (type 40 mode 100 - 180), the argument is
-one telephone number used to dial the telephone JJY service.
-The Hayes command ATDT is normally prepended to the number.
-The number can contain other modem control codes as well.
-<br><dt><code>reset</code> <code>[allpeers]</code> <code>[auth]</code> <code>[ctl]</code> <code>[io]</code> <code>[mem]</code> <code>[sys]</code> <code>[timer]</code><dd>Reset one or more groups of counters maintained by
+time service.
+For the JJY driver (type 40 mode 100 - 180), the argument is
+one telephone number used to dial the telephone JJY service.
+The Hayes command ATDT is normally prepended to the number.
+The number can contain other modem control codes as well.
+</p></dd>
+<dt><code>reset</code> <code>[<code>allpeers</code>]</code> <code>[<code>auth</code>]</code> <code>[<code>ctl</code>]</code> <code>[<code>io</code>]</code> <code>[<code>mem</code>]</code> <code>[<code>sys</code>]</code> <code>[<code>timer</code>]</code></dt>
+<dd><p>Reset one or more groups of counters maintained by
<code>ntpd</code>
and exposed by
<code>ntpq</code>
and
-<code>ntpdc</code>.
-<br><dt><code>rlimit</code> <code>[memlock </code><kbd>Nmegabytes</kbd><code> | stacksize </code><kbd>N4kPages</kbd><code> filenum </code><kbd>Nfiledescriptors</kbd><code>]</code><dd>
- <dl>
-<dt><code>memlock</code> <kbd>Nmegabytes</kbd><dd>Specify the number of megabytes of memory that should be
-allocated and locked.
+<code>ntpdc</code>.
+</p></dd>
+<dt><code>rlimit</code> <code>[<code>memlock</code> <kbd>Nmegabytes</kbd> | <code>stacksize</code> <kbd>N4kPages</kbd> <code>filenum</code> <kbd>Nfiledescriptors</kbd>]</code></dt>
+<dd><dl compact="compact">
+<dt><code>memlock</code> <kbd>Nmegabytes</kbd></dt>
+<dd><p>Specify the number of megabytes of memory that should be
+allocated and locked.
Probably only available under Linux, this option may be useful
when dropping root (the
<code>-i</code>
-option).
-The default is 32 megabytes on non-Linux machines, and -1 under Linux.
--1 means "do not lock the process into memory".
-0 means "lock whatever memory the process wants into memory".
-<br><dt><code>stacksize</code> <kbd>N4kPages</kbd><dd>Specifies the maximum size of the process stack on systems with the
+option).
+The default is 32 megabytes on non-Linux machines, and -1 under Linux.
+-1 means &quot;do not lock the process into memory&quot;.
+0 means &quot;lock whatever memory the process wants into memory&quot;.
+</p></dd>
+<dt><code>stacksize</code> <kbd>N4kPages</kbd></dt>
+<dd><p>Specifies the maximum size of the process stack on systems with the
<code>mlockall()</code>
-function.
-Defaults to 50 4k pages (200 4k pages in OpenBSD).
-<br><dt><code>filenum</code> <kbd>Nfiledescriptors</kbd><dd>Specifies the maximum number of file descriptors ntpd may have open at once.
-Defaults to the system default.
+function.
+Defaults to 50 4k pages (200 4k pages in OpenBSD).
+</p></dd>
+<dt><code>filenum</code> <kbd>Nfiledescriptors</kbd></dt>
+<dd><p>Specifies the maximum number of file descriptors ntpd may have open at once.
+Defaults to the system default.
+</p></dd>
</dl>
- <br><dt><code>saveconfigdir</code> <kbd>directory_path</kbd><dd>Specify the directory in which to write configuration snapshots
+</dd>
+<dt><code>saveconfigdir</code> <kbd>directory_path</kbd></dt>
+<dd><p>Specify the directory in which to write configuration snapshots
requested with
-.Cm ntpq 's
+.Cm ntpq &rsquo;s
<code>saveconfig</code>
-command.
+command.
If
<code>saveconfigdir</code>
does not appear in the configuration file,
<code>saveconfig</code>
requests are rejected by
-<code>ntpd</code>.
-<br><dt><code>saveconfig</code> <kbd>filename</kbd><dd>Write the current configuration, including any runtime
+<code>ntpd</code>.
+</p></dd>
+<dt><code>saveconfig</code> <kbd>filename</kbd></dt>
+<dd><p>Write the current configuration, including any runtime
modifications given with
<code>:config</code>
or
<code>config-from-file</code>
to the
<code>ntpd</code>
-host's
+host&rsquo;s
<kbd>filename</kbd>
in the
-<code>saveconfigdir</code>.
+<code>saveconfigdir</code>.
This command will be rejected unless the
<code>saveconfigdir</code>
directive appears in
-.Cm ntpd 's
-configuration file.
+.Cm ntpd &rsquo;s
+configuration file.
<kbd>filename</kbd>
can use
<code>strftime(3)</code>
format directives to substitute the current date and time,
for example,
-<code>saveconfig\ ntp-%Y%m%d-%H%M%S.conf</code>.
+<code>saveconfig\ ntp-%Y%m%d-%H%M%S.conf</code>.
The filename used is stored in the system variable
-<code>savedconfig</code>.
-Authentication is required.
-<br><dt><code>setvar</code> <kbd>variable</kbd> <code>[default]</code><dd>This command adds an additional system variable.
+<code>savedconfig</code>.
+Authentication is required.
+</p></dd>
+<dt><code>setvar</code> <kbd>variable</kbd> <code>[<code>default</code>]</code></dt>
+<dd><p>This command adds an additional system variable.
These
variables can be used to distribute additional information such as
-the access policy.
+the access policy.
If the variable of the form
<code>name</code><code>=</code><kbd>value</kbd>
is followed by the
<code>default</code>
keyword, the
variable will be listed as part of the default system variables
-(<code>rv</code> command)).
+(<code>rv</code> command)).
These additional variables serve
-informational purposes only.
+informational purposes only.
They are not related to the protocol
-other that they can be listed.
+other that they can be listed.
The known protocol variables will
always override any variables defined via the
<code>setvar</code>
-mechanism.
+mechanism.
There are three special variables that contain the names
-of all variable of the same group.
+of all variable of the same group.
The
<code>sys_var_list</code>
holds
-the names of all system variables.
+the names of all system variables.
The
<code>peer_var_list</code>
holds
the names of all peer variables and the
<code>clock_var_list</code>
-holds the names of the reference clock variables.
-<br><dt><code>sysinfo</code><dd>Display operational summary.
-<br><dt><code>sysstats</code><dd>Show statistics counters maintained in the protocol module.
-<br><dt><code>tinker</code> <code>[allan </code><kbd>allan</kbd><code> | dispersion </code><kbd>dispersion</kbd><code> | freq </code><kbd>freq</kbd><code> | huffpuff </code><kbd>huffpuff</kbd><code> | panic </code><kbd>panic</kbd><code> | step </code><kbd>step</kbd><code> | stepback </code><kbd>stepback</kbd><code> | stepfwd </code><kbd>stepfwd</kbd><code> | stepout </code><kbd>stepout</kbd><code>]</code><dd>This command can be used to alter several system variables in
-very exceptional circumstances.
+holds the names of the reference clock variables.
+</p></dd>
+<dt><code>sysinfo</code></dt>
+<dd><p>Display operational summary.
+</p></dd>
+<dt><code>sysstats</code></dt>
+<dd><p>Show statistics counters maintained in the protocol module.
+</p></dd>
+<dt><code>tinker</code> <code>[<code>allan</code> <kbd>allan</kbd> | <code>dispersion</code> <kbd>dispersion</kbd> | <code>freq</code> <kbd>freq</kbd> | <code>huffpuff</code> <kbd>huffpuff</kbd> | <code>panic</code> <kbd>panic</kbd> | <code>step</code> <kbd>step</kbd> | <code>stepback</code> <kbd>stepback</kbd> | <code>stepfwd</code> <kbd>stepfwd</kbd> | <code>stepout</code> <kbd>stepout</kbd>]</code></dt>
+<dd><p>This command can be used to alter several system variables in
+very exceptional circumstances.
It should occur in the
-configuration file before any other configuration options.
+configuration file before any other configuration options.
The
default values of these variables have been carefully optimized for
-a wide range of network speeds and reliability expectations.
+a wide range of network speeds and reliability expectations.
In
general, they interact in intricate ways that are hard to predict
-and some combinations can result in some very nasty behavior.
+and some combinations can result in some very nasty behavior.
Very
rarely is it necessary to change the default values; but, some
folks cannot resist twisting the knobs anyway and this command is
-for them.
+for them.
Emphasis added: twisters are on their own and can expect
no help from the support group.
-
- <p>The variables operate as follows:
- <dl>
-<dt><code>allan</code> <kbd>allan</kbd><dd>The argument becomes the new value for the minimum Allan
+</p>
+<p>The variables operate as follows:
+</p><dl compact="compact">
+<dt><code>allan</code> <kbd>allan</kbd></dt>
+<dd><p>The argument becomes the new value for the minimum Allan
intercept, which is a parameter of the PLL/FLL clock discipline
-algorithm.
+algorithm.
The value in log2 seconds defaults to 7 (1024 s), which is also the lower
-limit.
-<br><dt><code>dispersion</code> <kbd>dispersion</kbd><dd>The argument becomes the new value for the dispersion increase rate,
-normally .000015 s/s.
-<br><dt><code>freq</code> <kbd>freq</kbd><dd>The argument becomes the initial value of the frequency offset in
-parts-per-million.
+limit.
+</p></dd>
+<dt><code>dispersion</code> <kbd>dispersion</kbd></dt>
+<dd><p>The argument becomes the new value for the dispersion increase rate,
+normally .000015 s/s.
+</p></dd>
+<dt><code>freq</code> <kbd>freq</kbd></dt>
+<dd><p>The argument becomes the initial value of the frequency offset in
+parts-per-million.
This overrides the value in the frequency file, if
-present, and avoids the initial training state if it is not.
-<br><dt><code>huffpuff</code> <kbd>huffpuff</kbd><dd>The argument becomes the new value for the experimental
-huff-n'-puff filter span, which determines the most recent interval
-the algorithm will search for a minimum delay.
+present, and avoids the initial training state if it is not.
+</p></dd>
+<dt><code>huffpuff</code> <kbd>huffpuff</kbd></dt>
+<dd><p>The argument becomes the new value for the experimental
+huff-n&rsquo;-puff filter span, which determines the most recent interval
+the algorithm will search for a minimum delay.
The lower limit is
-900 s (15 m), but a more reasonable value is 7200 (2 hours).
+900 s (15 m), but a more reasonable value is 7200 (2 hours).
There
is no default, since the filter is not enabled unless this command
-is given.
-<br><dt><code>panic</code> <kbd>panic</kbd><dd>The argument is the panic threshold, normally 1000 s.
+is given.
+</p></dd>
+<dt><code>panic</code> <kbd>panic</kbd></dt>
+<dd><p>The argument is the panic threshold, normally 1000 s.
If set to zero,
the panic sanity check is disabled and a clock offset of any value will
-be accepted.
-<br><dt><code>step</code> <kbd>step</kbd><dd>The argument is the step threshold, which by default is 0.128 s.
+be accepted.
+</p></dd>
+<dt><code>step</code> <kbd>step</kbd></dt>
+<dd><p>The argument is the step threshold, which by default is 0.128 s.
It can
-be set to any positive number in seconds.
+be set to any positive number in seconds.
If set to zero, step
-adjustments will never occur.
+adjustments will never occur.
Note: The kernel time discipline is
disabled if the step threshold is set to zero or greater than the
-default.
-<br><dt><code>stepback</code> <kbd>stepback</kbd><dd>The argument is the step threshold for the backward direction,
-which by default is 0.128 s.
+default.
+</p></dd>
+<dt><code>stepback</code> <kbd>stepback</kbd></dt>
+<dd><p>The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
It can
-be set to any positive number in seconds.
+be set to any positive number in seconds.
If both the forward and backward step thresholds are set to zero, step
-adjustments will never occur.
+adjustments will never occur.
Note: The kernel time discipline is
disabled if
each direction of step threshold are either
-set to zero or greater than .5 second.
-<br><dt><code>stepfwd</code> <kbd>stepfwd</kbd><dd>As for stepback, but for the forward direction.
-<br><dt><code>stepout</code> <kbd>stepout</kbd><dd>The argument is the stepout timeout, which by default is 900 s.
+set to zero or greater than .5 second.
+</p></dd>
+<dt><code>stepfwd</code> <kbd>stepfwd</kbd></dt>
+<dd><p>As for stepback, but for the forward direction.
+</p></dd>
+<dt><code>stepout</code> <kbd>stepout</kbd></dt>
+<dd><p>The argument is the stepout timeout, which by default is 900 s.
It can
-be set to any positive number in seconds.
+be set to any positive number in seconds.
If set to zero, the stepout
-pulses will not be suppressed.
+pulses will not be suppressed.
+</p></dd>
</dl>
- <br><dt><code>writevar</code> <kbd>assocID\ name</kbd> <kbd>=</kbd> <kbd>value</kbd> <kbd>[,...]</kbd><dd>Write (create or update) the specified variables.
+</dd>
+<dt><code>writevar</code> <kbd>assocID\ name</kbd> <kbd>=</kbd> <kbd>value</kbd> <kbd>[,...]</kbd></dt>
+<dd><p>Write (create or update) the specified variables.
If the
<code>assocID</code>
is zero, the variablea re from the
system variables
name space, otherwise they are from the
peer variables
-name space.
+name space.
The
<code>assocID</code>
-is required, as the same name can occur in both name spaces.
-<br><dt><code>trap</code> <kbd>host_address</kbd> <code>[port </code><kbd>port_number</kbd><code>]</code> <code>[interface </code><kbd>interface_address</kbd><code>]</code><dd>This command configures a trap receiver at the given host
+is required, as the same name can occur in both name spaces.
+</p></dd>
+<dt><code>trap</code> <kbd>host_address</kbd> <code>[<code>port</code> <kbd>port_number</kbd>]</code> <code>[<code>interface</code> <kbd>interface_address</kbd>]</code></dt>
+<dd><p>This command configures a trap receiver at the given host
address and port number for sending messages with the specified
-local interface address.
+local interface address.
If the port number is unspecified, a value
-of 18447 is used.
+of 18447 is used.
If the interface address is not specified, the
message is sent with a source address of the local interface the
-message is sent through.
+message is sent through.
Note that on a multihomed host the
-interface used may vary from time to time with routing changes.
-<br><dt><code>ttl</code> <kbd>hop</kbd> <kbd>...</kbd><dd>This command specifies a list of TTL values in increasing order.
-Up to 8 values can be specified.
+interface used may vary from time to time with routing changes.
+</p></dd>
+<dt><code>ttl</code> <kbd>hop</kbd> <kbd>...</kbd></dt>
+<dd><p>This command specifies a list of TTL values in increasing order.
+Up to 8 values can be specified.
In
<code>manycast</code>
-mode these values are used in-turn in an expanding-ring search.
+mode these values are used in-turn in an expanding-ring search.
The default is eight multiples of 32 starting at 31.
-
- <p>The trap receiver will generally log event messages and other
-information from the server in a log file.
+</p>
+<p>The trap receiver will generally log event messages and other
+information from the server in a log file.
While such monitor
programs may also request their own trap dynamically, configuring a
trap receiver will ensure that no messages are lost when the server
-is started.
-<br><dt><code>hop</code> <kbd>...</kbd><dd>This command specifies a list of TTL values in increasing order, up to 8
-values can be specified.
+is started.
+</p></dd>
+<dt><code>hop</code> <kbd>...</kbd></dt>
+<dd><p>This command specifies a list of TTL values in increasing order, up to 8
+values can be specified.
In manycast mode these values are used in turn in
-an expanding-ring search.
+an expanding-ring search.
The default is eight multiples of 32 starting at
-31.
+31.
+</p></dd>
</dl>
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp.conf</code> program.
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp.conf</code> program.
This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntp_002econf-Files">ntp.conf Files</a>: Files
-<li><a accesskey="2" href="#ntp_002econf-See-Also">ntp.conf See Also</a>: See Also
-<li><a accesskey="3" href="#ntp_002econf-Bugs">ntp.conf Bugs</a>: Bugs
-<li><a accesskey="4" href="#ntp_002econf-Notes">ntp.conf Notes</a>: Notes
-</ul>
-
-<div class="node">
-<p><hr>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-Files" accesskey="1">ntp.conf Files</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Files
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-See-Also" accesskey="2">ntp.conf See Also</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">See Also
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-Bugs" accesskey="3">ntp.conf Bugs</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Bugs
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002econf-Notes" accesskey="4">ntp.conf Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Notes
+</td></tr>
+</table>
+
+<hr>
<a name="ntp_002econf-Files"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#ntp_002econf-See-Also" accesskey="n" rel="next">ntp.conf See Also</a>, Previous: <a href="#Miscellaneous-Options" accesskey="p" rel="prev">Miscellaneous Options</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp.conf Files</h4>
-
- <dl>
-<dt><span class="file">/etc/ntp.conf</span><dd>the default name of the configuration file
-<br><dt><span class="file">ntp.keys</span><dd>private MD5 keys
-<br><dt><span class="file">ntpkey</span><dd>RSA private key
-<br><dt><span class="file">ntpkey_</span><kbd>host</kbd><dd>RSA public key
-<br><dt><span class="file">ntp_dh</span><dd>Diffie-Hellman agreement parameters
+<a name="ntp_002econf-Files-1"></a>
+<h4 class="subsection">1.1.8 ntp.conf Files</h4>
+<dl compact="compact">
+<dt><samp>/etc/ntp.conf</samp></dt>
+<dd><p>the default name of the configuration file
+</p></dd>
+<dt><samp>ntp.keys</samp></dt>
+<dd><p>private MD5 keys
+</p></dd>
+<dt><samp>ntpkey</samp></dt>
+<dd><p>RSA private key
+</p></dd>
+<dt><samp>ntpkey_</samp><kbd>host</kbd></dt>
+<dd><p>RSA public key
+</p></dd>
+<dt><samp>ntp_dh</samp></dt>
+<dd><p>Diffie-Hellman agreement parameters
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
+<hr>
<a name="ntp_002econf-See-Also"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#ntp_002econf-Bugs" accesskey="n" rel="next">ntp.conf Bugs</a>, Previous: <a href="#ntp_002econf-Files" accesskey="p" rel="prev">ntp.conf Files</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp.conf See Also</h4>
-
+<a name="ntp_002econf-See-Also-1"></a>
+<h4 class="subsection">1.1.9 ntp.conf See Also</h4>
<p><code>ntpd(1ntpdmdoc)</code>,
<code>ntpdc(1ntpdcmdoc)</code>,
<code>ntpq(1ntpqmdoc)</code>
-
- <p>In addition to the manual pages provided,
+</p>
+<p>In addition to the manual pages provided,
comprehensive documentation is available on the world wide web
at
-<code>http://www.ntp.org/</code>.
+<code>http://www.ntp.org/</code>.
A snapshot of this documentation is available in HTML format in
-<span class="file">/usr/share/doc/ntp</span>.
+<samp>/usr/share/doc/ntp</samp>.
<br>
-
- <p><br>
-David L. Mills, <em>Network Time Protocol (Version 4)</em>, RFC5905
-<div class="node">
-<p><hr>
-<a name="ntp_002econf-Bugs"></a>
+</p>
<br>
+<p>David L. Mills, <em>Network Time Protocol (Version 4)</em>, RFC5905
+</p><hr>
+<a name="ntp_002econf-Bugs"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntp_002econf-See-Also" accesskey="p" rel="prev">ntp.conf See Also</a>, Up: <a href="#ntp_002econf-Notes" accesskey="u" rel="up">ntp.conf Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp.conf Bugs</h4>
-
+<a name="ntp_002econf-Bugs-1"></a>
+<h4 class="subsection">1.1.10 ntp.conf Bugs</h4>
<p>The syntax checking is not picky; some combinations of
ridiculous and even hilarious options and modes may not be
detected.
-
- <p>The
-<span class="file">ntpkey_</span><kbd>host</kbd>
+</p>
+<p>The
+<samp>ntpkey_</samp><kbd>host</kbd>
files are really digital
-certificates.
+certificates.
These should be obtained via secure directory
-services when they become universally available.
-<div class="node">
-<p><hr>
-<a name="ntp_002econf-Notes"></a>
-<br>
+services when they become universally available.
+</p><hr>
+<div class="header">
+<p>
+ &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp.conf Notes</h4>
-
+<a name="ntp_002econf-Notes-1"></a>
+<h4 class="subsection">1.1.11 ntp.conf Notes</h4>
<p>This document was derived from FreeBSD.
+</p><hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/ntpd/ntp.conf.man.in b/contrib/ntp/ntpd/ntp.conf.man.in
index 0f2b211..d1d9ca5 100644
--- a/contrib/ntp/ntpd/ntp.conf.man.in
+++ b/contrib/ntp/ntpd/ntp.conf.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntp.conf 5 "27 Feb 2018" "4.2.8p11" "File Formats"
+.TH ntp.conf 5 "20 Feb 2019" "4.2.8p13" "File Formats"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-LkaqTP/ag-XkaiSP)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:22 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:43 AM by AutoGen 5.18.5
.\" From the definitions ntp.conf.def
.\" and the template file agman-cmd.tpl
.SH NAME
@@ -326,7 +326,7 @@ option.
All packets sent to and received from the server or peer are to
include authentication fields encrypted using the specified
\f\*[I-Font]key\f[]
-identifier with values from 1 to 65534, inclusive.
+identifier with values from 1 to 65535, inclusive.
The
default is to include no encryption field.
.TP 7
@@ -611,7 +611,7 @@ and reports at the NTP project page linked from
\f[C]http://www.ntp.org/\f[].
.SS Symmetric-Key Cryptography
The original RFC-1305 specification allows any one of possibly
-65,534 keys, each distinguished by a 32-bit key identifier, to
+65,535 keys, each distinguished by a 32-bit key identifier, to
authenticate an association.
The servers and clients involved must
agree on the key and key identifier to
@@ -932,7 +932,7 @@ The
\f\*[I-Font]key\f[]
argument is
the key identifier for a trusted key, where the value can be in the
-range 1 to 65,534, inclusive.
+range 1 to 65,535, inclusive.
.TP 7
.NOP \f\*[B-Font]crypto\f[] [\f\*[B-Font]cert\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]leap\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]randfile\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]host\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]sign\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]gq\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]gqpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]iffpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]mvpar\f[] \f\*[I-Font]file\f[]] [\f\*[B-Font]pw\f[] \f\*[I-Font]password\f[]]
This command requires the OpenSSL library.
@@ -1038,7 +1038,7 @@ The
\f\*[I-Font]key\f[]
argument is a key identifier
for the trusted key, where the value can be in the range 1 to
-65,534, inclusive.
+65,535, inclusive.
.TP 7
.NOP \f\*[B-Font]revoke\f[] \f\*[I-Font]logsec\f[]
Specifies the interval between re-randomization of certain
@@ -1067,7 +1067,7 @@ servers.
The
\f\*[I-Font]key\f[]
arguments are 32-bit unsigned
-integers with values from 1 to 65,534.
+integers with values from 1 to 65,535.
.PP
.SS Error Codes
The following error codes are reported via the NTP control
diff --git a/contrib/ntp/ntpd/ntp.conf.mdoc.in b/contrib/ntp/ntpd/ntp.conf.mdoc.in
index 321acc9..a1c795d 100644
--- a/contrib/ntp/ntpd/ntp.conf.mdoc.in
+++ b/contrib/ntp/ntpd/ntp.conf.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTP_CONF 5 File Formats
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:42 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:34 AM by AutoGen 5.18.5
.\" From the definitions ntp.conf.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -325,7 +325,7 @@ option.
All packets sent to and received from the server or peer are to
include authentication fields encrypted using the specified
.Ar key
-identifier with values from 1 to 65534, inclusive.
+identifier with values from 1 to 65535, inclusive.
The
default is to include no encryption field.
.It Cm minpoll Ar minpoll
@@ -583,7 +583,7 @@ and reports at the NTP project page linked from
.Li http://www.ntp.org/ .
.Ss Symmetric\-Key Cryptography
The original RFC\-1305 specification allows any one of possibly
-65,534 keys, each distinguished by a 32\-bit key identifier, to
+65,535 keys, each distinguished by a 32\-bit key identifier, to
authenticate an association.
The servers and clients involved must
agree on the key and key identifier to
@@ -877,7 +877,7 @@ The
.Ar key
argument is
the key identifier for a trusted key, where the value can be in the
-range 1 to 65,534, inclusive.
+range 1 to 65,535, inclusive.
.It Xo Ic crypto
.Op Cm cert Ar file
.Op Cm leap Ar file
@@ -981,7 +981,7 @@ The
.Ar key
argument is a key identifier
for the trusted key, where the value can be in the range 1 to
-65,534, inclusive.
+65,535, inclusive.
.It Ic revoke Ar logsec
Specifies the interval between re\-randomization of certain
cryptographic values used by the Autokey scheme, as a power of 2 in
@@ -1008,7 +1008,7 @@ servers.
The
.Ar key
arguments are 32\-bit unsigned
-integers with values from 1 to 65,534.
+integers with values from 1 to 65,535.
.El
.Ss Error Codes
The following error codes are reported via the NTP control
diff --git a/contrib/ntp/ntpd/ntp.keys.5man b/contrib/ntp/ntpd/ntp.keys.5man
index b107e02..2642c56 100644
--- a/contrib/ntp/ntpd/ntp.keys.5man
+++ b/contrib/ntp/ntpd/ntp.keys.5man
@@ -1,8 +1,8 @@
-.TH ntp.keys 5man "27 Feb 2018" "4.2.8p11" "File Formats"
+.TH ntp.keys 5man "20 Feb 2019" "4.2.8p13" "File Formats"
.\"
.\" EDIT THIS FILE WITH CAUTION (ntp.man)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:26 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:44 AM by AutoGen 5.18.5
.\" From the definitions ntp.keys.def
.\" and the template file agman-file.tpl
.Sh NAME
@@ -54,7 +54,7 @@ statement in the configuration file.
While key number 0 is fixed by the NTP standard
(as 56 zero bits)
and may not be changed,
-one or more keys numbered between 1 and 65534
+one or more keys numbered between 1 and 65535
may be arbitrarily set in the keys file.
.sp \n(Ppu
.ne 2
@@ -73,7 +73,7 @@ Key entries use a fixed format of the form
where
\f\*[I-Font]keyno\f[]
-is a positive integer (between 1 and 65534),
+is a positive integer (between 1 and 65535),
\f\*[I-Font]type\f[]
is the message digest algorithm,
\f\*[I-Font]key\f[]
diff --git a/contrib/ntp/ntpd/ntp.keys.5mdoc b/contrib/ntp/ntpd/ntp.keys.5mdoc
index bec3980..8a2dbcbc 100644
--- a/contrib/ntp/ntpd/ntp.keys.5mdoc
+++ b/contrib/ntp/ntpd/ntp.keys.5mdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTP_KEYS 5mdoc File Formats
-.Os SunOS 5.10
+.Os FreeBSD 11.2-RELEASE_SI
.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:46 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:35 AM by AutoGen 5.18.5
.\" From the definitions ntp.keys.def
.\" and the template file agmdoc-file.tpl
.Sh NAME
@@ -37,7 +37,7 @@ statement in the configuration file.
While key number 0 is fixed by the NTP standard
(as 56 zero bits)
and may not be changed,
-one or more keys numbered between 1 and 65534
+one or more keys numbered between 1 and 65535
may be arbitrarily set in the keys file.
.Pp
The key file uses the same comment conventions
@@ -48,7 +48,7 @@ Key entries use a fixed format of the form
.Pp
where
.Ar keyno
-is a positive integer (between 1 and 65534),
+is a positive integer (between 1 and 65535),
.Ar type
is the message digest algorithm,
.Ar key
diff --git a/contrib/ntp/ntpd/ntp.keys.def b/contrib/ntp/ntpd/ntp.keys.def
index 88dd2aa..e73ce4d 100644
--- a/contrib/ntp/ntpd/ntp.keys.def
+++ b/contrib/ntp/ntpd/ntp.keys.def
@@ -36,7 +36,7 @@ statement in the configuration file.
While key number 0 is fixed by the NTP standard
(as 56 zero bits)
and may not be changed,
-one or more keys numbered between 1 and 65534
+one or more keys numbered between 1 and 65535
may be arbitrarily set in the keys file.
.Pp
The key file uses the same comment conventions
@@ -47,7 +47,7 @@ Key entries use a fixed format of the form
.Pp
where
.Ar keyno
-is a positive integer (between 1 and 65534),
+is a positive integer (between 1 and 65535),
.Ar type
is the message digest algorithm,
.Ar key
diff --git a/contrib/ntp/ntpd/ntp.keys.html b/contrib/ntp/ntpd/ntp.keys.html
index 28a4076..08d8922 100644
--- a/contrib/ntp/ntpd/ntp.keys.html
+++ b/contrib/ntp/ntpd/ntp.keys.html
@@ -1,103 +1,145 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>NTP Symmetric Key</title>
-<meta http-equiv="Content-Type" content="text/html">
+
<meta name="description" content="NTP Symmetric Key">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta name="keywords" content="NTP Symmetric Key">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">NTP Symmetric Key</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002ekeys-Description">ntp.keys Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">NTP's Symmetric Key File User Manual</h2>
+<body lang="en">
+<h1 class="settitle" align="center">NTP Symmetric Key</h1>
-<p>This document describes the symmetric key file for the NTP Project's
-<code>ntpd</code> program.
- <p>This document applies to version 4.2.8p11 of <code>ntp.keys</code>.
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">NTP's Symmetric Key File User Manual</a>
-</ul>
+
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002ekeys-Description" accesskey="n" rel="next">ntp.keys Description</a>, Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
</div>
+<a name="NTP_0027s-Symmetric-Key-File-User-Manual"></a>
+<h1 class="top">NTP&rsquo;s Symmetric Key File User Manual</h1>
-<ul class="menu">
-<li><a accesskey="1" href="#ntp_002ekeys-Description">ntp.keys Description</a>
-<li><a accesskey="2" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>
-</ul>
+<p>This document describes the symmetric key file for the NTP Project&rsquo;s
+<code>ntpd</code> program.
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntp.keys</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
-<div class="node">
-<p><hr>
-<a name="ntp_002ekeys-Description"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Description" href="#toc-Description">1 Description</a></li>
+</ul>
</div>
-<!-- node-name, next, previous, up -->
-<h3 class="section">Description</h3>
+
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002ekeys-Description" accesskey="1">ntp.keys Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002ekeys-Notes" accesskey="2">ntp.keys Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="ntp_002ekeys-Description"></a>
+<div class="header">
+<p>
+Previous: <a href="#Top" accesskey="p" rel="prev">Top</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
+</div>
+<a name="Description"></a>
+<h2 class="chapter">1 Description</h2>
<p>The name and location of the symmetric key file for <code>ntpd</code> can
be specified in a configuration file, by default <code>/etc/ntp.keys</code>.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002ekeys-Notes" accesskey="1">ntp.keys Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
-<div class="node">
-<p><hr>
+<hr>
<a name="ntp_002ekeys-Notes"></a>
-<br>
+<div class="header">
+<p>
+Previous: <a href="#ntp_002ekeys-See-Also" accesskey="p" rel="prev">ntp.keys See Also</a>, Up: <a href="#ntp_002ekeys-Description" accesskey="u" rel="up">ntp.keys Description</a> &nbsp; </p>
</div>
+<a name="Notes-about-ntp_002ekeys"></a>
+<h3 class="section">1.1 Notes about ntp.keys</h3>
+<a name="index-ntp_002ekeys"></a>
+<a name="index-NTP-symmetric-key-file-format"></a>
-<h3 class="section">Notes about ntp.keys</h3>
-<p><a name="index-ntp_002ekeys-1"></a><a name="index-NTP-symmetric-key-file-format-2"></a>
- <p>This document describes the format of an NTP symmetric key file.
+<p>This document describes the format of an NTP symmetric key file.
For a description of the use of this type of file, see the
-"Authentication Support"
+&quot;Authentication Support&quot;
section of the
<code>ntp.conf(5)</code>
page.
-
- <p><code>ntpd(8)</code>
+</p>
+<p><code>ntpd(8)</code>
reads its keys from a file specified using the
<code>-k</code>
command line option or the
<code>keys</code>
-statement in the configuration file.
+statement in the configuration file.
While key number 0 is fixed by the NTP standard
(as 56 zero bits)
and may not be changed,
-one or more keys numbered between 1 and 65534
+one or more keys numbered between 1 and 65535
may be arbitrarily set in the keys file.
-
- <p>The key file uses the same comment conventions
-as the configuration file.
+</p>
+<p>The key file uses the same comment conventions
+as the configuration file.
Key entries use a fixed format of the form
+</p>
+<div class="example">
+<pre class="example"><kbd>keyno</kbd> <kbd>type</kbd> <kbd>key</kbd> <kbd>opt_IP_list</kbd>
+</pre></div>
-<pre class="example"> <kbd>keyno</kbd> <kbd>type</kbd> <kbd>key</kbd> <kbd>opt_IP_list</kbd>
-</pre>
- <p>where
+<p>where
<kbd>keyno</kbd>
-is a positive integer (between 1 and 65534),
+is a positive integer (between 1 and 65535),
<kbd>type</kbd>
is the message digest algorithm,
<kbd>key</kbd>
@@ -106,111 +148,120 @@ is the key itself, and
is an optional comma-separated list of IPs
where the
<kbd>keyno</kbd>
-should be trusted.
-that are allowed to serve time.
+should be trusted.
+that are allowed to serve time.
Each IP in
<kbd>opt_IP_list</kbd>
may contain an optional
<code>/subnetbits</code>
specification which identifies the number of bits for
-the desired subnet of trust.
+the desired subnet of trust.
If
<kbd>opt_IP_list</kbd>
is empty,
any properly-authenticated message will be
accepted.
-
- <p>The
+</p>
+<p>The
<kbd>key</kbd>
may be given in a format
controlled by the
<kbd>type</kbd>
-field.
+field.
The
<kbd>type</kbd>
<code>MD5</code>
-is always supported.
+is always supported.
If
<code>ntpd</code>
was built with the OpenSSL library
-then any digest library supported by that library may be specified.
+then any digest library supported by that library may be specified.
However, if compliance with FIPS 140-2 is required the
<kbd>type</kbd>
must be either
<code>SHA</code>
or
<code>SHA1</code>.
-
- <p>What follows are some key types, and corresponding formats:
-
- <dl>
-<dt><code>MD5</code><dd>The key is 1 to 16 printable characters terminated by
+</p>
+<p>What follows are some key types, and corresponding formats:
+</p>
+<dl compact="compact">
+<dt><code>MD5</code></dt>
+<dd><p>The key is 1 to 16 printable characters terminated by
an EOL,
whitespace,
or
a
<code>#</code>
-(which is the "start of comment" character).
-
- <br><dt><code>SHA</code><br><dt><code>SHA1</code><br><dt><code>RMD160</code><dd>The key is a hex-encoded ASCII string of 40 characters,
-which is truncated as necessary.
+(which is the &quot;start of comment&quot; character).
+</p>
+</dd>
+<dt><code>SHA</code></dt>
+<dt><code>SHA1</code></dt>
+<dt><code>RMD160</code></dt>
+<dd><p>The key is a hex-encoded ASCII string of 40 characters,
+which is truncated as necessary.
+</p></dd>
</dl>
- <p>Note that the keys used by the
+<p>Note that the keys used by the
<code>ntpq(8)</code>
and
<code>ntpdc(8)</code>
programs are checked against passwords
requested by the programs and entered by hand,
so it is generally appropriate to specify these keys in ASCII format.
-
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp.keys</code> program.
+</p>
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp.keys</code> program.
This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002ekeys-Files" accesskey="1">ntp.keys Files</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Files
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002ekeys-See-Also" accesskey="2">ntp.keys See Also</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">See Also
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002ekeys-Notes" accesskey="3">ntp.keys Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Notes
+</td></tr>
+</table>
-<ul class="menu">
-<li><a accesskey="1" href="#ntp_002ekeys-Files">ntp.keys Files</a>: Files
-<li><a accesskey="2" href="#ntp_002ekeys-See-Also">ntp.keys See Also</a>: See Also
-<li><a accesskey="3" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>: Notes
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntp_002ekeys-Files"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002ekeys-See-Also">ntp.keys See Also</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>
-<br>
+<hr>
+<a name="ntp_002ekeys-Files"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002ekeys-See-Also" accesskey="n" rel="next">ntp.keys See Also</a>, Up: <a href="#ntp_002ekeys-Notes" accesskey="u" rel="up">ntp.keys Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp.keys Files</h4>
-
- <dl>
-<dt><span class="file">/etc/ntp.keys</span><dd>the default name of the configuration file
+<a name="ntp_002ekeys-Files-1"></a>
+<h4 class="subsection">1.1.1 ntp.keys Files</h4>
+<dl compact="compact">
+<dt><samp>/etc/ntp.keys</samp></dt>
+<dd><p>the default name of the configuration file
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
-<a name="ntp_002ekeys-See-Also"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002ekeys-Files">ntp.keys Files</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>
-<br>
+<hr>
+<a name="ntp_002ekeys-See-Also"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntp_002ekeys-Files" accesskey="p" rel="prev">ntp.keys Files</a>, Up: <a href="#ntp_002ekeys-Notes" accesskey="u" rel="up">ntp.keys Notes</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp.keys See Also</h4>
-
+<a name="ntp_002ekeys-See-Also-1"></a>
+<h4 class="subsection">1.1.2 ntp.keys See Also</h4>
<p><code>ntp.conf(5)</code>,
<code>ntpd(1ntpdmdoc)</code>,
<code>ntpdate(1ntpdatemdoc)</code>,
<code>ntpdc(1ntpdcmdoc)</code>,
<code>sntp(1sntpmdoc)</code>
-<div class="node">
-<p><hr>
-<a name="ntp_002ekeys-Notes"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002ekeys-See-Also">ntp.keys See Also</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002ekeys-Notes">ntp.keys Notes</a>
-<br>
+</p><hr>
+<div class="header">
+<p>
+ &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp.keys Notes</h4>
-
+<a name="ntp_002ekeys-Notes-1"></a>
+<h4 class="subsection">1.1.3 ntp.keys Notes</h4>
<p>This document was derived from FreeBSD.
+</p><hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/ntpd/ntp.keys.man.in b/contrib/ntp/ntpd/ntp.keys.man.in
index 3712747..9d8b995 100644
--- a/contrib/ntp/ntpd/ntp.keys.man.in
+++ b/contrib/ntp/ntpd/ntp.keys.man.in
@@ -1,8 +1,8 @@
-.TH ntp.keys 5 "27 Feb 2018" "4.2.8p11" "File Formats"
+.TH ntp.keys 5 "20 Feb 2019" "4.2.8p13" "File Formats"
.\"
.\" EDIT THIS FILE WITH CAUTION (ntp.man)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:26 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:44 AM by AutoGen 5.18.5
.\" From the definitions ntp.keys.def
.\" and the template file agman-file.tpl
.Sh NAME
@@ -54,7 +54,7 @@ statement in the configuration file.
While key number 0 is fixed by the NTP standard
(as 56 zero bits)
and may not be changed,
-one or more keys numbered between 1 and 65534
+one or more keys numbered between 1 and 65535
may be arbitrarily set in the keys file.
.sp \n(Ppu
.ne 2
@@ -73,7 +73,7 @@ Key entries use a fixed format of the form
where
\f\*[I-Font]keyno\f[]
-is a positive integer (between 1 and 65534),
+is a positive integer (between 1 and 65535),
\f\*[I-Font]type\f[]
is the message digest algorithm,
\f\*[I-Font]key\f[]
diff --git a/contrib/ntp/ntpd/ntp.keys.mdoc.in b/contrib/ntp/ntpd/ntp.keys.mdoc.in
index 6dc4f88..1bc36e3 100644
--- a/contrib/ntp/ntpd/ntp.keys.mdoc.in
+++ b/contrib/ntp/ntpd/ntp.keys.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTP_KEYS 5 File Formats
-.Os SunOS 5.10
+.Os FreeBSD 11.2-RELEASE_SI
.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:46 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:35 AM by AutoGen 5.18.5
.\" From the definitions ntp.keys.def
.\" and the template file agmdoc-file.tpl
.Sh NAME
@@ -37,7 +37,7 @@ statement in the configuration file.
While key number 0 is fixed by the NTP standard
(as 56 zero bits)
and may not be changed,
-one or more keys numbered between 1 and 65534
+one or more keys numbered between 1 and 65535
may be arbitrarily set in the keys file.
.Pp
The key file uses the same comment conventions
@@ -48,7 +48,7 @@ Key entries use a fixed format of the form
.Pp
where
.Ar keyno
-is a positive integer (between 1 and 65534),
+is a positive integer (between 1 and 65535),
.Ar type
is the message digest algorithm,
.Ar key
diff --git a/contrib/ntp/ntpd/ntp_config.c b/contrib/ntp/ntpd/ntp_config.c
index 003b153..0597393 100644
--- a/contrib/ntp/ntpd/ntp_config.c
+++ b/contrib/ntp/ntpd/ntp_config.c
@@ -364,7 +364,7 @@ static u_int32 get_match(const char *, struct masks *);
static u_int32 get_logmask(const char *);
static int/*BOOL*/ is_refclk_addr(const address_node * addr);
-static void appendstr(char *, size_t, char *);
+static void appendstr(char *, size_t, const char *);
#ifndef SIM
@@ -382,14 +382,14 @@ static void fatal_error(const char *fmt, ...)
#endif
{
va_list va;
-
+
va_start(va, fmt);
mvsyslog(LOG_EMERG, fmt, va);
va_end(va);
_exit(1);
}
-
+
/* FUNCTIONS FOR INITIALIZATION
* ----------------------------
*/
@@ -742,7 +742,7 @@ dump_config_tree(
atrv->value.i);
}
break;
-
+
case T_Double:
fprintf(df, " %s %s",
keyword(atrv->attr),
@@ -938,7 +938,7 @@ dump_config_tree(
if (T_Source == flag_tok_fifo->i) {
s = "source";
break;
- }
+ }
}
} else {
const char *ap = rest_node->addr->address;
@@ -1446,7 +1446,7 @@ create_unpeer_node(
/* accumulate with overflow retention */
u = (10 * u + *pch - '0') | (u & 0xFF000000u);
}
-
+
if (!*pch && u <= ASSOCID_MAX) {
my_node->assocID = (associd_t)u;
my_node->addr = NULL;
@@ -2065,8 +2065,12 @@ config_auth(
#ifdef AUTOKEY
/* crypto revoke command */
- if (ptree->auth.revoke)
- sys_revoke = 1UL << ptree->auth.revoke;
+ if (ptree->auth.revoke > 2 && ptree->auth.revoke < 32)
+ sys_revoke = (u_char)ptree->auth.revoke;
+ else if (ptree->auth.revoke)
+ msyslog(LOG_ERR,
+ "'revoke' value %d ignored",
+ ptree->auth.revoke);
#endif /* AUTOKEY */
}
#endif /* !SIM */
@@ -2112,6 +2116,10 @@ config_tos_clock(
break;
}
}
+
+ if (basedate_get_day() <= NTP_TO_UNIX_DAYS)
+ basedate_set_day(basedate_eval_buildstamp() - 11);
+
return ret;
}
@@ -2132,7 +2140,7 @@ config_tos(
* since three variables with interdependecies are involved. We
* just log an error but do not stop: This might be caused by
* remote config, and it might be fixed by remote config, too.
- */
+ */
int l_maxclock = sys_maxclock;
int l_minclock = sys_minclock;
int l_minsane = sys_minsane;
@@ -2162,7 +2170,7 @@ config_tos(
tos->value.d = 0;
}
break;
-
+
case T_Ceiling:
val = tos->value.d;
if (val > STRATUM_UNSPEC - 1) {
@@ -2194,8 +2202,8 @@ config_tos(
case T_Minsane:
val = tos->value.d;
- if ((int)tos->value.d < 1)
- tos->value.d = 1;
+ if ((int)tos->value.d < 0)
+ tos->value.d = 0;
l_minsane = (int)tos->value.d;
break;
}
@@ -2207,7 +2215,7 @@ config_tos(
" - daemon will not operate properly!",
l_minsane, l_minclock, l_maxclock);
}
-
+
/* -*- phase two: forward the values to the protocol machinery */
tos = HEAD_PFIFO(ptree->orphan_cmds);
for (; tos != NULL; tos = tos->link) {
@@ -3383,6 +3391,10 @@ config_ttl(
size_t i = 0;
int_node *curr_ttl;
+ /* [Bug 3465] There is a built-in default for the TTLs. We must
+ * overwrite 'sys_ttlmax' if we change that preset, and leave it
+ * alone otherwise!
+ */
curr_ttl = HEAD_PFIFO(ptree->ttl);
for (; curr_ttl != NULL; curr_ttl = curr_ttl->link) {
if (i < COUNTOF(sys_ttl))
@@ -3392,7 +3404,8 @@ config_ttl(
"ttl: Number of TTL entries exceeds %zu. Ignoring TTL %d...",
COUNTOF(sys_ttl), curr_ttl->i);
}
- sys_ttlmax = (i) ? (i - 1) : 0;
+ if (0 != i) /* anything written back at all? */
+ sys_ttlmax = i - 1;
}
#endif /* !SIM */
@@ -3621,10 +3634,8 @@ config_fudge(
err_flag = 1;
msyslog(LOG_ERR,
"unrecognized fudge reference clock address %s, line ignored",
- stoa(&addr_sock));
- }
-
- if (!ISREFCLOCKADR(&addr_sock)) {
+ addr_node->address);
+ } else if (!ISREFCLOCKADR(&addr_sock)) {
err_flag = 1;
msyslog(LOG_ERR,
"inappropriate address %s for the fudge command, line ignored",
@@ -3696,7 +3707,7 @@ config_fudge(
msyslog(LOG_ERR,
"Unexpected fudge flag %s (%d) for %s",
token_name(curr_opt->attr),
- curr_opt->attr, stoa(&addr_sock));
+ curr_opt->attr, addr_node->address);
exit(curr_opt->attr ? curr_opt->attr : 1);
}
}
@@ -3810,7 +3821,12 @@ config_vars(
case T_Automax:
#ifdef AUTOKEY
- sys_automax = curr_var->value.i;
+ if (curr_var->value.i > 2 && curr_var->value.i < 32)
+ sys_automax = (u_char)curr_var->value.i;
+ else
+ msyslog(LOG_ERR,
+ "'automax' value %d ignored",
+ curr_var->value.i);
#endif
break;
@@ -4565,7 +4581,7 @@ config_ntpd(
if (config_tos_clock(ptree))
clamp_systime();
}
-
+
config_nic_rules(ptree, input_from_files);
config_monitor(ptree);
config_auth(ptree);
@@ -4845,7 +4861,7 @@ is_refclk_addr(
const address_node * addr
)
{
- return addr && addr->address && !strncmp(addr->address, "127.127.", 6);
+ return addr && addr->address && !strncmp(addr->address, "127.127.", 8);
}
static void
@@ -5463,7 +5479,7 @@ static void
appendstr(
char *string,
size_t s,
- char *new
+ const char *new
)
{
if (*string != '\0') {
diff --git a/contrib/ntp/ntpd/ntp_control.c b/contrib/ntp/ntpd/ntp_control.c
index d98f6aa..49a197e 100644
--- a/contrib/ntp/ntpd/ntp_control.c
+++ b/contrib/ntp/ntpd/ntp_control.c
@@ -916,7 +916,7 @@ is_safe_filename(const char * name)
u_int widx, bidx, mask;
if ( ! (name && *name))
return FALSE;
-
+
mask = 1u;
while (0 != (widx = (u_char)*name++)) {
bidx = (widx & 15) << 1;
@@ -955,7 +955,7 @@ save_config(
* level. On POSIX systems we could allow '\\' but such
* filenames are tricky to manipulate from a shell, so just
* reject both types of slashes on all platforms.
- */
+ */
/* TALOS-CAN-0062: block directory traversal for VMS, too */
static const char * illegal_in_filename =
#if defined(VMS)
@@ -983,8 +983,8 @@ save_config(
# if defined(_O_TEXT) /* windows, again */
| _O_TEXT
#endif
- ;
-
+ ;
+
char filespec[128];
char filename[128];
char fullpath[512];
@@ -1046,7 +1046,7 @@ save_config(
/* copy data directly as we exactly know the size */
memcpy(filespec, reqpt, reqlen);
filespec[reqlen] = '\0';
-
+
/*
* allow timestamping of the saved config filename with
* strftime() format such as:
@@ -1110,7 +1110,7 @@ save_config(
*/
prc = snprintf(fullpath, sizeof(fullpath), "%s%s",
saveconfigdir, filename);
- if (prc < 0 || prc >= sizeof(fullpath)) {
+ if (prc < 0 || (size_t)prc >= sizeof(fullpath)) {
ctl_printf("saveconfig exceeded maximum path length (%u)",
(u_int)sizeof(fullpath));
ctl_flushpkt(0);
@@ -1127,8 +1127,8 @@ save_config(
fptr = fdopen(fd, "w");
if (NULL == fptr || -1 == dump_all_config_trees(fptr, 1)) {
- ctl_printf("Unable to save configuration to file '%s': %m",
- filename);
+ ctl_printf("Unable to save configuration to file '%s': %s",
+ filename, strerror(errno));
msyslog(LOG_ERR,
"saveconfig %s from %s failed", filename,
stoa(&rbufp->recv_srcadr));
@@ -1154,7 +1154,7 @@ save_config(
#else /* !SAVECONFIG follows */
ctl_printf("%s",
"saveconfig unavailable, configured with --disable-saveconfig");
-#endif
+#endif
ctl_flushpkt(0);
}
@@ -1506,11 +1506,11 @@ ctl_putdata_ex(
} else {
datanotbinflag = TRUE;
add_len = 3;
-
+
if (datasent) {
*datapt++ = ',';
datalinelen++;
-
+
/* sum up total length */
for (argi = 0, src_len = 0; argi < argc; ++argi)
src_len += argv[argi].len;
@@ -1539,14 +1539,14 @@ ctl_putdata_ex(
/* Not enough room in this one, flush it out. */
if (src_len < cur_len)
cur_len = src_len;
-
+
memcpy(datapt, src_ptr, cur_len);
datapt += cur_len;
datalinelen += cur_len;
src_ptr += cur_len;
src_len -= cur_len;
-
+
ctl_flushpkt(CTL_MORE);
cur_len = (size_t)(dataend - datapt);
}
@@ -1571,7 +1571,7 @@ ctl_putdata(
)
{
CtlMemBufT args[1];
-
+
args[0].buf = dp;
args[0].len = dlen;
ctl_putdata_ex(args, 1, bin);
@@ -1594,7 +1594,7 @@ ctl_putstr(
)
{
CtlMemBufT args[4];
-
+
args[0].buf = tag;
args[0].len = strlen(tag);
if (data && len) {
@@ -1606,7 +1606,9 @@ ctl_putstr(
args[3].len = 1;
ctl_putdata_ex(args, 4, FALSE);
} else {
- ctl_putdata_ex(args, 1, FALSE);
+ args[1].buf = "=\"\"";
+ args[1].len = 3;
+ ctl_putdata_ex(args, 2, FALSE);
}
}
@@ -1628,17 +1630,17 @@ ctl_putunqstr(
)
{
CtlMemBufT args[3];
-
+
args[0].buf = tag;
args[0].len = strlen(tag);
+ args[1].buf = "=";
+ args[1].len = 1;
if (data && len) {
- args[1].buf = "=";
- args[1].len = 1;
- args[2].buf = data;
- args[2].len = len;
- ctl_putdata_ex(args, 3, FALSE);
+ args[2].buf = data;
+ args[2].len = len;
+ ctl_putdata_ex(args, 3, FALSE);
} else {
- ctl_putdata_ex(args, 1, FALSE);
+ ctl_putdata_ex(args, 2, FALSE);
}
}
@@ -1656,7 +1658,7 @@ ctl_putdblf(
{
char buffer[40];
int rc;
-
+
rc = snprintf(buffer, sizeof(buffer),
(use_f ? "%.*f" : "%.*g"),
precision, d);
@@ -1677,7 +1679,7 @@ ctl_putuint(
int rc;
rc = snprintf(buffer, sizeof(buffer), "%lu", uval);
- INSIST(rc >= 0 && rc < sizeof(buffer));
+ INSIST(rc >= 0 && (size_t)rc < sizeof(buffer));
ctl_putunqstr(tag, buffer, rc);
}
@@ -1716,7 +1718,7 @@ ctl_putfs(
{
char buffer[16];
int rc;
-
+
time_t fstamp = (time_t)uval - JAN_1970;
struct tm *tm = gmtime(&fstamp);
@@ -1744,7 +1746,7 @@ ctl_puthex(
{
char buffer[24]; /* must fit 64bit int! */
int rc;
-
+
rc = snprintf(buffer, sizeof(buffer), "0x%lx", uval);
INSIST(rc >= 0 && (size_t)rc < sizeof(buffer));
ctl_putunqstr(tag, buffer, rc);
@@ -1762,9 +1764,9 @@ ctl_putint(
{
char buffer[24]; /*must fit 64bit int */
int rc;
-
+
rc = snprintf(buffer, sizeof(buffer), "%ld", ival);
- INSIST(rc >= 0 && rc < sizeof(buffer));
+ INSIST(rc >= 0 && (size_t)rc < sizeof(buffer));
ctl_putunqstr(tag, buffer, rc);
}
@@ -1780,7 +1782,7 @@ ctl_putts(
{
char buffer[24];
int rc;
-
+
rc = snprintf(buffer, sizeof(buffer),
"0x%08lx.%08lx",
(u_long)ts->l_ui, (u_long)ts->l_uf);
@@ -1800,7 +1802,7 @@ ctl_putadr(
)
{
const char *cq;
-
+
if (NULL == addr)
cq = numtoa(addr32);
else
@@ -1827,7 +1829,9 @@ ctl_putrefid(
bytes.w = refid;
for (nc = 0; nc < sizeof(bytes.b) && bytes.b[nc]; ++nc)
- if (!isprint(bytes.b[nc]))
+ if ( !isprint(bytes.b[nc])
+ || isspace(bytes.b[nc])
+ || bytes.b[nc] == ',' )
bytes.b[nc] = '.';
ctl_putunqstr(tag, (const char*)bytes.b, nc);
}
@@ -1874,11 +1878,11 @@ ctl_printf(
va_list va;
char fmtbuf[128];
int rc;
-
+
va_start(va, fmt);
rc = vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, va);
va_end(va);
- if (rc < 0 || rc >= sizeof(fmtbuf))
+ if (rc < 0 || (size_t)rc >= sizeof(fmtbuf))
strcpy(fmtbuf + sizeof(fmtbuf) - strlen(ellipsis) - 1,
ellipsis);
ctl_putdata(fmtbuf, strlen(fmtbuf), 0);
@@ -1906,11 +1910,13 @@ ctl_putsys(
static struct timex ntx;
static u_long ntp_adjtime_time;
- static const double to_ms =
+ static const double to_ms_usec =
+ 1.0e-3; /* usec to msec */
+ static const double to_ms_nusec =
# ifdef STA_NANO
1.0e-6; /* nsec to msec */
# else
- 1.0e-3; /* usec to msec */
+ to_ms_usec;
# endif
/*
@@ -1951,10 +1957,10 @@ ctl_putsys(
break;
case CS_REFID:
- if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC)
- ctl_putadr(sys_var[varid].text, sys_refid, NULL);
- else
+ if (REFID_ISTEXT(sys_stratum))
ctl_putrefid(sys_var[varid].text, sys_refid);
+ else
+ ctl_putadr(sys_var[varid].text, sys_refid, NULL);
break;
case CS_REFTIME:
@@ -2315,7 +2321,7 @@ ctl_putsys(
case CS_K_OFFSET:
CTL_IF_KERNLOOP(
ctl_putdblf,
- (sys_var[varid].text, 0, -1, to_ms * ntx.offset)
+ (sys_var[varid].text, 0, -1, to_ms_nusec * ntx.offset)
);
break;
@@ -2330,7 +2336,7 @@ ctl_putsys(
CTL_IF_KERNLOOP(
ctl_putdblf,
(sys_var[varid].text, 0, 6,
- to_ms * ntx.maxerror)
+ to_ms_usec * ntx.maxerror)
);
break;
@@ -2338,7 +2344,7 @@ ctl_putsys(
CTL_IF_KERNLOOP(
ctl_putdblf,
(sys_var[varid].text, 0, 6,
- to_ms * ntx.esterror)
+ to_ms_usec * ntx.esterror)
);
break;
@@ -2362,7 +2368,7 @@ ctl_putsys(
CTL_IF_KERNLOOP(
ctl_putdblf,
(sys_var[varid].text, 0, 6,
- to_ms * ntx.precision)
+ to_ms_usec * ntx.precision)
);
break;
@@ -2390,7 +2396,7 @@ ctl_putsys(
case CS_K_PPS_JITTER:
CTL_IF_KERNPPS(
ctl_putdbl,
- (sys_var[varid].text, to_ms * ntx.jitter)
+ (sys_var[varid].text, to_ms_nusec * ntx.jitter)
);
break;
@@ -2678,11 +2684,10 @@ ctl_putpeer(
break;
}
#endif
- if (p->stratum > 1 && p->stratum < STRATUM_UNSPEC)
- ctl_putadr(peer_var[id].text, p->refid,
- NULL);
- else
+ if (REFID_ISTEXT(p->stratum))
ctl_putrefid(peer_var[id].text, p->refid);
+ else
+ ctl_putadr(peer_var[id].text, p->refid, NULL);
break;
case CP_REFTIME:
@@ -3061,7 +3066,7 @@ ctl_getitem(
* packet; If it's EOV, it will never be NULL again until the
* variable is found and processed in a given 'var_list'. (That
* is, a result is returned that is neither NULL nor EOV).
- */
+ */
static const struct ctl_var eol = { 0, EOV, NULL };
static char buf[128];
static u_long quiet_until;
@@ -3101,7 +3106,7 @@ ctl_getitem(
++plhead;
while (plhead != pltail && isspace((u_char)pltail[-1]))
--pltail;
-
+
/* check payload size, terminate packet on overflow */
plsize = (size_t)(pltail - plhead);
if (plsize >= sizeof(buf))
@@ -3126,7 +3131,7 @@ ctl_getitem(
* variable lists after an EoV was returned. (Such a behavior
* actually caused Bug 3008.)
*/
-
+
if (NULL == var_list)
return &eol;
@@ -3443,11 +3448,11 @@ write_variables(
* Look through the variables. Dump out at the first sign of
* trouble.
*/
- while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
+ while ((v = ctl_getitem(sys_var, &valuep)) != NULL) {
ext_var = 0;
if (v->flags & EOV) {
- if ((v = ctl_getitem(ext_sys_var, &valuep)) !=
- 0) {
+ v = ctl_getitem(ext_sys_var, &valuep);
+ if (v != NULL) {
if (v->flags & EOV) {
ctl_error(CERR_UNKNOWNVAR);
return;
@@ -3461,16 +3466,24 @@ write_variables(
ctl_error(CERR_PERMISSION);
return;
}
- if (!ext_var && (*valuep == '\0' || !atoint(valuep,
- &val))) {
+ /* [bug 3565] writing makes sense only if we *have* a
+ * value in the packet!
+ */
+ if (valuep == NULL) {
ctl_error(CERR_BADFMT);
return;
}
- if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) {
- ctl_error(CERR_BADVALUE);
- return;
+ if (!ext_var) {
+ if ( !(*valuep && atoint(valuep, &val))) {
+ ctl_error(CERR_BADFMT);
+ return;
+ }
+ if ((val & ~LEAP_NOTINSYNC) != 0) {
+ ctl_error(CERR_BADVALUE);
+ return;
+ }
}
-
+
if (ext_var) {
octets = strlen(v->text) + strlen(valuep) + 2;
vareqv = emalloc(octets);
@@ -3647,7 +3660,7 @@ static u_int32 derive_nonce(
/* [Bug 3457] set flags and don't kill them again */
EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
EVP_DigestInit_ex(ctx, EVP_get_digestbynid(NID_md5), NULL);
-# else
+# else
EVP_DigestInit(ctx, EVP_get_digestbynid(NID_md5));
# endif
EVP_DigestUpdate(ctx, salt, sizeof(salt));
@@ -3944,7 +3957,7 @@ static void read_mru_list(
int restrict_mask
)
{
- static const char nulltxt[1] = { '\0' };
+ static const char nulltxt[1] = { '\0' };
static const char nonce_text[] = "nonce";
static const char frags_text[] = "frags";
static const char limit_text[] = "limit";
@@ -3954,7 +3967,7 @@ static void read_mru_list(
static const char maxlstint_text[] = "maxlstint";
static const char laddr_text[] = "laddr";
static const char resaxx_fmt[] = "0x%hx";
-
+
u_int limit;
u_short frags;
u_short resall;
diff --git a/contrib/ntp/ntpd/ntp_crypto.c b/contrib/ntp/ntpd/ntp_crypto.c
index fd74222..fa0017f 100644
--- a/contrib/ntp/ntpd/ntp_crypto.c
+++ b/contrib/ntp/ntpd/ntp_crypto.c
@@ -353,8 +353,8 @@ make_keylist(
* included in the hash is zero if broadcast mode, the peer
* cookie if client mode or the host cookie if symmetric modes.
*/
- mpoll = 1 << min(peer->ppoll, peer->hpoll);
- lifetime = min(1U << sys_automax, NTP_MAXSESSION * mpoll);
+ mpoll = 1U << min(peer->ppoll, peer->hpoll);
+ lifetime = min((1UL << sys_automax), NTP_MAXSESSION * mpoll);
if (peer->hmode == MODE_BROADCAST)
cookie = 0;
else
@@ -1486,7 +1486,8 @@ crypto_verify(
return (XEVNT_LEN);
i = (vallen + 3) / 4;
- siglen = ntohl(ep->pkt[i++]);
+ siglen = ntohl(ep->pkt[i]);
+ ++i;
if ( siglen > MAX_VALLEN
|| len - VALUE_LEN < ((vallen + 3) / 4) * 4
|| len - VALUE_LEN - ((vallen + 3) / 4) * 4
diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c
index ed5f0dc..b89b996 100644
--- a/contrib/ntp/ntpd/ntp_io.c
+++ b/contrib/ntp/ntpd/ntp_io.c
@@ -1612,6 +1612,34 @@ set_wildcard_reuse(
}
#endif /* OS_NEEDS_REUSEADDR_FOR_IFADDRBIND */
+static isc_boolean_t
+check_flags(
+ sockaddr_u *psau,
+ const char *name,
+ u_int32 flags
+ )
+{
+#if defined(SIOCGIFAFLAG_IN)
+ struct ifreq ifr;
+ int fd;
+
+ if (psau->sa.sa_family != AF_INET)
+ return ISC_FALSE;
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return ISC_FALSE;
+ ZERO(ifr);
+ memcpy(&ifr.ifr_addr, &psau->sa, sizeof(ifr.ifr_addr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFAFLAG_IN, &ifr) < 0) {
+ close(fd);
+ return ISC_FALSE;
+ }
+ close(fd);
+ if ((ifr.ifr_addrflags & flags) != 0)
+ return ISC_TRUE;
+#endif /* SIOCGIFAFLAG_IN */
+ return ISC_FALSE;
+}
static isc_boolean_t
check_flags6(
@@ -1661,19 +1689,32 @@ is_valid(
const char *name
)
{
- u_int32 flags6;
+ u_int32 flags;
- flags6 = 0;
+ flags = 0;
+ switch (psau->sa.sa_family) {
+ case AF_INET:
+#ifdef IN_IFF_DETACHED
+ flags |= IN_IFF_DETACHED;
+#endif
+#ifdef IN_IFF_TENTATIVE
+ flags |= IN_IFF_TENTATIVE;
+#endif
+ return check_flags(psau, name, flags) ? ISC_FALSE : ISC_TRUE;
+ case AF_INET6:
#ifdef IN6_IFF_DEPARTED
- flags6 |= IN6_IFF_DEPARTED;
+ flags |= IN6_IFF_DEPARTED;
#endif
#ifdef IN6_IFF_DETACHED
- flags6 |= IN6_IFF_DETACHED;
+ flags |= IN6_IFF_DETACHED;
#endif
#ifdef IN6_IFF_TENTATIVE
- flags6 |= IN6_IFF_TENTATIVE;
+ flags |= IN6_IFF_TENTATIVE;
#endif
- return check_flags6(psau, name, flags6) ? ISC_FALSE : ISC_TRUE;
+ return check_flags6(psau, name, flags) ? ISC_FALSE : ISC_TRUE;
+ default:
+ return ISC_FALSE;
+ }
}
/*
@@ -3092,7 +3133,7 @@ sendpkt(
int cc;
int rc;
u_char cttl;
- l_fp fp_zero = { 0, 0 };
+ l_fp fp_zero = { { 0 }, 0 };
ismcast = IS_MCAST(dest);
if (!ismcast)
diff --git a/contrib/ntp/ntpd/ntp_loopfilter.c b/contrib/ntp/ntpd/ntp_loopfilter.c
index 8d44fb1..01772bd 100644
--- a/contrib/ntp/ntpd/ntp_loopfilter.c
+++ b/contrib/ntp/ntpd/ntp_loopfilter.c
@@ -246,7 +246,11 @@ ntp_adjtime_error_handler(
)
{
char des[1024] = ""; /* Decoded Error Status */
+ char *dbp, *ebp;
+ dbp = des;
+ ebp = dbp + sizeof(des);
+
switch (ret) {
case -1:
switch (saved_errno) {
@@ -363,37 +367,37 @@ or, from ntp_adjtime():
/* error (see status word) */
if (ptimex->status & STA_UNSYNC)
- snprintf(des, sizeof(des), "%s%sClock Unsynchronized",
- des, (*des) ? "; " : "");
+ xsbprintf(&dbp, ebp, "%sClock Unsynchronized",
+ (*des) ? "; " : "");
if (ptimex->status & STA_CLOCKERR)
- snprintf(des, sizeof(des), "%s%sClock Error",
- des, (*des) ? "; " : "");
+ xsbprintf(&dbp, ebp, "%sClock Error",
+ (*des) ? "; " : "");
if (!(ptimex->status & STA_PPSSIGNAL)
&& ptimex->status & STA_PPSFREQ)
- snprintf(des, sizeof(des), "%s%sPPS Frequency Sync wanted but no PPS",
- des, (*des) ? "; " : "");
+ xsbprintf(&dbp, ebp, "%sPPS Frequency Sync wanted but no PPS",
+ (*des) ? "; " : "");
if (!(ptimex->status & STA_PPSSIGNAL)
&& ptimex->status & STA_PPSTIME)
- snprintf(des, sizeof(des), "%s%sPPS Time Sync wanted but no PPS signal",
- des, (*des) ? "; " : "");
+ xsbprintf(&dbp, ebp, "%sPPS Time Sync wanted but no PPS signal",
+ (*des) ? "; " : "");
if ( ptimex->status & STA_PPSTIME
&& ptimex->status & STA_PPSJITTER)
- snprintf(des, sizeof(des), "%s%sPPS Time Sync wanted but PPS Jitter exceeded",
- des, (*des) ? "; " : "");
+ xsbprintf(&dbp, ebp, "%sPPS Time Sync wanted but PPS Jitter exceeded",
+ (*des) ? "; " : "");
if ( ptimex->status & STA_PPSFREQ
&& ptimex->status & STA_PPSWANDER)
- snprintf(des, sizeof(des), "%s%sPPS Frequency Sync wanted but PPS Wander exceeded",
- des, (*des) ? "; " : "");
+ xsbprintf(&dbp, ebp, "%sPPS Frequency Sync wanted but PPS Wander exceeded",
+ (*des) ? "; " : "");
if ( ptimex->status & STA_PPSFREQ
&& ptimex->status & STA_PPSERROR)
- snprintf(des, sizeof(des), "%s%sPPS Frequency Sync wanted but Calibration error detected",
- des, (*des) ? "; " : "");
+ xsbprintf(&dbp, ebp, "%sPPS Frequency Sync wanted but Calibration error detected",
+ (*des) ? "; " : "");
if (pps_call && !(ptimex->status & STA_PPSSIGNAL))
report_event(EVNT_KERN, NULL,
@@ -1099,10 +1103,14 @@ start_kern_loop(void)
pll_control = TRUE;
ZERO(ntv);
ntv.modes = MOD_BITS;
- ntv.status = STA_PLL;
- ntv.maxerror = MAXDISPERSE;
- ntv.esterror = MAXDISPERSE;
- ntv.constant = sys_poll; /* why is it that here constant is unconditionally set to sys_poll, whereas elsewhere is is modified depending on nanosecond vs. microsecond kernel? */
+ ntv.status = STA_PLL | STA_UNSYNC;
+ ntv.maxerror = MAXDISPERSE * 1.0e6;
+ ntv.esterror = MAXDISPERSE * 1.0e6;
+ ntv.constant = sys_poll;
+ /* ^^^^^^^^ why is it that here constant is
+ * unconditionally set to sys_poll, whereas elsewhere is is
+ * modified depending on nanosecond vs. microsecond kernel?
+ */
#ifdef SIGSYS
/*
* Use sigsetjmp() to save state and then call ntp_adjtime(); if
diff --git a/contrib/ntp/ntpd/ntp_parser.c b/contrib/ntp/ntpd/ntp_parser.c
index 782019c..8156a5f 100644
--- a/contrib/ntp/ntpd/ntp_parser.c
+++ b/contrib/ntp/ntpd/ntp_parser.c
@@ -62,7 +62,7 @@
/* Copy the first part of user declarations. */
-#line 11 "../../ntpd/ntp_parser.y" /* yacc.c:339 */
+#line 11 "ntp_parser.y" /* yacc.c:339 */
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -76,6 +76,7 @@
#include "ntp_scanner.h"
#include "ntp_config.h"
#include "ntp_crypto.h"
+ #include "ntp_calendar.h"
#include "ntpsim.h" /* HMS: Do we really want this all the time? */
/* SK: It might be a good idea to always
@@ -96,7 +97,7 @@
# define ONLY_SIM(a) NULL
#endif
-#line 100 "ntp_parser.c" /* yacc.c:339 */
+#line 101 "ntp_parser.c" /* yacc.c:339 */
# ifndef YY_NULLPTR
# if defined __cplusplus && 201103L <= __cplusplus
@@ -540,7 +541,7 @@ extern int yydebug;
union YYSTYPE
{
-#line 51 "../../ntpd/ntp_parser.y" /* yacc.c:355 */
+#line 52 "ntp_parser.y" /* yacc.c:355 */
char * String;
double Double;
@@ -559,7 +560,7 @@ union YYSTYPE
script_info * Sim_script;
script_info_fifo * Sim_script_fifo;
-#line 563 "ntp_parser.c" /* yacc.c:355 */
+#line 564 "ntp_parser.c" /* yacc.c:355 */
};
typedef union YYSTYPE YYSTYPE;
@@ -576,7 +577,7 @@ int yyparse (void);
/* Copy the second part of user declarations. */
-#line 580 "ntp_parser.c" /* yacc.c:358 */
+#line 581 "ntp_parser.c" /* yacc.c:358 */
#ifdef short
# undef short
@@ -893,39 +894,39 @@ static const yytype_uint8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 377, 377, 381, 382, 383, 398, 399, 400, 401,
- 402, 403, 404, 405, 406, 407, 408, 409, 410, 411,
- 419, 429, 430, 431, 432, 433, 437, 438, 443, 448,
- 450, 456, 457, 465, 466, 467, 471, 476, 477, 478,
- 479, 480, 481, 482, 483, 487, 489, 494, 495, 496,
- 497, 498, 499, 503, 508, 517, 527, 528, 538, 540,
- 542, 544, 555, 562, 564, 569, 571, 573, 575, 577,
- 587, 593, 594, 602, 604, 616, 617, 618, 619, 620,
- 629, 634, 639, 647, 649, 651, 653, 658, 659, 660,
- 661, 662, 663, 664, 665, 666, 670, 671, 680, 682,
- 691, 701, 706, 714, 715, 716, 717, 718, 719, 720,
- 721, 726, 727, 735, 745, 754, 769, 774, 775, 779,
- 780, 784, 785, 786, 787, 788, 789, 790, 799, 803,
- 807, 815, 823, 831, 846, 861, 874, 875, 895, 896,
- 904, 905, 906, 907, 908, 909, 910, 911, 912, 913,
- 914, 915, 916, 917, 918, 919, 920, 924, 929, 937,
- 942, 943, 944, 948, 953, 961, 966, 967, 968, 969,
- 970, 971, 972, 973, 981, 991, 996, 1004, 1006, 1008,
- 1017, 1019, 1024, 1025, 1029, 1030, 1031, 1032, 1040, 1045,
- 1050, 1058, 1063, 1064, 1065, 1074, 1076, 1081, 1086, 1094,
- 1096, 1113, 1114, 1115, 1116, 1117, 1118, 1122, 1123, 1124,
- 1125, 1126, 1127, 1135, 1140, 1145, 1153, 1158, 1159, 1160,
- 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1176, 1177, 1178,
- 1185, 1192, 1199, 1215, 1234, 1236, 1238, 1240, 1242, 1244,
- 1251, 1256, 1257, 1258, 1262, 1266, 1275, 1276, 1280, 1281,
- 1282, 1286, 1297, 1315, 1327, 1332, 1334, 1339, 1340, 1348,
- 1350, 1358, 1363, 1371, 1396, 1403, 1413, 1414, 1418, 1419,
- 1420, 1421, 1425, 1426, 1427, 1431, 1436, 1441, 1449, 1450,
- 1451, 1452, 1453, 1454, 1455, 1465, 1470, 1478, 1483, 1491,
- 1493, 1497, 1502, 1507, 1515, 1520, 1528, 1537, 1538, 1542,
- 1543, 1547, 1555, 1573, 1577, 1582, 1590, 1595, 1596, 1600,
- 1605, 1613, 1618, 1623, 1628, 1633, 1641, 1646, 1651, 1659,
- 1664, 1665, 1666, 1667, 1668
+ 0, 378, 378, 382, 383, 384, 399, 400, 401, 402,
+ 403, 404, 405, 406, 407, 408, 409, 410, 411, 412,
+ 420, 430, 431, 432, 433, 434, 438, 439, 444, 449,
+ 451, 457, 458, 466, 467, 468, 472, 477, 478, 479,
+ 480, 481, 482, 483, 484, 488, 490, 495, 496, 497,
+ 498, 499, 500, 504, 509, 518, 528, 529, 539, 541,
+ 543, 545, 556, 563, 565, 570, 572, 574, 576, 578,
+ 588, 594, 595, 603, 605, 617, 618, 619, 620, 621,
+ 630, 635, 640, 648, 650, 652, 654, 659, 660, 661,
+ 662, 663, 664, 665, 666, 667, 671, 672, 681, 683,
+ 692, 702, 707, 715, 716, 717, 718, 719, 720, 721,
+ 722, 727, 728, 736, 746, 755, 770, 775, 776, 780,
+ 781, 785, 786, 787, 788, 789, 790, 791, 800, 804,
+ 808, 816, 824, 832, 847, 862, 875, 876, 896, 897,
+ 905, 906, 907, 908, 909, 910, 911, 912, 913, 914,
+ 915, 916, 917, 918, 919, 920, 921, 925, 930, 938,
+ 943, 944, 945, 949, 954, 962, 967, 968, 969, 970,
+ 971, 972, 973, 974, 982, 992, 997, 1005, 1007, 1009,
+ 1018, 1020, 1025, 1026, 1030, 1031, 1032, 1033, 1041, 1046,
+ 1051, 1059, 1064, 1065, 1066, 1075, 1077, 1082, 1087, 1095,
+ 1097, 1114, 1115, 1116, 1117, 1118, 1119, 1123, 1124, 1125,
+ 1126, 1127, 1128, 1136, 1141, 1146, 1154, 1159, 1160, 1161,
+ 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1177, 1178, 1179,
+ 1186, 1193, 1200, 1216, 1235, 1237, 1239, 1241, 1243, 1245,
+ 1252, 1257, 1258, 1259, 1263, 1267, 1276, 1277, 1281, 1282,
+ 1283, 1287, 1298, 1316, 1328, 1333, 1335, 1340, 1341, 1349,
+ 1351, 1359, 1364, 1372, 1397, 1404, 1414, 1415, 1419, 1420,
+ 1421, 1422, 1426, 1427, 1428, 1432, 1437, 1442, 1450, 1451,
+ 1452, 1453, 1454, 1455, 1456, 1466, 1471, 1479, 1484, 1492,
+ 1494, 1498, 1503, 1508, 1516, 1521, 1529, 1538, 1539, 1543,
+ 1544, 1548, 1556, 1574, 1578, 1583, 1591, 1596, 1597, 1601,
+ 1606, 1614, 1619, 1624, 1629, 1634, 1642, 1647, 1652, 1660,
+ 1665, 1666, 1667, 1668, 1669
};
#endif
@@ -2126,7 +2127,7 @@ yyreduce:
switch (yyn)
{
case 5:
-#line 384 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 385 "ntp_parser.y" /* yacc.c:1646 */
{
/* I will need to incorporate much more fine grained
* error messages. The following should suffice for
@@ -2139,85 +2140,85 @@ yyreduce:
ip_ctx->errpos.nline,
ip_ctx->errpos.ncol);
}
-#line 2143 "ntp_parser.c" /* yacc.c:1646 */
+#line 2144 "ntp_parser.c" /* yacc.c:1646 */
break;
case 20:
-#line 420 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 421 "ntp_parser.y" /* yacc.c:1646 */
{
peer_node *my_node;
my_node = create_peer_node((yyvsp[-2].Integer), (yyvsp[-1].Address_node), (yyvsp[0].Attr_val_fifo));
APPEND_G_FIFO(cfgt.peers, my_node);
}
-#line 2154 "ntp_parser.c" /* yacc.c:1646 */
+#line 2155 "ntp_parser.c" /* yacc.c:1646 */
break;
case 27:
-#line 439 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 440 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Address_node) = create_address_node((yyvsp[0].String), (yyvsp[-1].Integer)); }
-#line 2160 "ntp_parser.c" /* yacc.c:1646 */
+#line 2161 "ntp_parser.c" /* yacc.c:1646 */
break;
case 28:
-#line 444 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 445 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Address_node) = create_address_node((yyvsp[0].String), AF_UNSPEC); }
-#line 2166 "ntp_parser.c" /* yacc.c:1646 */
+#line 2167 "ntp_parser.c" /* yacc.c:1646 */
break;
case 29:
-#line 449 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 450 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Integer) = AF_INET; }
-#line 2172 "ntp_parser.c" /* yacc.c:1646 */
+#line 2173 "ntp_parser.c" /* yacc.c:1646 */
break;
case 30:
-#line 451 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 452 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Integer) = AF_INET6; }
-#line 2178 "ntp_parser.c" /* yacc.c:1646 */
+#line 2179 "ntp_parser.c" /* yacc.c:1646 */
break;
case 31:
-#line 456 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 457 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val_fifo) = NULL; }
-#line 2184 "ntp_parser.c" /* yacc.c:1646 */
+#line 2185 "ntp_parser.c" /* yacc.c:1646 */
break;
case 32:
-#line 458 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 459 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2193 "ntp_parser.c" /* yacc.c:1646 */
+#line 2194 "ntp_parser.c" /* yacc.c:1646 */
break;
case 36:
-#line 472 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 473 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[0].Integer)); }
-#line 2199 "ntp_parser.c" /* yacc.c:1646 */
+#line 2200 "ntp_parser.c" /* yacc.c:1646 */
break;
case 45:
-#line 488 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 489 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer)); }
-#line 2205 "ntp_parser.c" /* yacc.c:1646 */
+#line 2206 "ntp_parser.c" /* yacc.c:1646 */
break;
case 46:
-#line 490 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 491 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_uval((yyvsp[-1].Integer), (yyvsp[0].Integer)); }
-#line 2211 "ntp_parser.c" /* yacc.c:1646 */
+#line 2212 "ntp_parser.c" /* yacc.c:1646 */
break;
case 53:
-#line 504 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 505 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_sval((yyvsp[-1].Integer), (yyvsp[0].String)); }
-#line 2217 "ntp_parser.c" /* yacc.c:1646 */
+#line 2218 "ntp_parser.c" /* yacc.c:1646 */
break;
case 55:
-#line 518 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 519 "ntp_parser.y" /* yacc.c:1646 */
{
unpeer_node *my_node;
@@ -2225,85 +2226,85 @@ yyreduce:
if (my_node)
APPEND_G_FIFO(cfgt.unpeers, my_node);
}
-#line 2229 "ntp_parser.c" /* yacc.c:1646 */
+#line 2230 "ntp_parser.c" /* yacc.c:1646 */
break;
case 58:
-#line 539 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 540 "ntp_parser.y" /* yacc.c:1646 */
{ cfgt.broadcastclient = 1; }
-#line 2235 "ntp_parser.c" /* yacc.c:1646 */
+#line 2236 "ntp_parser.c" /* yacc.c:1646 */
break;
case 59:
-#line 541 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 542 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.manycastserver, (yyvsp[0].Address_fifo)); }
-#line 2241 "ntp_parser.c" /* yacc.c:1646 */
+#line 2242 "ntp_parser.c" /* yacc.c:1646 */
break;
case 60:
-#line 543 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 544 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.multicastclient, (yyvsp[0].Address_fifo)); }
-#line 2247 "ntp_parser.c" /* yacc.c:1646 */
+#line 2248 "ntp_parser.c" /* yacc.c:1646 */
break;
case 61:
-#line 545 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 546 "ntp_parser.y" /* yacc.c:1646 */
{ cfgt.mdnstries = (yyvsp[0].Integer); }
-#line 2253 "ntp_parser.c" /* yacc.c:1646 */
+#line 2254 "ntp_parser.c" /* yacc.c:1646 */
break;
case 62:
-#line 556 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 557 "ntp_parser.y" /* yacc.c:1646 */
{
attr_val *atrv;
atrv = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer));
APPEND_G_FIFO(cfgt.vars, atrv);
}
-#line 2264 "ntp_parser.c" /* yacc.c:1646 */
+#line 2265 "ntp_parser.c" /* yacc.c:1646 */
break;
case 63:
-#line 563 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 564 "ntp_parser.y" /* yacc.c:1646 */
{ cfgt.auth.control_key = (yyvsp[0].Integer); }
-#line 2270 "ntp_parser.c" /* yacc.c:1646 */
+#line 2271 "ntp_parser.c" /* yacc.c:1646 */
break;
case 64:
-#line 565 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 566 "ntp_parser.y" /* yacc.c:1646 */
{
cfgt.auth.cryptosw++;
CONCAT_G_FIFOS(cfgt.auth.crypto_cmd_list, (yyvsp[0].Attr_val_fifo));
}
-#line 2279 "ntp_parser.c" /* yacc.c:1646 */
+#line 2280 "ntp_parser.c" /* yacc.c:1646 */
break;
case 65:
-#line 570 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 571 "ntp_parser.y" /* yacc.c:1646 */
{ cfgt.auth.keys = (yyvsp[0].String); }
-#line 2285 "ntp_parser.c" /* yacc.c:1646 */
+#line 2286 "ntp_parser.c" /* yacc.c:1646 */
break;
case 66:
-#line 572 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 573 "ntp_parser.y" /* yacc.c:1646 */
{ cfgt.auth.keysdir = (yyvsp[0].String); }
-#line 2291 "ntp_parser.c" /* yacc.c:1646 */
+#line 2292 "ntp_parser.c" /* yacc.c:1646 */
break;
case 67:
-#line 574 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 575 "ntp_parser.y" /* yacc.c:1646 */
{ cfgt.auth.request_key = (yyvsp[0].Integer); }
-#line 2297 "ntp_parser.c" /* yacc.c:1646 */
+#line 2298 "ntp_parser.c" /* yacc.c:1646 */
break;
case 68:
-#line 576 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 577 "ntp_parser.y" /* yacc.c:1646 */
{ cfgt.auth.revoke = (yyvsp[0].Integer); }
-#line 2303 "ntp_parser.c" /* yacc.c:1646 */
+#line 2304 "ntp_parser.c" /* yacc.c:1646 */
break;
case 69:
-#line 578 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 579 "ntp_parser.y" /* yacc.c:1646 */
{
/* [Bug 948] leaves it open if appending or
* replacing the trusted key list is the right
@@ -2313,38 +2314,38 @@ yyreduce:
DESTROY_G_FIFO(cfgt.auth.trusted_key_list, destroy_attr_val); /* remove for append */
CONCAT_G_FIFOS(cfgt.auth.trusted_key_list, (yyvsp[0].Attr_val_fifo));
}
-#line 2317 "ntp_parser.c" /* yacc.c:1646 */
+#line 2318 "ntp_parser.c" /* yacc.c:1646 */
break;
case 70:
-#line 588 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 589 "ntp_parser.y" /* yacc.c:1646 */
{ cfgt.auth.ntp_signd_socket = (yyvsp[0].String); }
-#line 2323 "ntp_parser.c" /* yacc.c:1646 */
+#line 2324 "ntp_parser.c" /* yacc.c:1646 */
break;
case 71:
-#line 593 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 594 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val_fifo) = NULL; }
-#line 2329 "ntp_parser.c" /* yacc.c:1646 */
+#line 2330 "ntp_parser.c" /* yacc.c:1646 */
break;
case 72:
-#line 595 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 596 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2338 "ntp_parser.c" /* yacc.c:1646 */
+#line 2339 "ntp_parser.c" /* yacc.c:1646 */
break;
case 73:
-#line 603 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 604 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_sval((yyvsp[-1].Integer), (yyvsp[0].String)); }
-#line 2344 "ntp_parser.c" /* yacc.c:1646 */
+#line 2345 "ntp_parser.c" /* yacc.c:1646 */
break;
case 74:
-#line 605 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 606 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val) = NULL;
cfgt.auth.revoke = (yyvsp[0].Integer);
@@ -2353,65 +2354,65 @@ yyreduce:
"please use 'revoke %d' instead.",
cfgt.auth.revoke, cfgt.auth.revoke);
}
-#line 2357 "ntp_parser.c" /* yacc.c:1646 */
+#line 2358 "ntp_parser.c" /* yacc.c:1646 */
break;
case 80:
-#line 630 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 631 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.orphan_cmds, (yyvsp[0].Attr_val_fifo)); }
-#line 2363 "ntp_parser.c" /* yacc.c:1646 */
+#line 2364 "ntp_parser.c" /* yacc.c:1646 */
break;
case 81:
-#line 635 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 636 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2372 "ntp_parser.c" /* yacc.c:1646 */
+#line 2373 "ntp_parser.c" /* yacc.c:1646 */
break;
case 82:
-#line 640 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 641 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2381 "ntp_parser.c" /* yacc.c:1646 */
+#line 2382 "ntp_parser.c" /* yacc.c:1646 */
break;
case 83:
-#line 648 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 649 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_dval((yyvsp[-1].Integer), (double)(yyvsp[0].Integer)); }
-#line 2387 "ntp_parser.c" /* yacc.c:1646 */
+#line 2388 "ntp_parser.c" /* yacc.c:1646 */
break;
case 84:
-#line 650 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 651 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_dval((yyvsp[-1].Integer), (yyvsp[0].Double)); }
-#line 2393 "ntp_parser.c" /* yacc.c:1646 */
+#line 2394 "ntp_parser.c" /* yacc.c:1646 */
break;
case 85:
-#line 652 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 653 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_dval((yyvsp[-1].Integer), (double)(yyvsp[0].Integer)); }
-#line 2399 "ntp_parser.c" /* yacc.c:1646 */
+#line 2400 "ntp_parser.c" /* yacc.c:1646 */
break;
case 86:
-#line 654 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 655 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival(T_Basedate, (yyvsp[0].Integer)); }
-#line 2405 "ntp_parser.c" /* yacc.c:1646 */
+#line 2406 "ntp_parser.c" /* yacc.c:1646 */
break;
case 98:
-#line 681 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 682 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.stats_list, (yyvsp[0].Int_fifo)); }
-#line 2411 "ntp_parser.c" /* yacc.c:1646 */
+#line 2412 "ntp_parser.c" /* yacc.c:1646 */
break;
case 99:
-#line 683 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 684 "ntp_parser.y" /* yacc.c:1646 */
{
if (lex_from_file()) {
cfgt.stats_dir = (yyvsp[0].String);
@@ -2420,55 +2421,55 @@ yyreduce:
yyerror("statsdir remote configuration ignored");
}
}
-#line 2424 "ntp_parser.c" /* yacc.c:1646 */
+#line 2425 "ntp_parser.c" /* yacc.c:1646 */
break;
case 100:
-#line 692 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 693 "ntp_parser.y" /* yacc.c:1646 */
{
filegen_node *fgn;
fgn = create_filegen_node((yyvsp[-1].Integer), (yyvsp[0].Attr_val_fifo));
APPEND_G_FIFO(cfgt.filegen_opts, fgn);
}
-#line 2435 "ntp_parser.c" /* yacc.c:1646 */
+#line 2436 "ntp_parser.c" /* yacc.c:1646 */
break;
case 101:
-#line 702 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 703 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Int_fifo) = (yyvsp[-1].Int_fifo);
APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[0].Integer)));
}
-#line 2444 "ntp_parser.c" /* yacc.c:1646 */
+#line 2445 "ntp_parser.c" /* yacc.c:1646 */
break;
case 102:
-#line 707 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 708 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Int_fifo) = NULL;
APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[0].Integer)));
}
-#line 2453 "ntp_parser.c" /* yacc.c:1646 */
+#line 2454 "ntp_parser.c" /* yacc.c:1646 */
break;
case 111:
-#line 726 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 727 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val_fifo) = NULL; }
-#line 2459 "ntp_parser.c" /* yacc.c:1646 */
+#line 2460 "ntp_parser.c" /* yacc.c:1646 */
break;
case 112:
-#line 728 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 729 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2468 "ntp_parser.c" /* yacc.c:1646 */
+#line 2469 "ntp_parser.c" /* yacc.c:1646 */
break;
case 113:
-#line 736 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 737 "ntp_parser.y" /* yacc.c:1646 */
{
if (lex_from_file()) {
(yyval.Attr_val) = create_attr_sval((yyvsp[-1].Integer), (yyvsp[0].String));
@@ -2478,11 +2479,11 @@ yyreduce:
yyerror("filegen file remote config ignored");
}
}
-#line 2482 "ntp_parser.c" /* yacc.c:1646 */
+#line 2483 "ntp_parser.c" /* yacc.c:1646 */
break;
case 114:
-#line 746 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 747 "ntp_parser.y" /* yacc.c:1646 */
{
if (lex_from_file()) {
(yyval.Attr_val) = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer));
@@ -2491,11 +2492,11 @@ yyreduce:
yyerror("filegen type remote config ignored");
}
}
-#line 2495 "ntp_parser.c" /* yacc.c:1646 */
+#line 2496 "ntp_parser.c" /* yacc.c:1646 */
break;
case 115:
-#line 755 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 756 "ntp_parser.y" /* yacc.c:1646 */
{
const char *err;
@@ -2510,33 +2511,33 @@ yyreduce:
yyerror(err);
}
}
-#line 2514 "ntp_parser.c" /* yacc.c:1646 */
+#line 2515 "ntp_parser.c" /* yacc.c:1646 */
break;
case 116:
-#line 770 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 771 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[0].Integer)); }
-#line 2520 "ntp_parser.c" /* yacc.c:1646 */
+#line 2521 "ntp_parser.c" /* yacc.c:1646 */
break;
case 128:
-#line 800 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 801 "ntp_parser.y" /* yacc.c:1646 */
{
CONCAT_G_FIFOS(cfgt.discard_opts, (yyvsp[0].Attr_val_fifo));
}
-#line 2528 "ntp_parser.c" /* yacc.c:1646 */
+#line 2529 "ntp_parser.c" /* yacc.c:1646 */
break;
case 129:
-#line 804 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 805 "ntp_parser.y" /* yacc.c:1646 */
{
CONCAT_G_FIFOS(cfgt.mru_opts, (yyvsp[0].Attr_val_fifo));
}
-#line 2536 "ntp_parser.c" /* yacc.c:1646 */
+#line 2537 "ntp_parser.c" /* yacc.c:1646 */
break;
case 130:
-#line 808 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 809 "ntp_parser.y" /* yacc.c:1646 */
{
restrict_node *rn;
@@ -2544,11 +2545,11 @@ yyreduce:
lex_current()->curpos.nline);
APPEND_G_FIFO(cfgt.restrict_opts, rn);
}
-#line 2548 "ntp_parser.c" /* yacc.c:1646 */
+#line 2549 "ntp_parser.c" /* yacc.c:1646 */
break;
case 131:
-#line 816 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 817 "ntp_parser.y" /* yacc.c:1646 */
{
restrict_node *rn;
@@ -2556,11 +2557,11 @@ yyreduce:
lex_current()->curpos.nline);
APPEND_G_FIFO(cfgt.restrict_opts, rn);
}
-#line 2560 "ntp_parser.c" /* yacc.c:1646 */
+#line 2561 "ntp_parser.c" /* yacc.c:1646 */
break;
case 132:
-#line 824 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 825 "ntp_parser.y" /* yacc.c:1646 */
{
restrict_node *rn;
@@ -2568,11 +2569,11 @@ yyreduce:
lex_current()->curpos.nline);
APPEND_G_FIFO(cfgt.restrict_opts, rn);
}
-#line 2572 "ntp_parser.c" /* yacc.c:1646 */
+#line 2573 "ntp_parser.c" /* yacc.c:1646 */
break;
case 133:
-#line 832 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 833 "ntp_parser.y" /* yacc.c:1646 */
{
restrict_node *rn;
@@ -2587,11 +2588,11 @@ yyreduce:
lex_current()->curpos.nline);
APPEND_G_FIFO(cfgt.restrict_opts, rn);
}
-#line 2591 "ntp_parser.c" /* yacc.c:1646 */
+#line 2592 "ntp_parser.c" /* yacc.c:1646 */
break;
case 134:
-#line 847 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 848 "ntp_parser.y" /* yacc.c:1646 */
{
restrict_node *rn;
@@ -2606,11 +2607,11 @@ yyreduce:
lex_current()->curpos.nline);
APPEND_G_FIFO(cfgt.restrict_opts, rn);
}
-#line 2610 "ntp_parser.c" /* yacc.c:1646 */
+#line 2611 "ntp_parser.c" /* yacc.c:1646 */
break;
case 135:
-#line 862 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 863 "ntp_parser.y" /* yacc.c:1646 */
{
restrict_node * rn;
@@ -2619,17 +2620,17 @@ yyreduce:
NULL, NULL, (yyvsp[-1].Integer), (yyvsp[0].Int_fifo), lex_current()->curpos.nline);
APPEND_G_FIFO(cfgt.restrict_opts, rn);
}
-#line 2623 "ntp_parser.c" /* yacc.c:1646 */
+#line 2624 "ntp_parser.c" /* yacc.c:1646 */
break;
case 136:
-#line 874 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 875 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Integer) = -1; }
-#line 2629 "ntp_parser.c" /* yacc.c:1646 */
+#line 2630 "ntp_parser.c" /* yacc.c:1646 */
break;
case 137:
-#line 876 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 877 "ntp_parser.y" /* yacc.c:1646 */
{
if (((yyvsp[0].Integer) < -1) || ((yyvsp[0].Integer) > 100)) {
struct FILE_INFO * ip_ctx;
@@ -2645,115 +2646,115 @@ yyreduce:
}
(yyval.Integer) = (yyvsp[0].Integer);
}
-#line 2649 "ntp_parser.c" /* yacc.c:1646 */
+#line 2650 "ntp_parser.c" /* yacc.c:1646 */
break;
case 138:
-#line 895 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 896 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Int_fifo) = NULL; }
-#line 2655 "ntp_parser.c" /* yacc.c:1646 */
+#line 2656 "ntp_parser.c" /* yacc.c:1646 */
break;
case 139:
-#line 897 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 898 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Int_fifo) = (yyvsp[-1].Int_fifo);
APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[0].Integer)));
}
-#line 2664 "ntp_parser.c" /* yacc.c:1646 */
+#line 2665 "ntp_parser.c" /* yacc.c:1646 */
break;
case 157:
-#line 925 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 926 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2673 "ntp_parser.c" /* yacc.c:1646 */
+#line 2674 "ntp_parser.c" /* yacc.c:1646 */
break;
case 158:
-#line 930 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 931 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2682 "ntp_parser.c" /* yacc.c:1646 */
+#line 2683 "ntp_parser.c" /* yacc.c:1646 */
break;
case 159:
-#line 938 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 939 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer)); }
-#line 2688 "ntp_parser.c" /* yacc.c:1646 */
+#line 2689 "ntp_parser.c" /* yacc.c:1646 */
break;
case 163:
-#line 949 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 950 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2697 "ntp_parser.c" /* yacc.c:1646 */
+#line 2698 "ntp_parser.c" /* yacc.c:1646 */
break;
case 164:
-#line 954 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 955 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2706 "ntp_parser.c" /* yacc.c:1646 */
+#line 2707 "ntp_parser.c" /* yacc.c:1646 */
break;
case 165:
-#line 962 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 963 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer)); }
-#line 2712 "ntp_parser.c" /* yacc.c:1646 */
+#line 2713 "ntp_parser.c" /* yacc.c:1646 */
break;
case 174:
-#line 982 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 983 "ntp_parser.y" /* yacc.c:1646 */
{
addr_opts_node *aon;
aon = create_addr_opts_node((yyvsp[-1].Address_node), (yyvsp[0].Attr_val_fifo));
APPEND_G_FIFO(cfgt.fudge, aon);
}
-#line 2723 "ntp_parser.c" /* yacc.c:1646 */
+#line 2724 "ntp_parser.c" /* yacc.c:1646 */
break;
case 175:
-#line 992 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 993 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2732 "ntp_parser.c" /* yacc.c:1646 */
+#line 2733 "ntp_parser.c" /* yacc.c:1646 */
break;
case 176:
-#line 997 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 998 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2741 "ntp_parser.c" /* yacc.c:1646 */
+#line 2742 "ntp_parser.c" /* yacc.c:1646 */
break;
case 177:
-#line 1005 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1006 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_dval((yyvsp[-1].Integer), (yyvsp[0].Double)); }
-#line 2747 "ntp_parser.c" /* yacc.c:1646 */
+#line 2748 "ntp_parser.c" /* yacc.c:1646 */
break;
case 178:
-#line 1007 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1008 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer)); }
-#line 2753 "ntp_parser.c" /* yacc.c:1646 */
+#line 2754 "ntp_parser.c" /* yacc.c:1646 */
break;
case 179:
-#line 1009 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1010 "ntp_parser.y" /* yacc.c:1646 */
{
if ((yyvsp[0].Integer) >= 0 && (yyvsp[0].Integer) <= 16) {
(yyval.Attr_val) = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer));
@@ -2762,89 +2763,89 @@ yyreduce:
yyerror("fudge factor: stratum value not in [0..16], ignored");
}
}
-#line 2766 "ntp_parser.c" /* yacc.c:1646 */
+#line 2767 "ntp_parser.c" /* yacc.c:1646 */
break;
case 180:
-#line 1018 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1019 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_sval((yyvsp[-1].Integer), (yyvsp[0].String)); }
-#line 2772 "ntp_parser.c" /* yacc.c:1646 */
+#line 2773 "ntp_parser.c" /* yacc.c:1646 */
break;
case 181:
-#line 1020 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1021 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_sval((yyvsp[-1].Integer), (yyvsp[0].String)); }
-#line 2778 "ntp_parser.c" /* yacc.c:1646 */
+#line 2779 "ntp_parser.c" /* yacc.c:1646 */
break;
case 188:
-#line 1041 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1042 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.rlimit, (yyvsp[0].Attr_val_fifo)); }
-#line 2784 "ntp_parser.c" /* yacc.c:1646 */
+#line 2785 "ntp_parser.c" /* yacc.c:1646 */
break;
case 189:
-#line 1046 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1047 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2793 "ntp_parser.c" /* yacc.c:1646 */
+#line 2794 "ntp_parser.c" /* yacc.c:1646 */
break;
case 190:
-#line 1051 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1052 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2802 "ntp_parser.c" /* yacc.c:1646 */
+#line 2803 "ntp_parser.c" /* yacc.c:1646 */
break;
case 191:
-#line 1059 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1060 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer)); }
-#line 2808 "ntp_parser.c" /* yacc.c:1646 */
+#line 2809 "ntp_parser.c" /* yacc.c:1646 */
break;
case 195:
-#line 1075 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1076 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.enable_opts, (yyvsp[0].Attr_val_fifo)); }
-#line 2814 "ntp_parser.c" /* yacc.c:1646 */
+#line 2815 "ntp_parser.c" /* yacc.c:1646 */
break;
case 196:
-#line 1077 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1078 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.disable_opts, (yyvsp[0].Attr_val_fifo)); }
-#line 2820 "ntp_parser.c" /* yacc.c:1646 */
+#line 2821 "ntp_parser.c" /* yacc.c:1646 */
break;
case 197:
-#line 1082 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1083 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2829 "ntp_parser.c" /* yacc.c:1646 */
+#line 2830 "ntp_parser.c" /* yacc.c:1646 */
break;
case 198:
-#line 1087 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1088 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2838 "ntp_parser.c" /* yacc.c:1646 */
+#line 2839 "ntp_parser.c" /* yacc.c:1646 */
break;
case 199:
-#line 1095 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1096 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[0].Integer)); }
-#line 2844 "ntp_parser.c" /* yacc.c:1646 */
+#line 2845 "ntp_parser.c" /* yacc.c:1646 */
break;
case 200:
-#line 1097 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1098 "ntp_parser.y" /* yacc.c:1646 */
{
if (lex_from_file()) {
(yyval.Attr_val) = create_attr_ival(T_Flag, (yyvsp[0].Integer));
@@ -2858,74 +2859,74 @@ yyreduce:
yyerror(err_str);
}
}
-#line 2862 "ntp_parser.c" /* yacc.c:1646 */
+#line 2863 "ntp_parser.c" /* yacc.c:1646 */
break;
case 213:
-#line 1136 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1137 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.tinker, (yyvsp[0].Attr_val_fifo)); }
-#line 2868 "ntp_parser.c" /* yacc.c:1646 */
+#line 2869 "ntp_parser.c" /* yacc.c:1646 */
break;
case 214:
-#line 1141 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1142 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2877 "ntp_parser.c" /* yacc.c:1646 */
+#line 2878 "ntp_parser.c" /* yacc.c:1646 */
break;
case 215:
-#line 1146 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1147 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 2886 "ntp_parser.c" /* yacc.c:1646 */
+#line 2887 "ntp_parser.c" /* yacc.c:1646 */
break;
case 216:
-#line 1154 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1155 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_dval((yyvsp[-1].Integer), (yyvsp[0].Double)); }
-#line 2892 "ntp_parser.c" /* yacc.c:1646 */
+#line 2893 "ntp_parser.c" /* yacc.c:1646 */
break;
case 229:
-#line 1179 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1180 "ntp_parser.y" /* yacc.c:1646 */
{
attr_val *av;
av = create_attr_dval((yyvsp[-1].Integer), (yyvsp[0].Double));
APPEND_G_FIFO(cfgt.vars, av);
}
-#line 2903 "ntp_parser.c" /* yacc.c:1646 */
+#line 2904 "ntp_parser.c" /* yacc.c:1646 */
break;
case 230:
-#line 1186 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1187 "ntp_parser.y" /* yacc.c:1646 */
{
attr_val *av;
av = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer));
APPEND_G_FIFO(cfgt.vars, av);
}
-#line 2914 "ntp_parser.c" /* yacc.c:1646 */
+#line 2915 "ntp_parser.c" /* yacc.c:1646 */
break;
case 231:
-#line 1193 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1194 "ntp_parser.y" /* yacc.c:1646 */
{
attr_val *av;
av = create_attr_sval((yyvsp[-1].Integer), (yyvsp[0].String));
APPEND_G_FIFO(cfgt.vars, av);
}
-#line 2925 "ntp_parser.c" /* yacc.c:1646 */
+#line 2926 "ntp_parser.c" /* yacc.c:1646 */
break;
case 232:
-#line 1200 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1201 "ntp_parser.y" /* yacc.c:1646 */
{
char error_text[64];
attr_val *av;
@@ -2941,11 +2942,11 @@ yyreduce:
yyerror(error_text);
}
}
-#line 2945 "ntp_parser.c" /* yacc.c:1646 */
+#line 2946 "ntp_parser.c" /* yacc.c:1646 */
break;
case 233:
-#line 1216 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1217 "ntp_parser.y" /* yacc.c:1646 */
{
if (!lex_from_file()) {
YYFREE((yyvsp[-1].String)); /* avoid leak */
@@ -2964,68 +2965,68 @@ yyreduce:
}
YYFREE((yyvsp[-1].String)); /* avoid leak */
}
-#line 2968 "ntp_parser.c" /* yacc.c:1646 */
+#line 2969 "ntp_parser.c" /* yacc.c:1646 */
break;
case 234:
-#line 1235 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1236 "ntp_parser.y" /* yacc.c:1646 */
{ lex_flush_stack(); }
-#line 2974 "ntp_parser.c" /* yacc.c:1646 */
+#line 2975 "ntp_parser.c" /* yacc.c:1646 */
break;
case 235:
-#line 1237 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1238 "ntp_parser.y" /* yacc.c:1646 */
{ /* see drift_parm below for actions */ }
-#line 2980 "ntp_parser.c" /* yacc.c:1646 */
+#line 2981 "ntp_parser.c" /* yacc.c:1646 */
break;
case 236:
-#line 1239 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1240 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.logconfig, (yyvsp[0].Attr_val_fifo)); }
-#line 2986 "ntp_parser.c" /* yacc.c:1646 */
+#line 2987 "ntp_parser.c" /* yacc.c:1646 */
break;
case 237:
-#line 1241 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1242 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.phone, (yyvsp[0].String_fifo)); }
-#line 2992 "ntp_parser.c" /* yacc.c:1646 */
+#line 2993 "ntp_parser.c" /* yacc.c:1646 */
break;
case 238:
-#line 1243 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1244 "ntp_parser.y" /* yacc.c:1646 */
{ APPEND_G_FIFO(cfgt.setvar, (yyvsp[0].Set_var)); }
-#line 2998 "ntp_parser.c" /* yacc.c:1646 */
+#line 2999 "ntp_parser.c" /* yacc.c:1646 */
break;
case 239:
-#line 1245 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1246 "ntp_parser.y" /* yacc.c:1646 */
{
addr_opts_node *aon;
aon = create_addr_opts_node((yyvsp[-1].Address_node), (yyvsp[0].Attr_val_fifo));
APPEND_G_FIFO(cfgt.trap, aon);
}
-#line 3009 "ntp_parser.c" /* yacc.c:1646 */
+#line 3010 "ntp_parser.c" /* yacc.c:1646 */
break;
case 240:
-#line 1252 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1253 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.ttl, (yyvsp[0].Attr_val_fifo)); }
-#line 3015 "ntp_parser.c" /* yacc.c:1646 */
+#line 3016 "ntp_parser.c" /* yacc.c:1646 */
break;
case 245:
-#line 1267 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1268 "ntp_parser.y" /* yacc.c:1646 */
{
#ifndef LEAP_SMEAR
yyerror("Built without LEAP_SMEAR support.");
#endif
}
-#line 3025 "ntp_parser.c" /* yacc.c:1646 */
+#line 3026 "ntp_parser.c" /* yacc.c:1646 */
break;
case 251:
-#line 1287 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1288 "ntp_parser.y" /* yacc.c:1646 */
{
if (lex_from_file()) {
attr_val *av;
@@ -3036,11 +3037,11 @@ yyreduce:
yyerror("driftfile remote configuration ignored");
}
}
-#line 3040 "ntp_parser.c" /* yacc.c:1646 */
+#line 3041 "ntp_parser.c" /* yacc.c:1646 */
break;
case 252:
-#line 1298 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1299 "ntp_parser.y" /* yacc.c:1646 */
{
if (lex_from_file()) {
attr_val *av;
@@ -3057,11 +3058,11 @@ yyreduce:
yyerror("driftfile remote configuration ignored");
}
}
-#line 3061 "ntp_parser.c" /* yacc.c:1646 */
+#line 3062 "ntp_parser.c" /* yacc.c:1646 */
break;
case 253:
-#line 1315 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1316 "ntp_parser.y" /* yacc.c:1646 */
{
if (lex_from_file()) {
attr_val *av;
@@ -3071,71 +3072,71 @@ yyreduce:
yyerror("driftfile remote configuration ignored");
}
}
-#line 3075 "ntp_parser.c" /* yacc.c:1646 */
+#line 3076 "ntp_parser.c" /* yacc.c:1646 */
break;
case 254:
-#line 1328 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1329 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Set_var) = create_setvar_node((yyvsp[-3].String), (yyvsp[-1].String), (yyvsp[0].Integer)); }
-#line 3081 "ntp_parser.c" /* yacc.c:1646 */
+#line 3082 "ntp_parser.c" /* yacc.c:1646 */
break;
case 256:
-#line 1334 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1335 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Integer) = 0; }
-#line 3087 "ntp_parser.c" /* yacc.c:1646 */
+#line 3088 "ntp_parser.c" /* yacc.c:1646 */
break;
case 257:
-#line 1339 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1340 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val_fifo) = NULL; }
-#line 3093 "ntp_parser.c" /* yacc.c:1646 */
+#line 3094 "ntp_parser.c" /* yacc.c:1646 */
break;
case 258:
-#line 1341 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1342 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 3102 "ntp_parser.c" /* yacc.c:1646 */
+#line 3103 "ntp_parser.c" /* yacc.c:1646 */
break;
case 259:
-#line 1349 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1350 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival((yyvsp[-1].Integer), (yyvsp[0].Integer)); }
-#line 3108 "ntp_parser.c" /* yacc.c:1646 */
+#line 3109 "ntp_parser.c" /* yacc.c:1646 */
break;
case 260:
-#line 1351 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1352 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val) = create_attr_sval((yyvsp[-1].Integer), estrdup((yyvsp[0].Address_node)->address));
destroy_address_node((yyvsp[0].Address_node));
}
-#line 3117 "ntp_parser.c" /* yacc.c:1646 */
+#line 3118 "ntp_parser.c" /* yacc.c:1646 */
break;
case 261:
-#line 1359 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1360 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 3126 "ntp_parser.c" /* yacc.c:1646 */
+#line 3127 "ntp_parser.c" /* yacc.c:1646 */
break;
case 262:
-#line 1364 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1365 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 3135 "ntp_parser.c" /* yacc.c:1646 */
+#line 3136 "ntp_parser.c" /* yacc.c:1646 */
break;
case 263:
-#line 1372 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1373 "ntp_parser.y" /* yacc.c:1646 */
{
char prefix;
char * type;
@@ -3157,141 +3158,141 @@ yyreduce:
(yyval.Attr_val) = create_attr_sval(prefix, estrdup(type));
YYFREE((yyvsp[0].String));
}
-#line 3161 "ntp_parser.c" /* yacc.c:1646 */
+#line 3162 "ntp_parser.c" /* yacc.c:1646 */
break;
case 264:
-#line 1397 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1398 "ntp_parser.y" /* yacc.c:1646 */
{
nic_rule_node *nrn;
nrn = create_nic_rule_node((yyvsp[0].Integer), NULL, (yyvsp[-1].Integer));
APPEND_G_FIFO(cfgt.nic_rules, nrn);
}
-#line 3172 "ntp_parser.c" /* yacc.c:1646 */
+#line 3173 "ntp_parser.c" /* yacc.c:1646 */
break;
case 265:
-#line 1404 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1405 "ntp_parser.y" /* yacc.c:1646 */
{
nic_rule_node *nrn;
nrn = create_nic_rule_node(0, (yyvsp[0].String), (yyvsp[-1].Integer));
APPEND_G_FIFO(cfgt.nic_rules, nrn);
}
-#line 3183 "ntp_parser.c" /* yacc.c:1646 */
+#line 3184 "ntp_parser.c" /* yacc.c:1646 */
break;
case 275:
-#line 1432 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1433 "ntp_parser.y" /* yacc.c:1646 */
{ CONCAT_G_FIFOS(cfgt.reset_counters, (yyvsp[0].Int_fifo)); }
-#line 3189 "ntp_parser.c" /* yacc.c:1646 */
+#line 3190 "ntp_parser.c" /* yacc.c:1646 */
break;
case 276:
-#line 1437 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1438 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Int_fifo) = (yyvsp[-1].Int_fifo);
APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[0].Integer)));
}
-#line 3198 "ntp_parser.c" /* yacc.c:1646 */
+#line 3199 "ntp_parser.c" /* yacc.c:1646 */
break;
case 277:
-#line 1442 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1443 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Int_fifo) = NULL;
APPEND_G_FIFO((yyval.Int_fifo), create_int_node((yyvsp[0].Integer)));
}
-#line 3207 "ntp_parser.c" /* yacc.c:1646 */
+#line 3208 "ntp_parser.c" /* yacc.c:1646 */
break;
case 285:
-#line 1466 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1467 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), create_int_node((yyvsp[0].Integer)));
}
-#line 3216 "ntp_parser.c" /* yacc.c:1646 */
+#line 3217 "ntp_parser.c" /* yacc.c:1646 */
break;
case 286:
-#line 1471 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1472 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), create_int_node((yyvsp[0].Integer)));
}
-#line 3225 "ntp_parser.c" /* yacc.c:1646 */
+#line 3226 "ntp_parser.c" /* yacc.c:1646 */
break;
case 287:
-#line 1479 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1480 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-1].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 3234 "ntp_parser.c" /* yacc.c:1646 */
+#line 3235 "ntp_parser.c" /* yacc.c:1646 */
break;
case 288:
-#line 1484 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1485 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[0].Attr_val));
}
-#line 3243 "ntp_parser.c" /* yacc.c:1646 */
+#line 3244 "ntp_parser.c" /* yacc.c:1646 */
break;
case 289:
-#line 1492 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1493 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_ival('i', (yyvsp[0].Integer)); }
-#line 3249 "ntp_parser.c" /* yacc.c:1646 */
+#line 3250 "ntp_parser.c" /* yacc.c:1646 */
break;
case 291:
-#line 1498 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1499 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_rangeval('-', (yyvsp[-3].Integer), (yyvsp[-1].Integer)); }
-#line 3255 "ntp_parser.c" /* yacc.c:1646 */
+#line 3256 "ntp_parser.c" /* yacc.c:1646 */
break;
case 292:
-#line 1503 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1504 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.String_fifo) = (yyvsp[-1].String_fifo);
APPEND_G_FIFO((yyval.String_fifo), create_string_node((yyvsp[0].String)));
}
-#line 3264 "ntp_parser.c" /* yacc.c:1646 */
+#line 3265 "ntp_parser.c" /* yacc.c:1646 */
break;
case 293:
-#line 1508 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1509 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.String_fifo) = NULL;
APPEND_G_FIFO((yyval.String_fifo), create_string_node((yyvsp[0].String)));
}
-#line 3273 "ntp_parser.c" /* yacc.c:1646 */
+#line 3274 "ntp_parser.c" /* yacc.c:1646 */
break;
case 294:
-#line 1516 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1517 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Address_fifo) = (yyvsp[-1].Address_fifo);
APPEND_G_FIFO((yyval.Address_fifo), (yyvsp[0].Address_node));
}
-#line 3282 "ntp_parser.c" /* yacc.c:1646 */
+#line 3283 "ntp_parser.c" /* yacc.c:1646 */
break;
case 295:
-#line 1521 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1522 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Address_fifo) = NULL;
APPEND_G_FIFO((yyval.Address_fifo), (yyvsp[0].Address_node));
}
-#line 3291 "ntp_parser.c" /* yacc.c:1646 */
+#line 3292 "ntp_parser.c" /* yacc.c:1646 */
break;
case 296:
-#line 1529 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1530 "ntp_parser.y" /* yacc.c:1646 */
{
if ((yyvsp[0].Integer) != 0 && (yyvsp[0].Integer) != 1) {
yyerror("Integer value is not boolean (0 or 1). Assuming 1");
@@ -3300,35 +3301,35 @@ yyreduce:
(yyval.Integer) = (yyvsp[0].Integer);
}
}
-#line 3304 "ntp_parser.c" /* yacc.c:1646 */
+#line 3305 "ntp_parser.c" /* yacc.c:1646 */
break;
case 297:
-#line 1537 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1538 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Integer) = 1; }
-#line 3310 "ntp_parser.c" /* yacc.c:1646 */
+#line 3311 "ntp_parser.c" /* yacc.c:1646 */
break;
case 298:
-#line 1538 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1539 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Integer) = 0; }
-#line 3316 "ntp_parser.c" /* yacc.c:1646 */
+#line 3317 "ntp_parser.c" /* yacc.c:1646 */
break;
case 299:
-#line 1542 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1543 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Double) = (double)(yyvsp[0].Integer); }
-#line 3322 "ntp_parser.c" /* yacc.c:1646 */
+#line 3323 "ntp_parser.c" /* yacc.c:1646 */
break;
case 301:
-#line 1548 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1549 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Integer) = basedate_eval_string((yyvsp[0].String)); YYFREE((yyvsp[0].String)); }
-#line 3328 "ntp_parser.c" /* yacc.c:1646 */
+#line 3329 "ntp_parser.c" /* yacc.c:1646 */
break;
case 302:
-#line 1556 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1557 "ntp_parser.y" /* yacc.c:1646 */
{
sim_node *sn;
@@ -3338,125 +3339,125 @@ yyreduce:
/* Revert from ; to \n for end-of-command */
old_config_style = 1;
}
-#line 3342 "ntp_parser.c" /* yacc.c:1646 */
+#line 3343 "ntp_parser.c" /* yacc.c:1646 */
break;
case 303:
-#line 1573 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1574 "ntp_parser.y" /* yacc.c:1646 */
{ old_config_style = 0; }
-#line 3348 "ntp_parser.c" /* yacc.c:1646 */
+#line 3349 "ntp_parser.c" /* yacc.c:1646 */
break;
case 304:
-#line 1578 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1579 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-2].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[-1].Attr_val));
}
-#line 3357 "ntp_parser.c" /* yacc.c:1646 */
+#line 3358 "ntp_parser.c" /* yacc.c:1646 */
break;
case 305:
-#line 1583 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1584 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[-1].Attr_val));
}
-#line 3366 "ntp_parser.c" /* yacc.c:1646 */
+#line 3367 "ntp_parser.c" /* yacc.c:1646 */
break;
case 306:
-#line 1591 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1592 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_dval((yyvsp[-2].Integer), (yyvsp[0].Double)); }
-#line 3372 "ntp_parser.c" /* yacc.c:1646 */
+#line 3373 "ntp_parser.c" /* yacc.c:1646 */
break;
case 309:
-#line 1601 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1602 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Sim_server_fifo) = (yyvsp[-1].Sim_server_fifo);
APPEND_G_FIFO((yyval.Sim_server_fifo), (yyvsp[0].Sim_server));
}
-#line 3381 "ntp_parser.c" /* yacc.c:1646 */
+#line 3382 "ntp_parser.c" /* yacc.c:1646 */
break;
case 310:
-#line 1606 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1607 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Sim_server_fifo) = NULL;
APPEND_G_FIFO((yyval.Sim_server_fifo), (yyvsp[0].Sim_server));
}
-#line 3390 "ntp_parser.c" /* yacc.c:1646 */
+#line 3391 "ntp_parser.c" /* yacc.c:1646 */
break;
case 311:
-#line 1614 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1615 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Sim_server) = ONLY_SIM(create_sim_server((yyvsp[-4].Address_node), (yyvsp[-2].Double), (yyvsp[-1].Sim_script_fifo))); }
-#line 3396 "ntp_parser.c" /* yacc.c:1646 */
+#line 3397 "ntp_parser.c" /* yacc.c:1646 */
break;
case 312:
-#line 1619 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1620 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Double) = (yyvsp[-1].Double); }
-#line 3402 "ntp_parser.c" /* yacc.c:1646 */
+#line 3403 "ntp_parser.c" /* yacc.c:1646 */
break;
case 313:
-#line 1624 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1625 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Address_node) = (yyvsp[0].Address_node); }
-#line 3408 "ntp_parser.c" /* yacc.c:1646 */
+#line 3409 "ntp_parser.c" /* yacc.c:1646 */
break;
case 314:
-#line 1629 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1630 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Sim_script_fifo) = (yyvsp[-1].Sim_script_fifo);
APPEND_G_FIFO((yyval.Sim_script_fifo), (yyvsp[0].Sim_script));
}
-#line 3417 "ntp_parser.c" /* yacc.c:1646 */
+#line 3418 "ntp_parser.c" /* yacc.c:1646 */
break;
case 315:
-#line 1634 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1635 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Sim_script_fifo) = NULL;
APPEND_G_FIFO((yyval.Sim_script_fifo), (yyvsp[0].Sim_script));
}
-#line 3426 "ntp_parser.c" /* yacc.c:1646 */
+#line 3427 "ntp_parser.c" /* yacc.c:1646 */
break;
case 316:
-#line 1642 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1643 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Sim_script) = ONLY_SIM(create_sim_script_info((yyvsp[-3].Double), (yyvsp[-1].Attr_val_fifo))); }
-#line 3432 "ntp_parser.c" /* yacc.c:1646 */
+#line 3433 "ntp_parser.c" /* yacc.c:1646 */
break;
case 317:
-#line 1647 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1648 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = (yyvsp[-2].Attr_val_fifo);
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[-1].Attr_val));
}
-#line 3441 "ntp_parser.c" /* yacc.c:1646 */
+#line 3442 "ntp_parser.c" /* yacc.c:1646 */
break;
case 318:
-#line 1652 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1653 "ntp_parser.y" /* yacc.c:1646 */
{
(yyval.Attr_val_fifo) = NULL;
APPEND_G_FIFO((yyval.Attr_val_fifo), (yyvsp[-1].Attr_val));
}
-#line 3450 "ntp_parser.c" /* yacc.c:1646 */
+#line 3451 "ntp_parser.c" /* yacc.c:1646 */
break;
case 319:
-#line 1660 "../../ntpd/ntp_parser.y" /* yacc.c:1646 */
+#line 1661 "ntp_parser.y" /* yacc.c:1646 */
{ (yyval.Attr_val) = create_attr_dval((yyvsp[-2].Integer), (yyvsp[0].Double)); }
-#line 3456 "ntp_parser.c" /* yacc.c:1646 */
+#line 3457 "ntp_parser.c" /* yacc.c:1646 */
break;
-#line 3460 "ntp_parser.c" /* yacc.c:1646 */
+#line 3461 "ntp_parser.c" /* yacc.c:1646 */
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -3684,7 +3685,7 @@ yyreturn:
#endif
return yyresult;
}
-#line 1671 "../../ntpd/ntp_parser.y" /* yacc.c:1906 */
+#line 1672 "ntp_parser.y" /* yacc.c:1906 */
void
diff --git a/contrib/ntp/ntpd/ntp_parser.h b/contrib/ntp/ntpd/ntp_parser.h
index 308c2d4..e24b3f4 100644
--- a/contrib/ntp/ntpd/ntp_parser.h
+++ b/contrib/ntp/ntpd/ntp_parser.h
@@ -454,7 +454,7 @@ extern int yydebug;
union YYSTYPE
{
-#line 51 "../../ntpd/ntp_parser.y" /* yacc.c:1909 */
+#line 52 "ntp_parser.y" /* yacc.c:1909 */
char * String;
double Double;
diff --git a/contrib/ntp/ntpd/ntp_proto.c b/contrib/ntp/ntpd/ntp_proto.c
index fb8a837..eb66351 100644
--- a/contrib/ntp/ntpd/ntp_proto.c
+++ b/contrib/ntp/ntpd/ntp_proto.c
@@ -33,7 +33,7 @@
/*
* This macro defines the authentication state. If x is 1 authentication
- * is required; othewise it is optional.
+ * is required; otherwise it is optional.
*/
#define AUTH(x, y) ((x) ? (y) == AUTH_OK \
: (y) == AUTH_OK || (y) == AUTH_NONE)
@@ -272,7 +272,7 @@ kiss_code_check(
}
-/*
+/*
* Check that NAK is valid
*/
nak_code
@@ -315,7 +315,7 @@ valid_NAK(
return INVALIDNAK;
}
- /*
+ /*
* Make sure that the extra field in the packet is all zeros
*/
rpkt = &rbufp->recv_pkt;
@@ -324,10 +324,13 @@ valid_NAK(
return INVALIDNAK;
}
- /*
- * Only valid if peer uses a key
+ /*
+ * During the first few packets of the autokey dance there will
+ * not (yet) be a keyid, but in this case FLAG_SKEY is set.
+ * So the NAK is invalid if either there's no peer, or
+ * if the keyid is 0 and FLAG_SKEY is not set.
*/
- if (!peer || !peer->keyid || !(peer->flags & FLAG_SKEY)) {
+ if (!peer || (!peer->keyid && !(peer->flags & FLAG_SKEY))) {
return INVALIDNAK;
}
@@ -372,14 +375,21 @@ transmit(
hpoll = peer->hpoll;
/*
+ * If we haven't received anything (even if unsync) since last
+ * send, reset ppoll.
+ */
+ if (peer->outdate > peer->timelastrec && !peer->reach)
+ peer->ppoll = peer->maxpoll;
+
+ /*
* In broadcast mode the poll interval is never changed from
* minpoll.
*/
if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) {
peer->outdate = current_time;
+ poll_update(peer, hpoll);
if (sys_leap != LEAP_NOTINSYNC)
peer_xmit(peer);
- poll_update(peer, hpoll);
return;
}
@@ -398,6 +408,7 @@ transmit(
*/
if (peer->cast_flags & MDF_ACAST) {
peer->outdate = current_time;
+ poll_update(peer, hpoll);
if (peer->unreach > sys_beacon) {
peer->unreach = 0;
peer->ttl = 0;
@@ -409,7 +420,6 @@ transmit(
peer_xmit(peer);
}
peer->unreach++;
- poll_update(peer, hpoll);
return;
}
@@ -427,11 +437,11 @@ transmit(
*/
if (peer->cast_flags & MDF_POOL) {
peer->outdate = current_time;
+ poll_update(peer, hpoll);
if ( (peer_associations <= 2 * sys_maxclock)
&& ( peer_associations < sys_maxclock
|| sys_survivors < sys_minclock))
pool_xmit(peer);
- poll_update(peer, hpoll);
return;
}
@@ -539,9 +549,9 @@ transmit(
/*
* Do not transmit if in broadcast client mode.
*/
+ poll_update(peer, hpoll);
if (peer->hmode != MODE_BCLIENT)
peer_xmit(peer);
- poll_update(peer, hpoll);
return;
}
@@ -645,7 +655,7 @@ receive(
hisleap = PKT_LEAP(pkt->li_vn_mode);
hismode = (int)PKT_MODE(pkt->li_vn_mode);
hisstratum = PKT_TO_STRATUM(pkt->stratum);
- DPRINTF(2, ("receive: at %ld %s<-%s ippeerlimit %d mode %d iflags %s restrict %s org %#010x.%08x xmt %#010x.%08x\n",
+ DPRINTF(1, ("receive: at %ld %s<-%s ippeerlimit %d mode %d iflags %s restrict %s org %#010x.%08x xmt %#010x.%08x\n",
current_time, stoa(&rbufp->dstadr->sin),
stoa(&rbufp->recv_srcadr), r4a.ippeerlimit, hismode,
build_iflags(rbufp->dstadr->flags),
@@ -737,7 +747,7 @@ receive(
} else {
DPRINTF(2, ("receive: drop: MODE_UNSPEC\n"));
sys_badlength++;
- return; /* invalid mode */
+ return; /* invalid mode */
}
}
@@ -841,7 +851,7 @@ receive(
/*
** Packet Data Verification Layer
**
- ** This layer verifies the packet data content. If
+ ** This layer verifies the packet data content. If
** authentication is required, a MAC must be present.
** If a MAC is present, it must validate.
** Crypto-NAK? Look - a shiny thing!
@@ -949,7 +959,7 @@ receive(
if (0 != peer) {
peer->badNAK++;
}
- msyslog(LOG_ERR, "Invalid-NAK error at %ld %s<-%s",
+ msyslog(LOG_ERR, "Invalid-NAK error at %ld %s<-%s",
current_time, stoa(dstadr_sin), stoa(&rbufp->recv_srcadr));
return;
}
@@ -957,7 +967,7 @@ receive(
if (has_mac == 0) {
restrict_mask &= ~RES_MSSNTP;
is_authentic = AUTH_NONE; /* not required */
- DPRINTF(2, ("receive: at %ld %s<-%s mode %d/%s:%s len %d org %#010x.%08x xmt %#010x.%08x NOMAC\n",
+ DPRINTF(1, ("receive: at %ld %s<-%s mode %d/%s:%s len %d org %#010x.%08x xmt %#010x.%08x NOMAC\n",
current_time, stoa(dstadr_sin),
stoa(&rbufp->recv_srcadr), hismode, hm_str, am_str,
authlen,
@@ -966,7 +976,7 @@ receive(
} else if (crypto_nak_test == VALIDNAK) {
restrict_mask &= ~RES_MSSNTP;
is_authentic = AUTH_CRYPTO; /* crypto-NAK */
- DPRINTF(2, ("receive: at %ld %s<-%s mode %d/%s:%s keyid %08x len %d auth %d org %#010x.%08x xmt %#010x.%08x MAC4\n",
+ DPRINTF(1, ("receive: at %ld %s<-%s mode %d/%s:%s keyid %08x len %d auth %d org %#010x.%08x xmt %#010x.%08x CRYPTONAK\n",
current_time, stoa(dstadr_sin),
stoa(&rbufp->recv_srcadr), hismode, hm_str, am_str,
skeyid, authlen + has_mac, is_authentic,
@@ -989,13 +999,19 @@ receive(
&& (memcmp(zero_key, (char *)pkt + authlen + 4,
MAX_MD5_LEN - 4) == 0)) {
is_authentic = AUTH_NONE;
+ DPRINTF(1, ("receive: at %ld %s<-%s mode %d/%s:%s len %d org %#010x.%08x xmt %#010x.%08x SIGND\n",
+ current_time, stoa(dstadr_sin),
+ stoa(&rbufp->recv_srcadr), hismode, hm_str, am_str,
+ authlen,
+ ntohl(pkt->org.l_ui), ntohl(pkt->org.l_uf),
+ ntohl(pkt->xmt.l_ui), ntohl(pkt->xmt.l_uf)));
#endif /* HAVE_NTP_SIGND */
} else {
/*
* has_mac is not 0
* Not a VALID_NAK
- * Not an MS-SNTP SIGND packet
+ * Not an MS-SNTP SIGND packet
*
* So there is a MAC here.
*/
@@ -1054,7 +1070,7 @@ receive(
ANY_INTERFACE_CHOOSE(&rbufp->recv_srcadr)) {
DPRINTF(2, ("receive: drop: BCAST from wildcard\n"));
sys_restricted++;
- return; /* no wildcard */
+ return; /* no wildcard */
}
pkeyid = 0;
if (!SOCK_UNSPEC(&rbufp->dstadr->bcast))
@@ -1106,7 +1122,7 @@ receive(
if (crypto_flags && skeyid > NTP_MAXKEY)
authtrust(skeyid, 0);
#endif /* AUTOKEY */
- DPRINTF(2, ("receive: at %ld %s<-%s mode %d/%s:%s keyid %08x len %d auth %d org %#010x.%08x xmt %#010x.%08x\n",
+ DPRINTF(1, ("receive: at %ld %s<-%s mode %d/%s:%s keyid %08x len %d auth %d org %#010x.%08x xmt %#010x.%08x MAC\n",
current_time, stoa(dstadr_sin),
stoa(&rbufp->recv_srcadr), hismode, hm_str, am_str,
skeyid, authlen + has_mac, is_authentic,
@@ -1198,6 +1214,8 @@ receive(
* client association; a symmetric active packet mobilizes a
* symmetric passive association.
*/
+ DPRINTF(1, ("receive: MATCH_ASSOC dispatch: mode %d/%s:%s \n",
+ hismode, hm_str, am_str));
switch (retcode) {
/*
@@ -1373,7 +1391,7 @@ receive(
if (NULL == peer) {
DPRINTF(2, ("receive: AM_MANYCAST drop: duplicate\n"));
sys_declined++;
- return; /* ignore duplicate */
+ return; /* ignore duplicate */
}
/*
@@ -1511,10 +1529,10 @@ receive(
* is fixed at this value.
*/
peer = newpeer(&rbufp->recv_srcadr, NULL, match_ep,
- r4a.ippeerlimit, MODE_CLIENT, hisversion,
- pkt->ppoll, pkt->ppoll,
- FLAG_BC_VOL | FLAG_IBURST | FLAG_PREEMPT, MDF_BCLNT,
- 0, skeyid, sys_ident);
+ r4a.ippeerlimit, MODE_CLIENT, hisversion,
+ pkt->ppoll, pkt->ppoll,
+ FLAG_BC_VOL | FLAG_IBURST | FLAG_PREEMPT, MDF_BCLNT,
+ 0, skeyid, sys_ident);
if (NULL == peer) {
DPRINTF(2, ("receive: AM_NEWBCL drop: empty newpeer() failed\n"));
sys_restricted++;
@@ -1529,15 +1547,19 @@ receive(
return; /* hooray */
/*
- * This is the first packet received from a symmetric active
- * peer. If the packet is authentic, the first he sent, and
- * RES_NOEPEER is not enabled, mobilize a passive association
- * If not, kiss the frog.
+ * This is the first packet received from a potential ephemeral
+ * symmetric active peer. First, deal with broken Windows clients.
+ * Then, if NOEPEER is enabled, drop it. If the packet meets our
+ * authenticty requirements and is the first he sent, mobilize
+ * a passive association.
+ * Otherwise, kiss the frog.
*
* There are cases here where we do not call record_raw_stats().
*/
case AM_NEWPASS:
+ DEBUG_REQUIRE(MODE_ACTIVE == hismode);
+
#ifdef AUTOKEY
/*
* Do not respond if not the same group.
@@ -1551,27 +1573,33 @@ receive(
if (!AUTH(sys_authenticate | (restrict_mask &
(RES_NOPEER | RES_DONTTRUST)), is_authentic)
) {
- if (0 == (restrict_mask & RES_NOEPEER)) {
- /*
- * If authenticated but cannot mobilize an
- * association, send a symmetric passive
- * response without mobilizing an association.
- * This is for drat broken Windows clients. See
- * Microsoft KB 875424 for preferred workaround.
- */
- if (AUTH(restrict_mask & RES_DONTTRUST,
- is_authentic)) {
- fast_xmit(rbufp, MODE_PASSIVE, skeyid,
- restrict_mask);
- return; /* hooray */
- }
- if (is_authentic == AUTH_ERROR) {
- fast_xmit(rbufp, MODE_ACTIVE, 0,
- restrict_mask);
- sys_restricted++;
- return;
- }
+ /*
+ * If authenticated but cannot mobilize an
+ * association, send a symmetric passive
+ * response without mobilizing an association.
+ * This is for drat broken Windows clients. See
+ * Microsoft KB 875424 for preferred workaround.
+ */
+ if (AUTH(restrict_mask & RES_DONTTRUST,
+ is_authentic)) {
+ fast_xmit(rbufp, MODE_PASSIVE, skeyid,
+ restrict_mask);
+ return; /* hooray */
}
+ /* HMS: Why is this next set of lines a feature? */
+ if (is_authentic == AUTH_ERROR) {
+ fast_xmit(rbufp, MODE_PASSIVE, 0,
+ restrict_mask);
+ sys_restricted++;
+ return;
+ }
+
+ if (restrict_mask & RES_NOEPEER) {
+ DPRINTF(2, ("receive: AM_NEWPASS drop: NOEPEER\n"));
+ sys_declined++;
+ return;
+ }
+
/* [Bug 2941]
* If we got here, the packet isn't part of an
* existing association, either isn't correctly
@@ -1593,6 +1621,12 @@ receive(
return;
}
+ if (restrict_mask & RES_NOEPEER) {
+ DPRINTF(2, ("receive: AM_NEWPASS drop: NOEPEER\n"));
+ sys_declined++;
+ return;
+ }
+
/*
* Do not respond if synchronized and if stratum is
* below the floor or at or above the ceiling. Note,
@@ -1670,8 +1704,8 @@ receive(
}
/* This is error-worthy */
- if (pkt->ppoll < peer->minpoll ||
- pkt->ppoll > peer->maxpoll ) {
+ if ( pkt->ppoll < peer->minpoll
+ || pkt->ppoll > peer->maxpoll) {
msyslog(LOG_INFO, "receive: broadcast poll of %u from %s is out-of-range (%d to %d)!",
pkt->ppoll, stoa(&rbufp->recv_srcadr),
peer->minpoll, peer->maxpoll);
@@ -1719,7 +1753,7 @@ receive(
* network is trustable, so we take our accepted
* broadcast packets as we receive them. But
* some folks might want to take additional poll
- * delays before believing a backward step.
+ * delays before believing a backward step.
*/
if (sys_bcpollbstep) {
/* pkt->ppoll or peer->ppoll ? */
@@ -1735,8 +1769,8 @@ receive(
tdiff = p_xmt;
L_SUB(&tdiff, &peer->bxmt);
}
- if (tdiff.l_i < 0 &&
- (current_time - peer->timereceived) < deadband)
+ if ( tdiff.l_i < 0
+ && (current_time - peer->timereceived) < deadband)
{
msyslog(LOG_INFO, "receive: broadcast packet from %s contains non-monotonic timestamp: %#010x.%08x -> %#010x.%08x",
stoa(&rbufp->recv_srcadr),
@@ -2431,6 +2465,7 @@ process_packet(
peer->seldisptoolarge++;
DPRINTF(1, ("packet: flash header %04x\n",
peer->flash));
+ poll_update(peer, peer->hpoll); /* ppoll updated? */
return;
}
@@ -2586,7 +2621,7 @@ process_packet(
* between the unicast timestamp and the broadcast
* timestamp. This works for both basic and interleaved
* modes.
- * [Bug 3031] Don't keep this peer when the delay
+ * [Bug 3031] Don't keep this peer when the delay
* calculation gives reason to suspect clock steps.
* This is assumed for delays > 50ms.
*/
@@ -2977,8 +3012,6 @@ poll_update(
} else {
if (peer->retry > 0)
hpoll = peer->minpoll;
- else if (!(peer->reach))
- hpoll = peer->hpoll;
else
hpoll = min(peer->ppoll, peer->hpoll);
#ifdef REFCLOCK
@@ -3072,6 +3105,10 @@ peer_clear(
peer->stratum = STRATUM_UNSPEC;
memcpy(&peer->refid, ident, 4);
#ifdef REFCLOCK
+ } else {
+ /* Clear refclock sample filter */
+ peer->procptr->codeproc = 0;
+ peer->procptr->coderecv = 0;
}
#endif
@@ -3987,7 +4024,7 @@ peer_xmit(
DPRINTF(1, ("peer_xmit: at %ld %s->%s mode %d len %zu xmt %#010x.%08x\n",
current_time,
peer->dstadr ? stoa(&peer->dstadr->sin) : "-",
- stoa(&peer->srcadr), peer->hmode, sendlen,
+ stoa(&peer->srcadr), peer->hmode, sendlen,
xmt_tx.l_ui, xmt_tx.l_uf));
return;
}
@@ -4330,7 +4367,7 @@ leap_smear_add_offs(
return;
}
-#endif /* LEAP_SMEAR */
+#endif /* LEAP_SMEAR */
/*
diff --git a/contrib/ntp/ntpd/ntp_refclock.c b/contrib/ntp/ntpd/ntp_refclock.c
index a0dbd4c..d109b71 100644
--- a/contrib/ntp/ntpd/ntp_refclock.c
+++ b/contrib/ntp/ntpd/ntp_refclock.c
@@ -112,7 +112,7 @@ refclock_report(
/* ignore others */
break;
}
- if (pp->lastevent < 15)
+ if ((code != CEVNT_NOMINAL) && (pp->lastevent < 15))
pp->lastevent++;
if (pp->currentstatus != code) {
pp->currentstatus = (u_char)code;
diff --git a/contrib/ntp/ntpd/ntp_request.c b/contrib/ntp/ntpd/ntp_request.c
index e541f7c..5358508 100644
--- a/contrib/ntp/ntpd/ntp_request.c
+++ b/contrib/ntp/ntpd/ntp_request.c
@@ -890,6 +890,7 @@ peer_info (
ip->flags |= INFO_FLAG_SHORTLIST;
ip->leap = pp->leap;
ip->hmode = pp->hmode;
+ ip->pmode = pp->pmode;
ip->keyid = pp->keyid;
ip->stratum = pp->stratum;
ip->ppoll = pp->ppoll;
@@ -2535,7 +2536,15 @@ get_clock_info(
DTOLFP(clock_stat.fudgetime2, &ltmp);
HTONL_FP(&ltmp, &ic->fudgetime2);
ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1);
+ /* [Bug3527] Backward Incompatible: ic->fudgeval2 is
+ * a string, instantiated via memcpy() so there is no
+ * endian issue to correct.
+ */
+#ifdef DISABLE_BUG3527_FIX
ic->fudgeval2 = htonl(clock_stat.fudgeval2);
+#else
+ ic->fudgeval2 = clock_stat.fudgeval2;
+#endif
free_varlist(clock_stat.kv_list);
diff --git a/contrib/ntp/ntpd/ntp_timer.c b/contrib/ntp/ntpd/ntp_timer.c
index 9ee35f8..9725b5b 100644
--- a/contrib/ntp/ntpd/ntp_timer.c
+++ b/contrib/ntp/ntpd/ntp_timer.c
@@ -82,8 +82,8 @@ u_long orphwait; /* orphan wait time */
#ifdef AUTOKEY
static u_long revoke_timer; /* keys revoke timer */
static u_long keys_timer; /* session key timer */
-u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
-u_long sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
+u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
+u_char sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
#endif /* AUTOKEY */
/*
@@ -404,7 +404,7 @@ timer(void)
* Garbage collect expired keys.
*/
if (keys_timer <= current_time) {
- keys_timer += 1 << sys_automax;
+ keys_timer += (1UL << sys_automax);
auth_agekeys();
}
@@ -413,7 +413,7 @@ timer(void)
* to regenerate cookies.
*/
if (revoke_timer && revoke_timer <= current_time) {
- revoke_timer += 1 << sys_revoke;
+ revoke_timer += (1UL << sys_revoke);
RAND_bytes((u_char *)&sys_private, 4);
}
#endif /* AUTOKEY */
diff --git a/contrib/ntp/ntpd/ntpd-opts.c b/contrib/ntp/ntpd/ntpd-opts.c
index 47b0808..f07269d 100644
--- a/contrib/ntp/ntpd/ntpd-opts.c
+++ b/contrib/ntp/ntpd/ntpd-opts.c
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntpd-opts.c)
*
- * It has been AutoGen-ed February 27, 2018 at 05:13:19 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:56:15 AM by AutoGen 5.18.5
* From the definitions ntpd-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This source file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -75,7 +75,7 @@ extern FILE * option_usage_fp;
* static const strings for ntpd options
*/
static char const ntpd_opt_strs[3132] =
-/* 0 */ "ntpd 4.2.8p11\n"
+/* 0 */ "ntpd 4.2.8p13\n"
"Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n"
"This is free software. It is licensed for use, modification and\n"
"redistribution under the terms of the NTP License, copies of which\n"
@@ -205,12 +205,12 @@ static char const ntpd_opt_strs[3132] =
/* 2901 */ "output version information and exit\0"
/* 2937 */ "version\0"
/* 2945 */ "NTPD\0"
-/* 2950 */ "ntpd - NTP daemon program - Ver. 4.2.8p11\n"
+/* 2950 */ "ntpd - NTP daemon program - Ver. 4.2.8p13\n"
"Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \\\n"
"\t\t[ <server1> ... <serverN> ]\n\0"
/* 3082 */ "http://bugs.ntp.org, bugs@ntp.org\0"
/* 3116 */ "\n\0"
-/* 3118 */ "ntpd 4.2.8p11";
+/* 3118 */ "ntpd 4.2.8p13";
/**
* ipv4 option description with
@@ -1529,7 +1529,7 @@ static void bogus_function(void) {
translate option names.
*/
/* referenced via ntpdOptions.pzCopyright */
- puts(_("ntpd 4.2.8p11\n\
+ puts(_("ntpd 4.2.8p13\n\
Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n\
This is free software. It is licensed for use, modification and\n\
redistribution under the terms of the NTP License, copies of which\n\
@@ -1670,7 +1670,7 @@ implied warranty.\n"));
puts(_("output version information and exit"));
/* referenced via ntpdOptions.pzUsageTitle */
- puts(_("ntpd - NTP daemon program - Ver. 4.2.8p11\n\
+ puts(_("ntpd - NTP daemon program - Ver. 4.2.8p13\n\
Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \\\n\
\t\t[ <server1> ... <serverN> ]\n"));
@@ -1678,7 +1678,7 @@ Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \\\n\
puts(_("\n"));
/* referenced via ntpdOptions.pzFullVersion */
- puts(_("ntpd 4.2.8p11"));
+ puts(_("ntpd 4.2.8p13"));
/* referenced via ntpdOptions.pzFullUsage */
puts(_("<<<NOT-FOUND>>>"));
diff --git a/contrib/ntp/ntpd/ntpd-opts.h b/contrib/ntp/ntpd/ntpd-opts.h
index 3372d4d..e7e8a60 100644
--- a/contrib/ntp/ntpd/ntpd-opts.h
+++ b/contrib/ntp/ntpd/ntpd-opts.h
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntpd-opts.h)
*
- * It has been AutoGen-ed February 27, 2018 at 05:13:17 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:56:15 AM by AutoGen 5.18.5
* From the definitions ntpd-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This header file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -53,7 +53,7 @@
* tolerable version is at least as old as what was current when the header
* template was released.
*/
-#define AO_TEMPLATE_VERSION 167936
+#define AO_TEMPLATE_VERSION 167937
#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
|| (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
# error option template version mismatches autoopts/options.h header
@@ -106,9 +106,9 @@ typedef enum {
/** count of all options for ntpd */
#define OPTION_CT 38
/** ntpd version */
-#define NTPD_VERSION "4.2.8p11"
+#define NTPD_VERSION "4.2.8p13"
/** Full ntpd version text */
-#define NTPD_FULL_VERSION "ntpd 4.2.8p11"
+#define NTPD_FULL_VERSION "ntpd 4.2.8p13"
/**
* Interface defines for all options. Replace "n" with the UPPER_CASED
diff --git a/contrib/ntp/ntpd/ntpd.1ntpdman b/contrib/ntp/ntpd/ntpd.1ntpdman
index ec02e0c..92d053e 100644
--- a/contrib/ntp/ntpd/ntpd.1ntpdman
+++ b/contrib/ntp/ntpd/ntpd.1ntpdman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpd 1ntpdman "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH ntpd 1ntpdman "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-Ffa4WQ/ag-RfaWVQ)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:30 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:46 AM by AutoGen 5.18.5
.\" From the definitions ntpd-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/ntpd/ntpd.1ntpdmdoc b/contrib/ntp/ntpd/ntpd.1ntpdmdoc
index 339d2cf..9620898 100644
--- a/contrib/ntp/ntpd/ntpd.1ntpdmdoc
+++ b/contrib/ntp/ntpd/ntpd.1ntpdmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPD 1ntpdmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpd-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:47 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:37 AM by AutoGen 5.18.5
.\" From the definitions ntpd-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/ntpd/ntpd.c b/contrib/ntp/ntpd/ntpd.c
index d4204ef..912da26 100644
--- a/contrib/ntp/ntpd/ntpd.c
+++ b/contrib/ntp/ntpd/ntpd.c
@@ -104,6 +104,10 @@
#endif
#endif
+#ifdef SYS_WINNT
+# include "ntservice.h"
+#endif
+
#ifdef _AIX
# include <ulimit.h>
#endif /* _AIX */
@@ -182,7 +186,6 @@ char *group; /* group to switch to */
const char *chrootdir; /* directory to chroot to */
uid_t sw_uid;
gid_t sw_gid;
-char *endp;
struct group *gr;
struct passwd *pw;
#endif /* HAVE_DROPROOT */
@@ -523,6 +526,236 @@ set_process_priority(void)
}
#endif /* !SIM */
+#if !defined(SIM) && !defined(SYS_WINNT)
+/*
+ * Detach from terminal (much like daemon())
+ * Nothe that this function calls exit()
+ */
+# ifdef HAVE_WORKING_FORK
+static void
+detach_from_terminal(
+ int pipe_fds[2],
+ long wait_sync,
+ const char *logfilename
+ )
+{
+ int rc;
+ int exit_code;
+# if !defined(HAVE_SETSID) && !defined (HAVE_SETPGID) && defined(TIOCNOTTY)
+ int fid;
+# endif
+# ifdef _AIX
+ struct sigaction sa;
+# endif
+
+ rc = fork();
+ if (-1 == rc) {
+ exit_code = (errno) ? errno : -1;
+ msyslog(LOG_ERR, "fork: %m");
+ exit(exit_code);
+ }
+ if (rc > 0) {
+ /* parent */
+ exit_code = wait_child_sync_if(pipe_fds[0],
+ wait_sync);
+ exit(exit_code);
+ }
+
+ /*
+ * child/daemon
+ * close all open files excepting waitsync_fd_to_close.
+ * msyslog() unreliable until after init_logging().
+ */
+ closelog();
+ if (syslog_file != NULL) {
+ fclose(syslog_file);
+ syslog_file = NULL;
+ syslogit = TRUE;
+ }
+ close_all_except(waitsync_fd_to_close);
+ INSIST(0 == open("/dev/null", 0) && 1 == dup2(0, 1) \
+ && 2 == dup2(0, 2));
+
+ init_logging(progname, 0, TRUE);
+ /* we lost our logfile (if any) daemonizing */
+ setup_logfile(logfilename);
+
+# ifdef SYS_DOMAINOS
+ {
+ uid_$t puid;
+ status_$t st;
+
+ proc2_$who_am_i(&puid);
+ proc2_$make_server(&puid, &st);
+ }
+# endif /* SYS_DOMAINOS */
+# ifdef HAVE_SETSID
+ if (setsid() == (pid_t)-1)
+ msyslog(LOG_ERR, "setsid(): %m");
+# elif defined(HAVE_SETPGID)
+ if (setpgid(0, 0) == -1)
+ msyslog(LOG_ERR, "setpgid(): %m");
+# else /* !HAVE_SETSID && !HAVE_SETPGID follows */
+# ifdef TIOCNOTTY
+ fid = open("/dev/tty", 2);
+ if (fid >= 0) {
+ ioctl(fid, (u_long)TIOCNOTTY, NULL);
+ close(fid);
+ }
+# endif /* TIOCNOTTY */
+ ntp_setpgrp(0, getpid());
+# endif /* !HAVE_SETSID && !HAVE_SETPGID */
+# ifdef _AIX
+ /* Don't get killed by low-on-memory signal. */
+ sa.sa_handler = catch_danger;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGDANGER, &sa, NULL);
+# endif /* _AIX */
+
+ return;
+}
+# endif /* HAVE_WORKING_FORK */
+
+#ifdef HAVE_DROPROOT
+/*
+ * Map user name/number to user ID
+*/
+static int
+map_user(
+ )
+{
+ char *endp;
+
+ if (isdigit((unsigned char)*user)) {
+ sw_uid = (uid_t)strtoul(user, &endp, 0);
+ if (*endp != '\0')
+ goto getuser;
+
+ if ((pw = getpwuid(sw_uid)) != NULL) {
+ free(user);
+ user = estrdup(pw->pw_name);
+ sw_gid = pw->pw_gid;
+ } else {
+ errno = 0;
+ msyslog(LOG_ERR, "Cannot find user ID %s", user);
+ return 0;
+ }
+
+ } else {
+getuser:
+ errno = 0;
+ if ((pw = getpwnam(user)) != NULL) {
+ sw_uid = pw->pw_uid;
+ sw_gid = pw->pw_gid;
+ } else {
+ if (errno)
+ msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user);
+ else
+ msyslog(LOG_ERR, "Cannot find user `%s'", user);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Map group name/number to group ID
+*/
+static int
+map_group(void)
+{
+ char *endp;
+
+ if (isdigit((unsigned char)*group)) {
+ sw_gid = (gid_t)strtoul(group, &endp, 0);
+ if (*endp != '\0')
+ goto getgroup;
+ } else {
+getgroup:
+ if ((gr = getgrnam(group)) != NULL) {
+ sw_gid = gr->gr_gid;
+ } else {
+ errno = 0;
+ msyslog(LOG_ERR, "Cannot find group `%s'", group);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int
+set_group_ids(void)
+{
+ if (user && initgroups(user, sw_gid)) {
+ msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user);
+ return 0;
+ }
+ if (group && setgid(sw_gid)) {
+ msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group);
+ return 0;
+ }
+ if (group && setegid(sw_gid)) {
+ msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group);
+ return 0;
+ }
+ if (group) {
+ if (0 != setgroups(1, &sw_gid)) {
+ msyslog(LOG_ERR, "setgroups(1, %d) failed: %m", sw_gid);
+ return 0;
+ }
+ }
+ else if (pw)
+ if (0 != initgroups(pw->pw_name, pw->pw_gid)) {
+ msyslog(LOG_ERR, "initgroups(<%s>, %d) filed: %m", pw->pw_name, pw->pw_gid);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+set_user_ids(void)
+{
+ if (user && setuid(sw_uid)) {
+ msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user);
+ return 0;
+ }
+ if (user && seteuid(sw_uid)) {
+ msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Change (effective) user and group IDs, also initialize the supplementary group access list
+ */
+int set_user_group_ids(void);
+int
+set_user_group_ids(void)
+{
+ /* If the the user was already mapped, no need to map it again */
+ if ((NULL != user) && (0 == sw_uid)) {
+ if (0 == map_user())
+ exit (-1);
+ }
+ /* same applies for the group */
+ if ((NULL != group) && (0 == sw_gid)) {
+ if (0 == map_group())
+ exit (-1);
+ }
+
+ if (getegid() != sw_gid && 0 == set_group_ids())
+ return 0;
+ if (geteuid() != sw_uid && 0 == set_user_ids())
+ return 0;
+
+ return 1;
+}
+#endif /* HAVE_DROPROOT */
+#endif /* !SIM */
/*
* Main program. Initialize us, disconnect us from the tty if necessary,
@@ -549,12 +782,6 @@ ntpdmain(
int pipe_fds[2];
int rc;
int exit_code;
-# ifdef _AIX
- struct sigaction sa;
-# endif
-# if !defined(HAVE_SETSID) && !defined (HAVE_SETPGID) && defined(TIOCNOTTY)
- int fid;
-# endif
# endif /* HAVE_WORKING_FORK*/
# ifdef SCO5_CLOCK
int fd;
@@ -718,6 +945,11 @@ ntpdmain(
init_lib();
# ifdef SYS_WINNT
/*
+ * Make sure the service is initialized before we do anything else
+ */
+ ntservice_init();
+
+ /*
* Start interpolation thread, must occur before first
* get_systime()
*/
@@ -736,70 +968,7 @@ ntpdmain(
if (!nofork) {
# ifdef HAVE_WORKING_FORK
- rc = fork();
- if (-1 == rc) {
- exit_code = (errno) ? errno : -1;
- msyslog(LOG_ERR, "fork: %m");
- exit(exit_code);
- }
- if (rc > 0) {
- /* parent */
- exit_code = wait_child_sync_if(pipe_fds[0],
- wait_sync);
- exit(exit_code);
- }
-
- /*
- * child/daemon
- * close all open files excepting waitsync_fd_to_close.
- * msyslog() unreliable until after init_logging().
- */
- closelog();
- if (syslog_file != NULL) {
- fclose(syslog_file);
- syslog_file = NULL;
- syslogit = TRUE;
- }
- close_all_except(waitsync_fd_to_close);
- INSIST(0 == open("/dev/null", 0) && 1 == dup2(0, 1) \
- && 2 == dup2(0, 2));
-
- init_logging(progname, 0, TRUE);
- /* we lost our logfile (if any) daemonizing */
- setup_logfile(logfilename);
-
-# ifdef SYS_DOMAINOS
- {
- uid_$t puid;
- status_$t st;
-
- proc2_$who_am_i(&puid);
- proc2_$make_server(&puid, &st);
- }
-# endif /* SYS_DOMAINOS */
-# ifdef HAVE_SETSID
- if (setsid() == (pid_t)-1)
- msyslog(LOG_ERR, "setsid(): %m");
-# elif defined(HAVE_SETPGID)
- if (setpgid(0, 0) == -1)
- msyslog(LOG_ERR, "setpgid(): %m");
-# else /* !HAVE_SETSID && !HAVE_SETPGID follows */
-# ifdef TIOCNOTTY
- fid = open("/dev/tty", 2);
- if (fid >= 0) {
- ioctl(fid, (u_long)TIOCNOTTY, NULL);
- close(fid);
- }
-# endif /* TIOCNOTTY */
- ntp_setpgrp(0, getpid());
-# endif /* !HAVE_SETSID && !HAVE_SETPGID */
-# ifdef _AIX
- /* Don't get killed by low-on-memory signal. */
- sa.sa_handler = catch_danger;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sigaction(SIGDANGER, &sa, NULL);
-# endif /* _AIX */
+ detach_from_terminal(pipe_fds, wait_sync, logfilename);
# endif /* HAVE_WORKING_FORK */
}
@@ -972,51 +1141,12 @@ ntpdmain(
# endif /* HAVE_LINUX_CAPABILITIES || HAVE_SOLARIS_PRIVS */
if (user != NULL) {
- if (isdigit((unsigned char)*user)) {
- sw_uid = (uid_t)strtoul(user, &endp, 0);
- if (*endp != '\0')
- goto getuser;
-
- if ((pw = getpwuid(sw_uid)) != NULL) {
- free(user);
- user = estrdup(pw->pw_name);
- sw_gid = pw->pw_gid;
- } else {
- errno = 0;
- msyslog(LOG_ERR, "Cannot find user ID %s", user);
- exit (-1);
- }
-
- } else {
-getuser:
- errno = 0;
- if ((pw = getpwnam(user)) != NULL) {
- sw_uid = pw->pw_uid;
- sw_gid = pw->pw_gid;
- } else {
- if (errno)
- msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user);
- else
- msyslog(LOG_ERR, "Cannot find user `%s'", user);
- exit (-1);
- }
- }
+ if (0 == map_user())
+ exit (-1);
}
if (group != NULL) {
- if (isdigit((unsigned char)*group)) {
- sw_gid = (gid_t)strtoul(group, &endp, 0);
- if (*endp != '\0')
- goto getgroup;
- } else {
-getgroup:
- if ((gr = getgrnam(group)) != NULL) {
- sw_gid = gr->gr_gid;
- } else {
- errno = 0;
- msyslog(LOG_ERR, "Cannot find group `%s'", group);
- exit (-1);
- }
- }
+ if (0 == map_group())
+ exit (-1);
}
if (chrootdir ) {
@@ -1050,37 +1180,8 @@ getgroup:
exit(-1);
}
# endif /* HAVE_SOLARIS_PRIVS */
- if (user && initgroups(user, sw_gid)) {
- msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user);
- exit (-1);
- }
- if (group && setgid(sw_gid)) {
- msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group);
- exit (-1);
- }
- if (group && setegid(sw_gid)) {
- msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group);
- exit (-1);
- }
- if (group) {
- if (0 != setgroups(1, &sw_gid)) {
- msyslog(LOG_ERR, "setgroups(1, %d) failed: %m", sw_gid);
- exit (-1);
- }
- }
- else if (pw)
- if (0 != initgroups(pw->pw_name, pw->pw_gid)) {
- msyslog(LOG_ERR, "initgroups(<%s>, %d) filed: %m", pw->pw_name, pw->pw_gid);
- exit (-1);
- }
- if (user && setuid(sw_uid)) {
- msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user);
- exit (-1);
- }
- if (user && seteuid(sw_uid)) {
- msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user);
- exit (-1);
- }
+ if (0 == set_user_group_ids())
+ exit(-1);
# if !defined(HAVE_LINUX_CAPABILITIES) && !defined(HAVE_SOLARIS_PRIVS)
/*
@@ -1245,6 +1346,10 @@ int scmp_sc[] = {
}
#endif /* LIBSECCOMP and KERN_SECCOMP */
+#ifdef SYS_WINNT
+ ntservice_isup();
+#endif
+
# ifdef HAVE_IO_COMPLETION_PORT
for (;;) {
diff --git a/contrib/ntp/ntpd/ntpd.html b/contrib/ntp/ntpd/ntpd.html
index 3af0cc5..50a3ac8 100644
--- a/contrib/ntp/ntpd/ntpd.html
+++ b/contrib/ntp/ntpd/ntpd.html
@@ -1,128 +1,179 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>ntpd: Network Time Protocol (NTP) Daemon User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="ntpd: Network Time Protocol (NTP) Daemon User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>ntpd: Network Time Protocol (NTP) Daemon User&rsquo;s Manual</title>
+
+<meta name="description" content="ntpd: Network Time Protocol (NTP) Daemon User&rsquo;s Manual">
+<meta name="keywords" content="ntpd: Network Time Protocol (NTP) Daemon User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">ntpd: Network Time Protocol (NTP) Daemon User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Description">ntpd Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">ntpd: Network Time Protocol (NTP) Daemon User Manual</h2>
+<body lang="en">
+<h1 class="settitle" align="center">ntpd: Network Time Protocol (NTP) Daemon User&rsquo;s Manual</h1>
+
+
+
+
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-Description" accesskey="n" rel="next">ntpd Description</a>, Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="ntpd_003a-Network-Time-Protocol-_0028NTP_0029-Daemon-User-Manual"></a>
+<h1 class="top">ntpd: Network Time Protocol (NTP) Daemon User Manual</h1>
<p>The <code>ntpd</code> program is an operating system daemon that synchronizes the
-system clock to remote NTP time servers or local reference clocks.
+system clock to remote NTP time servers or local reference clocks.
It is a complete implementation of NTP version 4 defined by RFC-5905, but
also retains compatible with version 3 defined by RFC-1305 and versions
-1 and 2, defined by RFC-1059 and RFC-1119, respectively.
+1 and 2, defined by RFC-1059 and RFC-1119, respectively.
The program can operate in any of several modes, including client/server,
symmetric and broadcast modes, and with both symmetric-key and public-key
cryptography.
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntpd</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
+
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Description" href="#toc-Description">1 Description</a></li>
+</ul>
+</div>
- <p>This document applies to version 4.2.8p11 of <code>ntpd</code>.
-<ul class="menu">
-<li><a accesskey="1" href="#ntpd-Description">ntpd Description</a>: Description
-<li><a accesskey="2" href="#ntpd-Invocation">ntpd Invocation</a>: Invoking ntpd
-<li><a accesskey="3" href="#Usage">Usage</a>: Usage
-</ul>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-Description" accesskey="1">ntpd Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-Invocation" accesskey="2">ntpd Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking ntpd
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="3">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+</table>
-<div class="node">
-<p><hr>
+<hr>
<a name="ntpd-Description"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#ntpd-Invocation" accesskey="n" rel="next">ntpd Invocation</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Description</h3>
+<a name="Description"></a>
+<h2 class="chapter">1 Description</h2>
<p>The <code>ntpd</code> program ordinarily requires
-a configuration file described at <a href="#ntp_002econf">ntp.conf</a>.
+a configuration file described at &lsquo;ntp.conf&rsquo;.
This configuration file contains configuration commands described on
-the pages listed above.
+the pages listed above.
However a client can discover remote servers and configure them
-automatically.
+automatically.
This makes it possible to deploy a fleet of workstations without
specifying configuration details specific to the local environment.
-
- <p>The <code>ntpd</code> program normally operates continuously while adjusting the
+</p>
+<p>The <code>ntpd</code> program normally operates continuously while adjusting the
system time and frequency, but in some cases this might not be
-practical.
+practical.
With the <code>-q</code> option <code>ntpd</code> operates as in continuous mode, but
-exits just after setting the clock for the first time.
+exits just after setting the clock for the first time.
Most applications will probably want to specify the <code>iburst</code>
-option with the <code>server</code> command.
+option with the <code>server</code> command.
With this option an initial volley of messages is exchanged to
-groom the data and set the clock in about ten seconds' time.
-If nothing is heard after a few minutes' time,
+groom the data and set the clock in about ten seconds&rsquo; time.
+If nothing is heard after a few minutes&rsquo; time,
the daemon times out and exits without setting the clock.
-
-<div class="node">
-<p><hr>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-Invocation" accesskey="1">ntpd Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="2">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
<a name="ntpd-Invocation"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Usage" accesskey="n" rel="next">Usage</a>, Previous: <a href="#ntpd-Description" accesskey="p" rel="prev">ntpd Description</a>, Up: <a href="#ntpd-Description" accesskey="u" rel="up">ntpd Description</a> &nbsp; </p>
</div>
+<a name="Invoking-ntpd"></a>
+<h3 class="section">1.1 Invoking ntpd</h3>
+<a name="index-ntpd"></a>
+<a name="index-NTP-daemon-program"></a>
-<h3 class="section">Invoking ntpd</h3>
-<p><a name="index-ntpd-1"></a><a name="index-NTP-daemon-program-2"></a>
- <p>The
+<p>The
<code>ntpd</code>
utility is an operating system daemon which sets
and maintains the system time of day in synchronism with Internet
-standard time servers.
+standard time servers.
It is a complete implementation of the
Network Time Protocol (NTP) version 4, as defined by RFC-5905,
but also retains compatibility with
version 3, as defined by RFC-1305, and versions 1
and 2, as defined by RFC-1059 and RFC-1119, respectively.
-
- <p>The
+</p>
+<p>The
<code>ntpd</code>
utility does most computations in 64-bit floating point
arithmetic and does relatively clumsy 64-bit fixed point operations
only when necessary to preserve the ultimate precision, about 232
-picoseconds.
+picoseconds.
While the ultimate precision is not achievable with
ordinary workstations and networks of today, it may be required
with future gigahertz CPU clocks and gigabit LANs.
-
- <p>Ordinarily,
+</p>
+<p>Ordinarily,
<code>ntpd</code>
reads the
<code>ntp.conf(5)</code>
configuration file at startup time in order to determine the
-synchronization sources and operating modes.
+synchronization sources and operating modes.
It is also possible to
specify a working, although limited, configuration entirely on the
-command line, obviating the need for a configuration file.
+command line, obviating the need for a configuration file.
This may
be particularly useful when the local host is to be configured as a
broadcast/multicast client, with all peers being determined by
listening to broadcasts at run time.
-
- <p>If NetInfo support is built into
+</p>
+<p>If NetInfo support is built into
<code>ntpd</code>
then
<code>ntpd</code>
@@ -133,8 +184,8 @@ file cannot be read and no file is
specified by the
<code>-c</code>
option.
-
- <p>Various internal
+</p>
+<p>Various internal
<code>ntpd</code>
variables can be displayed and
configuration options altered while the
@@ -145,8 +196,8 @@ using the
and
<code>ntpdc(1ntpdcmdoc)</code>
utility programs.
-
- <p>When
+</p>
+<p>When
<code>ntpd</code>
starts it looks at the value of
<code>umask(2)</code>,
@@ -155,72 +206,110 @@ and if zero
will set the
<code>umask(2)</code>
to 022.
-
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntpd</code> program.
+</p>
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntpd</code> program.
This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntpd-usage">ntpd usage</a>: ntpd help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#ntpd-ipv4">ntpd ipv4</a>: ipv4 option (-4)
-<li><a accesskey="3" href="#ntpd-ipv6">ntpd ipv6</a>: ipv6 option (-6)
-<li><a accesskey="4" href="#ntpd-authreq">ntpd authreq</a>: authreq option (-a)
-<li><a accesskey="5" href="#ntpd-authnoreq">ntpd authnoreq</a>: authnoreq option (-A)
-<li><a accesskey="6" href="#ntpd-configfile">ntpd configfile</a>: configfile option (-c)
-<li><a accesskey="7" href="#ntpd-driftfile">ntpd driftfile</a>: driftfile option (-f)
-<li><a accesskey="8" href="#ntpd-panicgate">ntpd panicgate</a>: panicgate option (-g)
-<li><a accesskey="9" href="#ntpd-force_002dstep_002donce">ntpd force-step-once</a>: force-step-once option (-G)
-<li><a href="#ntpd-jaildir">ntpd jaildir</a>: jaildir option (-i)
-<li><a href="#ntpd-interface">ntpd interface</a>: interface option (-I)
-<li><a href="#ntpd-keyfile">ntpd keyfile</a>: keyfile option (-k)
-<li><a href="#ntpd-logfile">ntpd logfile</a>: logfile option (-l)
-<li><a href="#ntpd-novirtualips">ntpd novirtualips</a>: novirtualips option (-L)
-<li><a href="#ntpd-modifymmtimer">ntpd modifymmtimer</a>: modifymmtimer option (-M)
-<li><a href="#ntpd-nice">ntpd nice</a>: nice option (-N)
-<li><a href="#ntpd-pidfile">ntpd pidfile</a>: pidfile option (-p)
-<li><a href="#ntpd-priority">ntpd priority</a>: priority option (-P)
-<li><a href="#ntpd-quit">ntpd quit</a>: quit option (-q)
-<li><a href="#ntpd-propagationdelay">ntpd propagationdelay</a>: propagationdelay option (-r)
-<li><a href="#ntpd-saveconfigquit">ntpd saveconfigquit</a>: saveconfigquit option
-<li><a href="#ntpd-statsdir">ntpd statsdir</a>: statsdir option (-s)
-<li><a href="#ntpd-trustedkey">ntpd trustedkey</a>: trustedkey option (-t)
-<li><a href="#ntpd-user">ntpd user</a>: user option (-u)
-<li><a href="#ntpd-updateinterval">ntpd updateinterval</a>: updateinterval option (-U)
-<li><a href="#ntpd-wait_002dsync">ntpd wait-sync</a>: wait-sync option (-w)
-<li><a href="#ntpd-slew">ntpd slew</a>: slew option (-x)
-<li><a href="#ntpd-usepcc">ntpd usepcc</a>: usepcc option
-<li><a href="#ntpd-pccfreq">ntpd pccfreq</a>: pccfreq option
-<li><a href="#ntpd-mdns">ntpd mdns</a>: mdns option (-m)
-<li><a href="#ntpd-config">ntpd config</a>: presetting/configuring ntpd
-<li><a href="#ntpd-exit-status">ntpd exit status</a>: exit status
-<li><a href="#ntpd-Usage">ntpd Usage</a>: Usage
-<li><a href="#ntpd-Files">ntpd Files</a>: Files
-<li><a href="#ntpd-See-Also">ntpd See Also</a>: See Also
-<li><a href="#ntpd-Bugs">ntpd Bugs</a>: Bugs
-<li><a href="#ntpd-Notes">ntpd Notes</a>: Notes
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntpd-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-ipv4">ntpd ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-usage" accesskey="1">ntpd usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntpd help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-ipv4" accesskey="2">ntpd ipv4</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv4 option (-4)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-ipv6" accesskey="3">ntpd ipv6</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv6 option (-6)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-authreq" accesskey="4">ntpd authreq</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">authreq option (-a)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-authnoreq" accesskey="5">ntpd authnoreq</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">authnoreq option (-A)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-configfile" accesskey="6">ntpd configfile</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">configfile option (-c)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-driftfile" accesskey="7">ntpd driftfile</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">driftfile option (-f)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-panicgate" accesskey="8">ntpd panicgate</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">panicgate option (-g)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-force_002dstep_002donce" accesskey="9">ntpd force-step-once</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">force-step-once option (-G)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-jaildir">ntpd jaildir</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">jaildir option (-i)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-interface">ntpd interface</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">interface option (-I)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-keyfile">ntpd keyfile</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">keyfile option (-k)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-logfile">ntpd logfile</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">logfile option (-l)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-novirtualips">ntpd novirtualips</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">novirtualips option (-L)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-modifymmtimer">ntpd modifymmtimer</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">modifymmtimer option (-M)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-nice">ntpd nice</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">nice option (-N)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-pidfile">ntpd pidfile</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">pidfile option (-p)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-priority">ntpd priority</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">priority option (-P)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-quit">ntpd quit</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">quit option (-q)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-propagationdelay">ntpd propagationdelay</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">propagationdelay option (-r)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-saveconfigquit">ntpd saveconfigquit</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">saveconfigquit option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-statsdir">ntpd statsdir</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">statsdir option (-s)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-trustedkey">ntpd trustedkey</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">trustedkey option (-t)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-user">ntpd user</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">user option (-u)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-updateinterval">ntpd updateinterval</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">updateinterval option (-U)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-wait_002dsync">ntpd wait-sync</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">wait-sync option (-w)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-slew">ntpd slew</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">slew option (-x)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-usepcc">ntpd usepcc</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">usepcc option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-pccfreq">ntpd pccfreq</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">pccfreq option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-mdns">ntpd mdns</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">mdns option (-m)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-config">ntpd config</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">presetting/configuring ntpd
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-exit-status">ntpd exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-Usage">ntpd Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-Files">ntpd Files</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Files
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-See-Also">ntpd See Also</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">See Also
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-Bugs">ntpd Bugs</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Bugs
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpd-Notes">ntpd Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Notes
+</td></tr>
+</table>
+
+<hr>
+<a name="ntpd-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-ipv4" accesskey="n" rel="next">ntpd ipv4</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpd help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-ntpd-help-3"></a>
-This is the automatically generated usage text for ntpd.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="ntpd-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h4 class="subsection">1.1.1 ntpd help/usage (<samp>--help</samp>)</h4>
+<a name="index-ntpd-help"></a>
+
+<p>This is the automatically generated usage text for ntpd.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">ntpd - NTP daemon program - Ver. 4.2.8p10
+</p>
+<div class="example">
+<pre class="example">ntpd - NTP daemon program - Ver. 4.2.8p12
Usage: ntpd [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]... \
[ &lt;server1&gt; ... &lt;serverN&gt; ]
Flg Arg Option-Name Description
@@ -289,149 +378,143 @@ The following option preset mechanisms are supported:
- examining environment variables named NTPD_*
Please send bug reports to: &lt;http://bugs.ntp.org, bugs@ntp.org&gt;
-</pre>
- <div class="node">
-<p><hr>
-<a name="ntpd-ipv4"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-ipv6">ntpd ipv6</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-usage">ntpd usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">ipv4 option (-4)</h4>
+</pre></div>
-<p><a name="index-ntpd_002dipv4-4"></a>
-This is the &ldquo;force ipv4 dns name resolution&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv6.
-</ul>
-
- <p>Force DNS resolution of following host names on the command line
-to the IPv4 namespace.
-<div class="node">
-<p><hr>
-<a name="ntpd-ipv6"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-authreq">ntpd authreq</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-ipv4">ntpd ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<hr>
+<a name="ntpd-ipv4"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-ipv6" accesskey="n" rel="next">ntpd ipv6</a>, Previous: <a href="#ntpd-usage" accesskey="p" rel="prev">ntpd usage</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ipv6 option (-6)</h4>
-
-<p><a name="index-ntpd_002dipv6-5"></a>
-This is the &ldquo;force ipv6 dns name resolution&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv4.
-</ul>
-
- <p>Force DNS resolution of following host names on the command line
-to the IPv6 namespace.
-<div class="node">
-<p><hr>
-<a name="ntpd-authreq"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-authnoreq">ntpd authnoreq</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-ipv6">ntpd ipv6</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<a name="ipv4-option-_0028_002d4_0029"></a>
+<h4 class="subsection">1.1.2 ipv4 option (-4)</h4>
+<a name="index-ntpd_002dipv4"></a>
+
+<p>This is the &ldquo;force ipv4 dns name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv6.
+</li></ul>
+
+<p>Force DNS resolution of following host names on the command line
+to the IPv4 namespace.
+</p><hr>
+<a name="ntpd-ipv6"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-authreq" accesskey="n" rel="next">ntpd authreq</a>, Previous: <a href="#ntpd-ipv4" accesskey="p" rel="prev">ntpd ipv4</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">authreq option (-a)</h4>
-
-<p><a name="index-ntpd_002dauthreq-6"></a>
-This is the &ldquo;require crypto authentication&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-authnoreq.
-</ul>
-
- <p>Require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is the default.
-<div class="node">
-<p><hr>
-<a name="ntpd-authnoreq"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-configfile">ntpd configfile</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-authreq">ntpd authreq</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<a name="ipv6-option-_0028_002d6_0029"></a>
+<h4 class="subsection">1.1.3 ipv6 option (-6)</h4>
+<a name="index-ntpd_002dipv6"></a>
+
+<p>This is the &ldquo;force ipv6 dns name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv4.
+</li></ul>
+
+<p>Force DNS resolution of following host names on the command line
+to the IPv6 namespace.
+</p><hr>
+<a name="ntpd-authreq"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-authnoreq" accesskey="n" rel="next">ntpd authnoreq</a>, Previous: <a href="#ntpd-ipv6" accesskey="p" rel="prev">ntpd ipv6</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">authnoreq option (-A)</h4>
-
-<p><a name="index-ntpd_002dauthnoreq-7"></a>
-This is the &ldquo;do not require crypto authentication&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-authreq.
-</ul>
-
- <p>Do not require cryptographic authentication for broadcast client,
-multicast client and symmetric passive associations.
-This is almost never a good idea.
-<div class="node">
-<p><hr>
-<a name="ntpd-configfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-driftfile">ntpd driftfile</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-authnoreq">ntpd authnoreq</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<a name="authreq-option-_0028_002da_0029"></a>
+<h4 class="subsection">1.1.4 authreq option (-a)</h4>
+<a name="index-ntpd_002dauthreq"></a>
+
+<p>This is the &ldquo;require crypto authentication&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+authnoreq.
+</li></ul>
+
+<p>Require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is the default.
+</p><hr>
+<a name="ntpd-authnoreq"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-configfile" accesskey="n" rel="next">ntpd configfile</a>, Previous: <a href="#ntpd-authreq" accesskey="p" rel="prev">ntpd authreq</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="authnoreq-option-_0028_002dA_0029"></a>
+<h4 class="subsection">1.1.5 authnoreq option (-A)</h4>
+<a name="index-ntpd_002dauthnoreq"></a>
+
+<p>This is the &ldquo;do not require crypto authentication&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+authreq.
+</li></ul>
+
+<p>Do not require cryptographic authentication for broadcast client,
+multicast client and symmetric passive associations.
+This is almost never a good idea.
+</p><hr>
+<a name="ntpd-configfile"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-driftfile" accesskey="n" rel="next">ntpd driftfile</a>, Previous: <a href="#ntpd-authnoreq" accesskey="p" rel="prev">ntpd authnoreq</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
+</div>
+<a name="configfile-option-_0028_002dc_0029"></a>
+<h4 class="subsection">1.1.6 configfile option (-c)</h4>
+<a name="index-ntpd_002dconfigfile"></a>
-<h4 class="subsection">configfile option (-c)</h4>
-
-<p><a name="index-ntpd_002dconfigfile-8"></a>
-This is the &ldquo;configuration file name&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;configuration file name&rdquo; option.
+This option takes a string argument.
The name and path of the configuration file,
-<span class="file">/etc/ntp.conf</span>
-by default.
-<div class="node">
-<p><hr>
-<a name="ntpd-driftfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-panicgate">ntpd panicgate</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-configfile">ntpd configfile</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<samp>/etc/ntp.conf</samp>
+by default.
+</p><hr>
+<a name="ntpd-driftfile"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-panicgate" accesskey="n" rel="next">ntpd panicgate</a>, Previous: <a href="#ntpd-configfile" accesskey="p" rel="prev">ntpd configfile</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="driftfile-option-_0028_002df_0029"></a>
+<h4 class="subsection">1.1.7 driftfile option (-f)</h4>
+<a name="index-ntpd_002ddriftfile"></a>
-<h4 class="subsection">driftfile option (-f)</h4>
-
-<p><a name="index-ntpd_002ddriftfile-9"></a>
-This is the &ldquo;frequency drift file name&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;frequency drift file name&rdquo; option.
+This option takes a string argument.
The name and path of the frequency file,
-<span class="file">/etc/ntp.drift</span>
-by default.
+<samp>/etc/ntp.drift</samp>
+by default.
This is the same operation as the
<code>driftfile</code> <kbd>driftfile</kbd>
configuration specification in the
-<span class="file">/etc/ntp.conf</span>
-file.
-<div class="node">
-<p><hr>
-<a name="ntpd-panicgate"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-force_002dstep_002donce">ntpd force-step-once</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-driftfile">ntpd driftfile</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<samp>/etc/ntp.conf</samp>
+file.
+</p><hr>
+<a name="ntpd-panicgate"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-force_002dstep_002donce" accesskey="n" rel="next">ntpd force-step-once</a>, Previous: <a href="#ntpd-driftfile" accesskey="p" rel="prev">ntpd driftfile</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">panicgate option (-g)</h4>
-
-<p><a name="index-ntpd_002dpanicgate-10"></a>
-This is the &ldquo;allow the first adjustment to be big&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>Normally,
+<a name="panicgate-option-_0028_002dg_0029"></a>
+<h4 class="subsection">1.1.8 panicgate option (-g)</h4>
+<a name="index-ntpd_002dpanicgate"></a>
+
+<p>This is the &ldquo;allow the first adjustment to be big&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>Normally,
<code>ntpd</code>
exits with a message to the system log if the offset exceeds the panic threshold, which is 1000 s by default. This option allows the time to be set to any value without restriction; however, this can happen only once. If the threshold is exceeded after that,
<code>ntpd</code>
@@ -439,581 +522,579 @@ will exit with a message to the system log. This option can be used with the
<code>-q</code>
and
<code>-x</code>
-options.
+options.
See the
<code>tinker</code>
-configuration file directive for other options.
-<div class="node">
-<p><hr>
-<a name="ntpd-force_002dstep_002donce"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-jaildir">ntpd jaildir</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-panicgate">ntpd panicgate</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+configuration file directive for other options.
+</p><hr>
+<a name="ntpd-force_002dstep_002donce"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-jaildir" accesskey="n" rel="next">ntpd jaildir</a>, Previous: <a href="#ntpd-panicgate" accesskey="p" rel="prev">ntpd panicgate</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="force_002dstep_002donce-option-_0028_002dG_0029"></a>
+<h4 class="subsection">1.1.9 force-step-once option (-G)</h4>
+<a name="index-ntpd_002dforce_002dstep_002donce"></a>
-<h4 class="subsection">force-step-once option (-G)</h4>
-
-<p><a name="index-ntpd_002dforce_002dstep_002donce-11"></a>
-This is the &ldquo;step any initial offset correction.&rdquo; option.
+<p>This is the &ldquo;step any initial offset correction.&rdquo; option.
Normally,
<code>ntpd</code>
steps the time if the time offset exceeds the step threshold,
-which is 128 ms by default, and otherwise slews the time.
+which is 128 ms by default, and otherwise slews the time.
This option forces the initial offset correction to be stepped,
-so the highest time accuracy can be achieved quickly.
+so the highest time accuracy can be achieved quickly.
However, this may also cause the time to be stepped back
so this option must not be used if
-applications requiring monotonic time are running.
-See the <code>tinker</code> configuration file directive for other options.
-<div class="node">
-<p><hr>
-<a name="ntpd-jaildir"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-interface">ntpd interface</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-force_002dstep_002donce">ntpd force-step-once</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+applications requiring monotonic time are running.
+See the <code>tinker</code> configuration file directive for other options.
+</p><hr>
+<a name="ntpd-jaildir"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-interface" accesskey="n" rel="next">ntpd interface</a>, Previous: <a href="#ntpd-force_002dstep_002donce" accesskey="p" rel="prev">ntpd force-step-once</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="jaildir-option-_0028_002di_0029"></a>
+<h4 class="subsection">1.1.10 jaildir option (-i)</h4>
+<a name="index-ntpd_002djaildir"></a>
-<h4 class="subsection">jaildir option (-i)</h4>
-
-<p><a name="index-ntpd_002djaildir-12"></a>
-This is the &ldquo;jail directory&rdquo; option.
+<p>This is the &ldquo;jail directory&rdquo; option.
This option takes a string argument.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>HAVE_DROPROOT</code> during the compilation.
+</li></ul>
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>HAVE_DROPROOT</code> during the compilation.
-</ul>
-
- <p>Chroot the server to the directory
+<p>Chroot the server to the directory
<kbd>jaildir</kbd>
-.
-This option also implies that the server attempts to drop root privileges at startup.
+.
+This option also implies that the server attempts to drop root privileges at startup.
You may need to also specify a
<code>-u</code>
-option.
+option.
This option is only available if the OS supports adjusting the clock
-without full root privileges.
+without full root privileges.
This option is supported under NetBSD (configure with
<code>--enable-clockctl</code>) or Linux (configure with
-<code>--enable-linuxcaps</code>) or Solaris (configure with <code>--enable-solarisprivs</code>).
-<div class="node">
-<p><hr>
-<a name="ntpd-interface"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-keyfile">ntpd keyfile</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-jaildir">ntpd jaildir</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<code>--enable-linuxcaps</code>) or Solaris (configure with <code>--enable-solarisprivs</code>).
+</p><hr>
+<a name="ntpd-interface"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-keyfile" accesskey="n" rel="next">ntpd keyfile</a>, Previous: <a href="#ntpd-jaildir" accesskey="p" rel="prev">ntpd jaildir</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">interface option (-I)</h4>
-
-<p><a name="index-ntpd_002dinterface-13"></a>
-This is the &ldquo;listen on an interface name or address&rdquo; option.
-This option takes a string argument <span class="file">iface</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>Open the network address given, or all the addresses associated with the
+<a name="interface-option-_0028_002dI_0029"></a>
+<h4 class="subsection">1.1.11 interface option (-I)</h4>
+<a name="index-ntpd_002dinterface"></a>
+
+<p>This is the &ldquo;listen on an interface name or address&rdquo; option.
+This option takes a string argument <samp>iface</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>Open the network address given, or all the addresses associated with the
given interface name. This option may appear multiple times. This option
-also implies not opening other addresses, except wildcard and localhost.
+also implies not opening other addresses, except wildcard and localhost.
This option is deprecated. Please consider using the configuration file
-<code>interface</code> command, which is more versatile.
-<div class="node">
-<p><hr>
-<a name="ntpd-keyfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-logfile">ntpd logfile</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-interface">ntpd interface</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">keyfile option (-k)</h4>
-
-<p><a name="index-ntpd_002dkeyfile-14"></a>
-This is the &ldquo;path to symmetric keys&rdquo; option.
-This option takes a string argument.
-Specify the name and path of the symmetric key file.
-<span class="file">/etc/ntp.keys</span>
-is the default.
+<code>interface</code> command, which is more versatile.
+</p><hr>
+<a name="ntpd-keyfile"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-logfile" accesskey="n" rel="next">ntpd logfile</a>, Previous: <a href="#ntpd-interface" accesskey="p" rel="prev">ntpd interface</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
+</div>
+<a name="keyfile-option-_0028_002dk_0029"></a>
+<h4 class="subsection">1.1.12 keyfile option (-k)</h4>
+<a name="index-ntpd_002dkeyfile"></a>
+
+<p>This is the &ldquo;path to symmetric keys&rdquo; option.
+This option takes a string argument.
+Specify the name and path of the symmetric key file.
+<samp>/etc/ntp.keys</samp>
+is the default.
This is the same operation as the
<code>keys</code> <kbd>keyfile</kbd>
-configuration file directive.
-<div class="node">
-<p><hr>
-<a name="ntpd-logfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-novirtualips">ntpd novirtualips</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-keyfile">ntpd keyfile</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">logfile option (-l)</h4>
-
-<p><a name="index-ntpd_002dlogfile-15"></a>
-This is the &ldquo;path to the log file&rdquo; option.
-This option takes a string argument.
-Specify the name and path of the log file.
-The default is the system log file.
+configuration file directive.
+</p><hr>
+<a name="ntpd-logfile"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-novirtualips" accesskey="n" rel="next">ntpd novirtualips</a>, Previous: <a href="#ntpd-keyfile" accesskey="p" rel="prev">ntpd keyfile</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
+</div>
+<a name="logfile-option-_0028_002dl_0029"></a>
+<h4 class="subsection">1.1.13 logfile option (-l)</h4>
+<a name="index-ntpd_002dlogfile"></a>
+
+<p>This is the &ldquo;path to the log file&rdquo; option.
+This option takes a string argument.
+Specify the name and path of the log file.
+The default is the system log file.
This is the same operation as the
<code>logfile</code> <kbd>logfile</kbd>
-configuration file directive.
-<div class="node">
-<p><hr>
-<a name="ntpd-novirtualips"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-modifymmtimer">ntpd modifymmtimer</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-logfile">ntpd logfile</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+configuration file directive.
+</p><hr>
+<a name="ntpd-novirtualips"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-modifymmtimer" accesskey="n" rel="next">ntpd modifymmtimer</a>, Previous: <a href="#ntpd-logfile" accesskey="p" rel="prev">ntpd logfile</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="novirtualips-option-_0028_002dL_0029"></a>
+<h4 class="subsection">1.1.14 novirtualips option (-L)</h4>
+<a name="index-ntpd_002dnovirtualips"></a>
-<h4 class="subsection">novirtualips option (-L)</h4>
-
-<p><a name="index-ntpd_002dnovirtualips-16"></a>
-This is the &ldquo;do not listen to virtual interfaces&rdquo; option.
+<p>This is the &ldquo;do not listen to virtual interfaces&rdquo; option.
Do not listen to virtual interfaces, defined as those with
names containing a colon. This option is deprecated. Please
consider using the configuration file <code>interface</code> command, which
-is more versatile.
-<div class="node">
-<p><hr>
-<a name="ntpd-modifymmtimer"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-nice">ntpd nice</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-novirtualips">ntpd novirtualips</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+is more versatile.
+</p><hr>
+<a name="ntpd-modifymmtimer"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-nice" accesskey="n" rel="next">ntpd nice</a>, Previous: <a href="#ntpd-novirtualips" accesskey="p" rel="prev">ntpd novirtualips</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">modifymmtimer option (-M)</h4>
-
-<p><a name="index-ntpd_002dmodifymmtimer-17"></a>
-This is the &ldquo;modify multimedia timer (windows only)&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
-</ul>
-
- <p>Set the Windows Multimedia Timer to highest resolution. This
+<a name="modifymmtimer-option-_0028_002dM_0029"></a>
+<h4 class="subsection">1.1.15 modifymmtimer option (-M)</h4>
+<a name="index-ntpd_002dmodifymmtimer"></a>
+
+<p>This is the &ldquo;modify multimedia timer (windows only)&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
+</li></ul>
+
+<p>Set the Windows Multimedia Timer to highest resolution. This
ensures the resolution does not change while ntpd is running,
-avoiding timekeeping glitches associated with changes.
-<div class="node">
-<p><hr>
-<a name="ntpd-nice"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-pidfile">ntpd pidfile</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-modifymmtimer">ntpd modifymmtimer</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+avoiding timekeeping glitches associated with changes.
+</p><hr>
+<a name="ntpd-nice"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-pidfile" accesskey="n" rel="next">ntpd pidfile</a>, Previous: <a href="#ntpd-modifymmtimer" accesskey="p" rel="prev">ntpd modifymmtimer</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="nice-option-_0028_002dN_0029"></a>
+<h4 class="subsection">1.1.16 nice option (-N)</h4>
+<a name="index-ntpd_002dnice"></a>
-<h4 class="subsection">nice option (-N)</h4>
-
-<p><a name="index-ntpd_002dnice-18"></a>
-This is the &ldquo;run at high priority&rdquo; option.
+<p>This is the &ldquo;run at high priority&rdquo; option.
To the extent permitted by the operating system, run
<code>ntpd</code>
-at the highest priority.
-<div class="node">
-<p><hr>
-<a name="ntpd-pidfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-priority">ntpd priority</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-nice">ntpd nice</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+at the highest priority.
+</p><hr>
+<a name="ntpd-pidfile"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-priority" accesskey="n" rel="next">ntpd priority</a>, Previous: <a href="#ntpd-nice" accesskey="p" rel="prev">ntpd nice</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="pidfile-option-_0028_002dp_0029"></a>
+<h4 class="subsection">1.1.17 pidfile option (-p)</h4>
+<a name="index-ntpd_002dpidfile"></a>
-<h4 class="subsection">pidfile option (-p)</h4>
-
-<p><a name="index-ntpd_002dpidfile-19"></a>
-This is the &ldquo;path to the pid file&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;path to the pid file&rdquo; option.
+This option takes a string argument.
Specify the name and path of the file used to record
-<code>ntpd</code>'s
-process ID.
+<code>ntpd</code>&rsquo;s
+process ID.
This is the same operation as the
<code>pidfile</code> <kbd>pidfile</kbd>
-configuration file directive.
-<div class="node">
-<p><hr>
-<a name="ntpd-priority"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-quit">ntpd quit</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-pidfile">ntpd pidfile</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+configuration file directive.
+</p><hr>
+<a name="ntpd-priority"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-quit" accesskey="n" rel="next">ntpd quit</a>, Previous: <a href="#ntpd-pidfile" accesskey="p" rel="prev">ntpd pidfile</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="priority-option-_0028_002dP_0029"></a>
+<h4 class="subsection">1.1.18 priority option (-P)</h4>
+<a name="index-ntpd_002dpriority"></a>
-<h4 class="subsection">priority option (-P)</h4>
-
-<p><a name="index-ntpd_002dpriority-20"></a>
-This is the &ldquo;process priority&rdquo; option.
-This option takes a number argument.
+<p>This is the &ldquo;process priority&rdquo; option.
+This option takes a number argument.
To the extent permitted by the operating system, run
<code>ntpd</code>
at the specified
<code>sched_setscheduler(SCHED_FIFO)</code>
-priority.
-<div class="node">
-<p><hr>
-<a name="ntpd-quit"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-propagationdelay">ntpd propagationdelay</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-priority">ntpd priority</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+priority.
+</p><hr>
+<a name="ntpd-quit"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-propagationdelay" accesskey="n" rel="next">ntpd propagationdelay</a>, Previous: <a href="#ntpd-priority" accesskey="p" rel="prev">ntpd priority</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">quit option (-q)</h4>
-
-<p><a name="index-ntpd_002dquit-21"></a>
-This is the &ldquo;set the time and quit&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-saveconfigquit, wait-sync.
-</ul>
-
- <p><code>ntpd</code>
+<a name="quit-option-_0028_002dq_0029"></a>
+<h4 class="subsection">1.1.19 quit option (-q)</h4>
+<a name="index-ntpd_002dquit"></a>
+
+<p>This is the &ldquo;set the time and quit&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+saveconfigquit, wait-sync.
+</li></ul>
+
+<p><code>ntpd</code>
will not daemonize and will exit after the clock is first
synchronized. This behavior mimics that of the
<code>ntpdate</code>
-program, which will soon be replaced with a shell script.
+program, which will soon be replaced with a shell script.
The
<code>-g</code>
and
<code>-x</code>
-options can be used with this option.
-Note: The kernel time discipline is disabled with this option.
-<div class="node">
-<p><hr>
-<a name="ntpd-propagationdelay"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-saveconfigquit">ntpd saveconfigquit</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-quit">ntpd quit</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">propagationdelay option (-r)</h4>
-
-<p><a name="index-ntpd_002dpropagationdelay-22"></a>
-This is the &ldquo;broadcast/propagation delay&rdquo; option.
-This option takes a string argument.
-Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
-<div class="node">
-<p><hr>
-<a name="ntpd-saveconfigquit"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-statsdir">ntpd statsdir</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-propagationdelay">ntpd propagationdelay</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">saveconfigquit option</h4>
-
-<p><a name="index-ntpd_002dsaveconfigquit-23"></a>
-This is the &ldquo;save parsed configuration and quit&rdquo; option.
-This option takes a string argument.
+options can be used with this option.
+Note: The kernel time discipline is disabled with this option.
+</p><hr>
+<a name="ntpd-propagationdelay"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-saveconfigquit" accesskey="n" rel="next">ntpd saveconfigquit</a>, Previous: <a href="#ntpd-quit" accesskey="p" rel="prev">ntpd quit</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
+</div>
+<a name="propagationdelay-option-_0028_002dr_0029"></a>
+<h4 class="subsection">1.1.20 propagationdelay option (-r)</h4>
+<a name="index-ntpd_002dpropagationdelay"></a>
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>SAVECONFIG</code> during the compilation.
-<li>must not appear in combination with any of the following options:
-quit, wait-sync.
-</ul>
+<p>This is the &ldquo;broadcast/propagation delay&rdquo; option.
+This option takes a string argument.
+Specify the default propagation delay from the broadcast/multicast server to this client. This is necessary only if the delay cannot be computed automatically by the protocol.
+</p><hr>
+<a name="ntpd-saveconfigquit"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-statsdir" accesskey="n" rel="next">ntpd statsdir</a>, Previous: <a href="#ntpd-propagationdelay" accesskey="p" rel="prev">ntpd propagationdelay</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
+</div>
+<a name="saveconfigquit-option"></a>
+<h4 class="subsection">1.1.21 saveconfigquit option</h4>
+<a name="index-ntpd_002dsaveconfigquit"></a>
- <p>Cause <code>ntpd</code> to parse its startup configuration file and save an
+<p>This is the &ldquo;save parsed configuration and quit&rdquo; option.
+This option takes a string argument.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>SAVECONFIG</code> during the compilation.
+</li><li> must not appear in combination with any of the following options:
+quit, wait-sync.
+</li></ul>
+
+<p>Cause <code>ntpd</code> to parse its startup configuration file and save an
equivalent to the given filename and exit. This option was
-designed for automated testing.
-<div class="node">
-<p><hr>
-<a name="ntpd-statsdir"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-trustedkey">ntpd trustedkey</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-saveconfigquit">ntpd saveconfigquit</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+designed for automated testing.
+</p><hr>
+<a name="ntpd-statsdir"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-trustedkey" accesskey="n" rel="next">ntpd trustedkey</a>, Previous: <a href="#ntpd-saveconfigquit" accesskey="p" rel="prev">ntpd saveconfigquit</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="statsdir-option-_0028_002ds_0029"></a>
+<h4 class="subsection">1.1.22 statsdir option (-s)</h4>
+<a name="index-ntpd_002dstatsdir"></a>
-<h4 class="subsection">statsdir option (-s)</h4>
-
-<p><a name="index-ntpd_002dstatsdir-24"></a>
-This is the &ldquo;statistics file location&rdquo; option.
-This option takes a string argument.
-Specify the directory path for files created by the statistics facility.
+<p>This is the &ldquo;statistics file location&rdquo; option.
+This option takes a string argument.
+Specify the directory path for files created by the statistics facility.
This is the same operation as the
<code>statsdir</code> <kbd>statsdir</kbd>
-configuration file directive.
-<div class="node">
-<p><hr>
-<a name="ntpd-trustedkey"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-user">ntpd user</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-statsdir">ntpd statsdir</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+configuration file directive.
+</p><hr>
+<a name="ntpd-trustedkey"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-user" accesskey="n" rel="next">ntpd user</a>, Previous: <a href="#ntpd-statsdir" accesskey="p" rel="prev">ntpd statsdir</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">trustedkey option (-t)</h4>
-
-<p><a name="index-ntpd_002dtrustedkey-25"></a>
-This is the &ldquo;trusted key number&rdquo; option.
-This option takes a string argument <span class="file">tkey</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>Add the specified key number to the trusted key list.
-<div class="node">
-<p><hr>
-<a name="ntpd-user"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-updateinterval">ntpd updateinterval</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-trustedkey">ntpd trustedkey</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<a name="trustedkey-option-_0028_002dt_0029"></a>
+<h4 class="subsection">1.1.23 trustedkey option (-t)</h4>
+<a name="index-ntpd_002dtrustedkey"></a>
+
+<p>This is the &ldquo;trusted key number&rdquo; option.
+This option takes a string argument <samp>tkey</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>Add the specified key number to the trusted key list.
+</p><hr>
+<a name="ntpd-user"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-updateinterval" accesskey="n" rel="next">ntpd updateinterval</a>, Previous: <a href="#ntpd-trustedkey" accesskey="p" rel="prev">ntpd trustedkey</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="user-option-_0028_002du_0029"></a>
+<h4 class="subsection">1.1.24 user option (-u)</h4>
+<a name="index-ntpd_002duser"></a>
-<h4 class="subsection">user option (-u)</h4>
-
-<p><a name="index-ntpd_002duser-26"></a>
-This is the &ldquo;run as userid (or userid:groupid)&rdquo; option.
+<p>This is the &ldquo;run as userid (or userid:groupid)&rdquo; option.
This option takes a string argument.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>HAVE_DROPROOT</code> during the compilation.
+</li></ul>
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>HAVE_DROPROOT</code> during the compilation.
-</ul>
-
- <p>Specify a user, and optionally a group, to switch to.
+<p>Specify a user, and optionally a group, to switch to.
This option is only available if the OS supports adjusting the clock
-without full root privileges.
+without full root privileges.
This option is supported under NetBSD (configure with
<code>--enable-clockctl</code>) or Linux (configure with
-<code>--enable-linuxcaps</code>) or Solaris (configure with <code>--enable-solarisprivs</code>).
-<div class="node">
-<p><hr>
-<a name="ntpd-updateinterval"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-wait_002dsync">ntpd wait-sync</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-user">ntpd user</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<code>--enable-linuxcaps</code>) or Solaris (configure with <code>--enable-solarisprivs</code>).
+</p><hr>
+<a name="ntpd-updateinterval"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-wait_002dsync" accesskey="n" rel="next">ntpd wait-sync</a>, Previous: <a href="#ntpd-user" accesskey="p" rel="prev">ntpd user</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="updateinterval-option-_0028_002dU_0029"></a>
+<h4 class="subsection">1.1.25 updateinterval option (-U)</h4>
+<a name="index-ntpd_002dupdateinterval"></a>
-<h4 class="subsection">updateinterval option (-U)</h4>
-
-<p><a name="index-ntpd_002dupdateinterval-27"></a>
-This is the &ldquo;interval in seconds between scans for new or dropped interfaces&rdquo; option.
-This option takes a number argument.
-Give the time in seconds between two scans for new or dropped interfaces.
+<p>This is the &ldquo;interval in seconds between scans for new or dropped interfaces&rdquo; option.
+This option takes a number argument.
+Give the time in seconds between two scans for new or dropped interfaces.
For systems with routing socket support the scans will be performed shortly after the interface change
-has been detected by the system.
-Use 0 to disable scanning. 60 seconds is the minimum time between scans.
-<div class="node">
-<p><hr>
-<a name="ntpd-wait_002dsync"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-slew">ntpd slew</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-updateinterval">ntpd updateinterval</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+has been detected by the system.
+Use 0 to disable scanning. 60 seconds is the minimum time between scans.
+</p><hr>
+<a name="ntpd-wait_002dsync"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-slew" accesskey="n" rel="next">ntpd slew</a>, Previous: <a href="#ntpd-updateinterval" accesskey="p" rel="prev">ntpd updateinterval</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="wait_002dsync-option-_0028_002dw_0029"></a>
+<h4 class="subsection">1.1.26 wait-sync option (-w)</h4>
+<a name="index-ntpd_002dwait_002dsync"></a>
-<h4 class="subsection">wait-sync option (-w)</h4>
-
-<p><a name="index-ntpd_002dwait_002dsync-28"></a>
-This is the &ldquo;seconds to wait for first clock sync&rdquo; option.
+<p>This is the &ldquo;seconds to wait for first clock sync&rdquo; option.
This option takes a number argument.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>HAVE_WORKING_FORK</code> during the compilation.
-<li>must not appear in combination with any of the following options:
-nofork, quit, saveconfigquit.
-</ul>
-
- <p>If greater than zero, alters <code>ntpd</code>'s behavior when forking to
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>HAVE_WORKING_FORK</code> during the compilation.
+</li><li> must not appear in combination with any of the following options:
+nofork, quit, saveconfigquit.
+</li></ul>
+
+<p>If greater than zero, alters <code>ntpd</code>&rsquo;s behavior when forking to
daemonize. Instead of exiting with status 0 immediately after
the fork, the parent waits up to the specified number of
seconds for the child to first synchronize the clock. The exit
status is zero (success) if the clock was synchronized,
-otherwise it is <code>ETIMEDOUT</code>.
+otherwise it is <code>ETIMEDOUT</code>.
This provides the option for a script starting <code>ntpd</code> to easily
-wait for the first set of the clock before proceeding.
-<div class="node">
-<p><hr>
-<a name="ntpd-slew"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-usepcc">ntpd usepcc</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-wait_002dsync">ntpd wait-sync</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">slew option (-x)</h4>
-
-<p><a name="index-ntpd_002dslew-29"></a>
-This is the &ldquo;slew up to 600 seconds&rdquo; option.
-Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
-This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
-Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
-Thus, an adjustment as much as 600 s will take almost 14 days to complete.
+wait for the first set of the clock before proceeding.
+</p><hr>
+<a name="ntpd-slew"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-usepcc" accesskey="n" rel="next">ntpd usepcc</a>, Previous: <a href="#ntpd-wait_002dsync" accesskey="p" rel="prev">ntpd wait-sync</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
+</div>
+<a name="slew-option-_0028_002dx_0029"></a>
+<h4 class="subsection">1.1.27 slew option (-x)</h4>
+<a name="index-ntpd_002dslew"></a>
+
+<p>This is the &ldquo;slew up to 600 seconds&rdquo; option.
+Normally, the time is slewed if the offset is less than the step threshold, which is 128 ms by default, and stepped if above the threshold.
+This option sets the threshold to 600 s, which is well within the accuracy window to set the clock manually.
+Note: Since the slew rate of typical Unix kernels is limited to 0.5 ms/s, each second of adjustment requires an amortization interval of 2000 s.
+Thus, an adjustment as much as 600 s will take almost 14 days to complete.
This option can be used with the
<code>-g</code>
and
<code>-q</code>
-options.
+options.
See the
<code>tinker</code>
-configuration file directive for other options.
-Note: The kernel time discipline is disabled with this option.
-<div class="node">
-<p><hr>
-<a name="ntpd-usepcc"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-pccfreq">ntpd pccfreq</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-slew">ntpd slew</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+configuration file directive for other options.
+Note: The kernel time discipline is disabled with this option.
+</p><hr>
+<a name="ntpd-usepcc"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-pccfreq" accesskey="n" rel="next">ntpd pccfreq</a>, Previous: <a href="#ntpd-slew" accesskey="p" rel="prev">ntpd slew</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">usepcc option</h4>
-
-<p><a name="index-ntpd_002dusepcc-30"></a>
-This is the &ldquo;use cpu cycle counter (windows only)&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
-</ul>
-
- <p>Attempt to substitute the CPU counter for <code>QueryPerformanceCounter</code>.
+<a name="usepcc-option"></a>
+<h4 class="subsection">1.1.28 usepcc option</h4>
+<a name="index-ntpd_002dusepcc"></a>
+
+<p>This is the &ldquo;use cpu cycle counter (windows only)&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
+</li></ul>
+
+<p>Attempt to substitute the CPU counter for <code>QueryPerformanceCounter</code>.
The CPU counter and <code>QueryPerformanceCounter</code> are compared, and if
they have the same frequency, the CPU counter (RDTSC on x86) is
-used directly, saving the overhead of a system call.
-<div class="node">
-<p><hr>
-<a name="ntpd-pccfreq"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-mdns">ntpd mdns</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-usepcc">ntpd usepcc</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+used directly, saving the overhead of a system call.
+</p><hr>
+<a name="ntpd-pccfreq"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-mdns" accesskey="n" rel="next">ntpd mdns</a>, Previous: <a href="#ntpd-usepcc" accesskey="p" rel="prev">ntpd usepcc</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="pccfreq-option"></a>
+<h4 class="subsection">1.1.29 pccfreq option</h4>
+<a name="index-ntpd_002dpccfreq"></a>
-<h4 class="subsection">pccfreq option</h4>
-
-<p><a name="index-ntpd_002dpccfreq-31"></a>
-This is the &ldquo;force cpu cycle counter use (windows only)&rdquo; option.
+<p>This is the &ldquo;force cpu cycle counter use (windows only)&rdquo; option.
This option takes a string argument.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
+</li></ul>
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>SYS_WINNT</code> during the compilation.
-</ul>
-
- <p>Force substitution the CPU counter for <code>QueryPerformanceCounter</code>.
+<p>Force substitution the CPU counter for <code>QueryPerformanceCounter</code>.
The CPU counter (RDTSC on x86) is used unconditionally with the
-given frequency (in Hz).
-<div class="node">
-<p><hr>
-<a name="ntpd-mdns"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-config">ntpd config</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-pccfreq">ntpd pccfreq</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+given frequency (in Hz).
+</p><hr>
+<a name="ntpd-mdns"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-config" accesskey="n" rel="next">ntpd config</a>, Previous: <a href="#ntpd-pccfreq" accesskey="p" rel="prev">ntpd pccfreq</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">mdns option (-m)</h4>
-
-<p><a name="index-ntpd_002dmdns-32"></a>
-This is the &ldquo;register with mdns as a ntp server&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>HAVE_DNSREGISTRATION</code> during the compilation.
-</ul>
-
- <p>Registers as an NTP server with the local mDNS server which allows
+<a name="mdns-option-_0028_002dm_0029"></a>
+<h4 class="subsection">1.1.30 mdns option (-m)</h4>
+<a name="index-ntpd_002dmdns"></a>
+
+<p>This is the &ldquo;register with mdns as a ntp server&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>HAVE_DNSREGISTRATION</code> during the compilation.
+</li></ul>
+
+<p>Registers as an NTP server with the local mDNS server which allows
the server to be discovered via mDNS client lookup.
+</p>
-<div class="node">
-<p><hr>
-<a name="ntpd-config"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-exit-status">ntpd exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-mdns">ntpd mdns</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<hr>
+<a name="ntpd-config"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-exit-status" accesskey="n" rel="next">ntpd exit status</a>, Previous: <a href="#ntpd-mdns" accesskey="p" rel="prev">ntpd mdns</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">presetting/configuring ntpd</h4>
+<a name="presetting_002fconfiguring-ntpd"></a>
+<h4 class="subsection">1.1.31 presetting/configuring ntpd</h4>
<p>Any option that is not marked as <i>not presettable</i> may be preset by
loading values from environment variables named <code>NTPD</code> and <code>NTPD_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
-the options listed above in upper case and segmented with underscores.
+the options listed above in upper case and segmented with underscores.
The <code>NTPD</code> variable will be tokenized and parsed like
the command line. The remaining variables are tested for existence and their
values are treated like option arguments.
+</p>
- <p>The command line options relating to configuration and/or usage help are:
-
-<h5 class="subsubheading">version (-)</h5>
+<p>The command line options relating to configuration and/or usage help are:
+</p>
+<a name="version-_0028_002d_0029"></a>
+<h4 class="subsubheading">version (-)</h4>
<p>Print the program version to standard out, optionally with licensing
information, then exit 0. The optional argument specifies how much licensing
-detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
+detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
Only the first letter of the argument is examined:
-
- <dl>
-<dt><span class="samp">version</span><dd>Only print the version. This is the default.
-<br><dt><span class="samp">copyright</span><dd>Name the copyright usage licensing terms.
-<br><dt><span class="samp">verbose</span><dd>Print the full copyright usage licensing terms.
+</p>
+<dl compact="compact">
+<dt>&lsquo;<samp>version</samp>&rsquo;</dt>
+<dd><p>Only print the version. This is the default.
+</p></dd>
+<dt>&lsquo;<samp>copyright</samp>&rsquo;</dt>
+<dd><p>Name the copyright usage licensing terms.
+</p></dd>
+<dt>&lsquo;<samp>verbose</samp>&rsquo;</dt>
+<dd><p>Print the full copyright usage licensing terms.
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
-<a name="ntpd-exit-status"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Usage">ntpd Usage</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-config">ntpd config</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<hr>
+<a name="ntpd-exit-status"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-Usage" accesskey="n" rel="next">ntpd Usage</a>, Previous: <a href="#ntpd-config" accesskey="p" rel="prev">ntpd config</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpd exit status</h4>
+<a name="ntpd-exit-status-1"></a>
+<h4 class="subsection">1.1.32 ntpd exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
</dl>
- <div class="node">
-<p><hr>
-<a name="ntpd-Usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Files">ntpd Files</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-exit-status">ntpd exit status</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<hr>
+<a name="ntpd-Usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-Files" accesskey="n" rel="next">ntpd Files</a>, Previous: <a href="#ntpd-exit-status" accesskey="p" rel="prev">ntpd exit status</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpd Usage</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntpd-Files"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-See-Also">ntpd See Also</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-Usage">ntpd Usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<a name="ntpd-Usage-1"></a>
+<h4 class="subsection">1.1.33 ntpd Usage</h4>
+<hr>
+<a name="ntpd-Files"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-See-Also" accesskey="n" rel="next">ntpd See Also</a>, Previous: <a href="#ntpd-Usage" accesskey="p" rel="prev">ntpd Usage</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpd Files</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntpd-See-Also"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Bugs">ntpd Bugs</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-Files">ntpd Files</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<a name="ntpd-Files-1"></a>
+<h4 class="subsection">1.1.34 ntpd Files</h4>
+<hr>
+<a name="ntpd-See-Also"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-Bugs" accesskey="n" rel="next">ntpd Bugs</a>, Previous: <a href="#ntpd-Files" accesskey="p" rel="prev">ntpd Files</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpd See Also</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntpd-Bugs"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpd-Notes">ntpd Notes</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-See-Also">ntpd See Also</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<a name="ntpd-See-Also-1"></a>
+<h4 class="subsection">1.1.35 ntpd See Also</h4>
+<hr>
+<a name="ntpd-Bugs"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpd-Notes" accesskey="n" rel="next">ntpd Notes</a>, Previous: <a href="#ntpd-See-Also" accesskey="p" rel="prev">ntpd See Also</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpd Bugs</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntpd-Notes"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpd-Bugs">ntpd Bugs</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpd-Invocation">ntpd Invocation</a>
-<br>
+<a name="ntpd-Bugs-1"></a>
+<h4 class="subsection">1.1.36 ntpd Bugs</h4>
+<hr>
+<a name="ntpd-Notes"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntpd-Bugs" accesskey="p" rel="prev">ntpd Bugs</a>, Up: <a href="#ntpd-Invocation" accesskey="u" rel="up">ntpd Invocation</a> &nbsp; </p>
</div>
+<a name="ntpd-Notes-1"></a>
+<h4 class="subsection">1.1.37 ntpd Notes</h4>
-<h4 class="subsection">ntpd Notes</h4>
-
-<div class="node">
-<p><hr>
+<hr>
<a name="Usage"></a>
-<br>
+<div class="header">
+<p>
+Previous: <a href="#ntpd-Invocation" accesskey="p" rel="prev">ntpd Invocation</a>, Up: <a href="#ntpd-Description" accesskey="u" rel="up">ntpd Description</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Usage</h3>
-
+<a name="Usage-1"></a>
+<h3 class="section">1.2 Usage</h3>
+
+<table>
+<thead><tr><th width="23%">What</th><th width="23%">Default</th><th width="5%">Flag</th><th width="15%">Option</th></tr></thead>
+<tr><td width="23%">configuration file</td><td width="23%"><code>/etc/ntp.conf</code></td><td width="5%"><code>-c</code></td><td width="15%"><code>conffile</code></td></tr>
+<tr><td width="23%">frequency file</td><td width="23%">none</td><td width="5%"><code>-f</code></td><td width="15%"><code>driftfile</code></td></tr>
+<tr><td width="23%">leapseconds file</td><td width="23%">none</td><td width="5%"></td><td width="15%"><code>leapfile</code></td></tr>
+<tr><td width="23%">process ID file</td><td width="23%">none</td><td width="5%"><code>-p</code></td><td width="15%"><code>pidfile</code></td></tr>
+<tr><td width="23%">log file</td><td width="23%">system log</td><td width="5%"><code>-l</code></td><td width="15%"><code>logfile</code></td></tr>
+<tr><td width="23%">include file</td><td width="23%">none</td><td width="5%">none</td><td width="15%"><code>includefile</code></td></tr>
+<tr><td width="23%">statistics path</td><td width="23%"><code>/var/NTP</code></td><td width="5%"><code>-s</code></td><td width="15%"><code>statsdir</code></td></tr>
+<tr><td width="23%">keys path</td><td width="23%"><code>/usr/local/etc</code></td><td width="5%"><code>-k</code></td><td width="15%"><code>keysdir</code></td></tr>
+</table>
+<hr>
+
+
+
+</body>
+</html>
diff --git a/contrib/ntp/ntpd/ntpd.man.in b/contrib/ntp/ntpd/ntpd.man.in
index d3f94c6..ed5a2f0 100644
--- a/contrib/ntp/ntpd/ntpd.man.in
+++ b/contrib/ntp/ntpd/ntpd.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpd @NTPD_MS@ "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH ntpd @NTPD_MS@ "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-Ffa4WQ/ag-RfaWVQ)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:30 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:46 AM by AutoGen 5.18.5
.\" From the definitions ntpd-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/ntpd/ntpd.mdoc.in b/contrib/ntp/ntpd/ntpd.mdoc.in
index 53b1f41..8e3d427 100644
--- a/contrib/ntp/ntpd/ntpd.mdoc.in
+++ b/contrib/ntp/ntpd/ntpd.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPD @NTPD_MS@ User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpd-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:47 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:37 AM by AutoGen 5.18.5
.\" From the definitions ntpd-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/ntpd/rc_cmdlength.c b/contrib/ntp/ntpd/rc_cmdlength.c
index 922312e..240fa0a 100644
--- a/contrib/ntp/ntpd/rc_cmdlength.c
+++ b/contrib/ntp/ntpd/rc_cmdlength.c
@@ -5,6 +5,8 @@
# include <unistd.h>
#endif
+// XXX: Move to header.
+size_t remoteconfig_cmdlength( const char *, const char *);
/* Bug 2853 */
/* evaluate the length of the command sequence. This breaks at the first
diff --git a/contrib/ntp/ntpd/refclock_bancomm.c b/contrib/ntp/ntpd/refclock_bancomm.c
index 49922e3..577ad27 100644
--- a/contrib/ntp/ntpd/refclock_bancomm.c
+++ b/contrib/ntp/ntpd/refclock_bancomm.c
@@ -60,6 +60,9 @@
#include <stdio.h>
#include <syslog.h>
#include <ctype.h>
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
struct btfp_time /* Structure for reading 5 time words */
/* in one ioctl(2) operation. */
@@ -74,17 +77,16 @@ struct btfp_time /* Structure for reading 5 time words */
#define IOCIOWN( l, n, s ) ( BTFPIOC | n )
/***** Simple ioctl commands *****/
-#define RUNLOCK IOCIOR(b, 19, int ) /* Release Capture Lockout */
-#define RCR0 IOCIOR(b, 22, int ) /* Read control register zero.*/
-#define WCR0 IOCIOWN(b, 23, int) /* Write control register zero*/
+#define RUNLOCK IOCIOR(b, 19, int ) /* Release Capture Lockout */
+#define RCR0 IOCIOR(b, 22, int ) /* Read control register zero.*/
+#define WCR0 IOCIOWN(b, 23, int) /* Write control register zero*/
/***** Compound ioctl commands *****/
/* Read all 5 time words in one call. */
-#define READTIME IOCIORN(b, 32, sizeof( struct btfp_time ))
-
#if defined(__FreeBSD__)
-#undef READTIME
-#define READTIME _IOR('u', 5, struct btfp_time )
+# define READTIME _IOR('u', 5, struct btfp_time )
+#else
+# define READTIME IOCIORN(b, 32, sizeof( struct btfp_time ))
#endif
/* Solaris specific section */
@@ -165,18 +167,76 @@ static void vme_poll (int unit, struct peer *);
struct vmedate *get_datumtime(struct vmedate *);
void tvme_fill(struct vmedate *, uint32_t btm[2]);
void stfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp);
-inline const char *DEVICE_NAME(int n);
+static const char *get_devicename(int n);
+/* [Bug 3558] and [Bug 1674] perlinger@ntp.org says:
+ *
+ * bcReadBinTime() is defined to use two DWORD pointers on Windows and
+ * Linux in the BANCOMM SDK. DWORD is of course Windows-specific
+ * (*shudder*), and it is defined as 'unsigned long' under
+ * Linux/Unix. (*sigh*)
+ *
+ * This creates quite some headache. The size of 'unsigned long' is
+ * platform/compiler/memory-model dependent (LP32 vs LP64 vs LLP64),
+ * while the card itself always creates 32bit time stamps. What a
+ * bummer. And DWORD has tendency to contain 64bit on Win64 (which is
+ * why we have a DWORD32 defined on Win64) so it can be used as
+ * substitute for 'UINT_PTR' in Windows API headers. I won't even try
+ * to comment on that, because anything I have to say will not be civil.
+ *
+ * We work around this by possibly using a wrapper function that makes
+ * the necessary conversions/casts. It might be a bit tricky to
+ * maintain the conditional logic below, but any lingering disease needs
+ * constant care to avoid a breakout.
+ */
+#if defined(__linux__)
+ typedef unsigned long bcBinTimeT;
+# if SIZEOF_LONG == 4
+# define safeReadBinTime bcReadBinTime
+# endif
+#elif defined(SYS_WINNT)
+ typedef DWORD bcBinTimeT;
+# if !defined(_WIN64) || _WIN64 == 0
+# define safeReadBinTime bcReadBinTime
+# endif
+#else
+ typedef uint32_t bcBinTimeT;
+# define safeReadBinTime bcReadBinTime
+#endif
/*
* Define the bc*() functions as weak so we can compile/link without them.
* Only clients with the card will have the proprietary vendor device driver
* and interface library needed for use on Linux/Windows platforms.
*/
-extern uint32_t __attribute__ ((weak)) bcReadBinTime(SYMMT_PCI_HANDLE, uint32_t *, uint32_t*, uint8_t*);
+extern uint32_t __attribute__ ((weak)) bcReadBinTime(SYMMT_PCI_HANDLE, bcBinTimeT*, bcBinTimeT*, uint8_t*);
extern SYMMT_PCI_HANDLE __attribute__ ((weak)) bcStartPci(void);
extern void __attribute__ ((weak)) bcStopPci(SYMMT_PCI_HANDLE);
+/* This is the conversion wrapper for the long/DWORD/uint32_t clash in
+ * reading binary times.
+ */
+#ifndef safeReadBinTime
+static uint32_t
+safeReadBinTime(
+ SYMMT_PCI_HANDLE hnd,
+ uint32_t *pt1,
+ uint32_t *pt2,
+ uint8_t *p3
+ )
+{
+ bcBinTimeT t1, t2;
+ uint32_t rc;
+
+ rc = bcReadBinTime(hnd, &t1, &t2, p3);
+ if (rc != 0) {
+ *pt1 = (uint32_t)t1;
+ *pt2 = (uint32_t)t2;
+ }
+ return rc;
+}
+#endif /* !defined(safeReadBinTime) */
+
/*
* Transfer vector
*/
@@ -195,15 +255,27 @@ int regvalue;
int tfp_type; /* mode selector, indicate platform and driver interface */
SYMMT_PCI_HANDLE stfp_handle;
-/**
- * this macro returns the device name based on
- * the platform we are running on and the device number
+/* This helper function returns the device name based on the platform we
+ * are running on and the device number.
+ *
+ * Uses a static buffer, so the result is valid only to the next call of
+ * this function!
*/
-#if defined(__sun__)
-inline const char *DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/stfp%d",n);return s;}
-#else
-inline const char* DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/btfp%d",n);return s;}
-#endif /**__sun__**/
+static const char*
+get_devicename(int n)
+{
+
+# if defined(__sun__)
+ static const char * const template ="/dev/stfp%d";
+# else
+ static const char * const template ="/dev/btfp%d";
+# endif
+ static char namebuf[20];
+
+ snprintf(namebuf, sizeof(namebuf), template, n);
+ namebuf[sizeof(namebuf)-1] = '\0'; /* paranoia rulez! */
+ return namebuf;
+}
/*
* vme_start - open the VME device and initialize data for processing
@@ -235,9 +307,9 @@ vme_start(
*/
#ifdef DEBUG
- printf("Opening DATUM DEVICE %s\n",DEVICE_NAME(peer->refclkunit));
+ printf("Opening DATUM DEVICE %s\n",get_devicename(peer->refclkunit));
#endif
- if ( (fd_vme = open(DEVICE_NAME(peer->refclkunit), O_RDWR)) < 0) {
+ if ( (fd_vme = open(get_devicename(peer->refclkunit), O_RDWR)) < 0) {
msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
return (0);
}
@@ -433,7 +505,7 @@ get_datumtime(struct vmedate *time_vme)
break;
case 2: /* Linux/Windows, PCI, 2 32bit time words */
- if (bcReadBinTime(stfp_handle, &btm[1], &btm[0], &dmy) == 0) {
+ if (safeReadBinTime(stfp_handle, &btm[1], &btm[0], &dmy) == 0) {
msyslog(LOG_ERR, "get_datumtime error: %m");
return(NULL);
}
@@ -512,10 +584,11 @@ void
tvme_fill(struct vmedate *time_vme, uint32_t btm[2])
{
struct tm maj;
- uint32_t dmaj, dmin;
+ time_t dmaj;
+ uint32_t dmin;
- dmaj = btm[1]; /* syntax sugar */
- dmin = btm[0];
+ dmaj = btm[1]; /* syntax sugar & expansion */
+ dmin = btm[0]; /* just syntax sugar */
gmtime_r(&dmaj, &maj);
time_vme->day = maj.tm_yday+1;
diff --git a/contrib/ntp/ntpd/refclock_datum.c b/contrib/ntp/ntpd/refclock_datum.c
index 9795cfa..09d72c6 100644
--- a/contrib/ntp/ntpd/refclock_datum.c
+++ b/contrib/ntp/ntpd/refclock_datum.c
@@ -485,7 +485,8 @@ datum_pts_receive(
struct recvbuf *rbufp
)
{
- int i, nb;
+ int i;
+ size_t nb;
l_fp tstmp;
struct peer *p;
struct datum_pts_unit *datum_pts;
diff --git a/contrib/ntp/ntpd/refclock_gpsdjson.c b/contrib/ntp/ntpd/refclock_gpsdjson.c
index c2d41ff..78a4fc8 100644
--- a/contrib/ntp/ntpd/refclock_gpsdjson.c
+++ b/contrib/ntp/ntpd/refclock_gpsdjson.c
@@ -1136,7 +1136,7 @@ json_token_skip(
const json_ctx * ctx,
tok_ref tid)
{
- if (tid >= 0 && (u_int)tid < ctx->ntok) {
+ if (tid >= 0 && tid < ctx->ntok) {
int len = ctx->tok[tid].size;
/* For arrays and objects, the size is the number of
* ITEMS in the compound. Thats the number of objects in
@@ -1164,7 +1164,7 @@ json_token_skip(
/* The next condition should never be true, but paranoia
* prevails...
*/
- if (tid < 0 || (u_int)tid > ctx->ntok)
+ if (tid < 0 || tid > ctx->ntok)
tid = ctx->ntok;
}
return tid;
diff --git a/contrib/ntp/ntpd/refclock_jupiter.c b/contrib/ntp/ntpd/refclock_jupiter.c
index 84d089d..8d6cde2 100644
--- a/contrib/ntp/ntpd/refclock_jupiter.c
+++ b/contrib/ntp/ntpd/refclock_jupiter.c
@@ -139,8 +139,7 @@ static void jupiter_canmsg (struct instance *, u_int);
static u_short jupiter_cksum (u_short *, u_int);
static int jupiter_config (struct instance *);
static void jupiter_debug (struct peer *, const char *,
- const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
+ const char *, ...) NTP_PRINTF(3, 4);
static const char * jupiter_parse_t (struct instance *, u_short *);
static const char * jupiter_parse_gpos (struct instance *, u_short *);
static void jupiter_platform (struct instance *, u_int);
@@ -159,10 +158,6 @@ static char * jupiter_send (struct instance *, struct jheader *);
static void jupiter_shutdown(int, struct peer *);
static int jupiter_start (int, struct peer *);
-static u_int get_full_week(u_int base_week, u_int gpos_week);
-static u_int get_base_week(void);
-
-
/*
* Transfer vector
*/
@@ -856,8 +851,7 @@ jupiter_parse_gpos(struct instance *instance, u_short *sp)
}
instance->gpos_sweek = DS2UI(jg->sweek);
- instance->gpos_gweek = get_full_week(get_base_week(),
- getshort(jg->gweek));
+ instance->gpos_gweek = basedate_expand_gpsweek(getshort(jg->gweek));
/* according to the protocol spec, the seconds-in-week cannot
* exceed the nominal value: Is it really necessary to normalise
@@ -1130,56 +1124,6 @@ jupiter_recv(struct instance *instance)
return (cc);
}
-static u_int
-get_base_week(void)
-{
- static int init_done /* = 0 */;
- static u_int base_week;
-
- /* Get the build date, convert to days since GPS epoch and
- * finally weeks since GPS epoch. Note that the build stamp is
- * trusted once it is fetched -- only dates before the GPS epoch
- * are not permitted. This will permit proper synchronisation
- * for a time range of 1024 weeks starting with 00:00:00 of the
- * last Sunday on or before the build time.
- *
- * If the impossible happens and fetching the build date fails,
- * a 1024-week cycle starting with 2016-01-03 is assumed to
- * avoid catastropic errors. This will work until 2035-08-19.
- */
- if (!init_done) {
- struct calendar bd;
- if (ntpcal_get_build_date(&bd)) {
- int32_t days = ntpcal_date_to_rd(&bd);
- if (days > RDN_GPS_EPOCH)
- days -= RDN_GPS_EPOCH;
- else
- days = 0;
- base_week = days / 7;
- } else {
- base_week = 1878; /* 2016-01-03, Sunday */
- msyslog(LOG_ERR,
- "refclock_jupiter: ntpcal_get_build_date() failed: %s",
- "using 2016-01-03 as GPS base!");
- }
- init_done = 1;
- }
- return base_week;
-}
-
-static u_int
-get_full_week(
- u_int base_week,
- u_int gpos_week
- )
-{
- /* Periodic extension on base week. Since the period is 1024
- * weeks and we do unsigned arithmetic here, we can do wonderful
- * things with masks and the well-defined overflow behaviour.
- */
- return base_week + ((gpos_week - base_week) & 1023);
-}
-
#else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
int refclock_jupiter_bs;
#endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
diff --git a/contrib/ntp/ntpd/refclock_parse.c b/contrib/ntp/ntpd/refclock_parse.c
index cfe2a89..9f5b0d7 100644
--- a/contrib/ntp/ntpd/refclock_parse.c
+++ b/contrib/ntp/ntpd/refclock_parse.c
@@ -4256,8 +4256,7 @@ mk_utcinfo(
struct tm *tm;
int nc;
- if (wnlsf < GPSWRAP)
- wnlsf += GPSWEEKS;
+ wnlsf = basedate_expand_gpsweek(wnlsf);
/* 'wnt' not used here: would need the same treatment as 'wnlsf */
t_ls = (time_t) wnlsf * SECSPERWEEK
diff --git a/contrib/ntp/ntpd/refclock_shm.c b/contrib/ntp/ntpd/refclock_shm.c
index f031a39..da38355 100644
--- a/contrib/ntp/ntpd/refclock_shm.c
+++ b/contrib/ntp/ntpd/refclock_shm.c
@@ -340,6 +340,7 @@ shm_poll(
if (pp->coderecv != pp->codeproc) {
/* have some samples, everything OK */
pp->lastref = pp->lastrec;
+ refclock_report(peer, CEVNT_NOMINAL);
refclock_receive(peer);
} else if (NULL == up->shm) { /* is this possible at all? */
/* we're out of business without SHM access */
diff --git a/contrib/ntp/ntpd/refclock_true.c b/contrib/ntp/ntpd/refclock_true.c
index 2799f3e..3590139 100644
--- a/contrib/ntp/ntpd/refclock_true.c
+++ b/contrib/ntp/ntpd/refclock_true.c
@@ -640,7 +640,7 @@ true_send(
size_t len = strlen(cmd);
true_debug(peer, "Send '%s'\n", cmd);
- if (write(pp->io.fd, cmd, (unsigned)len) != len)
+ if (write(pp->io.fd, cmd, len) != (ssize_t)len)
refclock_report(peer, CEVNT_FAULT);
else
pp->polls++;
diff --git a/contrib/ntp/ntpdate/Makefile.in b/contrib/ntp/ntpdate/Makefile.in
index a913e1a..bed1ff1 100644
--- a/contrib/ntp/ntpdate/Makefile.in
+++ b/contrib/ntp/ntpdate/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/ntpdate/ntpdate.c b/contrib/ntp/ntpdate/ntpdate.c
index 14cf22b..4cf0f62 100644
--- a/contrib/ntp/ntpdate/ntpdate.c
+++ b/contrib/ntp/ntpdate/ntpdate.c
@@ -154,7 +154,7 @@ char const *progname;
/*
* Systemwide parameters and flags
*/
-int sys_samples = DEFSAMPLES; /* number of samples/server */
+int sys_samples = 0; /* number of samples/server, will be modified later */
u_long sys_timeout = DEFTIMEOUT; /* timeout time, in TIMER_HZ units */
struct server *sys_servers; /* the server list */
int sys_numservers = 0; /* number of servers to poll */
@@ -220,7 +220,7 @@ void input_handler (void);
static int l_adj_systime (l_fp *);
static int l_step_systime (l_fp *);
-static void printserver (struct server *, FILE *);
+static void print_server (struct server *, FILE *);
#ifdef SYS_WINNT
int on = 1;
@@ -429,7 +429,7 @@ ntpdatemain (
default:
break;
}
-
+
if (errflg) {
(void) fprintf(stderr,
"usage: %s [-46bBdqsuv] [-a key#] [-e delay] [-k file] [-p samples] [-o version#] [-t timeo] server ...\n",
@@ -437,6 +437,14 @@ ntpdatemain (
exit(2);
}
+ /*
+ * If number of Samples (-p) not specified by user:
+ * - if a simple_query (-q) just ONE will do
+ * - otherwise the normal is DEFSAMPLES
+ */
+ if (sys_samples == 0)
+ sys_samples = (simple_query ? 1 : DEFSAMPLES);
+
if (debug || simple_query) {
#ifdef HAVE_SETVBUF
static char buf[BUFSIZ];
@@ -651,9 +659,6 @@ transmit(
{
struct pkt xpkt;
- if (debug)
- printf("transmit(%s)\n", stoa(&server->srcadr));
-
if (server->filter_nextpt < server->xmtcnt) {
l_fp ts;
/*
@@ -674,6 +679,9 @@ transmit(
return;
}
+ if (debug)
+ printf("transmit(%s)\n", stoa(&server->srcadr));
+
/*
* If we're here, send another message to the server. Fill in
* the packet and let 'er rip.
@@ -849,7 +857,7 @@ receive(
NTOHL_FP(&rpkt->xmt, &server->org);
/*
- * Make sure the server is at least somewhat sane. If not, try
+ * Make sure the server is at least somewhat sane. If not, try
* again.
*/
if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
@@ -956,7 +964,7 @@ clock_filter(
int ord[NTP_SHIFT];
INSIST((0 < sys_samples) && (sys_samples <= NTP_SHIFT));
-
+
/*
* Sort indices into increasing delay order
*/
@@ -1042,15 +1050,15 @@ clock_select(void)
/*
* This first chunk of code is supposed to go through all
* servers we know about to find the NTP_MAXLIST servers which
- * are most likely to succeed. We run through the list
+ * are most likely to succeed. We run through the list
* doing the sanity checks and trying to insert anyone who
- * looks okay. We are at all times aware that we should
+ * looks okay. We are at all times aware that we should
* only keep samples from the top two strata and we only need
* NTP_MAXLIST of them.
*/
nlist = 0; /* none yet */
for (server = sys_servers; server != NULL; server = server->next_server) {
- if (server->delay == 0) {
+ if (server->stratum == 0) {
if (debug)
printf("%s: Server dropped: no data\n", ntoa(&server->srcadr));
continue; /* no data */
@@ -1062,25 +1070,25 @@ clock_select(void)
}
if (server->delay > NTP_MAXWGT) {
if (debug)
- printf("%s: Server dropped: server too far away\n",
+ printf("%s: Server dropped: server too far away\n",
ntoa(&server->srcadr));
continue; /* too far away */
}
if (server->leap == LEAP_NOTINSYNC) {
if (debug)
- printf("%s: Server dropped: Leap not in sync\n", ntoa(&server->srcadr));
+ printf("%s: Server dropped: leap not in sync\n", ntoa(&server->srcadr));
continue; /* he's in trouble */
}
if (!L_ISHIS(&server->org, &server->reftime)) {
if (debug)
- printf("%s: Server dropped: server is very broken\n",
+ printf("%s: Server dropped: server is very broken\n",
ntoa(&server->srcadr));
continue; /* very broken host */
}
if ((server->org.l_ui - server->reftime.l_ui)
>= NTP_MAXAGE) {
if (debug)
- printf("%s: Server dropped: Server has gone too long without sync\n",
+ printf("%s: Server dropped: server has gone too long without sync\n",
ntoa(&server->srcadr));
continue; /* too long without sync */
}
@@ -1256,8 +1264,10 @@ clock_adjust(void)
server = clock_select();
if (debug || simple_query) {
+ if (debug)
+ printf ("\n");
for (sp = sys_servers; sp != NULL; sp = sp->next_server)
- printserver(sp, stdout);
+ print_server(sp, stdout);
}
if (server == 0) {
@@ -1283,31 +1293,17 @@ clock_adjust(void)
}
if (dostep) {
- if (simple_query || debug || l_step_systime(&server->offset)){
+ if (simple_query || l_step_systime(&server->offset)){
msyslog(LOG_NOTICE, "step time server %s offset %s sec",
stoa(&server->srcadr),
lfptoa(&server->offset, 6));
}
} else {
-#ifndef SYS_WINNT
if (simple_query || l_adj_systime(&server->offset)) {
msyslog(LOG_NOTICE, "adjust time server %s offset %s sec",
stoa(&server->srcadr),
lfptoa(&server->offset, 6));
}
-#else
- /* The NT SetSystemTimeAdjustment() call achieves slewing by
- * changing the clock frequency. This means that we cannot specify
- * it to slew the clock by a definite amount and then stop like
- * the Unix adjtime() routine. We can technically adjust the clock
- * frequency, have ntpdate sleep for a while, and then wake
- * up and reset the clock frequency, but this might cause some
- * grief if the user attempts to run ntpd immediately after
- * ntpdate and the socket is in use.
- */
- printf("\nThe -b option is required by ntpdate on Windows NT platforms\n");
- exit(1);
-#endif /* SYS_WINNT */
}
return(0);
}
@@ -1440,7 +1436,7 @@ findserver(
if (SRCPORT(addr) != NTP_PORT)
return 0;
- for (server = sys_servers; server != NULL;
+ for (server = sys_servers; server != NULL;
server = server->next_server) {
if (SOCK_EQ(addr, &server->srcadr))
return server;
@@ -1451,7 +1447,7 @@ findserver(
}
}
- if (mc_server != NULL) {
+ if (mc_server != NULL) {
struct server *sp;
@@ -1494,7 +1490,7 @@ timer(void)
* who's event timers have expired. Give these to
* the transmit routine.
*/
- for (server = sys_servers; server != NULL;
+ for (server = sys_servers; server != NULL;
server = server->next_server) {
if (server->event_time != 0
&& server->event_time <= current_time)
@@ -1520,7 +1516,7 @@ alarming(
alarm_flag++;
}
#else /* SYS_WINNT follows */
-void CALLBACK
+void CALLBACK
alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
UNUSED_ARG(uTimerID); UNUSED_ARG(uMsg); UNUSED_ARG(dwUser);
@@ -1605,24 +1601,26 @@ init_alarm(void)
#else /* SYS_WINNT follows */
_tzset();
- /*
- * Get privileges needed for fiddling with the clock
- */
+ if (!simple_query && !debug) {
+ /*
+ * Get privileges needed for fiddling with the clock
+ */
- /* get the current process token handle */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
- msyslog(LOG_ERR, "OpenProcessToken failed: %m");
- exit(1);
+ /* get the current process token handle */
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
+ msyslog(LOG_ERR, "OpenProcessToken failed: %m");
+ exit(1);
+ }
+ /* get the LUID for system-time privilege. */
+ LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
+ tkp.PrivilegeCount = 1; /* one privilege to set */
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ /* get set-time privilege for this process. */
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
+ /* cannot test return value of AdjustTokenPrivileges. */
+ if (GetLastError() != ERROR_SUCCESS)
+ msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
}
- /* get the LUID for system-time privilege. */
- LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
- tkp.PrivilegeCount = 1; /* one privilege to set */
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- /* get set-time privilege for this process. */
- AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
- /* cannot test return value of AdjustTokenPrivileges. */
- if (GetLastError() != ERROR_SUCCESS)
- msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
/*
* Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
@@ -1996,7 +1994,6 @@ input_handler(void)
}
-#if !defined SYS_WINNT && !defined SYS_CYGWIN32
/*
* adj_systime - do a big long slew of the system time
*/
@@ -2041,15 +2038,30 @@ l_adj_systime(
adjtv.tv_usec = -adjtv.tv_usec;
}
- if (adjtv.tv_usec != 0 && !debug) {
+ if (!debug && (adjtv.tv_usec != 0)) {
+ /* A time correction needs to be applied. */
+#if !defined SYS_WINNT && !defined SYS_CYGWIN32
+ /* Slew the time on systems that support this. */
if (adjtime(&adjtv, &oadjtv) < 0) {
msyslog(LOG_ERR, "Can't adjust the time of day: %m");
exit(1);
}
+#else /* SYS_WINNT or SYS_CYGWIN32 is defined */
+ /*
+ * The NT SetSystemTimeAdjustment() call achieves slewing by
+ * changing the clock frequency. This means that we cannot specify
+ * it to slew the clock by a definite amount and then stop like
+ * the Unix adjtime() routine. We can technically adjust the clock
+ * frequency, have ntpdate sleep for a while, and then wake
+ * up and reset the clock frequency, but this might cause some
+ * grief if the user attempts to run ntpd immediately after
+ * ntpdate and the socket is in use.
+ */
+ printf("\nSlewing the system time is not supported on Windows. Use the -b option to step the time.\n");
+#endif /* defined SYS_WINNT || defined SYS_CYGWIN32 */
}
return 1;
}
-#endif /* SYS_WINNT */
/*
@@ -2068,11 +2080,14 @@ l_step_systime(
int isneg;
int n;
- if (debug) return 1;
+ if (debug)
+ return 1;
+
/*
* Take the absolute value of the offset
*/
ftmp = *ts;
+
if (L_ISNEG(&ftmp)) {
L_NEG(&ftmp);
isneg = 1;
@@ -2082,9 +2097,9 @@ l_step_systime(
if (ftmp.l_ui >= 3) { /* Step it and slew - we might win */
LFPTOD(ts, dtemp);
n = step_systime(dtemp);
- if (!n)
- return n;
- if (isneg)
+ if (n == 0)
+ return 0;
+ if (isneg) /* WTF! */
ts->l_ui = ~0;
else
ts->l_ui = ~0;
@@ -2113,12 +2128,12 @@ l_step_systime(
}
-/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
+/* XXX ELIMINATE print_server similar in ntptrace.c, ntpdate.c */
/*
- * printserver - print detail information for a server
+ * print_server - print detail information for a server
*/
static void
-printserver(
+print_server(
register struct server *pp,
FILE *fp
)
@@ -2127,6 +2142,9 @@ printserver(
char junk[5];
const char *str;
+ if (pp->stratum == 0) /* Nothing received => nothing to print */
+ return;
+
if (!debug) {
(void) fprintf(fp, "server %s, stratum %d, offset %s, delay %s\n",
stoa(&pp->srcadr), pp->stratum,
@@ -2143,45 +2161,53 @@ printserver(
pp->leap & 0x1 ? '1' : '0',
pp->trust);
- if (pp->stratum == 1) {
- junk[4] = 0;
- memmove(junk, (char *)&pp->refid, 4);
+ if (REFID_ISTEXT(pp->stratum)) {
+ str = (char *) &pp->refid;
+ for (i=0; i<4 && str[i]; i++) {
+ junk[i] = (isprint(str[i]) ? str[i] : '.');
+ }
+ junk[i] = 0; // force terminating 0
str = junk;
} else {
- str = stoa(&pp->srcadr);
+ str = numtoa(pp->refid);
}
(void) fprintf(fp,
- "refid [%s], delay %s, dispersion %s\n",
- str, fptoa((s_fp)pp->delay, 5),
- ufptoa(pp->dispersion, 5));
+ "refid [%s], root delay %s, root dispersion %s\n",
+ str, fptoa((s_fp)pp->rootdelay, 6),
+ ufptoa(pp->rootdisp, 6));
- (void) fprintf(fp, "transmitted %d, in filter %d\n",
+ if (pp->xmtcnt != pp->filter_nextpt)
+ (void) fprintf(fp, "transmitted %d, in filter %d\n",
pp->xmtcnt, pp->filter_nextpt);
- (void) fprintf(fp, "reference time: %s\n",
+ (void) fprintf(fp, "reference time: %s\n",
prettydate(&pp->reftime));
(void) fprintf(fp, "originate timestamp: %s\n",
prettydate(&pp->org));
(void) fprintf(fp, "transmit timestamp: %s\n",
prettydate(&pp->xmt));
- (void) fprintf(fp, "filter delay: ");
- for (i = 0; i < NTP_SHIFT; i++) {
- (void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
- if (i == (NTP_SHIFT>>1)-1)
- (void) fprintf(fp, "\n ");
- }
- (void) fprintf(fp, "\n");
-
- (void) fprintf(fp, "filter offset:");
- for (i = 0; i < PEER_SHIFT; i++) {
- (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
- if (i == (PEER_SHIFT>>1)-1)
- (void) fprintf(fp, "\n ");
+ if (sys_samples > 1) {
+ (void) fprintf(fp, "filter delay: ");
+ for (i = 0; i < NTP_SHIFT; i++) {
+ if (i == (NTP_SHIFT>>1))
+ (void) fprintf(fp, "\n ");
+ (void) fprintf(fp, " %-10.10s",
+ (i<sys_samples ? fptoa(pp->filter_delay[i], 5) : "----"));
+ }
+ (void) fprintf(fp, "\n");
+
+ (void) fprintf(fp, "filter offset:");
+ for (i = 0; i < PEER_SHIFT; i++) {
+ if (i == (PEER_SHIFT>>1))
+ (void) fprintf(fp, "\n ");
+ (void) fprintf(fp, " %-10.10s",
+ (i<sys_samples ? lfptoa(&pp->filter_offset[i], 6): "----"));
+ }
+ (void) fprintf(fp, "\n");
}
- (void) fprintf(fp, "\n");
- (void) fprintf(fp, "delay %s, dispersion %s\n",
+ (void) fprintf(fp, "delay %s, dispersion %s, ",
fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
(void) fprintf(fp, "offset %s\n\n",
@@ -2227,7 +2253,7 @@ isc_boolean_t ntp_port_inuse(int af, u_short port)
* Check if NTP socket is already in use on this system
* This is only for Windows Systems, as they tend not to fail on the real bind() below
*/
-
+
SOCKET checksocket;
struct sockaddr_in checkservice;
checksocket = socket(af, SOCK_DGRAM, 0);
diff --git a/contrib/ntp/ntpdc/Makefile.in b/contrib/ntp/ntpdc/Makefile.in
index 1ae94fa..5abda60 100644
--- a/contrib/ntp/ntpdc/Makefile.in
+++ b/contrib/ntp/ntpdc/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/ntpdc/invoke-ntpdc.texi b/contrib/ntp/ntpdc/invoke-ntpdc.texi
index 94e4230..7370834 100644
--- a/contrib/ntp/ntpdc/invoke-ntpdc.texi
+++ b/contrib/ntp/ntpdc/invoke-ntpdc.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntpdc.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 05:15:06 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:56:51 AM by AutoGen 5.18.5
# From the definitions ntpdc-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -76,7 +76,7 @@ with a status code of 0.
@exampleindent 0
@example
-ntpdc - vendor-specific NTPD control program - Ver. 4.2.8p11
+ntpdc - vendor-specific NTPD control program - Ver. 4.2.8p13
Usage: ntpdc [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... [ host ...]
Flg Arg Option-Name Description
-4 no ipv4 Force IPv4 DNS name resolution
diff --git a/contrib/ntp/ntpdc/nl.pl b/contrib/ntp/ntpdc/nl.pl
index 73da2a8..9e79bf0 100755
--- a/contrib/ntp/ntpdc/nl.pl
+++ b/contrib/ntp/ntpdc/nl.pl
@@ -1,4 +1,4 @@
-#! /usr/local/bin/perl -w
+#! /ntpbuild/bin/perl -w
$found = 0;
$last = 0;
diff --git a/contrib/ntp/ntpdc/ntpdc-opts.c b/contrib/ntp/ntpdc/ntpdc-opts.c
index 4b7c102..2125040 100644
--- a/contrib/ntp/ntpdc/ntpdc-opts.c
+++ b/contrib/ntp/ntpdc/ntpdc-opts.c
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntpdc-opts.c)
*
- * It has been AutoGen-ed February 27, 2018 at 05:14:56 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:56:48 AM by AutoGen 5.18.5
* From the definitions ntpdc-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This source file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -69,7 +69,7 @@ extern FILE * option_usage_fp;
* static const strings for ntpdc options
*/
static char const ntpdc_opt_strs[1914] =
-/* 0 */ "ntpdc 4.2.8p11\n"
+/* 0 */ "ntpdc 4.2.8p13\n"
"Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n"
"This is free software. It is licensed for use, modification and\n"
"redistribution under the terms of the NTP License, copies of which\n"
@@ -128,14 +128,14 @@ static char const ntpdc_opt_strs[1914] =
/* 1695 */ "no-load-opts\0"
/* 1708 */ "no\0"
/* 1711 */ "NTPDC\0"
-/* 1717 */ "ntpdc - vendor-specific NTPD control program - Ver. 4.2.8p11\n"
+/* 1717 */ "ntpdc - vendor-specific NTPD control program - Ver. 4.2.8p13\n"
"Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... [ host ...]\n\0"
/* 1848 */ "$HOME\0"
/* 1854 */ ".\0"
/* 1856 */ ".ntprc\0"
/* 1863 */ "http://bugs.ntp.org, bugs@ntp.org\0"
/* 1897 */ "\n\0"
-/* 1899 */ "ntpdc 4.2.8p11";
+/* 1899 */ "ntpdc 4.2.8p13";
/**
* ipv4 option description with
@@ -796,7 +796,7 @@ static void bogus_function(void) {
translate option names.
*/
/* referenced via ntpdcOptions.pzCopyright */
- puts(_("ntpdc 4.2.8p11\n\
+ puts(_("ntpdc 4.2.8p13\n\
Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n\
This is free software. It is licensed for use, modification and\n\
redistribution under the terms of the NTP License, copies of which\n\
@@ -862,14 +862,14 @@ implied warranty.\n"));
puts(_("load options from a config file"));
/* referenced via ntpdcOptions.pzUsageTitle */
- puts(_("ntpdc - vendor-specific NTPD control program - Ver. 4.2.8p11\n\
+ puts(_("ntpdc - vendor-specific NTPD control program - Ver. 4.2.8p13\n\
Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... [ host ...]\n"));
/* referenced via ntpdcOptions.pzExplain */
puts(_("\n"));
/* referenced via ntpdcOptions.pzFullVersion */
- puts(_("ntpdc 4.2.8p11"));
+ puts(_("ntpdc 4.2.8p13"));
/* referenced via ntpdcOptions.pzFullUsage */
puts(_("<<<NOT-FOUND>>>"));
diff --git a/contrib/ntp/ntpdc/ntpdc-opts.h b/contrib/ntp/ntpdc/ntpdc-opts.h
index f0c4978..5af0193 100644
--- a/contrib/ntp/ntpdc/ntpdc-opts.h
+++ b/contrib/ntp/ntpdc/ntpdc-opts.h
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntpdc-opts.h)
*
- * It has been AutoGen-ed February 27, 2018 at 05:14:56 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:56:48 AM by AutoGen 5.18.5
* From the definitions ntpdc-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This header file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -53,7 +53,7 @@
* tolerable version is at least as old as what was current when the header
* template was released.
*/
-#define AO_TEMPLATE_VERSION 167936
+#define AO_TEMPLATE_VERSION 167937
#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
|| (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
# error option template version mismatches autoopts/options.h header
@@ -83,9 +83,9 @@ typedef enum {
/** count of all options for ntpdc */
#define OPTION_CT 15
/** ntpdc version */
-#define NTPDC_VERSION "4.2.8p11"
+#define NTPDC_VERSION "4.2.8p13"
/** Full ntpdc version text */
-#define NTPDC_FULL_VERSION "ntpdc 4.2.8p11"
+#define NTPDC_FULL_VERSION "ntpdc 4.2.8p13"
/**
* Interface defines for all options. Replace "n" with the UPPER_CASED
diff --git a/contrib/ntp/ntpdc/ntpdc.1ntpdcman b/contrib/ntp/ntpdc/ntpdc.1ntpdcman
index 6e19ef6..e74529e 100644
--- a/contrib/ntp/ntpdc/ntpdc.1ntpdcman
+++ b/contrib/ntp/ntpdc/ntpdc.1ntpdcman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpdc 1ntpdcman "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH ntpdc 1ntpdcman "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-MnaqKS/ag-YnaiJS)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:03 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:53 AM by AutoGen 5.18.5
.\" From the definitions ntpdc-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/ntpdc/ntpdc.1ntpdcmdoc b/contrib/ntp/ntpdc/ntpdc.1ntpdcmdoc
index 9b38582..fc6f55f 100644
--- a/contrib/ntp/ntpdc/ntpdc.1ntpdcmdoc
+++ b/contrib/ntp/ntpdc/ntpdc.1ntpdcmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPDC 1ntpdcmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpdc-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:09 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:50 AM by AutoGen 5.18.5
.\" From the definitions ntpdc-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/ntpdc/ntpdc.c b/contrib/ntp/ntpdc/ntpdc.c
index 3aeaddc..c54596e 100644
--- a/contrib/ntp/ntpdc/ntpdc.c
+++ b/contrib/ntp/ntpdc/ntpdc.c
@@ -226,15 +226,27 @@ static const char *chosts[MAXHOSTS];
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
/*
- * Jump buffer for longjumping back to the command level
+ * Jump buffer for longjumping back to the command level.
+ *
+ * See ntpq/ntpq.c for an explanation why 'sig{set,long}jmp()' is used
+ * when available.
*/
-static jmp_buf interrupt_buf;
-static volatile int jump = 0;
+#if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP
+# define JMP_BUF sigjmp_buf
+# define SETJMP(x) sigsetjmp((x), 1)
+# define LONGJMP(x, v) siglongjmp((x),(v))
+#else
+# define JMP_BUF jmp_buf
+# define SETJMP(x) setjmp((x))
+# define LONGJMP(x, v) longjmp((x),(v))
+#endif
+static JMP_BUF interrupt_buf;
+static volatile int jump = 0;
/*
* Pointer to current output unit
*/
-static FILE *current_output;
+static FILE *current_output = NULL;
/*
* Command table imported from ntpdc_ops.c
@@ -275,7 +287,6 @@ ntpdcmain(
char *argv[]
)
{
-
delay_time.l_ui = 0;
delay_time.l_uf = DEFDELAY;
@@ -352,7 +363,7 @@ ntpdcmain(
#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
if (interactive)
- (void) signal_no_reset(SIGINT, abortcmd);
+ (void) signal_no_reset(SIGINT, abortcmd);
#endif /* SYS_WINNT */
/*
@@ -393,31 +404,28 @@ openhost(
)
{
char temphost[LENHOSTNAME];
- int a_info, i;
+ int a_info;
struct addrinfo hints, *ai = NULL;
sockaddr_u addr;
size_t octets;
- register const char *cp;
+ const char *cp;
char name[LENHOSTNAME];
char service[5];
/*
* We need to get by the [] if they were entered
*/
-
- cp = hname;
-
- if (*cp == '[') {
- cp++;
- for (i = 0; *cp && *cp != ']'; cp++, i++)
- name[i] = *cp;
- if (*cp == ']') {
- name[i] = '\0';
- hname = name;
- } else {
+ if (*hname == '[') {
+ cp = strchr(hname + 1, ']');
+ if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) {
+ errno = EINVAL;
+ warning("%s", "bad hostname/address");
return 0;
}
- }
+ memcpy(name, hname + 1, octets);
+ name[octets] = '\0';
+ hname = name;
+ }
/*
* First try to resolve it as an ip address and if that fails,
@@ -944,7 +952,7 @@ sendrequest(
if (!maclen) {
fprintf(stderr, "Key not found\n");
return 1;
- } else if (maclen != (int)(info_auth_hashlen + sizeof(keyid_t))) {
+ } else if (maclen != (size_t)(info_auth_hashlen + sizeof(keyid_t))) {
fprintf(stderr,
"%zu octet MAC, %zu expected with %zu octet digest\n",
maclen, (info_auth_hashlen + sizeof(keyid_t)),
@@ -1118,12 +1126,14 @@ abortcmd(
int sig
)
{
-
if (current_output == stdout)
- (void) fflush(stdout);
+ (void)fflush(stdout);
putc('\n', stderr);
- (void) fflush(stderr);
- if (jump) longjmp(interrupt_buf, 1);
+ (void)fflush(stderr);
+ if (jump) {
+ jump = 0;
+ LONGJMP(interrupt_buf, 1);
+ }
}
#endif /* SYS_WINNT */
@@ -1235,14 +1245,22 @@ docmd(
current_output = stdout;
}
- if (interactive && setjmp(interrupt_buf)) {
- return;
+ if (interactive) {
+ if ( ! SETJMP(interrupt_buf)) {
+ jump = 1;
+ (xcmd->handler)(&pcmd, current_output);
+ jump = 0;
+ } else {
+ fflush(current_output);
+ fputs("\n >>> command aborted <<<\n", stderr);
+ fflush(stderr);
+ }
} else {
- jump = 1;
- (xcmd->handler)(&pcmd, current_output);
jump = 0;
- if (current_output != stdout)
- (void) fclose(current_output);
+ (xcmd->handler)(&pcmd, current_output);
+ }
+ if ((NULL != current_output) && (stdout != current_output)) {
+ (void)fclose(current_output);
current_output = NULL;
}
}
diff --git a/contrib/ntp/ntpdc/ntpdc.html b/contrib/ntp/ntpdc/ntpdc.html
index e133ec7..0d550eb 100644
--- a/contrib/ntp/ntpdc/ntpdc.html
+++ b/contrib/ntp/ntpdc/ntpdc.html
@@ -1,158 +1,220 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>ntpdc: NTPD Control User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="ntpdc: NTPD Control User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>ntpdc: NTPD Control User&rsquo;s Manual</title>
+
+<meta name="description" content="ntpdc: NTPD Control User&rsquo;s Manual">
+<meta name="keywords" content="ntpdc: NTPD Control User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">ntpdc: NTPD Control User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-Description">ntpdc Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">ntpdc: NTPD Control User Manual</h2>
+<body lang="en">
+<h1 class="settitle" align="center">ntpdc: NTPD Control User&rsquo;s Manual</h1>
+
+
-<p>This document describes the use of the NTP Project's <code>ntpdc</code> program,
+
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-Description" accesskey="n" rel="next">ntpdc Description</a>, Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="ntpdc_003a-NTPD-Control-User-Manual"></a>
+<h1 class="top">ntpdc: NTPD Control User Manual</h1>
+
+<p>This document describes the use of the NTP Project&rsquo;s <code>ntpdc</code> program,
that can be used to query a Network Time Protocol (NTP) server and
display the time offset of the system clock relative to the server
clock. Run as root, it can correct the system clock to this offset as
well. It can be run as an interactive command or from a cron job.
-
- <p>This document applies to version 4.2.8p11 of <code>ntpdc</code>.
-
- <p>The program implements the SNTP protocol as defined by RFC 5905, the NTPv4
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntpdc</code>.
+</p>
+<p>The program implements the SNTP protocol as defined by RFC 5905, the NTPv4
IETF specification.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">ntpdc: NTPD Control User Manual</a>
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Description" href="#toc-Description">1 Description</a></li>
</ul>
</div>
-<ul class="menu">
-<li><a accesskey="1" href="#ntpdc-Description">ntpdc Description</a>: Description
-<li><a accesskey="2" href="#ntpdc-Invocation">ntpdc Invocation</a>: Invoking ntpdc
-<li><a accesskey="3" href="#Usage">Usage</a>: Usage
-</ul>
-<div class="node">
-<p><hr>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-Description" accesskey="1">ntpdc Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-Invocation" accesskey="2">ntpdc Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking ntpdc
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="3">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+</table>
+
+<hr>
<a name="ntpdc-Description"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-Invocation" accesskey="n" rel="next">ntpdc Invocation</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Description</h3>
+<a name="Description"></a>
+<h2 class="chapter">1 Description</h2>
<p>By default, <code>ntpdc</code> writes the local data and time (i.e., not UTC) to the
standard output in the format:
+</p>
+<div class="example">
+<pre class="example">1996-10-15 20:17:25.123 (+0800) +4.567 +/- 0.089 secs
+</pre></div>
-<pre class="example"> 1996-10-15 20:17:25.123 (+0800) +4.567 +/- 0.089 secs
-</pre>
- <p>where
+<p>where
YYYY-MM-DD HH:MM:SS.SUBSEC is the local date and time,
(+0800) is the local timezone adjustment (so we would add 8 hours and 0 minutes to convert the reported local time to UTC),
and
the +4.567 +/- 0.089 secs indicates the time offset and
error bound of the system clock relative to the server clock.
-
-<div class="node">
-<p><hr>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-Invocation" accesskey="1">ntpdc Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="2">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
<a name="ntpdc-Invocation"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Usage" accesskey="n" rel="next">Usage</a>, Previous: <a href="#ntpdc-Description" accesskey="p" rel="prev">ntpdc Description</a>, Up: <a href="#ntpdc-Description" accesskey="u" rel="up">ntpdc Description</a> &nbsp; </p>
</div>
+<a name="Invoking-ntpdc"></a>
+<h3 class="section">1.1 Invoking ntpdc</h3>
+<a name="index-ntpdc"></a>
+<a name="index-vendor_002dspecific-NTPD-control-program"></a>
-<h3 class="section">Invoking ntpdc</h3>
-<p><a name="index-ntpdc-1"></a><a name="index-vendor_002dspecific-NTPD-control-program-2"></a>
- <p><code>ntpdc</code>
-is deprecated.
+<p><code>ntpdc</code>
+is deprecated.
Please use
<code>ntpq(1ntpqmdoc)</code> instead - it can do everything
<code>ntpdc</code>
used to do, and it does so using a much more sane interface.
-
- <p><code>ntpdc</code>
+</p>
+<p><code>ntpdc</code>
is a utility program used to query
<code>ntpd(1ntpdmdoc)</code>
about its
-current state and to request changes in that state.
-It uses NTP mode 7 control message formats described in the source code.
+current state and to request changes in that state.
+It uses NTP mode 7 control message formats described in the source code.
The program may
be run either in interactive mode or controlled using command line
-arguments.
+arguments.
Extensive state and statistics information is available
through the
<code>ntpdc</code>
-interface.
+interface.
In addition, nearly all the
configuration options which can be specified at startup using
-ntpd's configuration file may also be specified at run time using
+ntpd&rsquo;s configuration file may also be specified at run time using
<code>ntpdc</code>
-
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntpdc</code> program.
+</p>
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntpdc</code> program.
This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntpdc-usage">ntpdc usage</a>: ntpdc help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#ntpdc-ipv4">ntpdc ipv4</a>: ipv4 option (-4)
-<li><a accesskey="3" href="#ntpdc-ipv6">ntpdc ipv6</a>: ipv6 option (-6)
-<li><a accesskey="4" href="#ntpdc-command">ntpdc command</a>: command option (-c)
-<li><a accesskey="5" href="#ntpdc-interactive">ntpdc interactive</a>: interactive option (-i)
-<li><a accesskey="6" href="#ntpdc-listpeers">ntpdc listpeers</a>: listpeers option (-l)
-<li><a accesskey="7" href="#ntpdc-numeric">ntpdc numeric</a>: numeric option (-n)
-<li><a accesskey="8" href="#ntpdc-peers">ntpdc peers</a>: peers option (-p)
-<li><a accesskey="9" href="#ntpdc-showpeers">ntpdc showpeers</a>: showpeers option (-s)
-<li><a href="#ntpdc-config">ntpdc config</a>: presetting/configuring ntpdc
-<li><a href="#ntpdc-exit-status">ntpdc exit status</a>: exit status
-<li><a href="#ntpdc-Usage">ntpdc Usage</a>: Usage
-<li><a href="#ntpdc-See-Also">ntpdc See Also</a>: See Also
-<li><a href="#ntpdc-Authors">ntpdc Authors</a>: Authors
-<li><a href="#ntpdc-Bugs">ntpdc Bugs</a>: Bugs
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntpdc-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-ipv4">ntpdc ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-usage" accesskey="1">ntpdc usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntpdc help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-ipv4" accesskey="2">ntpdc ipv4</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv4 option (-4)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-ipv6" accesskey="3">ntpdc ipv6</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv6 option (-6)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-command" accesskey="4">ntpdc command</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">command option (-c)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-interactive" accesskey="5">ntpdc interactive</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">interactive option (-i)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-listpeers" accesskey="6">ntpdc listpeers</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">listpeers option (-l)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-numeric" accesskey="7">ntpdc numeric</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">numeric option (-n)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-peers" accesskey="8">ntpdc peers</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">peers option (-p)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-showpeers" accesskey="9">ntpdc showpeers</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">showpeers option (-s)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-config">ntpdc config</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">presetting/configuring ntpdc
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-exit-status">ntpdc exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-Usage">ntpdc Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-See-Also">ntpdc See Also</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">See Also
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-Authors">ntpdc Authors</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Authors
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpdc-Bugs">ntpdc Bugs</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Bugs
+</td></tr>
+</table>
+
+<hr>
+<a name="ntpdc-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-ipv4" accesskey="n" rel="next">ntpdc ipv4</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpdc help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-ntpdc-help-3"></a>
-This is the automatically generated usage text for ntpdc.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="ntpdc-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h4 class="subsection">1.1.1 ntpdc help/usage (<samp>--help</samp>)</h4>
+<a name="index-ntpdc-help"></a>
+
+<p>This is the automatically generated usage text for ntpdc.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">ntpdc - vendor-specific NTPD control program - Ver. 4.2.8p11
+</p>
+<div class="example">
+<pre class="example">ntpdc - vendor-specific NTPD control program - Ver. 4.2.8p13
Usage: ntpdc [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]... [ host ...]
Flg Arg Option-Name Description
-4 no ipv4 Force IPv4 DNS name resolution
@@ -196,320 +258,333 @@ The following option preset mechanisms are supported:
- examining environment variables named NTPDC_*
Please send bug reports to: &lt;http://bugs.ntp.org, bugs@ntp.org&gt;
-</pre>
- <div class="node">
-<p><hr>
-<a name="ntpdc-ipv4"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-ipv6">ntpdc ipv6</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-usage">ntpdc usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
-</div>
+</pre></div>
-<h4 class="subsection">ipv4 option (-4)</h4>
-
-<p><a name="index-ntpdc_002dipv4-4"></a>
-This is the &ldquo;force ipv4 dns name resolution&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv6.
-</ul>
-
- <p>Force DNS resolution of following host names on the command line
-to the IPv4 namespace.
-<div class="node">
-<p><hr>
-<a name="ntpdc-ipv6"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-command">ntpdc command</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-ipv4">ntpdc ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<hr>
+<a name="ntpdc-ipv4"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-ipv6" accesskey="n" rel="next">ntpdc ipv6</a>, Previous: <a href="#ntpdc-usage" accesskey="p" rel="prev">ntpdc usage</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ipv6 option (-6)</h4>
-
-<p><a name="index-ntpdc_002dipv6-5"></a>
-This is the &ldquo;force ipv6 dns name resolution&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv4.
-</ul>
-
- <p>Force DNS resolution of following host names on the command line
-to the IPv6 namespace.
-<div class="node">
-<p><hr>
-<a name="ntpdc-command"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-interactive">ntpdc interactive</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-ipv6">ntpdc ipv6</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<a name="ipv4-option-_0028_002d4_0029"></a>
+<h4 class="subsection">1.1.2 ipv4 option (-4)</h4>
+<a name="index-ntpdc_002dipv4"></a>
+
+<p>This is the &ldquo;force ipv4 dns name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv6.
+</li></ul>
+
+<p>Force DNS resolution of following host names on the command line
+to the IPv4 namespace.
+</p><hr>
+<a name="ntpdc-ipv6"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-command" accesskey="n" rel="next">ntpdc command</a>, Previous: <a href="#ntpdc-ipv4" accesskey="p" rel="prev">ntpdc ipv4</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">command option (-c)</h4>
-
-<p><a name="index-ntpdc_002dcommand-6"></a>
-This is the &ldquo;run a command and exit&rdquo; option.
-This option takes a string argument <span class="file">cmd</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>The following argument is interpreted as an interactive format command
+<a name="ipv6-option-_0028_002d6_0029"></a>
+<h4 class="subsection">1.1.3 ipv6 option (-6)</h4>
+<a name="index-ntpdc_002dipv6"></a>
+
+<p>This is the &ldquo;force ipv6 dns name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv4.
+</li></ul>
+
+<p>Force DNS resolution of following host names on the command line
+to the IPv6 namespace.
+</p><hr>
+<a name="ntpdc-command"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-interactive" accesskey="n" rel="next">ntpdc interactive</a>, Previous: <a href="#ntpdc-ipv6" accesskey="p" rel="prev">ntpdc ipv6</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
+</div>
+<a name="command-option-_0028_002dc_0029"></a>
+<h4 class="subsection">1.1.4 command option (-c)</h4>
+<a name="index-ntpdc_002dcommand"></a>
+
+<p>This is the &ldquo;run a command and exit&rdquo; option.
+This option takes a string argument <samp>cmd</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>The following argument is interpreted as an interactive format command
and is added to the list of commands to be executed on the specified
-host(s).
-<div class="node">
-<p><hr>
-<a name="ntpdc-interactive"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-listpeers">ntpdc listpeers</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-command">ntpdc command</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+host(s).
+</p><hr>
+<a name="ntpdc-interactive"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-listpeers" accesskey="n" rel="next">ntpdc listpeers</a>, Previous: <a href="#ntpdc-command" accesskey="p" rel="prev">ntpdc command</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">interactive option (-i)</h4>
-
-<p><a name="index-ntpdc_002dinteractive-7"></a>
-This is the &ldquo;force ntpq to operate in interactive mode&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-command, listpeers, peers, showpeers.
-</ul>
-
- <p>Force ntpq to operate in interactive mode. Prompts will be written
-to the standard output and commands read from the standard input.
-<div class="node">
-<p><hr>
-<a name="ntpdc-listpeers"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-numeric">ntpdc numeric</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-interactive">ntpdc interactive</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<a name="interactive-option-_0028_002di_0029"></a>
+<h4 class="subsection">1.1.5 interactive option (-i)</h4>
+<a name="index-ntpdc_002dinteractive"></a>
+
+<p>This is the &ldquo;force ntpq to operate in interactive mode&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+command, listpeers, peers, showpeers.
+</li></ul>
+
+<p>Force ntpq to operate in interactive mode. Prompts will be written
+to the standard output and commands read from the standard input.
+</p><hr>
+<a name="ntpdc-listpeers"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-numeric" accesskey="n" rel="next">ntpdc numeric</a>, Previous: <a href="#ntpdc-interactive" accesskey="p" rel="prev">ntpdc interactive</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">listpeers option (-l)</h4>
-
-<p><a name="index-ntpdc_002dlistpeers-8"></a>
-This is the &ldquo;print a list of the peers&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-command.
-</ul>
-
- <p>Print a list of the peers known to the server as well as a summary of
-their state. This is equivalent to the 'listpeers' interactive command.
-<div class="node">
-<p><hr>
-<a name="ntpdc-numeric"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-peers">ntpdc peers</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-listpeers">ntpdc listpeers</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<a name="listpeers-option-_0028_002dl_0029"></a>
+<h4 class="subsection">1.1.6 listpeers option (-l)</h4>
+<a name="index-ntpdc_002dlistpeers"></a>
+
+<p>This is the &ldquo;print a list of the peers&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+command.
+</li></ul>
+
+<p>Print a list of the peers known to the server as well as a summary of
+their state. This is equivalent to the &rsquo;listpeers&rsquo; interactive command.
+</p><hr>
+<a name="ntpdc-numeric"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-peers" accesskey="n" rel="next">ntpdc peers</a>, Previous: <a href="#ntpdc-listpeers" accesskey="p" rel="prev">ntpdc listpeers</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
+<a name="numeric-option-_0028_002dn_0029"></a>
+<h4 class="subsection">1.1.7 numeric option (-n)</h4>
+<a name="index-ntpdc_002dnumeric"></a>
-<h4 class="subsection">numeric option (-n)</h4>
-
-<p><a name="index-ntpdc_002dnumeric-9"></a>
-This is the &ldquo;numeric host addresses&rdquo; option.
+<p>This is the &ldquo;numeric host addresses&rdquo; option.
Output all host addresses in dotted-quad numeric format rather than
converting to the canonical host names.
-<div class="node">
-<p><hr>
-<a name="ntpdc-peers"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-showpeers">ntpdc showpeers</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-numeric">ntpdc numeric</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+</p><hr>
+<a name="ntpdc-peers"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-showpeers" accesskey="n" rel="next">ntpdc showpeers</a>, Previous: <a href="#ntpdc-numeric" accesskey="p" rel="prev">ntpdc numeric</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">peers option (-p)</h4>
-
-<p><a name="index-ntpdc_002dpeers-10"></a>
-This is the &ldquo;print a list of the peers&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-command.
-</ul>
-
- <p>Print a list of the peers known to the server as well as a summary
-of their state. This is equivalent to the 'peers' interactive command.
-<div class="node">
-<p><hr>
-<a name="ntpdc-showpeers"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-config">ntpdc config</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-peers">ntpdc peers</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<a name="peers-option-_0028_002dp_0029"></a>
+<h4 class="subsection">1.1.8 peers option (-p)</h4>
+<a name="index-ntpdc_002dpeers"></a>
+
+<p>This is the &ldquo;print a list of the peers&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+command.
+</li></ul>
+
+<p>Print a list of the peers known to the server as well as a summary
+of their state. This is equivalent to the &rsquo;peers&rsquo; interactive command.
+</p><hr>
+<a name="ntpdc-showpeers"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-config" accesskey="n" rel="next">ntpdc config</a>, Previous: <a href="#ntpdc-peers" accesskey="p" rel="prev">ntpdc peers</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">showpeers option (-s)</h4>
-
-<p><a name="index-ntpdc_002dshowpeers-11"></a>
-This is the &ldquo;show a list of the peers&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-command.
-</ul>
-
- <p>Print a list of the peers known to the server as well as a summary
-of their state. This is equivalent to the 'dmpeers' interactive command.
-
-<div class="node">
-<p><hr>
-<a name="ntpdc-config"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-exit-status">ntpdc exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-showpeers">ntpdc showpeers</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<a name="showpeers-option-_0028_002ds_0029"></a>
+<h4 class="subsection">1.1.9 showpeers option (-s)</h4>
+<a name="index-ntpdc_002dshowpeers"></a>
+
+<p>This is the &ldquo;show a list of the peers&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+command.
+</li></ul>
+
+<p>Print a list of the peers known to the server as well as a summary
+of their state. This is equivalent to the &rsquo;dmpeers&rsquo; interactive command.
+</p>
+
+<hr>
+<a name="ntpdc-config"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-exit-status" accesskey="n" rel="next">ntpdc exit status</a>, Previous: <a href="#ntpdc-showpeers" accesskey="p" rel="prev">ntpdc showpeers</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">presetting/configuring ntpdc</h4>
+<a name="presetting_002fconfiguring-ntpdc"></a>
+<h4 class="subsection">1.1.10 presetting/configuring ntpdc</h4>
<p>Any option that is not marked as <i>not presettable</i> may be preset by
-loading values from configuration ("rc" or "ini") files, and values from environment variables named <code>NTPDC</code> and <code>NTPDC_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
-the options listed above in upper case and segmented with underscores.
+loading values from configuration (&quot;rc&quot; or &quot;ini&quot;) files, and values from environment variables named <code>NTPDC</code> and <code>NTPDC_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
+the options listed above in upper case and segmented with underscores.
The <code>NTPDC</code> variable will be tokenized and parsed like
the command line. The remaining variables are tested for existence and their
values are treated like option arguments.
-
-<p class="noindent"><code>libopts</code> will search in 2 places for configuration files:
- <ul>
-<li>$HOME
-<li>$PWD
-</ul>
- The environment variables <code>HOME</code>, and <code>PWD</code>
-are expanded and replaced when <span class="file">ntpdc</span> runs.
-For any of these that are plain files, they are simply processed.
-For any that are directories, then a file named <span class="file">.ntprc</span> is searched for
+</p>
+
+<p><code>libopts</code> will search in 2 places for configuration files:
+</p><ul>
+<li> $HOME
+</li><li> $PWD
+</li></ul>
+<p>The environment variables <code>HOME</code>, and <code>PWD</code>
+are expanded and replaced when <samp>ntpdc</samp> runs.
+For any of these that are plain files, they are simply processed.
+For any that are directories, then a file named <samp>.ntprc</samp> is searched for
within that directory and processed.
-
- <p>Configuration files may be in a wide variety of formats.
+</p>
+<p>Configuration files may be in a wide variety of formats.
The basic format is an option name followed by a value (argument) on the
same line. Values may be separated from the option name with a colon,
equal sign or simply white space. Values may be continued across multiple
lines by escaping the newline with a backslash.
-
- <p>Multiple programs may also share the same initialization file.
+</p>
+<p>Multiple programs may also share the same initialization file.
Common options are collected at the top, followed by program specific
segments. The segments are separated by lines like:
-<pre class="example"> [NTPDC]
-</pre>
- <p class="noindent">or by
-<pre class="example"> &lt;?program ntpdc&gt;
-</pre>
- <p class="noindent">Do not mix these styles within one configuration file.
-
- <p>Compound values and carefully constructed string values may also be
+</p><div class="example">
+<pre class="example">[NTPDC]
+</pre></div>
+<p>or by
+</p><div class="example">
+<pre class="example">&lt;?program ntpdc&gt;
+</pre></div>
+<p>Do not mix these styles within one configuration file.
+</p>
+<p>Compound values and carefully constructed string values may also be
specified using XML syntax:
-<pre class="example"> &lt;option-name&gt;
- &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
- &lt;/option-name&gt;
-</pre>
- <p class="noindent">yielding an <code>option-name.sub-opt</code> string value of
-<pre class="example"> "...&lt;...&gt;..."
-</pre>
- <p><code>AutoOpts</code> does not track suboptions. You simply note that it is a
+</p><div class="example">
+<pre class="example">&lt;option-name&gt;
+ &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
+&lt;/option-name&gt;
+</pre></div>
+<p>yielding an <code>option-name.sub-opt</code> string value of
+</p><div class="example">
+<pre class="example">&quot;...&lt;...&gt;...&quot;
+</pre></div>
+<p><code>AutoOpts</code> does not track suboptions. You simply note that it is a
hierarchicly valued option. <code>AutoOpts</code> does provide a means for searching
the associated name/value pair list (see: optionFindValue).
-
- <p>The command line options relating to configuration and/or usage help are:
-
-<h5 class="subsubheading">version (-)</h5>
+</p>
+<p>The command line options relating to configuration and/or usage help are:
+</p>
+<a name="version-_0028_002d_0029"></a>
+<h4 class="subsubheading">version (-)</h4>
<p>Print the program version to standard out, optionally with licensing
information, then exit 0. The optional argument specifies how much licensing
-detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
+detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
Only the first letter of the argument is examined:
-
- <dl>
-<dt><span class="samp">version</span><dd>Only print the version. This is the default.
-<br><dt><span class="samp">copyright</span><dd>Name the copyright usage licensing terms.
-<br><dt><span class="samp">verbose</span><dd>Print the full copyright usage licensing terms.
+</p>
+<dl compact="compact">
+<dt>&lsquo;<samp>version</samp>&rsquo;</dt>
+<dd><p>Only print the version. This is the default.
+</p></dd>
+<dt>&lsquo;<samp>copyright</samp>&rsquo;</dt>
+<dd><p>Name the copyright usage licensing terms.
+</p></dd>
+<dt>&lsquo;<samp>verbose</samp>&rsquo;</dt>
+<dd><p>Print the full copyright usage licensing terms.
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
-<a name="ntpdc-exit-status"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-Usage">ntpdc Usage</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-config">ntpdc config</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<hr>
+<a name="ntpdc-exit-status"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-Usage" accesskey="n" rel="next">ntpdc Usage</a>, Previous: <a href="#ntpdc-config" accesskey="p" rel="prev">ntpdc config</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpdc exit status</h4>
+<a name="ntpdc-exit-status-1"></a>
+<h4 class="subsection">1.1.11 ntpdc exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
-<br><dt><span class="samp">66 (EX_NOINPUT)</span><dd>A specified configuration file could not be loaded.
-<br><dt><span class="samp">70 (EX_SOFTWARE)</span><dd>libopts had an internal operational error. Please report
-it to autogen-users@lists.sourceforge.net. Thank you.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
+<dt>&lsquo;<samp>66 (EX_NOINPUT)</samp>&rsquo;</dt>
+<dd><p>A specified configuration file could not be loaded.
+</p></dd>
+<dt>&lsquo;<samp>70 (EX_SOFTWARE)</samp>&rsquo;</dt>
+<dd><p>libopts had an internal operational error. Please report
+it to autogen-users@lists.sourceforge.net. Thank you.
+</p></dd>
</dl>
- <div class="node">
-<p><hr>
-<a name="ntpdc-Usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-See-Also">ntpdc See Also</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-exit-status">ntpdc exit status</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<hr>
+<a name="ntpdc-Usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-See-Also" accesskey="n" rel="next">ntpdc See Also</a>, Previous: <a href="#ntpdc-exit-status" accesskey="p" rel="prev">ntpdc exit status</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpdc Usage</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntpdc-See-Also"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-Authors">ntpdc Authors</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-Usage">ntpdc Usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<a name="ntpdc-Usage-1"></a>
+<h4 class="subsection">1.1.12 ntpdc Usage</h4>
+<hr>
+<a name="ntpdc-See-Also"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-Authors" accesskey="n" rel="next">ntpdc Authors</a>, Previous: <a href="#ntpdc-Usage" accesskey="p" rel="prev">ntpdc Usage</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpdc See Also</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntpdc-Authors"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpdc-Bugs">ntpdc Bugs</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-See-Also">ntpdc See Also</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<a name="ntpdc-See-Also-1"></a>
+<h4 class="subsection">1.1.13 ntpdc See Also</h4>
+<hr>
+<a name="ntpdc-Authors"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpdc-Bugs" accesskey="n" rel="next">ntpdc Bugs</a>, Previous: <a href="#ntpdc-See-Also" accesskey="p" rel="prev">ntpdc See Also</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpdc Authors</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntpdc-Bugs"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpdc-Authors">ntpdc Authors</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpdc-Invocation">ntpdc Invocation</a>
-<br>
+<a name="ntpdc-Authors-1"></a>
+<h4 class="subsection">1.1.14 ntpdc Authors</h4>
+<hr>
+<a name="ntpdc-Bugs"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntpdc-Authors" accesskey="p" rel="prev">ntpdc Authors</a>, Up: <a href="#ntpdc-Invocation" accesskey="u" rel="up">ntpdc Invocation</a> &nbsp; </p>
</div>
+<a name="ntpdc-Bugs-1"></a>
+<h4 class="subsection">1.1.15 ntpdc Bugs</h4>
-<h4 class="subsection">ntpdc Bugs</h4>
-
-<div class="node">
-<p><hr>
+<hr>
<a name="Usage"></a>
-<br>
+<div class="header">
+<p>
+Previous: <a href="#ntpdc-Invocation" accesskey="p" rel="prev">ntpdc Invocation</a>, Up: <a href="#ntpdc-Description" accesskey="u" rel="up">ntpdc Description</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Usage</h3>
+<a name="Usage-1"></a>
+<h3 class="section">1.2 Usage</h3>
<p>The simplest use of this program is as an unprivileged command to
-check the current time, offset, and error in the local clock.
+check the current time, offset, and error in the local clock.
For example:
+</p>
+<div class="example">
+<pre class="example">ntpdc ntpserver.somewhere
+</pre></div>
-<pre class="example"> ntpdc ntpserver.somewhere
-</pre>
- <p>With suitable privilege, it can be run as a command or in a
+<p>With suitable privilege, it can be run as a command or in a
<code>cron</code> job to reset the local clock from a reliable server, like
-the <code>ntpdate</code> and <code>rdate</code> commands.
+the <code>ntpdate</code> and <code>rdate</code> commands.
For example:
+</p>
+<div class="example">
+<pre class="example">ntpdc -a ntpserver.somewhere
+</pre></div>
+<hr>
+
-<pre class="example"> ntpdc -a ntpserver.somewhere
-</pre>
- </body></html>
+</body>
+</html>
diff --git a/contrib/ntp/ntpdc/ntpdc.man.in b/contrib/ntp/ntpdc/ntpdc.man.in
index 4b31f2e..8014390 100644
--- a/contrib/ntp/ntpdc/ntpdc.man.in
+++ b/contrib/ntp/ntpdc/ntpdc.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpdc @NTPDC_MS@ "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH ntpdc @NTPDC_MS@ "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-MnaqKS/ag-YnaiJS)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:03 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:53 AM by AutoGen 5.18.5
.\" From the definitions ntpdc-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/ntpdc/ntpdc.mdoc.in b/contrib/ntp/ntpdc/ntpdc.mdoc.in
index 3720f93..73f60c1 100644
--- a/contrib/ntp/ntpdc/ntpdc.mdoc.in
+++ b/contrib/ntp/ntpdc/ntpdc.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPDC @NTPDC_MS@ User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpdc-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:09 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:50 AM by AutoGen 5.18.5
.\" From the definitions ntpdc-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/ntpdc/ntpdc_ops.c b/contrib/ntp/ntpdc/ntpdc_ops.c
index 586ed7f0..3b50916 100644
--- a/contrib/ntp/ntpdc/ntpdc_ops.c
+++ b/contrib/ntp/ntpdc/ntpdc_ops.c
@@ -2713,8 +2713,17 @@ again:
lfptoa(&ts, 6));
(void) fprintf(fp, "stratum: %ld\n",
(u_long)ntohl(cl->fudgeval1));
+ /* [Bug3527] Backward Incompatible: cl->fudgeval2 is
+ * a string, instantiated via memcpy() so there is no
+ * endian issue to correct.
+ */
+#ifdef DISABLE_BUG3527_FIX
(void) fprintf(fp, "reference ID: %s\n",
refid_string(ntohl(cl->fudgeval2), 0));
+#else
+ (void) fprintf(fp, "reference ID: %s\n",
+ refid_string(cl->fudgeval2, 0));
+#endif
(void) fprintf(fp, "fudge flags: 0x%x\n",
cl->flags);
@@ -2920,7 +2929,7 @@ kerninfo(
size_t itemsize;
int res;
unsigned status;
- double tscale = 1e-6;
+ double tscale_usec = 1e-6, tscale_unano = 1e-6;
again:
res = doquery(impl_ver, REQ_GET_KERNEL, 0, 0, 0, (char *)NULL,
@@ -2945,16 +2954,16 @@ again:
*/
#ifdef STA_NANO
if (status & STA_NANO)
- tscale = 1e-9;
+ tscale_unano = 1e-9;
#endif
(void)fprintf(fp, "pll offset: %g s\n",
- (int32)ntohl(ik->offset) * tscale);
+ (int32)ntohl(ik->offset) * tscale_unano);
(void)fprintf(fp, "pll frequency: %s ppm\n",
fptoa((s_fp)ntohl(ik->freq), 3));
(void)fprintf(fp, "maximum error: %g s\n",
- (u_long)ntohl(ik->maxerror) * tscale);
+ (u_long)ntohl(ik->maxerror) * tscale_usec);
(void)fprintf(fp, "estimated error: %g s\n",
- (u_long)ntohl(ik->esterror) * tscale);
+ (u_long)ntohl(ik->esterror) * tscale_usec);
(void)fprintf(fp, "status: %04x ", status);
#ifdef STA_PLL
if (status & STA_PLL) (void)fprintf(fp, " pll");
@@ -3008,7 +3017,7 @@ again:
(void)fprintf(fp, "pll time constant: %ld\n",
(u_long)ntohl(ik->constant));
(void)fprintf(fp, "precision: %g s\n",
- (u_long)ntohl(ik->precision) * tscale);
+ (u_long)ntohl(ik->precision) * tscale_usec);
(void)fprintf(fp, "frequency tolerance: %s ppm\n",
fptoa((s_fp)ntohl(ik->tolerance), 0));
@@ -3027,7 +3036,7 @@ again:
(void)fprintf(fp, "pps stability: %s ppm\n",
fptoa((s_fp)ntohl(ik->stabil), 3));
(void)fprintf(fp, "pps jitter: %g s\n",
- (u_long)ntohl(ik->jitter) * tscale);
+ (u_long)ntohl(ik->jitter) * tscale_unano);
(void)fprintf(fp, "calibration interval: %d s\n",
1 << ntohs(ik->shift));
(void)fprintf(fp, "calibration cycles: %ld\n",
diff --git a/contrib/ntp/ntpq/Makefile.in b/contrib/ntp/ntpq/Makefile.in
index b208853..58d66dd 100644
--- a/contrib/ntp/ntpq/Makefile.in
+++ b/contrib/ntp/ntpq/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/ntpq/invoke-ntpq.texi b/contrib/ntp/ntpq/invoke-ntpq.texi
index 69f2088..bba6be6 100644
--- a/contrib/ntp/ntpq/invoke-ntpq.texi
+++ b/contrib/ntp/ntpq/invoke-ntpq.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntpq.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 05:15:26 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:01 AM by AutoGen 5.18.5
# From the definitions ntpq-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -944,7 +944,7 @@ with a status code of 0.
@exampleindent 0
@example
-ntpq - standard NTP query program - Ver. 4.2.8p11
+ntpq - standard NTP query program - Ver. 4.2.8p13
Usage: ntpq [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... [ host ...]
Flg Arg Option-Name Description
-4 no ipv4 Force IPv4 name resolution
diff --git a/contrib/ntp/ntpq/ntpq-opts.c b/contrib/ntp/ntpq/ntpq-opts.c
index 602d40f..987b6f6 100644
--- a/contrib/ntp/ntpq/ntpq-opts.c
+++ b/contrib/ntp/ntpq/ntpq-opts.c
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntpq-opts.c)
*
- * It has been AutoGen-ed February 27, 2018 at 05:15:12 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:56:54 AM by AutoGen 5.18.5
* From the definitions ntpq-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This source file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -69,7 +69,7 @@ extern FILE * option_usage_fp;
* static const strings for ntpq options
*/
static char const ntpq_opt_strs[1977] =
-/* 0 */ "ntpq 4.2.8p11\n"
+/* 0 */ "ntpq 4.2.8p13\n"
"Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n"
"This is free software. It is licensed for use, modification and\n"
"redistribution under the terms of the NTP License, copies of which\n"
@@ -132,13 +132,13 @@ static char const ntpq_opt_strs[1977] =
/* 1768 */ "no-load-opts\0"
/* 1781 */ "no\0"
/* 1784 */ "NTPQ\0"
-/* 1789 */ "ntpq - standard NTP query program - Ver. 4.2.8p11\n"
+/* 1789 */ "ntpq - standard NTP query program - Ver. 4.2.8p13\n"
"Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... [ host ...]\n\0"
/* 1909 */ "$HOME\0"
/* 1915 */ ".\0"
/* 1917 */ ".ntprc\0"
/* 1924 */ "http://bugs.ntp.org, bugs@ntp.org\0"
-/* 1958 */ "ntpq 4.2.8p11\0"
+/* 1958 */ "ntpq 4.2.8p13\0"
/* 1972 */ "hash";
/**
@@ -841,7 +841,7 @@ static void bogus_function(void) {
translate option names.
*/
/* referenced via ntpqOptions.pzCopyright */
- puts(_("ntpq 4.2.8p11\n\
+ puts(_("ntpq 4.2.8p13\n\
Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n\
This is free software. It is licensed for use, modification and\n\
redistribution under the terms of the NTP License, copies of which\n\
@@ -910,11 +910,11 @@ implied warranty.\n"));
puts(_("load options from a config file"));
/* referenced via ntpqOptions.pzUsageTitle */
- puts(_("ntpq - standard NTP query program - Ver. 4.2.8p11\n\
+ puts(_("ntpq - standard NTP query program - Ver. 4.2.8p13\n\
Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... [ host ...]\n"));
/* referenced via ntpqOptions.pzFullVersion */
- puts(_("ntpq 4.2.8p11"));
+ puts(_("ntpq 4.2.8p13"));
/* referenced via ntpqOptions.pzFullUsage */
puts(_("<<<NOT-FOUND>>>"));
diff --git a/contrib/ntp/ntpq/ntpq-opts.h b/contrib/ntp/ntpq/ntpq-opts.h
index ce90e50..5564ee3 100644
--- a/contrib/ntp/ntpq/ntpq-opts.h
+++ b/contrib/ntp/ntpq/ntpq-opts.h
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntpq-opts.h)
*
- * It has been AutoGen-ed February 27, 2018 at 05:15:12 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:56:54 AM by AutoGen 5.18.5
* From the definitions ntpq-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This header file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -53,7 +53,7 @@
* tolerable version is at least as old as what was current when the header
* template was released.
*/
-#define AO_TEMPLATE_VERSION 167936
+#define AO_TEMPLATE_VERSION 167937
#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
|| (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
# error option template version mismatches autoopts/options.h header
@@ -84,9 +84,9 @@ typedef enum {
/** count of all options for ntpq */
#define OPTION_CT 16
/** ntpq version */
-#define NTPQ_VERSION "4.2.8p11"
+#define NTPQ_VERSION "4.2.8p13"
/** Full ntpq version text */
-#define NTPQ_FULL_VERSION "ntpq 4.2.8p11"
+#define NTPQ_FULL_VERSION "ntpq 4.2.8p13"
/**
* Interface defines for all options. Replace "n" with the UPPER_CASED
diff --git a/contrib/ntp/ntpq/ntpq-subs.c b/contrib/ntp/ntpq/ntpq-subs.c
index acc175d1..8495e20 100644
--- a/contrib/ntp/ntpq/ntpq-subs.c
+++ b/contrib/ntp/ntpq/ntpq-subs.c
@@ -446,6 +446,7 @@ doaddvlist(
len = strlen(vars);
while (nextvar(&len, &vars, &name, &value)) {
+ INSIST(name && value);
vl = findlistvar(vlist, name);
if (NULL == vl) {
fprintf(stderr, "Variable list full\n");
@@ -481,6 +482,7 @@ dormvlist(
len = strlen(vars);
while (nextvar(&len, &vars, &name, &value)) {
+ INSIST(name && value);
vl = findlistvar(vlist, name);
if (vl == 0 || vl->name == 0) {
(void) fprintf(stderr, "Variable `%s' not found\n",
@@ -1153,7 +1155,7 @@ printassoc(
* Output a header
*/
(void) fprintf(fp,
- "\nind assid status conf reach auth condition last_event cnt\n");
+ "ind assid status conf reach auth condition last_event cnt\n");
(void) fprintf(fp,
"===========================================================\n");
for (i = 0; i < numassoc; i++) {
@@ -1475,31 +1477,36 @@ prettyinterval(
}
if (diff <= 2048) {
- snprintf(buf, cb, "%ld", diff);
+ snprintf(buf, cb, "%u", (unsigned int)diff);
return buf;
}
diff = (diff + 29) / 60;
if (diff <= 300) {
- snprintf(buf, cb, "%ldm", diff);
+ snprintf(buf, cb, "%um", (unsigned int)diff);
return buf;
}
diff = (diff + 29) / 60;
if (diff <= 96) {
- snprintf(buf, cb, "%ldh", diff);
+ snprintf(buf, cb, "%uh", (unsigned int)diff);
return buf;
}
diff = (diff + 11) / 24;
if (diff <= 999) {
- snprintf(buf, cb, "%ldd", diff);
+ snprintf(buf, cb, "%ud", (unsigned int)diff);
return buf;
}
/* years are only approximated... */
diff = (long)floor(diff / 365.25 + 0.5);
- snprintf(buf, cb, "%ldy", diff);
+ if (diff <= 999) {
+ snprintf(buf, cb, "%uy", (unsigned int)diff);
+ return buf;
+ }
+ /* Ok, this amounts to infinity... */
+ strlcpy(buf, "INF", cb);
return buf;
}
@@ -1638,10 +1645,14 @@ doprintpeers(
l_fp rec;
l_fp ts;
u_long poll_sec;
+ u_long flash = 0;
char type = '?';
- char whenbuf[8], pollbuf[8];
char clock_name[LENHOSTNAME];
-
+ char whenbuf[12], pollbuf[12];
+ /* [Bug 3482] formally whenbuf & pollbuf should be able to hold
+ * a full signed int. Not that we would use that much string
+ * data for it...
+ */
get_systime(&ts);
have_srchost = FALSE;
@@ -1657,6 +1668,7 @@ doprintpeers(
ZERO(estdisp);
while (nextvar(&datalen, &data, &name, &value)) {
+ INSIST(name && value);
if (!strcmp("srcadr", name) ||
!strcmp("peeradr", name)) {
if (!decodenetnum(value, &srcadr))
@@ -1771,6 +1783,8 @@ doprintpeers(
} else if (!strcmp("reftime", name)) {
if (!decodets(value, &reftime))
L_CLR(&reftime);
+ } else if (!strcmp("flash", name)) {
+ decodeuint(value, &flash);
} else {
// fprintf(stderr, "UNRECOGNIZED name=%s ", name);
}
@@ -1850,7 +1864,9 @@ doprintpeers(
+ 1 + 15 + 1, "");
else
fprintf(fp, "%c%-15.15s ", c, clock_name);
- if (!have_da_rid) {
+ if ((flash & TEST12) && (pvl != opeervarlist)) {
+ drlen = fprintf(fp, "(loop)");
+ } else if (!have_da_rid) {
drlen = 0;
} else {
drlen = strlen(dstadr_refid);
@@ -2381,7 +2397,7 @@ fetch_nonce(
return FALSE;
}
chars = rsize - (sizeof(nonce_eq) - 1);
- if (chars >= (int)cb_nonce)
+ if (chars >= cb_nonce)
return FALSE;
memcpy(nonce, rdata + sizeof(nonce_eq) - 1, chars);
nonce[chars] = '\0';
@@ -2647,6 +2663,7 @@ collect_mru_list(
have_addr_older = FALSE;
have_last_older = FALSE;
while (!qres && nextvar(&rsize, &rdata, &tag, &val)) {
+ INSIST(tag && val);
if (debug > 1)
fprintf(stderr, "nextvar gave: %s = %s\n",
tag, val);
@@ -3391,11 +3408,9 @@ ifstats(
fields = 0;
ui = 0;
while (nextvar(&dsize, &datap, &tag, &val)) {
+ INSIST(tag && val);
if (debug > 1)
- fprintf(stderr, "nextvar gave: %s = %s\n", tag,
- (NULL == val)
- ? ""
- : val);
+ fprintf(stderr, "nextvar gave: %s = %s\n", tag, val);
comprende = FALSE;
switch(tag[0]) {
@@ -3407,7 +3422,7 @@ ifstats(
case 'b':
if (1 == sscanf(tag, bcast_fmt, &ui) &&
- (NULL == val ||
+ ('\0' == *val ||
decodenetnum(val, &row.bcast)))
comprende = TRUE;
break;
@@ -3433,7 +3448,6 @@ ifstats(
case 'n':
if (1 == sscanf(tag, name_fmt, &ui)) {
/* strip quotes */
- INSIST(val);
len = strlen(val);
if (len >= 2 &&
len - 2 < sizeof(row.name)) {
@@ -3607,11 +3621,9 @@ reslist(
fields = 0;
ui = 0;
while (nextvar(&dsize, &datap, &tag, &val)) {
+ INSIST(tag && val);
if (debug > 1)
- fprintf(stderr, "nextvar gave: %s = %s\n", tag,
- (NULL == val)
- ? ""
- : val);
+ fprintf(stderr, "nextvar gave: %s = %s\n", tag, val);
comprende = FALSE;
switch(tag[0]) {
@@ -3718,8 +3730,7 @@ collect_display_vdc(
* the retrieved values.
*/
while (nextvar(&rsize, &rdata, &tag, &val)) {
- if (NULL == val)
- continue;
+ INSIST(tag && val);
n = 0;
for (pvdc = table; pvdc->tag != NULL; pvdc++) {
len = strlen(pvdc->tag);
@@ -3944,9 +3955,9 @@ monstats(
)
{
static vdc monstats_vdc[] = {
- VDC_INIT("mru_enabled", "enabled: ", NTP_STR),
+ VDC_INIT("mru_enabled", "enabled: ", NTP_STR),
VDC_INIT("mru_depth", "addresses: ", NTP_STR),
- VDC_INIT("mru_deepest", "peak addresses: ", NTP_STR),
+ VDC_INIT("mru_deepest", "peak addresses: ", NTP_STR),
VDC_INIT("mru_maxdepth", "maximum addresses: ", NTP_STR),
VDC_INIT("mru_mindepth", "reclaim above count:", NTP_STR),
VDC_INIT("mru_maxage", "reclaim older than: ", NTP_STR),
diff --git a/contrib/ntp/ntpq/ntpq.1ntpqman b/contrib/ntp/ntpq/ntpq.1ntpqman
index 2ef8a32..ce2af8c 100644
--- a/contrib/ntp/ntpq/ntpq.1ntpqman
+++ b/contrib/ntp/ntpq/ntpq.1ntpqman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpq 1ntpqman "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH ntpq 1ntpqman "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-D4aGRT/ag-Q4ayQT)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:22 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:02 AM by AutoGen 5.18.5
.\" From the definitions ntpq-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/ntpq/ntpq.1ntpqmdoc b/contrib/ntp/ntpq/ntpq.1ntpqmdoc
index 1d801e9..9589e22 100644
--- a/contrib/ntp/ntpq/ntpq.1ntpqmdoc
+++ b/contrib/ntp/ntpq/ntpq.1ntpqmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPQ 1ntpqmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpq-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:28 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:59 AM by AutoGen 5.18.5
.\" From the definitions ntpq-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/ntpq/ntpq.c b/contrib/ntp/ntpq/ntpq.c
index 17c2f17..6e7a5c37 100644
--- a/contrib/ntp/ntpq/ntpq.c
+++ b/contrib/ntp/ntpq/ntpq.c
@@ -32,18 +32,20 @@
#include "ntp_lineedit.h"
#include "ntp_debug.h"
#ifdef OPENSSL
-#include "openssl/evp.h"
-#include "openssl/objects.h"
-#include "openssl/err.h"
-#ifdef SYS_WINNT
-# include "openssl/opensslv.h"
-# if !defined(HAVE_EVP_MD_DO_ALL_SORTED) && OPENSSL_VERSION_NUMBER > 0x10000000L
-# define HAVE_EVP_MD_DO_ALL_SORTED 1
+# include "openssl/evp.h"
+# include "openssl/objects.h"
+# include "openssl/err.h"
+# ifdef SYS_WINNT
+# include "openssl/opensslv.h"
+# if !defined(HAVE_EVP_MD_DO_ALL_SORTED) && OPENSSL_VERSION_NUMBER > 0x10000000L
+# define HAVE_EVP_MD_DO_ALL_SORTED 1
+# endif
+# endif
+# include "libssl_compat.h"
+# ifdef HAVE_OPENSSL_CMAC_H
+# include <openssl/cmac.h>
+# define CMAC "AES128CMAC"
# endif
-#endif
-#include "libssl_compat.h"
-
-#define CMAC "AES128CMAC"
#endif
#include <ssl_applink.c>
@@ -111,10 +113,6 @@ int rawmode = 0;
*/
u_char pktversion = NTP_OLDVERSION + 1;
-/*
- * Don't jump if no set jmp.
- */
-volatile int jump = 0;
/*
* Format values
@@ -218,10 +216,8 @@ static void raw (struct parse *, FILE *);
static void cooked (struct parse *, FILE *);
static void authenticate (struct parse *, FILE *);
static void ntpversion (struct parse *, FILE *);
-static void warning (const char *, ...)
- __attribute__((__format__(__printf__, 1, 2)));
-static void error (const char *, ...)
- __attribute__((__format__(__printf__, 1, 2)));
+static void warning (const char *, ...) NTP_PRINTF(1, 2);
+static void error (const char *, ...) NTP_PRINTF(1, 2);
static u_long getkeyid (const char *);
static void atoascii (const char *, size_t, char *, size_t);
static void cookedprint (int, size_t, const char *, int, int, FILE *);
@@ -231,10 +227,20 @@ static void output (FILE *, const char *, const char *);
static void endoutput (FILE *);
static void outputarr (FILE *, char *, int, l_fp *);
static int assoccmp (const void *, const void *);
-static void on_ctrlc (void);
u_short varfmt (const char *);
+ void ntpq_custom_opt_handler(tOptions *, tOptDesc *);
+
+#ifndef BUILD_AS_LIB
+static char *list_digest_names(void);
+static char *insert_cmac (char *list);
+static void on_ctrlc (void);
static int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3);
-void ntpq_custom_opt_handler (tOptions *, tOptDesc *);
+# if defined(OPENSSL) && defined(HAVE_EVP_MD_DO_ALL_SORTED)
+static void list_md_fn (const EVP_MD *m, const char *from,
+ const char *to, void *arg);
+# endif /* defined(OPENSSL) && defined(HAVE_EVP_MD_DO_ALL_SORTED) */
+#endif /* !defined(BUILD_AS_LIB) */
+
/* read a character from memory and expand to integer */
static inline int
@@ -246,14 +252,6 @@ pgetc(
}
-#ifdef OPENSSL
-# ifdef HAVE_EVP_MD_DO_ALL_SORTED
-static void list_md_fn(const EVP_MD *m, const char *from,
- const char *to, void *arg );
-# endif
-#endif
-static char *insert_cmac(char *list);
-static char *list_digest_names(void);
/*
* Built-in commands we understand
@@ -422,14 +420,34 @@ chost chosts[MAXHOSTS];
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
/*
- * Jump buffer for longjumping back to the command level
+ * Jump buffer for longjumping back to the command level.
+ *
+ * Since we do this from a signal handler, we use 'sig{set,long}jmp()'
+ * if available. The signal is blocked by default during the excution of
+ * a signal handler, and it is unspecified if '{set,long}jmp()' save and
+ * restore the signal mask. They do on BSD, it depends on the GLIBC
+ * version on Linux, and the gods know what happens on other OSes...
+ *
+ * So we use the 'sig{set,long}jmp()' functions where available, because
+ * for them the semantics are well-defined. If we have to fall back to
+ * '{set,long}jmp()', the CTRL-C handling might be a bit erratic.
*/
-jmp_buf interrupt_buf;
+#if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP
+# define JMP_BUF sigjmp_buf
+# define SETJMP(x) sigsetjmp((x), 1)
+# define LONGJMP(x, v) siglongjmp((x),(v))
+#else
+# define JMP_BUF jmp_buf
+# define SETJMP(x) setjmp((x))
+# define LONGJMP(x, v) longjmp((x),(v))
+#endif
+static JMP_BUF interrupt_buf;
+static volatile int jump = 0;
/*
* Points at file being currently printed into
*/
-FILE *current_output;
+FILE *current_output = NULL;
/*
* Command table imported from ntpdc_ops.c
@@ -608,10 +626,10 @@ ntpqmain(
} else {
for (ihost = 0; ihost < numhosts; ihost++) {
if (openhost(chosts[ihost].name, chosts[ihost].fam)) {
- if (ihost)
+ if (ihost && current_output)
fputc('\n', current_output);
for (icmd = 0; icmd < numcmds; icmd++) {
- if (icmd)
+ if (icmd && current_output)
fputc('\n', current_output);
docmd(ccmds[icmd]);
}
@@ -636,29 +654,26 @@ openhost(
{
const char svc[] = "ntp";
char temphost[LENHOSTNAME];
- int a_info, i;
+ int a_info;
struct addrinfo hints, *ai;
sockaddr_u addr;
size_t octets;
- register const char *cp;
+ const char *cp;
char name[LENHOSTNAME];
/*
* We need to get by the [] if they were entered
*/
-
- cp = hname;
-
- if (*cp == '[') {
- cp++;
- for (i = 0; *cp && *cp != ']'; cp++, i++)
- name[i] = *cp;
- if (*cp == ']') {
- name[i] = '\0';
- hname = name;
- } else {
+ if (*hname == '[') {
+ cp = strchr(hname + 1, ']');
+ if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) {
+ errno = EINVAL;
+ warning("%s", "bad hostname/address");
return 0;
}
+ memcpy(name, hname + 1, octets);
+ name[octets] = '\0';
+ hname = name;
}
/*
@@ -1568,7 +1583,7 @@ abortcmd(void)
(void) fflush(stderr);
if (jump) {
jump = 0;
- longjmp(interrupt_buf, 1);
+ LONGJMP(interrupt_buf, 1);
}
return TRUE;
}
@@ -1656,23 +1671,29 @@ docmd(
perror("");
return;
}
- i = 1; /* flag we need a close */
} else {
current_output = stdout;
- i = 0; /* flag no close */
}
- if (interactive && setjmp(interrupt_buf)) {
- jump = 0;
- return;
+ if (interactive) {
+ if ( ! SETJMP(interrupt_buf)) {
+ jump = 1;
+ (xcmd->handler)(&pcmd, current_output);
+ jump = 0;
+ } else {
+ fflush(current_output);
+ fputs("\n >>> command aborted <<<\n", stderr);
+ fflush(stderr);
+ }
+
} else {
- jump++;
+ jump = 0;
(xcmd->handler)(&pcmd, current_output);
- jump = 0; /* HMS: 961106: was after fclose() */
- if (i) (void) fclose(current_output);
}
-
- return;
+ if ((NULL != current_output) && (stdout != current_output)) {
+ (void)fclose(current_output);
+ current_output = NULL;
+ }
}
@@ -2504,7 +2525,7 @@ ntp_poll(
/*
* showdrefid2str - return a string explanation of the value of drefid
*/
-static char *
+static const char *
showdrefid2str(void)
{
switch (drefid) {
@@ -3055,10 +3076,146 @@ trunc_left(
char circ_buf[NUMCB][CBLEN];
int nextcb = 0;
+/* --------------------------------------------------------------------
+ * Parsing a response value list
+ *
+ * This sounds simple (and it actually is not really hard) but it has
+ * some pitfalls.
+ *
+ * Rule1: CR/LF is never embedded in an item
+ * Rule2: An item is a name, optionally followed by a value
+ * Rule3: The value is separated from the name by a '='
+ * Rule4: Items are separated by a ','
+ * Rule5: values can be quoted by '"', in which case they can contain
+ * arbitrary characters but *not* '"', CR and LF
+ *
+ * There are a few implementations out there that require a somewhat
+ * relaxed attitude when parsing a value list, especially since we want
+ * to copy names and values into local buffers. If these would overflow,
+ * the item should be skipped without terminating the parsing sequence.
+ *
+ * Also, for empty values, there might be a '=' after the name or not;
+ * we treat that equivalent.
+ *
+ * Parsing an item definitely breaks on a CR/LF. If an item is not
+ * followed by a comma (','), parsing stops. In the middle of a quoted
+ * character sequence CR/LF terminates the parsing finally without
+ * returning a value.
+ *
+ * White space and other noise is ignored when parsing the data buffer;
+ * only CR, LF, ',', '=' and '"' are characters with a special meaning.
+ * White space is stripped from the names and values *after* working
+ * through the buffer, before making the local copies. If whitespace
+ * stripping results in an empty name, parsing resumes.
+ */
+
+/*
+ * nextvar parsing helpers
+ */
+
+/* predicate: allowed chars inside a quoted string */
+static int/*BOOL*/ cp_qschar(int ch)
+{
+ return ch && (ch != '"' && ch != '\r' && ch != '\n');
+}
+
+/* predicate: allowed chars inside an unquoted string */
+static int/*BOOL*/ cp_uqchar(int ch)
+{
+ return ch && (ch != ',' && ch != '"' && ch != '\r' && ch != '\n');
+}
+
+/* predicate: allowed chars inside a value name */
+static int/*BOOL*/ cp_namechar(int ch)
+{
+ return ch && (ch != ',' && ch != '=' && ch != '\r' && ch != '\n');
+}
+
+/* predicate: characters *between* list items. We're relaxed here. */
+static int/*BOOL*/ cp_ivspace(int ch)
+{
+ return (ch == ',' || (ch > 0 && ch <= ' '));
+}
+
+/* get current character (or NUL when on end) */
+static inline int
+pf_getch(
+ const char ** datap,
+ const char * endp
+ )
+{
+ return (*datap != endp)
+ ? *(const unsigned char*)*datap
+ : '\0';
+}
+
+/* get next character (or NUL when on end) */
+static inline int
+pf_nextch(
+ const char ** datap,
+ const char * endp
+ )
+{
+ return (*datap != endp && ++(*datap) != endp)
+ ? *(const unsigned char*)*datap
+ : '\0';
+}
+
+static size_t
+str_strip(
+ const char ** datap,
+ size_t len
+ )
+{
+ static const char empty[] = "";
+
+ if (*datap && len) {
+ const char * cpl = *datap;
+ const char * cpr = cpl + len;
+
+ while (cpl != cpr && *(const unsigned char*)cpl <= ' ')
+ ++cpl;
+ while (cpl != cpr && *(const unsigned char*)(cpr - 1) <= ' ')
+ --cpr;
+ *datap = cpl;
+ len = (size_t)(cpr - cpl);
+ } else {
+ *datap = empty;
+ len = 0;
+ }
+ return len;
+}
+
+static void
+pf_error(
+ const char * what,
+ const char * where,
+ const char * whend
+ )
+{
+# ifndef BUILD_AS_LIB
+
+ FILE * ofp = (debug > 0) ? stdout : stderr;
+ size_t len = (size_t)(whend - where);
+
+ if (len > 50) /* *must* fit into an 'int'! */
+ len = 50;
+ fprintf(ofp, "nextvar: %s: '%.*s'\n",
+ what, (int)len, where);
+
+# else /*defined(BUILD_AS_LIB)*/
+
+ UNUSED_ARG(what);
+ UNUSED_ARG(where);
+ UNUSED_ARG(whend);
+
+# endif /*defined(BUILD_AS_LIB)*/
+}
+
/*
* nextvar - find the next variable in the buffer
*/
-int
+int/*BOOL*/
nextvar(
size_t *datalen,
const char **datap,
@@ -3066,92 +3223,124 @@ nextvar(
char **vvalue
)
{
- const char *cp;
- const char *np;
- const char *cpend;
- size_t srclen;
- size_t len;
- static char name[MAXVARLEN];
- static char value[MAXVALLEN];
-
- cp = *datap;
- cpend = cp + *datalen;
-
- /*
- * Space past commas and white space
- */
- while (cp < cpend && (*cp == ',' || isspace(pgetc(cp))))
- cp++;
- if (cp >= cpend)
- return 0;
+ enum PState { sDone, sInit, sName, sValU, sValQ };
+
+ static char name[MAXVARLEN], value[MAXVALLEN];
- /*
- * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
- * over any white space and terminate it.
- */
- srclen = strcspn(cp, ",=\r\n");
- srclen = min(srclen, (size_t)(cpend - cp));
- len = srclen;
- while (len > 0 && isspace(pgetc(&cp[len - 1])))
- len--;
- if (len >= sizeof(name))
- return 0;
- if (len > 0)
- memcpy(name, cp, len);
- name[len] = '\0';
- *vname = name;
- cp += srclen;
+ const char *cp, *cpend;
+ const char *np, *vp;
+ size_t nlen, vlen;
+ int ch;
+ enum PState st;
+
+ cpend = *datap + *datalen;
- /*
- * Check if we hit the end of the buffer or a ','. If so we are done.
- */
- if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
- if (cp < cpend)
- cp++;
- *datap = cp;
- *datalen = size2int_sat(cpend - cp);
- *vvalue = NULL;
- return 1;
+ again:
+ np = vp = NULL;
+ nlen = vlen = 0;
+
+ st = sInit;
+ ch = pf_getch(datap, cpend);
+
+ while (st != sDone) {
+ switch (st)
+ {
+ case sInit: /* handle inter-item chars */
+ while (cp_ivspace(ch))
+ ch = pf_nextch(datap, cpend);
+ if (cp_namechar(ch)) {
+ np = *datap;
+ cp = np;
+ st = sName;
+ ch = pf_nextch(datap, cpend);
+ } else {
+ goto final_done;
+ }
+ break;
+
+ case sName: /* collect name */
+ while (cp_namechar(ch))
+ ch = pf_nextch(datap, cpend);
+ nlen = (size_t)(*datap - np);
+ if (ch == '=') {
+ ch = pf_nextch(datap, cpend);
+ vp = *datap;
+ st = sValU;
+ } else {
+ if (ch != ',')
+ *datap = cpend;
+ st = sDone;
+ }
+ break;
+
+ case sValU: /* collect unquoted part(s) of value */
+ while (cp_uqchar(ch))
+ ch = pf_nextch(datap, cpend);
+ if (ch == '"') {
+ ch = pf_nextch(datap, cpend);
+ st = sValQ;
+ } else {
+ vlen = (size_t)(*datap - vp);
+ if (ch != ',')
+ *datap = cpend;
+ st = sDone;
+ }
+ break;
+
+ case sValQ: /* collect quoted part(s) of value */
+ while (cp_qschar(ch))
+ ch = pf_nextch(datap, cpend);
+ if (ch == '"') {
+ ch = pf_nextch(datap, cpend);
+ st = sValU;
+ } else {
+ pf_error("no closing quote, stop", cp, cpend);
+ goto final_done;
+ }
+ break;
+
+ default:
+ pf_error("state machine error, stop", *datap, cpend);
+ goto final_done;
+ }
}
- /*
- * So far, so good. Copy out the value
+ /* If name or value do not fit their buffer, croak and start
+ * over. If there's no name at all after whitespace stripping,
+ * redo silently.
*/
- cp++; /* past '=' */
- while (cp < cpend && (isspace(pgetc(cp)) && *cp != '\r' && *cp != '\n'))
- cp++;
- np = cp;
- if ('"' == *np) {
- do {
- np++;
- } while (np < cpend && '"' != *np);
- if (np < cpend && '"' == *np)
- np++;
- } else {
- while (np < cpend && ',' != *np && '\r' != *np)
- np++;
+ nlen = str_strip(&np, nlen);
+ vlen = str_strip(&vp, vlen);
+
+ if (nlen == 0) {
+ goto again;
+ }
+ if (nlen >= sizeof(name)) {
+ pf_error("runaway name", np, cpend);
+ goto again;
+ }
+ if (vlen >= sizeof(value)) {
+ pf_error("runaway value", vp, cpend);
+ goto again;
}
- len = np - cp;
- if (np > cpend || len >= sizeof(value) ||
- (np < cpend && ',' != *np && '\r' != *np))
- return 0;
- memcpy(value, cp, len);
- /*
- * Trim off any trailing whitespace
- */
- while (len > 0 && isspace(pgetc(&value[len - 1])))
- len--;
- value[len] = '\0';
- /*
- * Return this. All done.
- */
- if (np < cpend && ',' == *np)
- np++;
- *datap = np;
- *datalen = size2int_sat(cpend - np);
+ /* copy name and value into NUL-terminated buffers */
+ memcpy(name, np, nlen);
+ name[nlen] = '\0';
+ *vname = name;
+
+ memcpy(value, vp, vlen);
+ value[vlen] = '\0';
*vvalue = value;
- return 1;
+
+ /* check if there's more to do or if we are finshed */
+ *datalen = (size_t)(cpend - *datap);
+ return TRUE;
+
+ final_done:
+ *datap = cpend;
+ *datalen = 0;
+ return FALSE;
}
@@ -3318,11 +3507,11 @@ outputarr(
* Hack to align delay and offset values
*/
for (i = (int)strlen(name); i < 11; i++)
- *bp++ = ' ';
+ *bp++ = ' ';
for (i = narr; i > 0; i--) {
- if (i != narr)
- *bp++ = ' ';
+ if (i != (size_t)narr)
+ *bp++ = ' ';
cp = lfptoms(lfp, 2);
len = strlen(cp);
if (len > 7) {
@@ -3346,44 +3535,61 @@ tstflags(
u_long val
)
{
- register char *cp, *s;
- size_t cb;
- register int i;
- register const char *sep;
+# if CBLEN < 10
+# error BLEN is too small -- increase!
+# endif
+
+ char *cp, *s;
+ size_t cb, i;
+ int l;
- sep = "";
s = cp = circ_buf[nextcb];
if (++nextcb >= NUMCB)
nextcb = 0;
cb = sizeof(circ_buf[0]);
- snprintf(cp, cb, "%02lx", val);
- cp += strlen(cp);
- cb -= strlen(cp);
+ l = snprintf(cp, cb, "%02lx", val);
+ if (l < 0 || (size_t)l >= cb)
+ goto fail;
+ cp += l;
+ cb -= l;
if (!val) {
- strlcat(cp, " ok", cb);
- cp += strlen(cp);
- cb -= strlen(cp);
+ l = strlcat(cp, " ok", cb);
+ if ((size_t)l >= cb)
+ goto fail;
+ cp += l;
+ cb -= l;
} else {
- if (cb) {
- *cp++ = ' ';
- cb--;
- }
- for (i = 0; i < (int)COUNTOF(tstflagnames); i++) {
+ const char *sep;
+
+ sep = " ";
+ for (i = 0; i < COUNTOF(tstflagnames); i++) {
if (val & 0x1) {
- snprintf(cp, cb, "%s%s", sep,
- tstflagnames[i]);
+ l = snprintf(cp, cb, "%s%s", sep,
+ tstflagnames[i]);
+ if (l < 0)
+ goto fail;
+ if ((size_t)l >= cb) {
+ cp += cb - 4;
+ cb = 4;
+ l = strlcpy (cp, "...", cb);
+ cp += l;
+ cb -= l;
+ break;
+ }
sep = ", ";
- cp += strlen(cp);
- cb -= strlen(cp);
+ cp += l;
+ cb -= l;
}
val >>= 1;
}
}
- if (cb)
- *cp = '\0';
return s;
+
+ fail:
+ *cp = '\0';
+ return s;
}
/*
@@ -3630,220 +3836,218 @@ ntpq_custom_opt_handler(
# define K_DELIM_STR ", "
struct hstate {
- char *list;
- const char **seen;
- int idx;
+ char *list;
+ const char **seen;
+ int idx;
};
+# ifndef BUILD_AS_LIB
static void
list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg)
{
- size_t len, n, digest_len;
- const char *name, **seen;
- struct hstate *hstate = arg;
- char *cp;
-
- /* m is MD obj, from is name or alias, to is base name for alias */
- if (!m || !from || to) {
- return; /* Ignore aliases */
- }
-
- /* Discard MACs that NTP won't accept. */
- /* Keep this consistent with keytype_from_text() in ssl_init.c. */
- if (EVP_MD_size(m) > (MAX_MAC_LEN - sizeof(keyid_t))) {
- return;
- }
-
- name = EVP_MD_name(m);
+ size_t len, n;
+ const char *name, **seen;
+ struct hstate *hstate = arg;
+ const char *cp;
+
+ /* m is MD obj, from is name or alias, to is base name for alias */
+ if (!m || !from || to)
+ return; /* Ignore aliases */
- /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
+ /* Discard MACs that NTP won't accept. */
+ /* Keep this consistent with keytype_from_text() in ssl_init.c. */
+ if (EVP_MD_size(m) > (MAX_MAC_LEN - sizeof(keyid_t)))
+ return;
+
+ name = EVP_MD_name(m);
+
+ /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
+
+ for (cp = name; *cp; cp++)
+ if (islower((unsigned char)*cp))
+ return;
- for (cp = name; *cp; cp++) {
- if (islower((unsigned char)*cp)) {
- return;
- }
- }
+ len = (cp - name) + 1;
+
+ /* There are duplicates. Discard if name has been seen. */
+
+ for (seen = hstate->seen; *seen; seen++)
+ if (!strcmp(*seen, name))
+ return;
- len = (cp - name) + 1;
+ n = (seen - hstate->seen) + 2;
+ hstate->seen = erealloc(hstate->seen, n * sizeof(*seen));
+ hstate->seen[n-2] = name;
+ hstate->seen[n-1] = NULL;
+
+ if (hstate->list != NULL)
+ len += strlen(hstate->list);
- /* There are duplicates. Discard if name has been seen. */
+ len += (hstate->idx >= K_PER_LINE)
+ ? strlen(K_NL_PFX_STR)
+ : strlen(K_DELIM_STR);
- for (seen = hstate->seen; *seen; seen++) {
- if (!strcmp(*seen, name)) {
- return;
+ if (hstate->list == NULL) {
+ hstate->list = (char *)emalloc(len);
+ hstate->list[0] = '\0';
+ } else {
+ hstate->list = (char *)erealloc(hstate->list, len);
}
- }
-
- n = (seen - hstate->seen) + 2;
- hstate->seen = erealloc(hstate->seen, n * sizeof(*seen));
- hstate->seen[n-2] = name;
- hstate->seen[n-1] = NULL;
-
- if (hstate->list != NULL) {
- len += strlen(hstate->list);
- }
-
- len += (hstate->idx >= K_PER_LINE)
- ? strlen(K_NL_PFX_STR)
- : strlen(K_DELIM_STR);
-
- if (hstate->list == NULL) {
- hstate->list = (char *)emalloc(len);
- hstate->list[0] = '\0';
- } else {
- hstate->list = (char *)erealloc(hstate->list, len);
- }
-
- sprintf(hstate->list + strlen(hstate->list), "%s%s",
- ((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR),
- name);
-
- if (hstate->idx >= K_PER_LINE) {
- hstate->idx = 1;
- } else {
- hstate->idx++;
- }
+
+ sprintf(hstate->list + strlen(hstate->list), "%s%s",
+ ((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR),
+ name);
+
+ if (hstate->idx >= K_PER_LINE)
+ hstate->idx = 1;
+ else
+ hstate->idx++;
}
+# endif /* !defined(BUILD_AS_LIB) */
-
+# ifndef BUILD_AS_LIB
/* Insert CMAC into SSL digests list */
static char *
insert_cmac(char *list)
{
- int insert;
- size_t len;
-
-
- /* If list empty, we need to insert CMAC on new line */
- insert = (!list || !*list);
-
- if (insert) {
- len = strlen(K_NL_PFX_STR) + strlen(CMAC);
- list = (char *)erealloc(list, len + 1);
- sprintf(list, "%s%s", K_NL_PFX_STR, CMAC);
- } else { /* List not empty */
- /* Check if CMAC already in list - future proofing */
- const char *cmac_sn;
- char *cmac_p;
-
- cmac_sn = OBJ_nid2sn(NID_cmac);
- cmac_p = list;
- insert = cmac_sn != NULL && *cmac_sn != '\0';
+#ifdef ENABLE_CMAC
+ int insert;
+ size_t len;
- /* CMAC in list if found, followed by nul char or ',' */
- while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) {
- cmac_p += strlen(cmac_sn);
- /* Still need to insert if not nul and not ',' */
- insert = *cmac_p && ',' != *cmac_p;
- }
- /* Find proper insertion point */
+ /* If list empty, we need to insert CMAC on new line */
+ insert = (!list || !*list);
+
if (insert) {
- char *last_nl;
- char *point;
- char *delim;
- int found;
-
- /* Default to start if list empty */
- found = 0;
- delim = list;
- len = strlen(list);
-
- /* While new lines */
- while (delim < list + len && *delim &&
- !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) {
- point = delim + strlen(K_NL_PFX_STR);
-
- /* While digest names on line */
- while (point < list + len && *point) {
- /* Another digest after on same or next line? */
- delim = strstr( point, K_DELIM_STR);
- last_nl = strstr( point, K_NL_PFX_STR);
-
- /* No - end of list */
- if (!delim && !last_nl) {
- delim = list + len;
- } else
- /* New line and no delim or before delim? */
- if (last_nl && (!delim || last_nl < delim)) {
- delim = last_nl;
- }
-
- /* Found insertion point where CMAC before entry? */
- if (strncmp(CMAC, point, delim - point) < 0) {
- found = 1;
- break;
- }
-
- if (delim < list + len && *delim &&
- !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) {
- point += strlen(K_DELIM_STR);
- } else {
- break;
- }
- } /* While digest names on line */
- } /* While new lines */
-
- /* If found in list */
- if (found) {
- /* insert cmac and delim */
- /* Space for list could move - save offset */
- ptrdiff_t p_offset = point - list;
- len += strlen(CMAC) + strlen(K_DELIM_STR);
+ len = strlen(K_NL_PFX_STR) + strlen(CMAC);
list = (char *)erealloc(list, len + 1);
- point = list + p_offset;
- /* move to handle src/dest overlap */
- memmove(point + strlen(CMAC) + strlen(K_DELIM_STR),
+ sprintf(list, "%s%s", K_NL_PFX_STR, CMAC);
+ } else { /* List not empty */
+ /* Check if CMAC already in list - future proofing */
+ const char *cmac_sn;
+ char *cmac_p;
+
+ cmac_sn = OBJ_nid2sn(NID_cmac);
+ cmac_p = list;
+ insert = cmac_sn != NULL && *cmac_sn != '\0';
+
+ /* CMAC in list if found, followed by nul char or ',' */
+ while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) {
+ cmac_p += strlen(cmac_sn);
+ /* Still need to insert if not nul and not ',' */
+ insert = *cmac_p && ',' != *cmac_p;
+ }
+
+ /* Find proper insertion point */
+ if (insert) {
+ char *last_nl;
+ char *point;
+ char *delim;
+ int found;
+
+ /* Default to start if list empty */
+ found = 0;
+ delim = list;
+ len = strlen(list);
+
+ /* While new lines */
+ while (delim < list + len && *delim &&
+ !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) {
+ point = delim + strlen(K_NL_PFX_STR);
+
+ /* While digest names on line */
+ while (point < list + len && *point) {
+ /* Another digest after on same or next line? */
+ delim = strstr( point, K_DELIM_STR);
+ last_nl = strstr( point, K_NL_PFX_STR);
+
+ /* No - end of list */
+ if (!delim && !last_nl) {
+ delim = list + len;
+ } else
+ /* New line and no delim or before delim? */
+ if (last_nl && (!delim || last_nl < delim)) {
+ delim = last_nl;
+ }
+
+ /* Found insertion point where CMAC before entry? */
+ if (strncmp(CMAC, point, delim - point) < 0) {
+ found = 1;
+ break;
+ }
+
+ if (delim < list + len && *delim &&
+ !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) {
+ point += strlen(K_DELIM_STR);
+ } else {
+ break;
+ }
+ } /* While digest names on line */
+ } /* While new lines */
+
+ /* If found in list */
+ if (found) {
+ /* insert cmac and delim */
+ /* Space for list could move - save offset */
+ ptrdiff_t p_offset = point - list;
+ len += strlen(CMAC) + strlen(K_DELIM_STR);
+ list = (char *)erealloc(list, len + 1);
+ point = list + p_offset;
+ /* move to handle src/dest overlap */
+ memmove(point + strlen(CMAC) + strlen(K_DELIM_STR),
point, strlen(point) + 1);
- strncpy(point, CMAC, strlen(CMAC));
- strncpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR));
- } else { /* End of list */
- /* append delim and cmac */
- len += strlen(K_DELIM_STR) + strlen(CMAC);
- list = (char *)erealloc(list, len + 1);
- strcpy(list + strlen(list), K_DELIM_STR);
- strcpy(list + strlen(list), CMAC);
- }
- } /* insert */
- } /* List not empty */
-
- return list;
+ strncpy(point, CMAC, strlen(CMAC));
+ strncpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR));
+ } else { /* End of list */
+ /* append delim and cmac */
+ len += strlen(K_DELIM_STR) + strlen(CMAC);
+ list = (char *)erealloc(list, len + 1);
+ strcpy(list + strlen(list), K_DELIM_STR);
+ strcpy(list + strlen(list), CMAC);
+ }
+ } /* insert */
+ } /* List not empty */
+#endif /*ENABLE_CMAC*/
+ return list;
}
+# endif /* !defined(BUILD_AS_LIB) */
# endif
#endif
+#ifndef BUILD_AS_LIB
static char *
list_digest_names(void)
{
- char *list = NULL;
-
+ char *list = NULL;
+
#ifdef OPENSSL
# ifdef HAVE_EVP_MD_DO_ALL_SORTED
- struct hstate hstate = { NULL, NULL, K_PER_LINE+1 };
-
- /* replace calloc(1, sizeof(const char *)) */
- hstate.seen = (const char **)emalloc_zero(sizeof(const char *));
-
- INIT_SSL();
- EVP_MD_do_all_sorted(list_md_fn, &hstate);
- list = hstate.list;
- free(hstate.seen);
-
- list = insert_cmac(list); /* Insert CMAC into SSL digests list */
-
+ struct hstate hstate = { NULL, NULL, K_PER_LINE+1 };
+
+ /* replace calloc(1, sizeof(const char *)) */
+ hstate.seen = (const char **)emalloc_zero(sizeof(const char *));
+
+ INIT_SSL();
+ EVP_MD_do_all_sorted(list_md_fn, &hstate);
+ list = hstate.list;
+ free(hstate.seen);
+
+ list = insert_cmac(list); /* Insert CMAC into SSL digests list */
+
# else
- list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)"));
- strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)");
+ list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)"));
+ strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)");
# endif
#else
- list = (char *)emalloc(sizeof("md5"));
- strcpy(list, "md5");
+ list = (char *)emalloc(sizeof("md5"));
+ strcpy(list, "md5");
#endif
-
- return list;
+
+ return list;
}
+#endif /* !defined(BUILD_AS_LIB) */
#define CTRLC_STACK_MAX 4
static volatile size_t ctrlc_stack_len = 0;
@@ -3881,6 +4085,7 @@ pop_ctrl_c_handler(
return FALSE;
}
+#ifndef BUILD_AS_LIB
static void
on_ctrlc(void)
{
@@ -3889,7 +4094,9 @@ on_ctrlc(void)
if ((*ctrlc_stack[--size])())
break;
}
+#endif /* !defined(BUILD_AS_LIB) */
+#ifndef BUILD_AS_LIB
static int
my_easprintf(
char ** ppinto,
@@ -3927,3 +4134,4 @@ my_easprintf(
*ppinto = buf;
return prc;
}
+#endif /* !defined(BUILD_AS_LIB) */
diff --git a/contrib/ntp/ntpq/ntpq.html b/contrib/ntp/ntpq/ntpq.html
index 55aafc8..7d465c9 100644
--- a/contrib/ntp/ntpq/ntpq.html
+++ b/contrib/ntp/ntpq/ntpq.html
@@ -1,202 +1,294 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>ntpq: Network Time Protocol Query User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="ntpq: Network Time Protocol Query User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>ntpq: Network Time Protocol Query User&rsquo;s Manual</title>
+
+<meta name="description" content="ntpq: Network Time Protocol Query User&rsquo;s Manual">
+<meta name="keywords" content="ntpq: Network Time Protocol Query User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">ntpq: Network Time Protocol Query User's Manual</h1>
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">ntpq: Network Time Protocol Query User Manual</a>
-</ul>
-</div>
+<body lang="en">
+<h1 class="settitle" align="center">ntpq: Network Time Protocol Query User&rsquo;s Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-Description">ntpq Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
+
+
+
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
+
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Description" href="#toc-Description">1 Description</a></li>
+</ul>
</div>
-<h2 class="unnumbered">ntpq: Network Time Protocol Query User Manual</h2>
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-Description" accesskey="n" rel="next">ntpq Description</a>, Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="ntpq_003a-Network-Time-Protocol-Query-User-Manual"></a>
+<h1 class="top">ntpq: Network Time Protocol Query User Manual</h1>
<p>The <code>ntpq</code> utility program is used to
monitor the operational status
and determine the performance of
<code>ntpd</code>, the NTP daemon.
-
- <p>This document applies to version 4.2.8p11 of <code>ntpq</code>.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntpq-Description">ntpq Description</a>
-<li><a accesskey="2" href="#ntpq-Invocation">ntpq Invocation</a>: Invoking ntpq
-<li><a accesskey="3" href="#Usage">Usage</a>
-<li><a accesskey="4" href="#Internal-Commands">Internal Commands</a>
-<li><a accesskey="5" href="#Control-Message-Commands">Control Message Commands</a>
-<li><a accesskey="6" href="#Status-Words-and-Kiss-Codes">Status Words and Kiss Codes</a>
-<li><a accesskey="7" href="#System-Variables">System Variables</a>
-<li><a accesskey="8" href="#Peer-Variables">Peer Variables</a>
-<li><a accesskey="9" href="#Clock-Variables">Clock Variables</a>
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntpq-Description"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Usage">Usage</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntpq</code>.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-Description" accesskey="1">ntpq Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-Invocation" accesskey="2">ntpq Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking ntpq
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="3">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Internal-Commands" accesskey="4">Internal Commands</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Control-Message-Commands" accesskey="5">Control Message Commands</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Status-Words-and-Kiss-Codes" accesskey="6">Status Words and Kiss Codes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#System-Variables" accesskey="7">System Variables</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Peer-Variables" accesskey="8">Peer Variables</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Clock-Variables" accesskey="9">Clock Variables</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="ntpq-Description"></a>
+<div class="header">
+<p>
+Next: <a href="#Usage" accesskey="n" rel="next">Usage</a>, Previous: <a href="#Top" accesskey="p" rel="prev">Top</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
+<a name="Description"></a>
+<h2 class="chapter">1 Description</h2>
-<!-- node-name, next, previous, up -->
-<h3 class="section">Description</h3>
-
-<p>The <code>ntpq</code> utility program is used to monitor NTP daemon <code>ntpd</code> operations and determine performance.
+<p>The <code>ntpq</code> utility program is used to monitor NTP daemon <code>ntpd</code> operations and determine performance.
It uses the standard NTP mode 6 control message formats defined in
-Appendix B of the NTPv3 specification RFC1305.
-The same formats are used in NTPv4, although some of the variable names have changed and new ones added.
+Appendix B of the NTPv3 specification RFC1305.
+The same formats are used in NTPv4, although some of the variable names have changed and new ones added.
The description on this page is for the NTPv4 variables.
-
- <p>The program can be run either in interactive mode or controlled using command line arguments. Requests to read and write arbitrary variables can be assembled, with raw and pretty-printed output options being available. The <code>ntpq</code> can also obtain and print a list of peers in a common format by sending multiple queries to the server.
-
- <p>If one or more request options is included on the command line when <code>ntpq</code> is executed, each of the requests will be sent to the NTP servers running on each of the hosts given as command line arguments, or on localhost by default. If no request options are given, <code>ntpq</code> will attempt to read commands from the standard input and execute these on the NTP server running on the first host given on the command line, again defaulting to localhost when no other host is specified. <code>ntpq</code> will prompt for commands if the standard input is a terminal device.
-
- <p><code>ntpq</code> uses NTP mode 6 packets to communicate with the NTP server, and hence can be used to query any compatible server on the network which permits it. Note that since NTP is a UDP protocol this communication will be somewhat unreliable, especially over large distances in terms of network topology. <code>ntpq</code> makes one attempt to retransmit requests, and will time requests out if the remote host is not heard from within a suitable timeout time.
-
- <p>Note that in contexts where a host name is expected, a <code>-4</code> qualifier preceding the host name forces DNS resolution to the IPv4 namespace, while a <code>-6</code> qualifier forces DNS resolution to the IPv6 namespace.
-
- <p>For examples and usage, see the <a href="debug.html">NTP Debugging Techniques</a> page.
-
-<div class="node">
-<p><hr>
+</p>
+<p>The program can be run either in interactive mode or controlled using command line arguments. Requests to read and write arbitrary variables can be assembled, with raw and pretty-printed output options being available. The <code>ntpq</code> can also obtain and print a list of peers in a common format by sending multiple queries to the server.
+</p>
+<p>If one or more request options is included on the command line when <code>ntpq</code> is executed, each of the requests will be sent to the NTP servers running on each of the hosts given as command line arguments, or on localhost by default. If no request options are given, <code>ntpq</code> will attempt to read commands from the standard input and execute these on the NTP server running on the first host given on the command line, again defaulting to localhost when no other host is specified. <code>ntpq</code> will prompt for commands if the standard input is a terminal device.
+</p>
+<p><code>ntpq</code> uses NTP mode 6 packets to communicate with the NTP server, and hence can be used to query any compatible server on the network which permits it. Note that since NTP is a UDP protocol this communication will be somewhat unreliable, especially over large distances in terms of network topology. <code>ntpq</code> makes one attempt to retransmit requests, and will time requests out if the remote host is not heard from within a suitable timeout time.
+</p>
+<p>Note that in contexts where a host name is expected, a <code>-4</code> qualifier preceding the host name forces DNS resolution to the IPv4 namespace, while a <code>-6</code> qualifier forces DNS resolution to the IPv6 namespace.
+</p>
+<p>For examples and usage, see the <a href="debug.html">NTP Debugging Techniques</a> page.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-Invocation" accesskey="1">ntpq Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="2">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Internal-Commands" accesskey="3">Internal Commands</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Control-Message-Commands" accesskey="4">Control Message Commands</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Status-Words-and-Kiss-Codes" accesskey="5">Status Words and Kiss Codes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#System-Variables" accesskey="6">System Variables</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Peer-Variables" accesskey="7">Peer Variables</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Clock-Variables" accesskey="8">Clock Variables</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
<a name="ntpq-Invocation"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Usage" accesskey="n" rel="next">Usage</a>, Previous: <a href="#ntpq-Description" accesskey="p" rel="prev">ntpq Description</a>, Up: <a href="#ntpq-Description" accesskey="u" rel="up">ntpq Description</a> &nbsp; </p>
</div>
+<a name="Invoking-ntpq"></a>
+<h3 class="section">1.1 Invoking ntpq</h3>
+<a name="index-ntpq"></a>
+<a name="index-standard-NTP-query-program"></a>
-<h3 class="section">Invoking ntpq</h3>
-
-<p><a name="index-ntpq-1"></a><a name="index-standard-NTP-query-program-2"></a>
- <p>The
+<p>The
<code>ntpq</code>
utility program is used to query NTP servers to monitor NTP operations
and performance, requesting
-information about current state and/or changes in that state.
+information about current state and/or changes in that state.
The program may be run either in interactive mode or controlled using
-command line arguments.
+command line arguments.
Requests to read and write arbitrary
variables can be assembled, with raw and pretty-printed output
-options being available.
+options being available.
The
<code>ntpq</code>
utility can also obtain and print a
list of peers in a common format by sending multiple queries to the
server.
-
- <p>If one or more request options is included on the command line
+</p>
+<p>If one or more request options is included on the command line
when
<code>ntpq</code>
is executed, each of the requests will be sent
to the NTP servers running on each of the hosts given as command
-line arguments, or on localhost by default.
+line arguments, or on localhost by default.
If no request options
are given,
<code>ntpq</code>
will attempt to read commands from the
standard input and execute these on the NTP server running on the
first host given on the command line, again defaulting to localhost
-when no other host is specified.
+when no other host is specified.
The
<code>ntpq</code>
utility will prompt for
commands if the standard input is a terminal device.
-
- <p><code>ntpq</code>
+</p>
+<p><code>ntpq</code>
uses NTP mode 6 packets to communicate with the
NTP server, and hence can be used to query any compatible server on
-the network which permits it.
+the network which permits it.
Note that since NTP is a UDP protocol
this communication will be somewhat unreliable, especially over
-large distances in terms of network topology.
+large distances in terms of network topology.
The
<code>ntpq</code>
utility makes
one attempt to retransmit requests, and will time requests out if
the remote host is not heard from within a suitable timeout
time.
-
- <p>Note that in contexts where a host name is expected, a
+</p>
+<p>Note that in contexts where a host name is expected, a
<code>-4</code>
qualifier preceding the host name forces resolution to the IPv4
namespace, while a
<code>-6</code>
-qualifier forces resolution to the IPv6 namespace.
+qualifier forces resolution to the IPv6 namespace.
For examples and usage, see the
-NTP Debugging Techniques
+&ldquo;NTP Debugging Techniques&rdquo;
page.
-
- <p>Specifying a
+</p>
+<p>Specifying a
command line option other than
<code>-i</code>
or
<code>-n</code>
will
cause the specified query (queries) to be sent to the indicated
-host(s) immediately.
+host(s) immediately.
Otherwise,
<code>ntpq</code>
will attempt to read
interactive format commands from the standard input.
-
-<h5 class="subsubsection">Internal Commands</h5>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-usage" accesskey="1">ntpq usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-ipv4" accesskey="2">ntpq ipv4</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-ipv6" accesskey="3">ntpq ipv6</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-command" accesskey="4">ntpq command</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-interactive" accesskey="5">ntpq interactive</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-numeric" accesskey="6">ntpq numeric</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-old_002drv" accesskey="7">ntpq old-rv</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-peers" accesskey="8">ntpq peers</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-refid" accesskey="9">ntpq refid</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-wide">ntpq wide</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-config">ntpq config</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-exit-status">ntpq exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<a name="Internal-Commands-1"></a>
+<h4 class="subsection">1.1.1 Internal Commands</h4>
<p>Interactive format commands consist of a keyword followed by zero
-to four arguments.
+to four arguments.
Only enough characters of the full keyword to
uniquely identify the command need be typed.
-
- <p>A
+</p>
+<p>A
number of interactive format commands are executed entirely within
the
<code>ntpq</code>
utility itself and do not result in NTP
-requests being sent to a server.
+requests being sent to a server.
These are described following.
- <dl>
-<dt><code>?</code> <code>[</code><kbd>command</kbd><code>]</code><br><dt><code>help</code> <code>[</code><kbd>command</kbd><code>]</code><dd>A
-?
+</p><dl compact="compact">
+<dt><code>?</code> <code>[<kbd>command</kbd>]</code></dt>
+<dt><code>help</code> <code>[<kbd>command</kbd>]</code></dt>
+<dd><p>A
+&lsquo;?&rsquo;
by itself will print a list of all the commands
known to
<code>ntpq</code>
A
-?
+&lsquo;?&rsquo;
followed by a command name will print function and usage
-information about the command.
-<br><dt><code>addvars</code> <kbd>name</kbd><code>[=</code><kbd>value</kbd><code>]</code><code>[,...]</code><br><dt><code>rmvars</code> <kbd>name</kbd><code>[,...]</code><br><dt><code>clearvars</code><br><dt><code>showvars</code><dd>The arguments to this command consist of a list of
+information about the command.
+</p></dd>
+<dt><code>addvars</code> <kbd>name</kbd><code>[=<kbd>value</kbd>]</code><code>[,...]</code></dt>
+<dt><code>rmvars</code> <kbd>name</kbd><code>[,...]</code></dt>
+<dt><code>clearvars</code></dt>
+<dt><code>showvars</code></dt>
+<dd><p>The arguments to this command consist of a list of
items of the form
-<kbd>name</kbd><code>[=</code><kbd>value</kbd><code>]</code>,
+<kbd>name</kbd><code>[=<kbd>value</kbd>]</code>,
where the
.No = Ns Ar value
is ignored, and can be omitted,
-in requests to the server to read variables.
+in requests to the server to read variables.
The
<code>ntpq</code>
utility maintains an internal list in which data to be included in
@@ -204,155 +296,190 @@ messages can be assembled, and displayed or set using the
<code>readlist</code>
and
<code>writelist</code>
-commands described below.
+commands described below.
The
<code>addvars</code>
command allows variables and their optional values to be added to
-the list.
+the list.
If more than one variable is to be added, the list should
-be comma-separated and not contain white space.
+be comma-separated and not contain white space.
The
<code>rmvars</code>
command can be used to remove individual variables from the list,
while the
<code>clearvars</code>
command removes all variables from the
-list.
+list.
The
<code>showvars</code>
-command displays the current list of optional variables.
-<br><dt><code>authenticate</code> <code>[yes|no]</code><dd>Normally
+command displays the current list of optional variables.
+</p></dd>
+<dt><code>authenticate</code> <code>[<code>yes</code>|<code>no</code>]</code></dt>
+<dd><p>Normally
<code>ntpq</code>
does not authenticate requests unless
-they are write requests.
+they are write requests.
The command
<code>authenticate</code> <code>yes</code>
causes
<code>ntpq</code>
to send authentication with all requests it
-makes.
+makes.
Authenticated requests causes some servers to handle
-requests slightly differently.
+requests slightly differently.
The command
<code>authenticate</code>
causes
<code>ntpq</code>
to display whether or not
-it is currently authenticating requests.
-<br><dt><code>cooked</code><dd>Causes output from query commands to be "cooked", so that
+it is currently authenticating requests.
+</p></dd>
+<dt><code>cooked</code></dt>
+<dd><p>Causes output from query commands to be &quot;cooked&quot;, so that
variables which are recognized by
<code>ntpq</code>
will have their
-values reformatted for human consumption.
+values reformatted for human consumption.
Variables which
<code>ntpq</code>
could not decode completely are
marked with a trailing
-?.
-<br><dt><code>debug</code> <code>[more|less|off]</code><dd>With no argument, displays the current debug level.
-Otherwise, the debugging level is changed as indicated.
-<br><dt><code>delay</code> <code>[</code><kbd>milliseconds</kbd><code>]</code><dd>Specify a time interval to be added to timestamps included in
-requests which require authentication.
+&lsquo;?&rsquo;.
+</p></dd>
+<dt><code>debug</code> <code>[<code>more</code>|<code>less</code>|<code>off</code>]</code></dt>
+<dd><p>With no argument, displays the current debug level.
+Otherwise, the debugging level is changed as indicated.
+</p></dd>
+<dt><code>delay</code> <code>[<kbd>milliseconds</kbd>]</code></dt>
+<dd><p>Specify a time interval to be added to timestamps included in
+requests which require authentication.
This is used to enable
(unreliable) server reconfiguration over long delay network paths
-or between machines whose clocks are unsynchronized.
+or between machines whose clocks are unsynchronized.
Actually the
server does not now require timestamps in authenticated requests,
-so this command may be obsolete.
-Without any arguments, displays the current delay.
-<br><dt><code>drefid</code> <code>[hash|ipv4]</code><dd>Display refids as IPv4 or hash.
+so this command may be obsolete.
+Without any arguments, displays the current delay.
+</p></dd>
+<dt><code>drefid</code> <code>[<code>hash</code>|<code>ipv4</code>]</code></dt>
+<dd><p>Display refids as IPv4 or hash.
Without any arguments, displays whether refids are shown as IPv4
-addresses or hashes.
-<br><dt><code>exit</code><dd>Exit
+addresses or hashes.
+</p></dd>
+<dt><code>exit</code></dt>
+<dd><p>Exit
<code>ntpq</code>
-<br><dt><code>host</code> <code>[</code><kbd>name</kbd><code>]</code><dd>Set the host to which future queries will be sent.
+</p></dd>
+<dt><code>host</code> <code>[<kbd>name</kbd>]</code></dt>
+<dd><p>Set the host to which future queries will be sent.
The
<kbd>name</kbd>
-may be either a host name or a numeric address.
-Without any arguments, displays the current host.
-<br><dt><code>hostnames</code> <code>[yes|no]</code><dd>If
+may be either a host name or a numeric address.
+Without any arguments, displays the current host.
+</p></dd>
+<dt><code>hostnames</code> <code>[<code>yes</code>|<code>no</code>]</code></dt>
+<dd><p>If
<code>yes</code>
is specified, host names are printed in
-information displays.
+information displays.
If
<code>no</code>
is specified, numeric
-addresses are printed instead.
+addresses are printed instead.
The default is
<code>yes</code>,
unless
modified using the command line
<code>-n</code>
-switch.
+switch.
Without any arguments, displays whether host names or numeric addresses
-are shown.
-<br><dt><code>keyid</code> <code>[</code><kbd>keyid</kbd><code>]</code><dd>This command allows the specification of a key number to be
-used to authenticate configuration requests.
+are shown.
+</p></dd>
+<dt><code>keyid</code> <code>[<kbd>keyid</kbd>]</code></dt>
+<dd><p>This command allows the specification of a key number to be
+used to authenticate configuration requests.
This must correspond
to the
<code>controlkey</code>
key number the server has been configured to use for this
-purpose.
+purpose.
Without any arguments, displays the current
-<kbd>keyid</kbd>.
-<br><dt><code>keytype</code> <code>[</code><kbd>digest</kbd><code>]</code><dd>Specify the digest algorithm to use for authenticating requests, with default
-<code>MD5</code>.
+<kbd>keyid</kbd>.
+</p></dd>
+<dt><code>keytype</code> <code>[<kbd>digest</kbd>]</code></dt>
+<dd><p>Specify the digest algorithm to use for authenticating requests, with default
+<code>MD5</code>.
If
<code>ntpq</code>
was built with OpenSSL support, and OpenSSL is installed,
<kbd>digest</kbd>
-can be any message digest algorithm supported by OpenSSL.
+can be any message digest algorithm supported by OpenSSL.
If no argument is given, the current
<code>keytype</code> <kbd>digest</kbd>
-algorithm used is displayed.
-<br><dt><code>ntpversion</code> <code>[1|2|3|4]</code><dd>Sets the NTP version number which
+algorithm used is displayed.
+</p></dd>
+<dt><code>ntpversion</code> <code>[<code>1</code>|<code>2</code>|<code>3</code>|<code>4</code>]</code></dt>
+<dd><p>Sets the NTP version number which
<code>ntpq</code>
claims in
-packets.
+packets.
Defaults to 3, and note that mode 6 control messages (and
-modes, for that matter) didn't exist in NTP version 1.
+modes, for that matter) didn&rsquo;t exist in NTP version 1.
There appear
-to be no servers left which demand version 1.
+to be no servers left which demand version 1.
With no argument, displays the current NTP version that will be used
-when communicating with servers.
-<br><dt><code>passwd</code><dd>This command prompts you to type in a password (which will not
+when communicating with servers.
+</p></dd>
+<dt><code>passwd</code></dt>
+<dd><p>This command prompts you to type in a password (which will not
be echoed) which will be used to authenticate configuration
-requests.
+requests.
The password must correspond to the key configured for
use by the NTP server for this purpose if such requests are to be
-successful.
-<br><dt><code>poll</code> <code>[</code><kbd>n</kbd><code>]</code> <code>[verbose]</code><dd>Poll an NTP server in client mode
+successful.
+</p></dd>
+<dt><code>poll</code> <code>[<kbd>n</kbd>]</code> <code>[<code>verbose</code>]</code></dt>
+<dd><p>Poll an NTP server in client mode
<kbd>n</kbd>
-times.
-Poll not implemented yet.
-<br><dt><code>quit</code><dd>Exit
+times.
+Poll not implemented yet.
+</p></dd>
+<dt><code>quit</code></dt>
+<dd><p>Exit
<code>ntpq</code>
-<br><dt><code>raw</code><dd>Causes all output from query commands is printed as received
-from the remote server.
+</p></dd>
+<dt><code>raw</code></dt>
+<dd><p>Causes all output from query commands is printed as received
+from the remote server.
The only formating/interpretation done on
the data is to transform nonascii data into a printable (but barely
-understandable) form.
-<br><dt><code>timeout</code> <code>[</code><kbd>milliseconds</kbd><code>]</code><dd>Specify a timeout period for responses to server queries.
+understandable) form.
+</p></dd>
+<dt><code>timeout</code> <code>[<kbd>milliseconds</kbd>]</code></dt>
+<dd><p>Specify a timeout period for responses to server queries.
The
-default is about 5000 milliseconds.
-Without any arguments, displays the current timeout period.
+default is about 5000 milliseconds.
+Without any arguments, displays the current timeout period.
Note that since
<code>ntpq</code>
retries each query once after a timeout, the total waiting time for
-a timeout will be twice the timeout value set.
-<br><dt><code>version</code><dd>Display the version of the
+a timeout will be twice the timeout value set.
+</p></dd>
+<dt><code>version</code></dt>
+<dd><p>Display the version of the
<code>ntpq</code>
-program.
+program.
+</p></dd>
</dl>
-<h5 class="subsubsection">Control Message Commands</h5>
-
-<p>Association ids are used to identify system, peer and clock variables.
+<a name="Control-Message-Commands-1"></a>
+<h4 class="subsubsection">1.1.1.1 Control Message Commands</h4>
+<p>Association ids are used to identify system, peer and clock variables.
System variables are assigned an association id of zero and system name
space, while each association is assigned a nonzero association id and
-peer namespace.
+peer namespace.
Most control commands send a single message to the server and expect a
-single response message.
+single response message.
The exceptions are the
<code>peers</code>
command, which sends a series of messages,
@@ -361,172 +488,262 @@ and the
and
<code>mreadvar</code>
commands, which iterate over a range of associations.
- <dl>
-<dt><code>apeers</code><dd>Display a list of peers in the form:
- <pre class="example"> [tally]remote refid assid st t when pool reach delay offset jitter
- </pre>
- <p>where the output is just like the
+</p><dl compact="compact">
+<dt><code>apeers</code></dt>
+<dd><p>Display a list of peers in the form:
+</p><div class="example">
+<pre class="example">[tally]remote refid assid st t when pool reach delay offset jitter
+</pre></div>
+<p>where the output is just like the
<code>peers</code>
command except that the
<code>refid</code>
-is displayed in hex format and the association number is also displayed.
-<br><dt><code>associations</code><dd>Display a list of mobilized associations in the form:
- <pre class="example"> ind assid status conf reach auth condition last_event cnt
- </pre>
- <dl>
-<dt>Sy Variable Ta Sy Description<br><dt><code>ind</code> <code>Ta</code> <code>index</code> <code>on</code> <code>this</code> <code>list</code><br><dt><code>assid</code> <code>Ta</code> <code>association</code> <code>id</code><br><dt><code>status</code> <code>Ta</code> <code>peer</code> <code>status</code> <code>word</code><br><dt><code>conf</code> <code>Ta</code> <code>yes</code>: <code>No</code> <code>persistent,</code> <code>no</code>: <code>No</code> <code>ephemeral</code><br><dt><code>reach</code> <code>Ta</code> <code>yes</code>: <code>No</code> <code>reachable,</code> <code>no</code>: <code>No</code> <code>unreachable</code><br><dt><code>auth</code> <code>Ta</code> <code>ok</code>, <code>yes</code>, <code>bad</code> <code>No</code> <code>and</code> <code>none</code><br><dt><code>condition</code> <code>Ta</code> <code>selection</code> <code>status</code> <code>(see</code> <code>the</code> <code>select</code> <code>No</code> <code>field</code> <code>of</code> <code>the</code> <code>peer</code> <code>status</code> <code>word)</code><br><dt><code>last_event</code> <code>Ta</code> <code>event</code> <code>report</code> <code>(see</code> <code>the</code> <code>event</code> <code>No</code> <code>field</code> <code>of</code> <code>the</code> <code>peer</code> <code>status</code> <code>word)</code><br><dt><code>cnt</code> <code>Ta</code> <code>event</code> <code>count</code> <code>(see</code> <code>the</code> <code>count</code> <code>No</code> <code>field</code> <code>of</code> <code>the</code> <code>peer</code> <code>status</code> <code>word)</code><dd></dl>
- <br><dt><code>authinfo</code><dd>Display the authentication statistics counters:
+is displayed in hex format and the association number is also displayed.
+</p></dd>
+<dt><code>associations</code></dt>
+<dd><p>Display a list of mobilized associations in the form:
+</p><div class="example">
+<pre class="example">ind assid status conf reach auth condition last_event cnt
+</pre></div>
+<dl compact="compact">
+<dt>Sy Variable Ta Sy Description</dt>
+<dt><code>ind</code> <code>Ta</code> <code>index</code> <code>on</code> <code>this</code> <code>list</code></dt>
+<dt><code>assid</code> <code>Ta</code> <code>association</code> <code>id</code></dt>
+<dt><code>status</code> <code>Ta</code> <code>peer</code> <code>status</code> <code>word</code></dt>
+<dt><code>conf</code> <code>Ta</code> <code>yes</code>: <code>No</code> <code>persistent,</code> <code>no</code>: <code>No</code> <code>ephemeral</code></dt>
+<dt><code>reach</code> <code>Ta</code> <code>yes</code>: <code>No</code> <code>reachable,</code> <code>no</code>: <code>No</code> <code>unreachable</code></dt>
+<dt><code>auth</code> <code>Ta</code> <code>ok</code>, <code>yes</code>, <code>bad</code> <code>No</code> <code>and</code> <code>none</code></dt>
+<dt><code>condition</code> <code>Ta</code> <code>selection</code> <code>status</code> <code>(see</code> <code>the</code> <code>select</code> <code>No</code> <code>field</code> <code>of</code> <code>the</code> <code>peer</code> <code>status</code> <code>word)</code></dt>
+<dt><code>last_event</code> <code>Ta</code> <code>event</code> <code>report</code> <code>(see</code> <code>the</code> <code>event</code> <code>No</code> <code>field</code> <code>of</code> <code>the</code> <code>peer</code> <code>status</code> <code>word)</code></dt>
+<dt><code>cnt</code> <code>Ta</code> <code>event</code> <code>count</code> <code>(see</code> <code>the</code> <code>count</code> <code>No</code> <code>field</code> <code>of</code> <code>the</code> <code>peer</code> <code>status</code> <code>word)</code></dt>
+</dl>
+</dd>
+<dt><code>authinfo</code></dt>
+<dd><p>Display the authentication statistics counters:
time since reset, stored keys, free keys, key lookups, keys not found,
-uncached keys, expired keys, encryptions, decryptions.
-<br><dt><code>clocklist</code> <code>[</code><kbd>associd</kbd><code>]</code><br><dt><code>cl</code> <code>[</code><kbd>associd</kbd><code>]</code><dd>Display all clock variables in the variable list for those associations
-supporting a reference clock.
-<br><dt><code>clockvar</code> <code>[</code><kbd>associd</kbd><code>]</code> <code>[</code><kbd>name</kbd><code>[=</code><kbd>value</kbd><code>]]</code><code>[,...]</code><br><dt><code>cv</code> <code>[</code><kbd>associd</kbd><code>]</code> <code>[</code><kbd>name</kbd><code>[=</code><kbd>value</kbd><code>]]</code><code>[,...]</code><dd>Display a list of clock variables for those associations supporting a
-reference clock.
-<br><dt><code>:config</code> <kbd>configuration command line</kbd><dd>Send the remainder of the command line, including whitespace, to the
+uncached keys, expired keys, encryptions, decryptions.
+</p></dd>
+<dt><code>clocklist</code> <code>[<kbd>associd</kbd>]</code></dt>
+<dt><code>cl</code> <code>[<kbd>associd</kbd>]</code></dt>
+<dd><p>Display all clock variables in the variable list for those associations
+supporting a reference clock.
+</p></dd>
+<dt><code>clockvar</code> <code>[<kbd>associd</kbd>]</code> <code>[<kbd>name</kbd><code>[=<kbd>value</kbd>]</code>]</code><code>[,...]</code></dt>
+<dt><code>cv</code> <code>[<kbd>associd</kbd>]</code> <code>[<kbd>name</kbd><code>[=<kbd>value</kbd>]</code>]</code><code>[,...]</code></dt>
+<dd><p>Display a list of clock variables for those associations supporting a
+reference clock.
+</p></dd>
+<dt><code>:config</code> <kbd>configuration command line</kbd></dt>
+<dd><p>Send the remainder of the command line, including whitespace, to the
server as a run-time configuration command in the same format as a line
-in the configuration file.
-This command is experimental until further notice and clarification.
-Authentication is of course required.
-<br><dt><code>config-from-file</code> <kbd>filename</kbd><dd>Send each line of
+in the configuration file.
+This command is experimental until further notice and clarification.
+Authentication is of course required.
+</p></dd>
+<dt><code>config-from-file</code> <kbd>filename</kbd></dt>
+<dd><p>Send each line of
<kbd>filename</kbd>
to the server as run-time configuration commands in the same format as
-lines in the configuration file.
-This command is experimental until further notice and clarification.
-Authentication is required.
-<br><dt><code>ifstats</code><dd>Display status and statistics counters for each local network interface address:
+lines in the configuration file.
+This command is experimental until further notice and clarification.
+Authentication is required.
+</p></dd>
+<dt><code>ifstats</code></dt>
+<dd><p>Display status and statistics counters for each local network interface address:
interface number, interface name and address or broadcast, drop, flag,
-ttl, mc, received, sent, send failed, peers, uptime.
-Authentication is required.
-<br><dt><code>iostats</code><dd>Display network and reference clock I/O statistics:
+ttl, mc, received, sent, send failed, peers, uptime.
+Authentication is required.
+</p></dd>
+<dt><code>iostats</code></dt>
+<dd><p>Display network and reference clock I/O statistics:
time since reset, receive buffers, free receive buffers, used receive buffers,
low water refills, dropped packets, ignored packets, received packets,
-packets sent, packet send failures, input wakeups, useful input wakeups.
-<br><dt><code>kerninfo</code><dd>Display kernel loop and PPS statistics:
+packets sent, packet send failures, input wakeups, useful input wakeups.
+</p></dd>
+<dt><code>kerninfo</code></dt>
+<dd><p>Display kernel loop and PPS statistics:
associd, status, pll offset, pll frequency, maximum error,
estimated error, kernel status, pll time constant, precision,
frequency tolerance, pps frequency, pps stability, pps jitter,
calibration interval, calibration cycles, jitter exceeded,
-stability exceeded, calibration errors.
+stability exceeded, calibration errors.
As with other ntpq output, times are in milliseconds; very small values
-may be shown as exponentials.
+may be shown as exponentials.
The precision value displayed is in milliseconds as well, unlike the
-precision system variable.
-<br><dt><code>lassociations</code><dd>Perform the same function as the associations command, except display
-mobilized and unmobilized associations, including all clients.
-<br><dt><code>lopeers</code> <code>[-4|-6]</code><dd>Display a list of all peers and clients showing
+precision system variable.
+</p></dd>
+<dt><code>lassociations</code></dt>
+<dd><p>Perform the same function as the associations command, except display
+mobilized and unmobilized associations, including all clients.
+</p></dd>
+<dt><code>lopeers</code> <code>[<code>-4</code>|<code>-6</code>]</code></dt>
+<dd><p>Display a list of all peers and clients showing
<code>dstadr</code>
-(associated with the given IP version).
-<br><dt><code>lpassociations</code><dd>Display the last obtained list of associations, including all clients.
-<br><dt><code>lpeers</code> <code>[-4|-6]</code><dd>Display a list of all peers and clients (associated with the given IP version).
-<br><dt><code>monstats</code><dd>Display monitor facility status, statistics, and limits:
+(associated with the given IP version).
+</p></dd>
+<dt><code>lpassociations</code></dt>
+<dd><p>Display the last obtained list of associations, including all clients.
+</p></dd>
+<dt><code>lpeers</code> <code>[<code>-4</code>|<code>-6</code>]</code></dt>
+<dd><p>Display a list of all peers and clients (associated with the given IP version).
+</p></dd>
+<dt><code>monstats</code></dt>
+<dd><p>Display monitor facility status, statistics, and limits:
enabled, addresses, peak addresses, maximum addresses,
-reclaim above count, reclaim older than, kilobytes, maximum kilobytes.
-<br><dt><code>mreadlist</code> <kbd>associdlo</kbd> <kbd>associdhi</kbd><br><dt><code>mrl</code> <kbd>associdlo</kbd> <kbd>associdhi</kbd><dd>Perform the same function as the
+reclaim above count, reclaim older than, kilobytes, maximum kilobytes.
+</p></dd>
+<dt><code>mreadlist</code> <kbd>associdlo</kbd> <kbd>associdhi</kbd></dt>
+<dt><code>mrl</code> <kbd>associdlo</kbd> <kbd>associdhi</kbd></dt>
+<dd><p>Perform the same function as the
<code>readlist</code>
-command for a range of association ids.
-<br><dt><code>mreadvar</code> <kbd>associdlo</kbd> <kbd>associdhi</kbd> <code>[</code><kbd>name</kbd><code>]</code><code>[,...]</code><dd>This range may be determined from the list displayed by any
-command showing associations.
-<br><dt><code>mrv</code> <kbd>associdlo</kbd> <kbd>associdhi</kbd> <code>[</code><kbd>name</kbd><code>]</code><code>[,...]</code><dd>Perform the same function as the
+command for a range of association ids.
+</p></dd>
+<dt><code>mreadvar</code> <kbd>associdlo</kbd> <kbd>associdhi</kbd> <code>[<kbd>name</kbd>]</code><code>[,...]</code></dt>
+<dd><p>This range may be determined from the list displayed by any
+command showing associations.
+</p></dd>
+<dt><code>mrv</code> <kbd>associdlo</kbd> <kbd>associdhi</kbd> <code>[<kbd>name</kbd>]</code><code>[,...]</code></dt>
+<dd><p>Perform the same function as the
<code>readvar</code>
-command for a range of association ids.
+command for a range of association ids.
This range may be determined from the list displayed by any
-command showing associations.
-<br><dt><code>mrulist</code> <code>[limited | kod | mincount=</code><kbd>count</kbd><code> | laddr=</code><kbd>localaddr</kbd><code> | sort=[-]</code><kbd>sortorder</kbd><code> | resany=</code><kbd>hexmask</kbd><code> | resall=</code><kbd>hexmask</kbd><code>]</code><dd>Display traffic counts of the most recently seen source addresses
-collected and maintained by the monitor facility.
+command showing associations.
+</p></dd>
+<dt><code>mrulist</code> <code>[<code>limited</code> | <code>kod</code> | <code>mincount</code>=<kbd>count</kbd> | <code>laddr</code>=<kbd>localaddr</kbd> | <code>sort</code>=<code>[-]</code><kbd>sortorder</kbd> | <code>resany</code>=<kbd>hexmask</kbd> | <code>resall</code>=<kbd>hexmask</kbd>]</code></dt>
+<dd><p>Display traffic counts of the most recently seen source addresses
+collected and maintained by the monitor facility.
With the exception of
<code>sort</code>=<code>[-]</code><kbd>sortorder</kbd>,
the options filter the list returned by
-<code>ntpd(8)</code>.
+<code>ntpd(8)</code>.
The
<code>limited</code>
and
<code>kod</code>
options return only entries representing client addresses from which the
-last packet received triggered either discarding or a KoD response.
+last packet received triggered either discarding or a KoD response.
The
<code>mincount</code>=<kbd>count</kbd>
option filters entries representing less than
<kbd>count</kbd>
-packets.
+packets.
The
<code>laddr</code>=<kbd>localaddr</kbd>
option filters entries for packets received on any local address other than
-<kbd>localaddr</kbd>.
+<kbd>localaddr</kbd>.
<code>resany</code>=<kbd>hexmask</kbd>
and
<code>resall</code>=<kbd>hexmask</kbd>
filter entries containing none or less than all, respectively, of the bits in
<kbd>hexmask</kbd>,
which must begin with
-<code>0x</code>.
+<code>0x</code>.
The
<kbd>sortorder</kbd>
defaults to
<code>lstint</code>
-and may be
+and may be
<code>addr</code>,
<code>avgint</code>,
<code>count</code>,
<code>lstint</code>,
or any of those preceded by
--
-to reverse the sort order.
+&lsquo;-&rsquo;
+to reverse the sort order.
The output columns are:
- <dl>
-<dt>Column<dd>Description
-<br><dt><code>lstint</code><dd>Interval in seconds between the receipt of the most recent packet from
+</p><dl compact="compact">
+<dt>Column</dt>
+<dd><p>Description
+</p></dd>
+<dt><code>lstint</code></dt>
+<dd><p>Interval in seconds between the receipt of the most recent packet from
this address and the completion of the retrieval of the MRU list by
<code>ntpq</code>
-<br><dt><code>avgint</code><dd>Average interval in s between packets from this address.
-<br><dt><code>rstr</code><dd>Restriction flags associated with this address.
+</p></dd>
+<dt><code>avgint</code></dt>
+<dd><p>Average interval in s between packets from this address.
+</p></dd>
+<dt><code>rstr</code></dt>
+<dd><p>Restriction flags associated with this address.
Most are copied unchanged from the matching
<code>restrict</code>
command, however 0x400 (kod) and 0x20 (limited) flags are cleared unless
-the last packet from this address triggered a rate control response.
-<br><dt><code>r</code><dd>Rate control indicator, either
+the last packet from this address triggered a rate control response.
+</p></dd>
+<dt><code>r</code></dt>
+<dd><p>Rate control indicator, either
a period,
<code>L</code>
or
<code>K</code>
for no rate control response,
-rate limiting by discarding, or rate limiting with a KoD response, respectively.
-<br><dt><code>m</code><dd>Packet mode.
-<br><dt><code>v</code><dd>Packet version number.
-<br><dt><code>count</code><dd>Packets received from this address.
-<br><dt><code>rport</code><dd>Source port of last packet from this address.
-<br><dt><code>remote</code> <code>address</code><dd>host or DNS name, numeric address, or address followed by
-claimed DNS name which could not be verified in parentheses.
+rate limiting by discarding, or rate limiting with a KoD response, respectively.
+</p></dd>
+<dt><code>m</code></dt>
+<dd><p>Packet mode.
+</p></dd>
+<dt><code>v</code></dt>
+<dd><p>Packet version number.
+</p></dd>
+<dt><code>count</code></dt>
+<dd><p>Packets received from this address.
+</p></dd>
+<dt><code>rport</code></dt>
+<dd><p>Source port of last packet from this address.
+</p></dd>
+<dt><code>remote</code> <code>address</code></dt>
+<dd><p>host or DNS name, numeric address, or address followed by
+claimed DNS name which could not be verified in parentheses.
+</p></dd>
</dl>
- <br><dt><code>opeers</code> <code>[-4 | -6]</code><dd>Obtain and print the old-style list of all peers and clients showing
+</dd>
+<dt><code>opeers</code> <code>[<code>-4</code> | <code>-6</code>]</code></dt>
+<dd><p>Obtain and print the old-style list of all peers and clients showing
<code>dstadr</code>
(associated with the given IP version),
rather than the
-<code>refid</code>.
-<br><dt><code>passociations</code><dd>Perform the same function as the
+<code>refid</code>.
+</p></dd>
+<dt><code>passociations</code></dt>
+<dd><p>Perform the same function as the
<code>associations</code>
command,
-except that it uses previously stored data rather than making a new query.
-<br><dt><code>peers</code><dd>Display a list of peers in the form:
- <pre class="example"> [tally]remote refid st t when pool reach delay offset jitter
- </pre>
- <dl>
-<dt>Variable<dd>Description
-<br><dt><code>[tally]</code><dd>single-character code indicating current value of the
+except that it uses previously stored data rather than making a new query.
+</p></dd>
+<dt><code>peers</code></dt>
+<dd><p>Display a list of peers in the form:
+</p><div class="example">
+<pre class="example">[tally]remote refid st t when pool reach delay offset jitter
+</pre></div>
+<dl compact="compact">
+<dt>Variable</dt>
+<dd><p>Description
+</p></dd>
+<dt><code>[tally]</code></dt>
+<dd><p>single-character code indicating current value of the
<code>select</code>
field of the
-.Lk decode.html#peer "peer status word"
-<br><dt><code>remote</code><dd>host name (or IP number) of peer.
+.Lk decode.html#peer &quot;peer status word&quot;
+</p></dd>
+<dt><code>remote</code></dt>
+<dd><p>host name (or IP number) of peer.
The value displayed will be truncated to 15 characters unless the
<code>ntpq</code>
<code>-w</code>
option is given, in which case the full value will be displayed
on the first line, and if too long,
-the remaining data will be displayed on the next line.
-<br><dt><code>refid</code><dd>source IP address or
-.Lk decode.html#kiss "'kiss code"
-<br><dt><code>st</code><dd>stratum: 0 for local reference clocks, 1 for servers with local
+the remaining data will be displayed on the next line.
+</p></dd>
+<dt><code>refid</code></dt>
+<dd><p>source IP address or
+.Lk decode.html#kiss &quot;&rsquo;kiss code&quot;
+</p></dd>
+<dt><code>st</code></dt>
+<dd><p>stratum: 0 for local reference clocks, 1 for servers with local
reference clocks, ..., 16 for unsynchronized server clocks
-<br><dt><code>t</code><dd><code>u</code>:
+</p></dd>
+<dt><code>t</code></dt>
+<dd><p><code>u</code>:
unicast or manycast client,
<code>b</code>:
broadcast or multicast client,
@@ -542,46 +759,67 @@ manycast server,
broadcast server,
<code>M</code>:
multicast server
-<br><dt><code>when</code><dd>time in seconds, minutes, hours, or days since the last packet
+</p></dd>
+<dt><code>when</code></dt>
+<dd><p>time in seconds, minutes, hours, or days since the last packet
was received, or
--
+&lsquo;-&rsquo;
if a packet has never been received
-<br><dt><code>poll</code><dd>poll interval (s)
-<br><dt><code>reach</code><dd>reach shift register (octal)
-<br><dt><code>delay</code><dd>roundtrip delay
-<br><dt><code>offset</code><dd>offset of server relative to this host
-<br><dt><code>jitter</code><dd>offset RMS error estimate.
+</p></dd>
+<dt><code>poll</code></dt>
+<dd><p>poll interval (s)
+</p></dd>
+<dt><code>reach</code></dt>
+<dd><p>reach shift register (octal)
+</p></dd>
+<dt><code>delay</code></dt>
+<dd><p>roundtrip delay
+</p></dd>
+<dt><code>offset</code></dt>
+<dd><p>offset of server relative to this host
+</p></dd>
+<dt><code>jitter</code></dt>
+<dd><p>offset RMS error estimate.
+</p></dd>
</dl>
- <br><dt><code>pstats</code> <kbd>associd</kbd><dd>Display the statistics for the peer with the given
+</dd>
+<dt><code>pstats</code> <kbd>associd</kbd></dt>
+<dd><p>Display the statistics for the peer with the given
<kbd>associd</kbd>:
associd, status, remote host, local address, time last received,
time until next send, reachability change, packets sent,
packets received, bad authentication, bogus origin, duplicate,
-bad dispersion, bad reference time, candidate order.
-<br><dt><code>readlist</code> <code>[</code><kbd>associd</kbd><code>]</code><br><dt><code>rl</code> <code>[</code><kbd>associd</kbd><code>]</code><dd>Display all system or peer variables.
+bad dispersion, bad reference time, candidate order.
+</p></dd>
+<dt><code>readlist</code> <code>[<kbd>associd</kbd>]</code></dt>
+<dt><code>rl</code> <code>[<kbd>associd</kbd>]</code></dt>
+<dd><p>Display all system or peer variables.
If the
<kbd>associd</kbd>
-is omitted, it is assumed to be zero.
-<br><dt><code>readvar</code> <code>[</code><kbd>associd</kbd> <kbd>name</kbd><code>[=</code><kbd>value</kbd><code>] [, ...]]</code><br><dt><code>rv</code> <code>[</code><kbd>associd</kbd> <kbd>name</kbd><code>[=</code><kbd>value</kbd><code>] [, ...]]</code><dd>Display the specified system or peer variables.
+is omitted, it is assumed to be zero.
+</p></dd>
+<dt><code>readvar</code> <code>[<kbd>associd</kbd> <kbd>name</kbd><code>[=<kbd>value</kbd>]</code> <code>[, ...]</code>]</code></dt>
+<dt><code>rv</code> <code>[<kbd>associd</kbd> <kbd>name</kbd><code>[=<kbd>value</kbd>]</code> <code>[, ...]</code>]</code></dt>
+<dd><p>Display the specified system or peer variables.
If
<kbd>associd</kbd>
is zero, the variables are from the
<a href="#System-Variables">System Variables</a>
name space, otherwise they are from the
<a href="#Peer-Variables">Peer Variables</a>
-name space.
+name space.
The
<kbd>associd</kbd>
-is required, as the same name can occur in both spaces.
+is required, as the same name can occur in both spaces.
If no
<kbd>name</kbd>
-is included, all operative variables in the name space are displayed.
+is included, all operative variables in the name space are displayed.
In this case only, if the
<kbd>associd</kbd>
-is omitted, it is assumed to be zero.
-Multiple names are specified with comma separators and without whitespace.
+is omitted, it is assumed to be zero.
+Multiple names are specified with comma separators and without whitespace.
Note that time values are represented in milliseconds
-and frequency values in parts-per-million (PPM).
+and frequency values in parts-per-million (PPM).
Some NTP timestamps are represented in the format
<kbd>YYYY</kbd><kbd>MM</kbd> <kbd>DD</kbd> <kbd>TTTT</kbd>,
where
@@ -592,270 +830,470 @@ the month of year,
<kbd>DD</kbd>
the day of month and
<kbd>TTTT</kbd>
-the time of day.
-<br><dt><code>reslist</code><dd>Display the access control (restrict) list for
+the time of day.
+</p></dd>
+<dt><code>reslist</code></dt>
+<dd><p>Display the access control (restrict) list for
<code>ntpq</code>
-Authentication is required.
-<br><dt><code>saveconfig</code> <kbd>filename</kbd><dd>Save the current configuration,
+Authentication is required.
+</p></dd>
+<dt><code>saveconfig</code> <kbd>filename</kbd></dt>
+<dd><p>Save the current configuration,
including any runtime modifications made by
<code>:config</code>
or
<code>config-from-file</code>,
to the NTP server host file
-<kbd>filename</kbd>.
+<kbd>filename</kbd>.
This command will be rejected by the server unless
-.Lk miscopt.html#saveconfigdir "saveconfigdir"
+.Lk miscopt.html#saveconfigdir &quot;saveconfigdir&quot;
appears in the
<code>ntpd(8)</code>
-configuration file.
+configuration file.
<kbd>filename</kbd>
can use
<code>date(1)</code>
format specifiers to substitute the current date and time, for
example,
- <pre class="example"> <code>saveconfig</code> <span class="file">ntp-%Y%m%d-%H%M%S.conf</span>.
- </pre>
- <p>The filename used is stored in system variable
-<code>savedconfig</code>.
-Authentication is required.
-<br><dt><code>sysinfo</code><dd>Display system operational summary:
+</p><div class="example">
+<pre class="example"><code>saveconfig</code> <samp>ntp-%Y%m%d-%H%M%S.conf</samp>.
+</pre></div>
+<p>The filename used is stored in system variable
+<code>savedconfig</code>.
+Authentication is required.
+</p></dd>
+<dt><code>sysinfo</code></dt>
+<dd><p>Display system operational summary:
associd, status, system peer, system peer mode, leap indicator,
stratum, log2 precision, root delay, root dispersion,
reference id, reference time, system jitter, clock jitter,
-clock wander, broadcast delay, symm. auth. delay.
-<br><dt><code>sysstats</code><dd>Display system uptime and packet counts maintained in the
+clock wander, broadcast delay, symm. auth. delay.
+</p></dd>
+<dt><code>sysstats</code></dt>
+<dd><p>Display system uptime and packet counts maintained in the
protocol module:
uptime, sysstats reset, packets received, current version,
older version, bad length or format, authentication failed,
declined, restricted, rate limited, KoD responses,
-processed for time.
-<br><dt><code>timerstats</code><dd>Display interval timer counters:
-time since reset, timer overruns, calls to transmit.
-<br><dt><code>writelist</code> <kbd>associd</kbd><dd>Set all system or peer variables included in the variable list.
-<br><dt><code>writevar</code> <kbd>associd</kbd> <kbd>name</kbd>=<kbd>value</kbd> <code>[, ...]</code><dd>Set the specified variables in the variable list.
+processed for time.
+</p></dd>
+<dt><code>timerstats</code></dt>
+<dd><p>Display interval timer counters:
+time since reset, timer overruns, calls to transmit.
+</p></dd>
+<dt><code>writelist</code> <kbd>associd</kbd></dt>
+<dd><p>Set all system or peer variables included in the variable list.
+</p></dd>
+<dt><code>writevar</code> <kbd>associd</kbd> <kbd>name</kbd>=<kbd>value</kbd> <code>[, ...]</code></dt>
+<dd><p>Set the specified variables in the variable list.
If the
<kbd>associd</kbd>
is zero, the variables are from the
<a href="#System-Variables">System Variables</a>
name space, otherwise they are from the
<a href="#Peer-Variables">Peer Variables</a>
-name space.
+name space.
The
<kbd>associd</kbd>
-is required, as the same name can occur in both spaces.
-Authentication is required.
+is required, as the same name can occur in both spaces.
+Authentication is required.
+</p></dd>
</dl>
-<h5 class="subsubsection">Status Words and Kiss Codes</h5>
-
+<a name="Status-Words-and-Kiss-Codes-1"></a>
+<h4 class="subsubsection">1.1.1.2 Status Words and Kiss Codes</h4>
<p>The current state of the operating program is shown
in a set of status words
-maintained by the system.
-Status information is also available on a per-association basis.
+maintained by the system.
+Status information is also available on a per-association basis.
These words are displayed by the
<code>readlist</code>
and
<code>associations</code>
-commands both in hexadecimal and in decoded short tip strings.
+commands both in hexadecimal and in decoded short tip strings.
The codes, tips and short explanations are documented on the
-.Lk decode.html "Event Messages and Status Words"
-page.
+.Lk decode.html &quot;Event Messages and Status Words&quot;
+page.
The page also includes a list of system and peer messages,
the code for the latest of which is included in the status word.
-
- <p>Information resulting from protocol machine state transitions
+</p>
+<p>Information resulting from protocol machine state transitions
is displayed using an informal set of ASCII strings called
-.Lk decode.html#kiss "kiss codes" .
-The original purpose was for kiss-o'-death (KoD) packets
-sent by the server to advise the client of an unusual condition.
+.Lk decode.html#kiss &quot;kiss codes&quot; .
+The original purpose was for kiss-o&rsquo;-death (KoD) packets
+sent by the server to advise the client of an unusual condition.
They are now displayed, when appropriate,
in the reference identifier field in various billboards.
-
-<h5 class="subsubsection">System Variables</h5>
-
+</p>
+<a name="System-Variables-1"></a>
+<h4 class="subsubsection">1.1.1.3 System Variables</h4>
<p>The following system variables appear in the
<code>readlist</code>
-billboard.
+billboard.
Not all variables are displayed in some configurations.
-
- <dl>
-<dt>Variable<dd>Description
-<br><dt><code>status</code><dd>.Lk decode.html#sys "system status word"
-<br><dt><code>version</code><dd>NTP software version and build time
-<br><dt><code>processor</code><dd>hardware platform and version
-<br><dt><code>system</code><dd>operating system and version
-<br><dt><code>leap</code><dd>leap warning indicator (0-3)
-<br><dt><code>stratum</code><dd>stratum (1-15)
-<br><dt><code>precision</code><dd>precision (log2 s)
-<br><dt><code>rootdelay</code><dd>total roundtrip delay to the primary reference clock
-<br><dt><code>rootdisp</code><dd>total dispersion to the primary reference clock
-<br><dt><code>refid</code><dd>reference id or
-.Lk decode.html#kiss "kiss code"
-<br><dt><code>reftime</code><dd>reference time
-<br><dt><code>clock</code><dd>date and time of day
-<br><dt><code>peer</code><dd>system peer association id
-<br><dt><code>tc</code><dd>time constant and poll exponent (log2 s) (3-17)
-<br><dt><code>mintc</code><dd>minimum time constant (log2 s) (3-10)
-<br><dt><code>offset</code><dd>combined offset of server relative to this host
-<br><dt><code>frequency</code><dd>frequency drift (PPM) relative to hardware clock
-<br><dt><code>sys_jitter</code><dd>combined system jitter
-<br><dt><code>clk_wander</code><dd>clock frequency wander (PPM)
-<br><dt><code>clk_jitter</code><dd>clock jitter
-<br><dt><code>tai</code><dd>TAI-UTC offset (s)
-<br><dt><code>leapsec</code><dd>NTP seconds when the next leap second is/was inserted
-<br><dt><code>expire</code><dd>NTP seconds when the NIST leapseconds file expires
+</p>
+<dl compact="compact">
+<dt>Variable</dt>
+<dd><p>Description
+</p></dd>
+<dt><code>status</code></dt>
+<dd><p>.Lk decode.html#sys &quot;system status word&quot;
+</p></dd>
+<dt><code>version</code></dt>
+<dd><p>NTP software version and build time
+</p></dd>
+<dt><code>processor</code></dt>
+<dd><p>hardware platform and version
+</p></dd>
+<dt><code>system</code></dt>
+<dd><p>operating system and version
+</p></dd>
+<dt><code>leap</code></dt>
+<dd><p>leap warning indicator (0-3)
+</p></dd>
+<dt><code>stratum</code></dt>
+<dd><p>stratum (1-15)
+</p></dd>
+<dt><code>precision</code></dt>
+<dd><p>precision (log2 s)
+</p></dd>
+<dt><code>rootdelay</code></dt>
+<dd><p>total roundtrip delay to the primary reference clock
+</p></dd>
+<dt><code>rootdisp</code></dt>
+<dd><p>total dispersion to the primary reference clock
+</p></dd>
+<dt><code>refid</code></dt>
+<dd><p>reference id or
+.Lk decode.html#kiss &quot;kiss code&quot;
+</p></dd>
+<dt><code>reftime</code></dt>
+<dd><p>reference time
+</p></dd>
+<dt><code>clock</code></dt>
+<dd><p>date and time of day
+</p></dd>
+<dt><code>peer</code></dt>
+<dd><p>system peer association id
+</p></dd>
+<dt><code>tc</code></dt>
+<dd><p>time constant and poll exponent (log2 s) (3-17)
+</p></dd>
+<dt><code>mintc</code></dt>
+<dd><p>minimum time constant (log2 s) (3-10)
+</p></dd>
+<dt><code>offset</code></dt>
+<dd><p>combined offset of server relative to this host
+</p></dd>
+<dt><code>frequency</code></dt>
+<dd><p>frequency drift (PPM) relative to hardware clock
+</p></dd>
+<dt><code>sys_jitter</code></dt>
+<dd><p>combined system jitter
+</p></dd>
+<dt><code>clk_wander</code></dt>
+<dd><p>clock frequency wander (PPM)
+</p></dd>
+<dt><code>clk_jitter</code></dt>
+<dd><p>clock jitter
+</p></dd>
+<dt><code>tai</code></dt>
+<dd><p>TAI-UTC offset (s)
+</p></dd>
+<dt><code>leapsec</code></dt>
+<dd><p>NTP seconds when the next leap second is/was inserted
+</p></dd>
+<dt><code>expire</code></dt>
+<dd><p>NTP seconds when the NIST leapseconds file expires
+</p></dd>
</dl>
- The jitter and wander statistics are exponentially-weighted RMS averages.
+<p>The jitter and wander statistics are exponentially-weighted RMS averages.
The system jitter is defined in the NTPv4 specification;
the clock jitter statistic is computed by the clock discipline module.
-
- <p>When the NTPv4 daemon is compiled with the OpenSSL software library,
+</p>
+<p>When the NTPv4 daemon is compiled with the OpenSSL software library,
additional system variables are displayed,
including some or all of the following,
depending on the particular Autokey dance:
- <dl>
-<dt>Variable<dd>Description
-<br><dt><code>host</code><dd>Autokey host name for this host
-<br><dt><code>ident</code><dd>Autokey group name for this host
-<br><dt><code>flags</code><dd>host flags (see Autokey specification)
-<br><dt><code>digest</code><dd>OpenSSL message digest algorithm
-<br><dt><code>signature</code><dd>OpenSSL digest/signature scheme
-<br><dt><code>update</code><dd>NTP seconds at last signature update
-<br><dt><code>cert</code><dd>certificate subject, issuer and certificate flags
-<br><dt><code>until</code><dd>NTP seconds when the certificate expires
+</p><dl compact="compact">
+<dt>Variable</dt>
+<dd><p>Description
+</p></dd>
+<dt><code>host</code></dt>
+<dd><p>Autokey host name for this host
+</p></dd>
+<dt><code>ident</code></dt>
+<dd><p>Autokey group name for this host
+</p></dd>
+<dt><code>flags</code></dt>
+<dd><p>host flags (see Autokey specification)
+</p></dd>
+<dt><code>digest</code></dt>
+<dd><p>OpenSSL message digest algorithm
+</p></dd>
+<dt><code>signature</code></dt>
+<dd><p>OpenSSL digest/signature scheme
+</p></dd>
+<dt><code>update</code></dt>
+<dd><p>NTP seconds at last signature update
+</p></dd>
+<dt><code>cert</code></dt>
+<dd><p>certificate subject, issuer and certificate flags
+</p></dd>
+<dt><code>until</code></dt>
+<dd><p>NTP seconds when the certificate expires
+</p></dd>
</dl>
-
-<h5 class="subsubsection">Peer Variables</h5>
-
+<a name="Peer-Variables-1"></a>
+<h4 class="subsubsection">1.1.1.4 Peer Variables</h4>
<p>The following peer variables appear in the
<code>readlist</code>
-billboard for each association.
+billboard for each association.
Not all variables are displayed in some configurations.
-
- <dl>
-<dt>Variable<dd>Description
-<br><dt><code>associd</code><dd>association id
-<br><dt><code>status</code><dd>.Lk decode.html#peer "peer status word"
-<br><dt><code>srcadr</code><dd>source (remote) IP address
-<br><dt><code>srcport</code><dd>source (remote) port
-<br><dt><code>dstadr</code><dd>destination (local) IP address
-<br><dt><code>dstport</code><dd>destination (local) port
-<br><dt><code>leap</code><dd>leap indicator (0-3)
-<br><dt><code>stratum</code><dd>stratum (0-15)
-<br><dt><code>precision</code><dd>precision (log2 s)
-<br><dt><code>rootdelay</code><dd>total roundtrip delay to the primary reference clock
-<br><dt><code>rootdisp</code><dd>total root dispersion to the primary reference clock
-<br><dt><code>refid</code><dd>reference id or
-.Lk decode.html#kiss "kiss code"
-<br><dt><code>reftime</code><dd>reference time
-<br><dt><code>rec</code><dd>last packet received time
-<br><dt><code>reach</code><dd>reach register (octal)
-<br><dt><code>unreach</code><dd>unreach counter
-<br><dt><code>hmode</code><dd>host mode (1-6)
-<br><dt><code>pmode</code><dd>peer mode (1-5)
-<br><dt><code>hpoll</code><dd>host poll exponent (log2 s) (3-17)
-<br><dt><code>ppoll</code><dd>peer poll exponent (log2 s) (3-17)
-<br><dt><code>headway</code><dd>headway (see
-.Lk rate.html "Rate Management and the Kiss-o'-Death Packet" )
-<br><dt><code>flash</code><dd>.Lk decode.html#flash "flash status word"
-<br><dt><code>keyid</code><dd>symmetric key id
-<br><dt><code>offset</code><dd>filter offset
-<br><dt><code>delay</code><dd>filter delay
-<br><dt><code>dispersion</code><dd>filter dispersion
-<br><dt><code>jitter</code><dd>filter jitter
-<br><dt><code>bias</code><dd>unicast/broadcast bias
-<br><dt><code>xleave</code><dd>interleave delay (see
-.Lk xleave.html "NTP Interleaved Modes" )
+</p>
+<dl compact="compact">
+<dt>Variable</dt>
+<dd><p>Description
+</p></dd>
+<dt><code>associd</code></dt>
+<dd><p>association id
+</p></dd>
+<dt><code>status</code></dt>
+<dd><p>.Lk decode.html#peer &quot;peer status word&quot;
+</p></dd>
+<dt><code>srcadr</code></dt>
+<dd><p>source (remote) IP address
+</p></dd>
+<dt><code>srcport</code></dt>
+<dd><p>source (remote) port
+</p></dd>
+<dt><code>dstadr</code></dt>
+<dd><p>destination (local) IP address
+</p></dd>
+<dt><code>dstport</code></dt>
+<dd><p>destination (local) port
+</p></dd>
+<dt><code>leap</code></dt>
+<dd><p>leap indicator (0-3)
+</p></dd>
+<dt><code>stratum</code></dt>
+<dd><p>stratum (0-15)
+</p></dd>
+<dt><code>precision</code></dt>
+<dd><p>precision (log2 s)
+</p></dd>
+<dt><code>rootdelay</code></dt>
+<dd><p>total roundtrip delay to the primary reference clock
+</p></dd>
+<dt><code>rootdisp</code></dt>
+<dd><p>total root dispersion to the primary reference clock
+</p></dd>
+<dt><code>refid</code></dt>
+<dd><p>reference id or
+.Lk decode.html#kiss &quot;kiss code&quot;
+</p></dd>
+<dt><code>reftime</code></dt>
+<dd><p>reference time
+</p></dd>
+<dt><code>rec</code></dt>
+<dd><p>last packet received time
+</p></dd>
+<dt><code>reach</code></dt>
+<dd><p>reach register (octal)
+</p></dd>
+<dt><code>unreach</code></dt>
+<dd><p>unreach counter
+</p></dd>
+<dt><code>hmode</code></dt>
+<dd><p>host mode (1-6)
+</p></dd>
+<dt><code>pmode</code></dt>
+<dd><p>peer mode (1-5)
+</p></dd>
+<dt><code>hpoll</code></dt>
+<dd><p>host poll exponent (log2 s) (3-17)
+</p></dd>
+<dt><code>ppoll</code></dt>
+<dd><p>peer poll exponent (log2 s) (3-17)
+</p></dd>
+<dt><code>headway</code></dt>
+<dd><p>headway (see
+.Lk rate.html &quot;Rate Management and the Kiss-o&rsquo;-Death Packet&quot; )
+</p></dd>
+<dt><code>flash</code></dt>
+<dd><p>.Lk decode.html#flash &quot;flash status word&quot;
+</p></dd>
+<dt><code>keyid</code></dt>
+<dd><p>symmetric key id
+</p></dd>
+<dt><code>offset</code></dt>
+<dd><p>filter offset
+</p></dd>
+<dt><code>delay</code></dt>
+<dd><p>filter delay
+</p></dd>
+<dt><code>dispersion</code></dt>
+<dd><p>filter dispersion
+</p></dd>
+<dt><code>jitter</code></dt>
+<dd><p>filter jitter
+</p></dd>
+<dt><code>bias</code></dt>
+<dd><p>unicast/broadcast bias
+</p></dd>
+<dt><code>xleave</code></dt>
+<dd><p>interleave delay (see
+.Lk xleave.html &quot;NTP Interleaved Modes&quot; )
+</p></dd>
</dl>
- The
+<p>The
<code>bias</code>
variable is calculated when the first broadcast packet is received
-after the calibration volley.
+after the calibration volley.
It represents the offset of the broadcast subgraph relative to the
-unicast subgraph.
+unicast subgraph.
The
<code>xleave</code>
-variable appears only for the interleaved symmetric and interleaved modes.
+variable appears only for the interleaved symmetric and interleaved modes.
It represents the internal queuing, buffering and transmission delays
for the preceding packet.
-
- <p>When the NTPv4 daemon is compiled with the OpenSSL software library,
+</p>
+<p>When the NTPv4 daemon is compiled with the OpenSSL software library,
additional peer variables are displayed, including the following:
- <dl>
-<dt>Variable<dd>Description
-<br><dt><code>flags</code><dd>peer flags (see Autokey specification)
-<br><dt><code>host</code><dd>Autokey server name
-<br><dt><code>flags</code><dd>peer flags (see Autokey specification)
-<br><dt><code>signature</code><dd>OpenSSL digest/signature scheme
-<br><dt><code>initsequence</code><dd>initial key id
-<br><dt><code>initkey</code><dd>initial key index
-<br><dt><code>timestamp</code><dd>Autokey signature timestamp
-<br><dt><code>ident</code><dd>Autokey group name for this association
+</p><dl compact="compact">
+<dt>Variable</dt>
+<dd><p>Description
+</p></dd>
+<dt><code>flags</code></dt>
+<dd><p>peer flags (see Autokey specification)
+</p></dd>
+<dt><code>host</code></dt>
+<dd><p>Autokey server name
+</p></dd>
+<dt><code>flags</code></dt>
+<dd><p>peer flags (see Autokey specification)
+</p></dd>
+<dt><code>signature</code></dt>
+<dd><p>OpenSSL digest/signature scheme
+</p></dd>
+<dt><code>initsequence</code></dt>
+<dd><p>initial key id
+</p></dd>
+<dt><code>initkey</code></dt>
+<dd><p>initial key index
+</p></dd>
+<dt><code>timestamp</code></dt>
+<dd><p>Autokey signature timestamp
+</p></dd>
+<dt><code>ident</code></dt>
+<dd><p>Autokey group name for this association
+</p></dd>
</dl>
-<h5 class="subsubsection">Clock Variables</h5>
-
+<a name="Clock-Variables-1"></a>
+<h4 class="subsubsection">1.1.1.5 Clock Variables</h4>
<p>The following clock variables appear in the
<code>clocklist</code>
-billboard for each association with a reference clock.
+billboard for each association with a reference clock.
Not all variables are displayed in some configurations.
- <dl>
-<dt>Variable<dd>Description
-<br><dt><code>associd</code><dd>association id
-<br><dt><code>status</code><dd>.Lk decode.html#clock "clock status word"
-<br><dt><code>device</code><dd>device description
-<br><dt><code>timecode</code><dd>ASCII time code string (specific to device)
-<br><dt><code>poll</code><dd>poll messages sent
-<br><dt><code>noreply</code><dd>no reply
-<br><dt><code>badformat</code><dd>bad format
-<br><dt><code>baddata</code><dd>bad date or time
-<br><dt><code>fudgetime1</code><dd>fudge time 1
-<br><dt><code>fudgetime2</code><dd>fudge time 2
-<br><dt><code>stratum</code><dd>driver stratum
-<br><dt><code>refid</code><dd>driver reference id
-<br><dt><code>flags</code><dd>driver flags
+</p><dl compact="compact">
+<dt>Variable</dt>
+<dd><p>Description
+</p></dd>
+<dt><code>associd</code></dt>
+<dd><p>association id
+</p></dd>
+<dt><code>status</code></dt>
+<dd><p>.Lk decode.html#clock &quot;clock status word&quot;
+</p></dd>
+<dt><code>device</code></dt>
+<dd><p>device description
+</p></dd>
+<dt><code>timecode</code></dt>
+<dd><p>ASCII time code string (specific to device)
+</p></dd>
+<dt><code>poll</code></dt>
+<dd><p>poll messages sent
+</p></dd>
+<dt><code>noreply</code></dt>
+<dd><p>no reply
+</p></dd>
+<dt><code>badformat</code></dt>
+<dd><p>bad format
+</p></dd>
+<dt><code>baddata</code></dt>
+<dd><p>bad date or time
+</p></dd>
+<dt><code>fudgetime1</code></dt>
+<dd><p>fudge time 1
+</p></dd>
+<dt><code>fudgetime2</code></dt>
+<dd><p>fudge time 2
+</p></dd>
+<dt><code>stratum</code></dt>
+<dd><p>driver stratum
+</p></dd>
+<dt><code>refid</code></dt>
+<dd><p>driver reference id
+</p></dd>
+<dt><code>flags</code></dt>
+<dd><p>driver flags
+</p></dd>
</dl>
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntpq</code> program.
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntpq</code> program.
This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntpq-usage">ntpq usage</a>: ntpq help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#ntpq-ipv4">ntpq ipv4</a>: ipv4 option (-4)
-<li><a accesskey="3" href="#ntpq-ipv6">ntpq ipv6</a>: ipv6 option (-6)
-<li><a accesskey="4" href="#ntpq-command">ntpq command</a>: command option (-c)
-<li><a accesskey="5" href="#ntpq-interactive">ntpq interactive</a>: interactive option (-i)
-<li><a accesskey="6" href="#ntpq-numeric">ntpq numeric</a>: numeric option (-n)
-<li><a accesskey="7" href="#ntpq-old_002drv">ntpq old-rv</a>: old-rv option
-<li><a accesskey="8" href="#ntpq-peers">ntpq peers</a>: peers option (-p)
-<li><a accesskey="9" href="#ntpq-refid">ntpq refid</a>: refid option (-r)
-<li><a href="#ntpq-wide">ntpq wide</a>: wide option (-w)
-<li><a href="#ntpq-config">ntpq config</a>: presetting/configuring ntpq
-<li><a href="#ntpq-exit-status">ntpq exit status</a>: exit status
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntpq-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-ipv4">ntpq ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-usage" accesskey="1">ntpq usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntpq help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-ipv4" accesskey="2">ntpq ipv4</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv4 option (-4)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-ipv6" accesskey="3">ntpq ipv6</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv6 option (-6)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-command" accesskey="4">ntpq command</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">command option (-c)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-interactive" accesskey="5">ntpq interactive</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">interactive option (-i)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-numeric" accesskey="6">ntpq numeric</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">numeric option (-n)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-old_002drv" accesskey="7">ntpq old-rv</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">old-rv option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-peers" accesskey="8">ntpq peers</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">peers option (-p)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-refid" accesskey="9">ntpq refid</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">refid option (-r)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-wide">ntpq wide</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">wide option (-w)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-config">ntpq config</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">presetting/configuring ntpq
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpq-exit-status">ntpq exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+</table>
+
+<hr>
+<a name="ntpq-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-ipv4" accesskey="n" rel="next">ntpq ipv4</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpq help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-ntpq-help-3"></a>
-This is the automatically generated usage text for ntpq.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="ntpq-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h4 class="subsection">1.1.2 ntpq help/usage (<samp>--help</samp>)</h4>
+<a name="index-ntpq-help"></a>
+
+<p>This is the automatically generated usage text for ntpq.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">ntpq - standard NTP query program - Ver. 4.2.8p10
+</p>
+<div class="example">
+<pre class="example">ntpq - standard NTP query program - Ver. 4.2.8p12
Usage: ntpq [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]... [ host ...]
Flg Arg Option-Name Description
-4 no ipv4 Force IPv4 name resolution
@@ -894,1046 +1332,827 @@ The following option preset mechanisms are supported:
- reading file ./.ntprc
- examining environment variables named NTPQ_*
-The valid "refid" option keywords are:
+The valid &quot;refid&quot; option keywords are:
hash ipv4
or an integer from 0 through 1
Please send bug reports to: &lt;http://bugs.ntp.org, bugs@ntp.org&gt;
-</pre>
- <div class="node">
-<p><hr>
-<a name="ntpq-ipv4"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-ipv6">ntpq ipv6</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-usage">ntpq usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">ipv4 option (-4)</h4>
-
-<p><a name="index-ntpq_002dipv4-4"></a>
-This is the &ldquo;force ipv4 name resolution&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv6.
-</ul>
+</pre></div>
- <p>Force resolution of following host names on the command line
-to the IPv4 namespace.
-<div class="node">
-<p><hr>
-<a name="ntpq-ipv6"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-command">ntpq command</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-ipv4">ntpq ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+<hr>
+<a name="ntpq-ipv4"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-ipv6" accesskey="n" rel="next">ntpq ipv6</a>, Previous: <a href="#ntpq-usage" accesskey="p" rel="prev">ntpq usage</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ipv6 option (-6)</h4>
-
-<p><a name="index-ntpq_002dipv6-5"></a>
-This is the &ldquo;force ipv6 name resolution&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv4.
-</ul>
-
- <p>Force resolution of following host names on the command line
-to the IPv6 namespace.
-<div class="node">
-<p><hr>
-<a name="ntpq-command"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-interactive">ntpq interactive</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-ipv6">ntpq ipv6</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+<a name="ipv4-option-_0028_002d4_0029"></a>
+<h4 class="subsection">1.1.3 ipv4 option (-4)</h4>
+<a name="index-ntpq_002dipv4"></a>
+
+<p>This is the &ldquo;force ipv4 name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv6.
+</li></ul>
+
+<p>Force resolution of following host names on the command line
+to the IPv4 namespace.
+</p><hr>
+<a name="ntpq-ipv6"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-command" accesskey="n" rel="next">ntpq command</a>, Previous: <a href="#ntpq-ipv4" accesskey="p" rel="prev">ntpq ipv4</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">command option (-c)</h4>
-
-<p><a name="index-ntpq_002dcommand-6"></a>
-This is the &ldquo;run a command and exit&rdquo; option.
-This option takes a string argument <span class="file">cmd</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>The following argument is interpreted as an interactive format command
+<a name="ipv6-option-_0028_002d6_0029"></a>
+<h4 class="subsection">1.1.4 ipv6 option (-6)</h4>
+<a name="index-ntpq_002dipv6"></a>
+
+<p>This is the &ldquo;force ipv6 name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv4.
+</li></ul>
+
+<p>Force resolution of following host names on the command line
+to the IPv6 namespace.
+</p><hr>
+<a name="ntpq-command"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-interactive" accesskey="n" rel="next">ntpq interactive</a>, Previous: <a href="#ntpq-ipv6" accesskey="p" rel="prev">ntpq ipv6</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
+</div>
+<a name="command-option-_0028_002dc_0029"></a>
+<h4 class="subsection">1.1.5 command option (-c)</h4>
+<a name="index-ntpq_002dcommand"></a>
+
+<p>This is the &ldquo;run a command and exit&rdquo; option.
+This option takes a string argument <samp>cmd</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>The following argument is interpreted as an interactive format command
and is added to the list of commands to be executed on the specified
-host(s).
-<div class="node">
-<p><hr>
-<a name="ntpq-interactive"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-numeric">ntpq numeric</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-command">ntpq command</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+host(s).
+</p><hr>
+<a name="ntpq-interactive"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-numeric" accesskey="n" rel="next">ntpq numeric</a>, Previous: <a href="#ntpq-command" accesskey="p" rel="prev">ntpq command</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">interactive option (-i)</h4>
-
-<p><a name="index-ntpq_002dinteractive-7"></a>
-This is the &ldquo;force ntpq to operate in interactive mode&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-command, peers.
-</ul>
-
- <p>Force <code>ntpq</code> to operate in interactive mode.
+<a name="interactive-option-_0028_002di_0029"></a>
+<h4 class="subsection">1.1.6 interactive option (-i)</h4>
+<a name="index-ntpq_002dinteractive"></a>
+
+<p>This is the &ldquo;force ntpq to operate in interactive mode&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+command, peers.
+</li></ul>
+
+<p>Force <code>ntpq</code> to operate in interactive mode.
Prompts will be written to the standard output and
-commands read from the standard input.
-<div class="node">
-<p><hr>
-<a name="ntpq-numeric"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-old_002drv">ntpq old-rv</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-interactive">ntpq interactive</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+commands read from the standard input.
+</p><hr>
+<a name="ntpq-numeric"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-old_002drv" accesskey="n" rel="next">ntpq old-rv</a>, Previous: <a href="#ntpq-interactive" accesskey="p" rel="prev">ntpq interactive</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
+<a name="numeric-option-_0028_002dn_0029"></a>
+<h4 class="subsection">1.1.7 numeric option (-n)</h4>
+<a name="index-ntpq_002dnumeric"></a>
-<h4 class="subsection">numeric option (-n)</h4>
-
-<p><a name="index-ntpq_002dnumeric-8"></a>
-This is the &ldquo;numeric host addresses&rdquo; option.
+<p>This is the &ldquo;numeric host addresses&rdquo; option.
Output all host addresses in dotted-quad numeric format rather than
-converting to the canonical host names.
-<div class="node">
-<p><hr>
-<a name="ntpq-old_002drv"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-peers">ntpq peers</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-numeric">ntpq numeric</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+converting to the canonical host names.
+</p><hr>
+<a name="ntpq-old_002drv"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-peers" accesskey="n" rel="next">ntpq peers</a>, Previous: <a href="#ntpq-numeric" accesskey="p" rel="prev">ntpq numeric</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
+<a name="old_002drv-option"></a>
+<h4 class="subsection">1.1.8 old-rv option</h4>
+<a name="index-ntpq_002dold_002drv"></a>
-<h4 class="subsection">old-rv option</h4>
-
-<p><a name="index-ntpq_002dold_002drv-9"></a>
-This is the &ldquo;always output status line with readvar&rdquo; option.
+<p>This is the &ldquo;always output status line with readvar&rdquo; option.
By default, <code>ntpq</code> now suppresses the <code>associd=...</code>
line that precedes the output of <code>readvar</code>
(alias <code>rv</code>) when a single variable is requested, such as
-<code>ntpq -c "rv 0 offset"</code>.
+<code>ntpq -c &quot;rv 0 offset&quot;</code>.
This option causes <code>ntpq</code> to include both lines of output
-for a single-variable <code>readvar</code>.
+for a single-variable <code>readvar</code>.
Using an environment variable to
preset this option in a script will enable both older and
-newer <code>ntpq</code> to behave identically in this regard.
-<div class="node">
-<p><hr>
-<a name="ntpq-peers"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-refid">ntpq refid</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-old_002drv">ntpq old-rv</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+newer <code>ntpq</code> to behave identically in this regard.
+</p><hr>
+<a name="ntpq-peers"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-refid" accesskey="n" rel="next">ntpq refid</a>, Previous: <a href="#ntpq-old_002drv" accesskey="p" rel="prev">ntpq old-rv</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">peers option (-p)</h4>
-
-<p><a name="index-ntpq_002dpeers-10"></a>
-This is the &ldquo;print a list of the peers&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-interactive.
-</ul>
-
- <p>Print a list of the peers known to the server as well as a summary
-of their state. This is equivalent to the 'peers' interactive command.
-<div class="node">
-<p><hr>
-<a name="ntpq-refid"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-wide">ntpq wide</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-peers">ntpq peers</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+<a name="peers-option-_0028_002dp_0029"></a>
+<h4 class="subsection">1.1.9 peers option (-p)</h4>
+<a name="index-ntpq_002dpeers"></a>
+
+<p>This is the &ldquo;print a list of the peers&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+interactive.
+</li></ul>
+
+<p>Print a list of the peers known to the server as well as a summary
+of their state. This is equivalent to the &rsquo;peers&rsquo; interactive command.
+</p><hr>
+<a name="ntpq-refid"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-wide" accesskey="n" rel="next">ntpq wide</a>, Previous: <a href="#ntpq-peers" accesskey="p" rel="prev">ntpq peers</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
+<a name="refid-option-_0028_002dr_0029"></a>
+<h4 class="subsection">1.1.10 refid option (-r)</h4>
+<a name="index-ntpq_002drefid"></a>
-<h4 class="subsection">refid option (-r)</h4>
-
-<p><a name="index-ntpq_002drefid-11"></a>
-This is the &ldquo;set default display type for s2+ refids&rdquo; option.
+<p>This is the &ldquo;set default display type for s2+ refids&rdquo; option.
This option takes a keyword argument.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>This option takes a keyword as its argument.
-The argument sets an enumeration value that can be tested by comparing the option value macro (OPT_VALUE_REFID).
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> This option takes a keyword as its argument.
+The argument sets an enumeration value that can be tested by comparing the option value macro (OPT_VALUE_REFID).
The available keywords are:
- <pre class="example"> hash ipv4
- </pre>
- <p>or their numeric equivalent.</ul>
-
- <p>Set the default display format for S2+ refids.
-<div class="node">
-<p><hr>
-<a name="ntpq-wide"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-config">ntpq config</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-refid">ntpq refid</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+<div class="example">
+<pre class="example"> hash ipv4
+</pre></div>
+
+<p>or their numeric equivalent.</p></li></ul>
+
+<p>Set the default display format for S2+ refids.
+</p><hr>
+<a name="ntpq-wide"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-config" accesskey="n" rel="next">ntpq config</a>, Previous: <a href="#ntpq-refid" accesskey="p" rel="prev">ntpq refid</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
+<a name="wide-option-_0028_002dw_0029"></a>
+<h4 class="subsection">1.1.11 wide option (-w)</h4>
+<a name="index-ntpq_002dwide"></a>
-<h4 class="subsection">wide option (-w)</h4>
-
-<p><a name="index-ntpq_002dwide-12"></a>
-This is the &ldquo;display the full 'remote' value&rdquo; option.
-Display the full value of the 'remote' value. If this requires
+<p>This is the &ldquo;display the full &rsquo;remote&rsquo; value&rdquo; option.
+Display the full value of the &rsquo;remote&rsquo; value. If this requires
more than 15 characters, display the full value, emit a newline,
and continue the data display properly indented on the next line.
+</p>
-<div class="node">
-<p><hr>
-<a name="ntpq-config"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpq-exit-status">ntpq exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-wide">ntpq wide</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+<hr>
+<a name="ntpq-config"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpq-exit-status" accesskey="n" rel="next">ntpq exit status</a>, Previous: <a href="#ntpq-wide" accesskey="p" rel="prev">ntpq wide</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">presetting/configuring ntpq</h4>
+<a name="presetting_002fconfiguring-ntpq"></a>
+<h4 class="subsection">1.1.12 presetting/configuring ntpq</h4>
<p>Any option that is not marked as <i>not presettable</i> may be preset by
-loading values from configuration ("rc" or "ini") files, and values from environment variables named <code>NTPQ</code> and <code>NTPQ_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
-the options listed above in upper case and segmented with underscores.
+loading values from configuration (&quot;rc&quot; or &quot;ini&quot;) files, and values from environment variables named <code>NTPQ</code> and <code>NTPQ_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
+the options listed above in upper case and segmented with underscores.
The <code>NTPQ</code> variable will be tokenized and parsed like
the command line. The remaining variables are tested for existence and their
values are treated like option arguments.
-
-<p class="noindent"><code>libopts</code> will search in 2 places for configuration files:
- <ul>
-<li>$HOME
-<li>$PWD
-</ul>
- The environment variables <code>HOME</code>, and <code>PWD</code>
-are expanded and replaced when <span class="file">ntpq</span> runs.
-For any of these that are plain files, they are simply processed.
-For any that are directories, then a file named <span class="file">.ntprc</span> is searched for
+</p>
+
+<p><code>libopts</code> will search in 2 places for configuration files:
+</p><ul>
+<li> $HOME
+</li><li> $PWD
+</li></ul>
+<p>The environment variables <code>HOME</code>, and <code>PWD</code>
+are expanded and replaced when <samp>ntpq</samp> runs.
+For any of these that are plain files, they are simply processed.
+For any that are directories, then a file named <samp>.ntprc</samp> is searched for
within that directory and processed.
-
- <p>Configuration files may be in a wide variety of formats.
+</p>
+<p>Configuration files may be in a wide variety of formats.
The basic format is an option name followed by a value (argument) on the
same line. Values may be separated from the option name with a colon,
equal sign or simply white space. Values may be continued across multiple
lines by escaping the newline with a backslash.
-
- <p>Multiple programs may also share the same initialization file.
+</p>
+<p>Multiple programs may also share the same initialization file.
Common options are collected at the top, followed by program specific
segments. The segments are separated by lines like:
-<pre class="example"> [NTPQ]
-</pre>
- <p class="noindent">or by
-<pre class="example"> &lt;?program ntpq&gt;
-</pre>
- <p class="noindent">Do not mix these styles within one configuration file.
-
- <p>Compound values and carefully constructed string values may also be
+</p><div class="example">
+<pre class="example">[NTPQ]
+</pre></div>
+<p>or by
+</p><div class="example">
+<pre class="example">&lt;?program ntpq&gt;
+</pre></div>
+<p>Do not mix these styles within one configuration file.
+</p>
+<p>Compound values and carefully constructed string values may also be
specified using XML syntax:
-<pre class="example"> &lt;option-name&gt;
- &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
- &lt;/option-name&gt;
-</pre>
- <p class="noindent">yielding an <code>option-name.sub-opt</code> string value of
-<pre class="example"> "...&lt;...&gt;..."
-</pre>
- <p><code>AutoOpts</code> does not track suboptions. You simply note that it is a
+</p><div class="example">
+<pre class="example">&lt;option-name&gt;
+ &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
+&lt;/option-name&gt;
+</pre></div>
+<p>yielding an <code>option-name.sub-opt</code> string value of
+</p><div class="example">
+<pre class="example">&quot;...&lt;...&gt;...&quot;
+</pre></div>
+<p><code>AutoOpts</code> does not track suboptions. You simply note that it is a
hierarchicly valued option. <code>AutoOpts</code> does provide a means for searching
the associated name/value pair list (see: optionFindValue).
-
- <p>The command line options relating to configuration and/or usage help are:
-
-<h5 class="subsubheading">version (-)</h5>
+</p>
+<p>The command line options relating to configuration and/or usage help are:
+</p>
+<a name="version-_0028_002d_0029"></a>
+<h4 class="subsubheading">version (-)</h4>
<p>Print the program version to standard out, optionally with licensing
information, then exit 0. The optional argument specifies how much licensing
-detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
+detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
Only the first letter of the argument is examined:
-
- <dl>
-<dt><span class="samp">version</span><dd>Only print the version. This is the default.
-<br><dt><span class="samp">copyright</span><dd>Name the copyright usage licensing terms.
-<br><dt><span class="samp">verbose</span><dd>Print the full copyright usage licensing terms.
+</p>
+<dl compact="compact">
+<dt>&lsquo;<samp>version</samp>&rsquo;</dt>
+<dd><p>Only print the version. This is the default.
+</p></dd>
+<dt>&lsquo;<samp>copyright</samp>&rsquo;</dt>
+<dd><p>Name the copyright usage licensing terms.
+</p></dd>
+<dt>&lsquo;<samp>verbose</samp>&rsquo;</dt>
+<dd><p>Print the full copyright usage licensing terms.
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
-<a name="ntpq-exit-status"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-config">ntpq config</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpq-Invocation">ntpq Invocation</a>
-<br>
+<hr>
+<a name="ntpq-exit-status"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntpq-config" accesskey="p" rel="prev">ntpq config</a>, Up: <a href="#ntpq-Invocation" accesskey="u" rel="up">ntpq Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntpq exit status</h4>
+<a name="ntpq-exit-status-1"></a>
+<h4 class="subsection">1.1.13 ntpq exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
-<br><dt><span class="samp">66 (EX_NOINPUT)</span><dd>A specified configuration file could not be loaded.
-<br><dt><span class="samp">70 (EX_SOFTWARE)</span><dd>libopts had an internal operational error. Please report
-it to autogen-users@lists.sourceforge.net. Thank you.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
+<dt>&lsquo;<samp>66 (EX_NOINPUT)</samp>&rsquo;</dt>
+<dd><p>A specified configuration file could not be loaded.
+</p></dd>
+<dt>&lsquo;<samp>70 (EX_SOFTWARE)</samp>&rsquo;</dt>
+<dd><p>libopts had an internal operational error. Please report
+it to autogen-users@lists.sourceforge.net. Thank you.
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
-<a name="Usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Internal-Commands">Internal Commands</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpq-Description">ntpq Description</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+<hr>
+<a name="Usage"></a>
+<div class="header">
+<p>
+Next: <a href="#Internal-Commands" accesskey="n" rel="next">Internal Commands</a>, Previous: <a href="#ntpq-Description" accesskey="p" rel="prev">ntpq Description</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Usage</h3>
-
-<p><table summary=""><tr align="left"><th valign="top" width="23%">What </th><th valign="top" width="23%">Default </th><th valign="top" width="5%">Flag </th><th valign="top" width="15%">Option
-<br></th></tr><tr align="left"><td valign="top" width="23%">configuration file
-</td><td valign="top" width="23%"><code>/etc/ntp.conf</code>
-</td><td valign="top" width="5%"><code>-c</code>
-</td><td valign="top" width="15%"><code>conffile</code>
-<br></td></tr><tr align="left"><td valign="top" width="23%">frequency file
-</td><td valign="top" width="23%">none
-</td><td valign="top" width="5%"><code>-f</code>
-</td><td valign="top" width="15%"><code>driftfile</code>
-<br></td></tr><tr align="left"><td valign="top" width="23%">leapseconds file
-</td><td valign="top" width="23%">none
-</td><td valign="top" width="5%">
-</td><td valign="top" width="15%"><code>leapfile</code>
-<br></td></tr><tr align="left"><td valign="top" width="23%">process ID file
-</td><td valign="top" width="23%">none
-</td><td valign="top" width="5%"><code>-p</code>
-</td><td valign="top" width="15%"><code>pidfile</code>
-<br></td></tr><tr align="left"><td valign="top" width="23%">log file
-</td><td valign="top" width="23%">system log
-</td><td valign="top" width="5%"><code>-l</code>
-</td><td valign="top" width="15%"><code>logfile</code>
-<br></td></tr><tr align="left"><td valign="top" width="23%">include file
-</td><td valign="top" width="23%">none
-</td><td valign="top" width="5%">none
-</td><td valign="top" width="15%"><code>includefile</code>
-<br></td></tr><tr align="left"><td valign="top" width="23%">statistics path
-</td><td valign="top" width="23%"><code>/var/NTP</code>
-</td><td valign="top" width="5%"><code>-s</code>
-</td><td valign="top" width="15%"><code>statsdir</code>
-<br></td></tr><tr align="left"><td valign="top" width="23%">keys path
-</td><td valign="top" width="23%"><code>/usr/local/etc</code>
-</td><td valign="top" width="5%"><code>-k</code>
-</td><td valign="top" width="15%"><code>keysdir</code>
-<br></td></tr></table>
-
-<div class="node">
-<p><hr>
-<a name="Internal-Commands"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Control-Message-Commands">Control Message Commands</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Usage">Usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+<a name="Usage-1"></a>
+<h3 class="section">1.2 Usage</h3>
+
+<table>
+<thead><tr><th width="23%">What</th><th width="23%">Default</th><th width="5%">Flag</th><th width="15%">Option</th></tr></thead>
+<tr><td width="23%">configuration file</td><td width="23%"><code>/etc/ntp.conf</code></td><td width="5%"><code>-c</code></td><td width="15%"><code>conffile</code></td></tr>
+<tr><td width="23%">frequency file</td><td width="23%">none</td><td width="5%"><code>-f</code></td><td width="15%"><code>driftfile</code></td></tr>
+<tr><td width="23%">leapseconds file</td><td width="23%">none</td><td width="5%"></td><td width="15%"><code>leapfile</code></td></tr>
+<tr><td width="23%">process ID file</td><td width="23%">none</td><td width="5%"><code>-p</code></td><td width="15%"><code>pidfile</code></td></tr>
+<tr><td width="23%">log file</td><td width="23%">system log</td><td width="5%"><code>-l</code></td><td width="15%"><code>logfile</code></td></tr>
+<tr><td width="23%">include file</td><td width="23%">none</td><td width="5%">none</td><td width="15%"><code>includefile</code></td></tr>
+<tr><td width="23%">statistics path</td><td width="23%"><code>/var/NTP</code></td><td width="5%"><code>-s</code></td><td width="15%"><code>statsdir</code></td></tr>
+<tr><td width="23%">keys path</td><td width="23%"><code>/usr/local/etc</code></td><td width="5%"><code>-k</code></td><td width="15%"><code>keysdir</code></td></tr>
+</table>
+
+<hr>
+<a name="Internal-Commands"></a>
+<div class="header">
+<p>
+Next: <a href="#Control-Message-Commands" accesskey="n" rel="next">Control Message Commands</a>, Previous: <a href="#Usage" accesskey="p" rel="prev">Usage</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Internal Commands</h3>
+<a name="Internal-Commands-2"></a>
+<h3 class="section">1.3 Internal Commands</h3>
<p>Interactive format commands consist of a keyword followed by zero to four arguments. Only enough characters of the full keyword to uniquely identify the command need be typed. The output of a command is normally sent to the standard output, but optionally the output of individual commands may be sent to a file by appending a <code>&gt;</code>, followed by a file name, to the command line. A number of interactive format commands are executed entirely within the <code>ntpq</code> program itself and do not result in NTP mode-6 requests being sent to a server. These are described following.
-
- <dl>
-<dt><code><a name="help"></a> ? [</code><kbd>command_keyword</kbd><code>]</code><dt><code>help [</code><kbd>command_keyword</kbd><code>]</code><dd>A <code>?</code> by itself will print a list of all the command keywords known to <code>ntpq</code>. A <code>?</code> followed by a command keyword will print function and usage information about the command.
-
- <br><dt><code><a name="addvars"></a> &gt;addvars </code><kbd>name</kbd><code> [ = </code><kbd>value</kbd><code>] [...]</code><dt><code>rmvars </code><kbd>name</kbd><code> [...]</code><dt><code>clearvars&lt;/dt&gt;</code><dd>The arguments to these commands consist of a list of items of the form
-<kbd>name</kbd><code> = </code><kbd>value</kbd>, where the <code>= </code><kbd>value</kbd> is ignored,
-and can be omitted in read requests.
+</p>
+<dl compact="compact">
+<dt><code><a name="help"></a><code>? [</code><kbd>command_keyword</kbd><code>]</code></code></dt>
+<dt><code><code>help [</code><kbd>command_keyword</kbd><code>]</code></code></dt>
+<dd><p>A <code>?</code> by itself will print a list of all the command keywords known to <code>ntpq</code>. A <code>?</code> followed by a command keyword will print function and usage information about the command.
+</p>
+</dd>
+<dt><code><a name="addvars"></a>&gt;<code>addvars <kbd>name</kbd> [ = <kbd>value</kbd>] [...]</code></code></dt>
+<dt><code><code>rmvars <kbd>name</kbd> [...]</code></code></dt>
+<dt><code><code>clearvars</code>&lt;/dt&gt;</code></dt>
+<dd><p>The arguments to these commands consist of a list of items of the form
+<code><kbd>name</kbd> = <kbd>value</kbd></code>, where the <code>= <kbd>value</kbd></code> is ignored,
+and can be omitted in read requests.
<code>ntpq</code> maintains an internal list in which data to be included
in control messages can be assembled, and sent using the <code>readlist</code>
-and <code>writelist</code> commands described below.
+and <code>writelist</code> commands described below.
The <code>addvars</code> command allows variables and optional values
-to be added to the list.
+to be added to the list.
If more than one variable is to be added
-the list should be comma-separated and not contain white space.
+the list should be comma-separated and not contain white space.
The <code>rmvars</code> command can be used to remove individual variables
from the list,
while the <code>clearlist</code> command removes all variables from the list.
-
- <br><dt><code><a name="cooked"></a> cooked</code><dd>Display server messages in prettyprint format.
-
- <br><dt><code><a name="debug"></a> debug more | less | off</code><dd>Turns internal query program debugging on and off.
-
- <br><dt><code><a name="delay"></a> delay </code><kbd>milliseconds</kbd><dd>Specify a time interval to be added to timestamps included in requests which require authentication. This is used to enable (unreliable) server reconfiguration over long delay network paths or between machines whose clocks are unsynchronized. Actually the server does not now require timestamps in authenticated requests, so this command may be obsolete.
-
- <br><dt><code><a name="host"></a> host </code><kbd>name</kbd><dd>Set the host to which future queries will be sent.
+</p>
+</dd>
+<dt><code><a name="cooked"></a><code>cooked</code></code></dt>
+<dd><p>Display server messages in prettyprint format.
+</p>
+</dd>
+<dt><code><a name="debug"></a><code>debug more | less | off</code></code></dt>
+<dd><p>Turns internal query program debugging on and off.
+</p>
+</dd>
+<dt><code><a name="delay"></a><code>delay <kbd>milliseconds</kbd></code></code></dt>
+<dd><p>Specify a time interval to be added to timestamps included in requests which require authentication. This is used to enable (unreliable) server reconfiguration over long delay network paths or between machines whose clocks are unsynchronized. Actually the server does not now require timestamps in authenticated requests, so this command may be obsolete.
+</p>
+</dd>
+<dt><code><a name="host"></a><code>host <kbd>name</kbd></code></code></dt>
+<dd><p>Set the host to which future queries will be sent.
The name may be either a DNS name or a numeric address.
-
- <br><dt><code><a name="hostnames"></a> hostnames [yes | no]</code><dd>If <code>yes</code> is specified, host names are printed in information displays.
-If <code>no</code> is specified, numeric addresses are printed instead.
+</p>
+</dd>
+<dt><code><a name="hostnames"></a><code>hostnames [yes | no]</code></code></dt>
+<dd><p>If <code>yes</code> is specified, host names are printed in information displays.
+If <code>no</code> is specified, numeric addresses are printed instead.
The default is <code>yes</code>,
unless modified using the command line <code>-n</code> switch.
-
- <br><dt><code><a name="keyid"></a> keyid </code><kbd>keyid</kbd><dd>This command specifies the key number to be used
-to authenticate configuration requests.
+</p>
+</dd>
+<dt><code><a name="keyid"></a><code>keyid <kbd>keyid</kbd></code></code></dt>
+<dd><p>This command specifies the key number to be used
+to authenticate configuration requests.
This must correspond to a key ID configured in <code>ntp.conf</code> for this purpose.
-
- <br><dt><code><a name="keytype"></a> keytype</code><dd>Specify the digest algorithm to use for authenticated requests,
-with default <code>MD5</code>.
+</p>
+</dd>
+<dt><code><a name="keytype"></a><code>keytype</code></code></dt>
+<dd><p>Specify the digest algorithm to use for authenticated requests,
+with default <code>MD5</code>.
If the OpenSSL library is installed,
-digest can be be any message digest algorithm supported by the library.
+digest can be be any message digest algorithm supported by the library.
The current selections are: <code>AES128CMAC</code>, <code>MD2</code>, <code>MD4</code>, <code>MD5</code>, <code>MDC2</code>, <code>RIPEMD160</code>, <code>SHA</code> and <code>SHA1</code>.
-
- <br><dt><code><a name="ntpversion"></a> ntpversion 1 | 2 | 3 | 4</code><dd>Sets the NTP version number which <code>ntpq</code> claims in packets.
-Defaults to 2.
+</p>
+</dd>
+<dt><code><a name="ntpversion"></a><code>ntpversion 1 | 2 | 3 | 4</code></code></dt>
+<dd><p>Sets the NTP version number which <code>ntpq</code> claims in packets.
+Defaults to 2.
Note that mode-6 control messages (and modes, for that matter)
-didn't exist in NTP version 1.
-
- <br><dt><code><a name="passwd"></a> passwd</code><dd>This command prompts for a password to authenticate requests.
+didn&rsquo;t exist in NTP version 1.
+</p>
+</dd>
+<dt><code><a name="passwd"></a><code>passwd</code></code></dt>
+<dd><p>This command prompts for a password to authenticate requests.
The password must correspond to the key ID configured in <code>ntp.conf</code> for this purpose.
-
- <br><dt><code><a name="quit"></a> quit</code><dd>Exit <code>ntpq</code>.
-
- <br><dt><code><a name="raw"></a> raw</code><dd>Display server messages as received and without reformatting.
-
- <br><dt><code><a name="timeout"></a> timeout </code><kbd>millseconds</kbd><dd>Specify a timeout period for responses to server queries.
-The default is about 5000 milliseconds.
+</p>
+</dd>
+<dt><code><a name="quit"></a><code>quit</code></code></dt>
+<dd><p>Exit <code>ntpq</code>.
+</p>
+</dd>
+<dt><code><a name="raw"></a><code>raw</code></code></dt>
+<dd><p>Display server messages as received and without reformatting.
+</p>
+</dd>
+<dt><code><a name="timeout"></a><code>timeout <kbd>milliseconds</kbd></code></code></dt>
+<dd><p>Specify a timeout period for responses to server queries.
+The default is about 5000 milliseconds.
Note that since <code>ntpq</code> retries each query once after a timeout
the total waiting time for a timeout will be twice the timeout value set.
+</p>
+</dd>
+</dl>
- </dl>
-
-<div class="node">
-<p><hr>
-<a name="Control-Message-Commands"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Status-Words-and-Kiss-Codes">Status Words and Kiss Codes</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Internal-Commands">Internal Commands</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+<hr>
+<a name="Control-Message-Commands"></a>
+<div class="header">
+<p>
+Next: <a href="#Status-Words-and-Kiss-Codes" accesskey="n" rel="next">Status Words and Kiss Codes</a>, Previous: <a href="#Internal-Commands" accesskey="p" rel="prev">Internal Commands</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
+<a name="Control-Message-Commands-2"></a>
+<h3 class="section">1.4 Control Message Commands</h3>
-<!-- node-name, next, previous, up -->
-<h3 class="section">Control Message Commands</h3>
-
-<p>Association IDs are used to identify system, peer and clock variables.
+<p>Association IDs are used to identify system, peer and clock variables.
System variables are assigned an association ID of zero and system name space,
-while each association is assigned a nonzero association ID and peer namespace.
+while each association is assigned a nonzero association ID and peer namespace.
Most control commands send a single mode-6 message to the server
-and expect a single response message.
+and expect a single response message.
The exceptions are the <code>peers</code> command,
which sends a series of messages,
and the <code>mreadlist</code> and <code>mreadvar</code> commands,
which iterate over a range of associations.
-
- <p><a name="as"></a>
- <dl>
-<dt><code>associations</code><dd>Display a list of mobilized associations in the form:
+</p>
+<a name="as"></a><dl compact="compact">
+<dt><code><code>associations</code></code></dt>
+<dd><p>Display a list of mobilized associations in the form:
<br>
<code>ind assid status conf reach auth condition last_event cnt</code>
-
- <p><table summary=""><tr align="left"><th valign="top" width="10%">Variable </th><th valign="top" width="40%">Description
-
- <p><br></th></tr><tr align="left"><td valign="top" width="10%"><code>ind</code>
-</td><td valign="top" width="40%">index on this list
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>assid</code>
-</td><td valign="top" width="40%">association ID
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>status</code>
-</td><td valign="top" width="40%"><a href="decode.html#peer">peer status word</a>
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>conf</code>
-</td><td valign="top" width="40%"><code>yes</code>: persistent, <code>no</code>: ephemeral
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>reach</code>
-</td><td valign="top" width="40%"><code>yes</code>: reachable, <code>no</code>: unreachable
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>auth</code>
-</td><td valign="top" width="40%"><code>ok</code>, <code>yes</code>, <code>bad</code> and <code>none</code>
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>condition</code>
-</td><td valign="top" width="40%">selection status (see the <code>select</code> field of the <a href="decode.html#peer">peer status word</a>)
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>last_event</code>
-</td><td valign="top" width="40%">event report (see the <code>event</code> field of the <a href="decode.html#peer">peer status word</a>)
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>cnt</code>
-event count (see the <code>count</code> field of the <a href="decode.html#peer">peer status word</a>)
-
- <br></td></tr></table>
-
- <br><dt><code><a name="cv"></a> clockvar </code><kbd>assocID</kbd><code> [</code><kbd>name</kbd><code> [ = </code><kbd>value</kbd><code> [...]] [...]]</code><dt><code>cv </code><kbd>assocID</kbd><code> [</code><kbd>name</kbd><code> [ = </code><kbd>value</kbd><code> [...] ][...]]</code><dd>Display a list of <a href="#clock">clock variables</a> for those associations supporting a reference clock.
-
- <br><dt><code><a name="_003aconfig"></a> :config [...]</code><dd>Send the remainder of the command line, including whitespace, to the server
+</p>
+<table>
+<thead><tr><th width="10%">Variable</th><th width="40%">Description</th></tr></thead>
+<tr><td width="10%"><code>ind</code></td><td width="40%">index on this list</td></tr>
+<tr><td width="10%"><code>assid</code></td><td width="40%">association ID</td></tr>
+<tr><td width="10%"><code>status</code></td><td width="40%"><a href="decode.html#peer">peer status word</a></td></tr>
+<tr><td width="10%"><code>conf</code></td><td width="40%"><code>yes</code>: persistent, <code>no</code>: ephemeral</td></tr>
+<tr><td width="10%"><code>reach</code></td><td width="40%"><code>yes</code>: reachable, <code>no</code>: unreachable</td></tr>
+<tr><td width="10%"><code>auth</code></td><td width="40%"><code>ok</code>, <code>yes</code>, <code>bad</code> and <code>none</code></td></tr>
+<tr><td width="10%"><code>condition</code></td><td width="40%">selection status (see the <code>select</code> field of the <a href="decode.html#peer">peer status word</a>)</td></tr>
+<tr><td width="10%"><code>last_event</code></td><td width="40%">event report (see the <code>event</code> field of the <a href="decode.html#peer">peer status word</a>)</td></tr>
+<tr><td width="10%"><code>cnt</code>
+event count (see the <code>count</code> field of the <a href="decode.html#peer">peer status word</a>)</td></tr>
+</table>
+
+</dd>
+<dt><code><a name="cv"></a>clockvar <kbd>assocID</kbd> [<kbd>name</kbd> [ = <kbd>value</kbd> [...]] [...]]</code></dt>
+<dt><code>cv <kbd>assocID</kbd> [<kbd>name</kbd> [ = <kbd>value</kbd> [...] ][...]]</code></dt>
+<dd><p>Display a list of &lsquo;clock variables&rsquo; for those associations supporting a reference clock.
+</p>
+</dd>
+<dt><code><a name="g_t_003aconfig"></a>:config [...]</code></dt>
+<dd><p>Send the remainder of the command line, including whitespace, to the server
as a run-time configuration command in the same format
-as the configuration file.
-This command is experimental until further notice and clarification.
+as the configuration file.
+This command is experimental until further notice and clarification.
Authentication is of course required.
-
- <br><dt><code><a name="config_002dfrom_002dfile"></a> config-from-file </code><kbd>filename</kbd><dd>Send the each line of <kbd>filename</kbd> to the server as
-run-time configuration commands in the same format as the configuration file.
-This command is experimental until further notice and clarification.
+</p>
+</dd>
+<dt><code><a name="config_002dfrom_002dfile"></a>config-from-file <kbd>filename</kbd></code></dt>
+<dd><p>Send the each line of <kbd>filename</kbd> to the server as
+run-time configuration commands in the same format as the configuration file.
+This command is experimental until further notice and clarification.
Authentication is required.
-
- <br><dt><code><a name="ifstats"></a> ifstats</code><dd>Display statistics for each local network address.
+</p>
+</dd>
+<dt><code><a name="ifstats"></a>ifstats</code></dt>
+<dd><p>Display statistics for each local network address.
Authentication is required.
-
- <br><dt><code><a name="iostats"></a> iostats</code><dd>Display network and reference clock I/O statistics.
-
- <br><dt><code><a name="kerninfo"></a> kerninfo</code><dd>Display kernel loop and PPS statistics.
-As with other ntpq output, times are in milliseconds.
+</p>
+</dd>
+<dt><code><a name="iostats"></a>iostats</code></dt>
+<dd><p>Display network and reference clock I/O statistics.
+</p>
+</dd>
+<dt><code><a name="kerninfo"></a>kerninfo</code></dt>
+<dd><p>Display kernel loop and PPS statistics.
+As with other ntpq output, times are in milliseconds.
The precision value displayed is in milliseconds as well,
unlike the precision system variable.
-
- <br><dt><code><a name="lassoc"></a> lassociations</code><dd>Perform the same function as the associations command,
+</p>
+</dd>
+<dt><code><a name="lassoc"></a>lassociations</code></dt>
+<dd><p>Perform the same function as the associations command,
except display mobilized and unmobilized associations.
-
- <br><dt><code><a name="monstats"></a> monstats</code><dd>Display monitor facility statistics.
-
- <br><dt><code><a name="mrulist"></a> mrulist [limited | kod | mincount=</code><kbd>count</kbd><code> | laddr=</code><kbd>localaddr</kbd><code> | sort=</code><kbd>sortorder</kbd><code> | resany=</code><kbd>hexmask</kbd><code> | resall=</code><kbd>hexmask</kbd><code>]</code><dd>Obtain and print traffic counts collected and maintained by
-the monitor facility.
-With the exception of <code>sort=</code><kbd>sortorder</kbd>,
-the options filter the list returned by <code>ntpd</code>.
+</p>
+</dd>
+<dt><code><a name="monstats"></a>monstats</code></dt>
+<dd><p>Display monitor facility statistics.
+</p>
+</dd>
+<dt><code><a name="mrulist"></a>mrulist [limited | kod | mincount=<kbd>count</kbd> | laddr=<kbd>localaddr</kbd> | sort=<kbd>sortorder</kbd> | resany=<kbd>hexmask</kbd> | resall=<kbd>hexmask</kbd>]</code></dt>
+<dd><p>Obtain and print traffic counts collected and maintained by
+the monitor facility.
+With the exception of <code>sort=<kbd>sortorder</kbd></code>,
+the options filter the list returned by <code>ntpd</code>.
The <code>limited</code> and <code>kod</code> options return only entries
representing client addresses from which the last packet received
-triggered either discarding or a KoD response.
-The <code>mincount=</code><kbd>count</kbd> option filters entries representing
-less than <kbd>count</kbd> packets.
-The <code>laddr=</code><kbd>localaddr</kbd> option filters entries for packets
-received on any local address other than <kbd>localaddr</kbd>.
-<code>resany=</code><kbd>hexmask</kbd> and <code>resall=</code><kbd>hexmask</kbd>
+triggered either discarding or a KoD response.
+The <code>mincount=<kbd>count</kbd></code> option filters entries representing
+less than <code><kbd>count</kbd></code> packets.
+The <code>laddr=<kbd>localaddr</kbd></code> option filters entries for packets
+received on any local address other than <code><kbd>localaddr</kbd></code>.
+<code>resany=<kbd>hexmask</kbd></code> and <code>resall=<kbd>hexmask</kbd></code>
filter entries containing none or less than all, respectively,
-of the bits in <kbd>hexmask</kbd>, which must begin with <code>0x</code>.
+of the bits in <code><kbd>hexmask</kbd></code>, which must begin with <code>0x</code>.
<br>
-The <kbd>sortorder</kbd> defaults to <code>lstint</code> and may be any of
+The <code><kbd>sortorder</kbd></code> defaults to <code>lstint</code> and may be any of
<code>addr</code>, <code>count</code>, <code>avgint</code>, <code>lstint</code>, or
-any of those preceded by a minus sign (hyphen) to reverse the sort order.
+any of those preceded by a minus sign (hyphen) to reverse the sort order.
The output columns are:
-
- <p><table summary=""><tr align="left"><th valign="top" width="10%">Column </th><th valign="top" width="40%">Description
-
- <p><br></th></tr><tr align="left"><td valign="top" width="10%"><code>lstint</code>
-</td><td valign="top" width="40%">
-Interval in s between the receipt of the most recent packet from this
-address and the completion of the retrieval of the MRU list by <code>ntpq</code>
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>avgint</code>
-</td><td valign="top" width="40%">
-Average interval in s between packets from this address.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>rstr</code>
-</td><td valign="top" width="40%">
-Restriction flags associated with this address.
+</p>
+<table>
+<thead><tr><th width="10%">Column</th><th width="40%">Description</th></tr></thead>
+<tr><td width="10%"><code>lstint</code></td><td width="40%">Interval in s between the receipt of the most recent packet from this
+address and the completion of the retrieval of the MRU list by <code>ntpq</code></td></tr>
+<tr><td width="10%"><code>avgint</code></td><td width="40%">Average interval in s between packets from this address.</td></tr>
+<tr><td width="10%"><code>rstr</code></td><td width="40%">Restriction flags associated with this address.
Most are copied unchanged from the matching <code>restrict</code> command,
however 0x400 (kod) and 0x20 (limited) flags are cleared unless
-the last packet from this address triggered a rate control response.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>r</code>
-</td><td valign="top" width="40%">
-Rate control indicator, either a period, <code>L</code> or <code>K</code> for
+the last packet from this address triggered a rate control response.</td></tr>
+<tr><td width="10%"><code>r</code></td><td width="40%">Rate control indicator, either a period, <code>L</code> or <code>K</code> for
no rate control response, rate limiting by discarding, or
-rate limiting with a KoD response, respectively.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>m</code>
-</td><td valign="top" width="40%">
-Packet mode.
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>v</code>
-</td><td valign="top" width="40%">
-Packet version number.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>count</code>
-</td><td valign="top" width="40%">
-Packets received from this address.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>rport</code>
-</td><td valign="top" width="40%">
-Source port of last packet from this address.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>remote address</code>
-</td><td valign="top" width="40%">
-DNS name, numeric address, or address followed by claimed DNS name which
-could not be verified in parentheses.
-
- <br></td></tr></table>
-
- <br><dt><code><a name="mreadvar"></a> mreadvar </code><kbd>assocID</kbd> <kbd>assocID</kbd><code> [ </code><kbd>variable_name</kbd><code> [ = </code><kbd>value</kbd><code>[ ... ]</code><dt><code><a name="mrv"></a> mrv </code><kbd>assocID</kbd> <kbd>assocID</kbd><code> [ </code><kbd>variable_name</kbd><code> [ = </code><kbd>value</kbd><code>[ ... ]</code><dd>Perform the same function as the <code>readvar</code> command,
-except for a range of association IDs.
+rate limiting with a KoD response, respectively.</td></tr>
+<tr><td width="10%"><code>m</code></td><td width="40%">Packet mode.</td></tr>
+<tr><td width="10%"><code>v</code></td><td width="40%">Packet version number.</td></tr>
+<tr><td width="10%"><code>count</code></td><td width="40%">Packets received from this address.</td></tr>
+<tr><td width="10%"><code>rport</code></td><td width="40%">Source port of last packet from this address.</td></tr>
+<tr><td width="10%"><code>remote address</code></td><td width="40%">DNS name, numeric address, or address followed by claimed DNS name which
+could not be verified in parentheses.</td></tr>
+</table>
+
+</dd>
+<dt><code><a name="mreadvar"></a><code>mreadvar <kbd>assocID</kbd> <kbd>assocID</kbd> [ <kbd>variable_name</kbd> [ = <kbd>value</kbd>[ ... ]</code></code></dt>
+<dt><code><a name="mrv"></a><code>mrv <kbd>assocID</kbd> <kbd>assocID</kbd> [ <kbd>variable_name</kbd> [ = <kbd>value</kbd>[ ... ]</code></code></dt>
+<dd><p>Perform the same function as the <code>readvar</code> command,
+except for a range of association IDs.
This range is determined from the association list cached by
the most recent <code>associations</code> command.
-
- <br><dt><code><a name="passoc"></a> passociations</code><dd>Perform the same function as the <code>associations command</code>, except that
+</p>
+</dd>
+<dt><code><a name="passoc"></a><code>passociations</code></code></dt>
+<dd><p>Perform the same function as the <code>associations command</code>, except that
it uses previously stored data rather than making a new query.
-
- <br><dt><code><a name="pe"></a> peers</code><dd>Display a list of peers in the form:
+</p>
+</dd>
+<dt><code><a name="pe"></a><code>peers</code></code></dt>
+<dd><p>Display a list of peers in the form:
<br>
<code>[tally]remote refid st t when pool reach delay offset jitter</code>
-
- <p><table summary=""><tr align="left"><th valign="top" width="10%">Variable </th><th valign="top" width="20%">Description
-<br></th></tr><tr align="left"><td valign="top" width="10%"><code>[tally]</code>
-</td><td valign="top" width="20%">
-single-character code indicating current value of the <code>select</code> field
-of the <a href="decode.html#peer">peer status word</a>.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>remote</code>
-</td><td valign="top" width="20%">
-host name (or IP number) of peer
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>refid</code>
-</td><td valign="top" width="20%">
-association ID or <a href="decode.html#kiss">kiss code</a>.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>st</code>
-</td><td valign="top" width="20%">
-stratum
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>t</code>
-</td><td valign="top" width="20%">
-<code>u</code>: unicast or manycast client,
+</p>
+<table>
+<thead><tr><th width="10%">Variable</th><th width="20%">Description</th></tr></thead>
+<tr><td width="10%"><code>[tally]</code></td><td width="20%">single-character code indicating current value of the <code>select</code> field
+of the <a href="decode.html#peer">peer status word</a>.</td></tr>
+<tr><td width="10%"><code>remote</code></td><td width="20%">host name (or IP number) of peer</td></tr>
+<tr><td width="10%"><code>refid</code></td><td width="20%">association ID or <a href="decode.html#kiss">kiss code</a>.</td></tr>
+<tr><td width="10%"><code>st</code></td><td width="20%">stratum</td></tr>
+<tr><td width="10%"><code>t</code></td><td width="20%"><code>u</code>: unicast or manycast client,
<code>b</code>: broadcast or multicast client,
<code>l</code>: local (reference clock),
<code>s</code>: symmetric (peer),
<code>A</code>: manycast server,
<code>B</code>: broadcast server,
-<code>M</code>: multicast server.
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>when</code>
-</td><td valign="top" width="20%">
-sec/min/hr since last received packet
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>poll</code>
-</td><td valign="top" width="20%">
-poll interval (log(2) s)
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>reach</code>
-</td><td valign="top" width="20%">
-reach shift register (octal)
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>delay</code>
-</td><td valign="top" width="20%">
-roundtrip delay
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>offset</code>
-</td><td valign="top" width="20%">
-offset of server relative to this host
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>jitter</code>
-</td><td valign="top" width="20%">
-jitter
-
- <br></td></tr></table>
-
- <br><dt><code><a name="rv"></a> readvar </code><kbd>assocID</kbd> <kbd>name</kbd><code> [ = </code><kbd>value</kbd><code> ] [,...]</code><dt><code>rv </code><kbd>assocID</kbd><code> [ </code><kbd>name</kbd><code> ] [,...]</code><dd>Display the specified variables.
-If <kbd>assocID</kbd> is zero,
-the variables are from the <a href="#system">system variables</a> name space,
-otherwise they are from the <a href="#peer">peer variables</a> name space.
-The <kbd>assocID</kbd> is required, as the same name can occur in both spaces.
+<code>M</code>: multicast server.</td></tr>
+<tr><td width="10%"><code>when</code></td><td width="20%">sec/min/hr since last received packet</td></tr>
+<tr><td width="10%"><code>poll</code></td><td width="20%">poll interval (log(2) s)</td></tr>
+<tr><td width="10%"><code>reach</code></td><td width="20%">reach shift register (octal)</td></tr>
+<tr><td width="10%"><code>delay</code></td><td width="20%">roundtrip delay</td></tr>
+<tr><td width="10%"><code>offset</code></td><td width="20%">offset of server relative to this host</td></tr>
+<tr><td width="10%"><code>jitter</code></td><td width="20%">jitter</td></tr>
+</table>
+
+</dd>
+<dt><code><a name="rv"></a>readvar <kbd>assocID</kbd> <kbd>name</kbd> [ = <kbd>value</kbd> ] [,...]</code></dt>
+<dt><code>rv <kbd>assocID</kbd> [ <kbd>name</kbd> ] [,...]</code></dt>
+<dd><p>Display the specified variables.
+If <code><kbd>assocID</kbd></code> is zero,
+the variables are from the &lsquo;system variables&rsquo; name space,
+otherwise they are from the &lsquo;peer variables&rsquo; name space.
+The <kbd>assocID</kbd> is required, as the same name can occur in both spaces.
If no <kbd>name</kbd> is included,
-all operative variables in the name space are displayed.
-In this case only, if the <kbd>assocID</kbd> is omitted, it is assumed zero.
-Multiple names are specified with comma separators and without whitespace.
+all operative variables in the name space are displayed.
+In this case only, if the <code><kbd>assocID</kbd></code> is omitted, it is assumed zero.
+Multiple names are specified with comma separators and without whitespace.
Note that time values are represented in milliseconds and
-frequency values in parts-per-million (PPM).
+frequency values in parts-per-million (PPM).
Some NTP timestamps are represented in the format YYYYMMDDTTTT,
where YYYY is the year, MM the month of year, DD the day of month and
TTTT the time of day.
-
- <br><dt><code><a name="saveconfig"></a> saveconfig </code><kbd>filename</kbd><dd>Write the current configuration, including any runtime modifications
+</p>
+</dd>
+<dt><code><a name="saveconfig"></a><code>saveconfig <kbd>filename</kbd></code></code></dt>
+<dd><p>Write the current configuration, including any runtime modifications
given with <code>:config</code> or <code>config-from-file</code>,
-to the ntpd host's file <kbd>filename</kbd>.
+to the ntpd host&rsquo;s file <kbd>filename</kbd>.
This command will be rejected by the server unless
<a href="miscopt.html#saveconfigdir">saveconfigdir</a>
-appears in the <code>ntpd</code> configuration file.
+appears in the <code>ntpd</code> configuration file.
<kbd>filename</kbd> can use <code>strftime()</code> format specifiers
to substitute the current date and time, for example,
-<code>saveconfig ntp-%Y%m%d-%H%M%S.conf</code>.
-The filename used is stored in system variable <code>savedconfig</code>.
+<code>saveconfig ntp-%Y%m%d-%H%M%S.conf</code>.
+The filename used is stored in system variable <code>savedconfig</code>.
Authentication is required.
-
- <br><dt><code><a name="writevar"></a> writevar </code><kbd>assocID</kbd> <kbd>name</kbd><code> = </code><kbd>value</kbd><code> [,...]</code><dd>Write the specified variables.
-If the <kbd>assocID</kbd> is zero, the variables are from the
-<a href="#system">system variables</a> name space, otherwise they are from the
-<a href="#peer">peer variables</a> name space.
-The <kbd>assocID</kbd> is required,
+</p>
+</dd>
+<dt><code><a name="writevar"></a>writevar <kbd>assocID</kbd> <kbd>name</kbd> = <kbd>value</kbd> [,...]</code></dt>
+<dd><p>Write the specified variables.
+If the <code><kbd>assocID</kbd></code> is zero, the variables are from the
+&lsquo;system variables&rsquo; name space, otherwise they are from the
+&lsquo;peer variables&rsquo; name space.
+The <code><kbd>assocID</kbd></code> is required,
as the same name can occur in both spaces.
+</p>
+</dd>
+<dt><code><a name="sysinfo"></a><code>sysinfo</code></code></dt>
+<dd><p>Display operational summary.
+</p>
+</dd>
+<dt><code><a name="sysstats"></a><code>sysstats</code></code></dt>
+<dd><p>Print statistics counters maintained in the protocol module.
+</p>
+</dd>
+</dl>
- <br><dt><code><a name="sysinfo"></a> sysinfo</code><dd>Display operational summary.
-
- <br><dt><code><a name="sysstats"></a> sysstats</code><dd>Print statistics counters maintained in the protocol module.
-
- </dl>
-
-<div class="node">
-<p><hr>
-<a name="Status-Words-and-Kiss-Codes"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#System-Variables">System Variables</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Control-Message-Commands">Control Message Commands</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+<hr>
+<a name="Status-Words-and-Kiss-Codes"></a>
+<div class="header">
+<p>
+Next: <a href="#System-Variables" accesskey="n" rel="next">System Variables</a>, Previous: <a href="#Control-Message-Commands" accesskey="p" rel="prev">Control Message Commands</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Status Words and Kiss Codes</h3>
+<a name="Status-Words-and-Kiss-Codes-2"></a>
+<h3 class="section">1.5 Status Words and Kiss Codes</h3>
<p>The current state of the operating program is shown
in a set of status words maintained by the system
-and each association separately.
+and each association separately.
These words are displayed in the <code>rv</code> and <code>as</code> commands
-both in hexadecimal and decoded short tip strings.
+both in hexadecimal and decoded short tip strings.
The codes, tips and short explanations are on the
-<a href="decode.html">Event Messages and Status Words</a> page.
+<a href="decode.html">Event Messages and Status Words</a> page.
The page also includes a list of system and peer messages,
the code for the latest of which is included in the status word.
-
- <p>Information resulting from protocol machine state transitions
+</p>
+<p>Information resulting from protocol machine state transitions
is displayed using an informal set of ASCII strings called
-<a href="decode.html#kiss">kiss codes</a>.
-The original purpose was for kiss-o'-death (KoD) packets sent
-by the server to advise the client of an unusual condition.
+<a href="decode.html#kiss">kiss codes</a>.
+The original purpose was for kiss-o&rsquo;-death (KoD) packets sent
+by the server to advise the client of an unusual condition.
They are now displayed, when appropriate,
in the reference identifier field in various billboards.
-
-<div class="node">
-<p><hr>
-<a name="System-Variables"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Peer-Variables">Peer Variables</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Status-Words-and-Kiss-Codes">Status Words and Kiss Codes</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+</p>
+<hr>
+<a name="System-Variables"></a>
+<div class="header">
+<p>
+Next: <a href="#Peer-Variables" accesskey="n" rel="next">Peer Variables</a>, Previous: <a href="#Status-Words-and-Kiss-Codes" accesskey="p" rel="prev">Status Words and Kiss Codes</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
+<a name="System-Variables-2"></a>
+<h3 class="section">1.6 System Variables</h3>
-<!-- node-name, next, previous, up -->
-<h3 class="section">System Variables</h3>
-
-<p>The following system variables appear in the <code>rv</code> billboard.
+<p>The following system variables appear in the <code>rv</code> billboard.
Not all variables are displayed in some configurations.
-
- <p><table summary=""><tr align="left"><th valign="top" width="10%">Variable </th><th valign="top" width="20%">Description
-
-<p><br></th></tr><tr align="left"><td valign="top" width="10%"><code>status</code>
-</td><td valign="top" width="20%">
-<a href="decode.html#sys">system status word</a>
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>version</code>
-</td><td valign="top" width="20%">
-NTP software version and build time
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>processor</code>
-</td><td valign="top" width="20%">
-hardware platform and version
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>system</code>
-</td><td valign="top" width="20%">
-operating system and version
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>leap</code>
-</td><td valign="top" width="20%">
-leap warning indicator (0-3)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>stratum</code>
-</td><td valign="top" width="20%">
-stratum (1-15)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>precision</code>
-</td><td valign="top" width="20%">
-precision (log(2) s)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>rootdelay</code>
-</td><td valign="top" width="20%">
-total roundtrip delay to the primary reference clock
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>rootdisp</code>
-</td><td valign="top" width="20%">
-total dispersion to the primary reference clock
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>peer</code>
-</td><td valign="top" width="20%">
-system peer association ID
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>tc</code>
-time constant and poll exponent (log(2) s) (3-17)
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>mintc</code>
-minimum time constant (log(2) s) (3-10)
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>clock</code>
-</td><td valign="top" width="20%">
-date and time of day
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>refid</code>
-reference ID or <a href="decode.html#kiss">kiss code</a>
-
- <p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>reftime</code>
-</td><td valign="top" width="20%">
-reference time
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>offset</code>
-</td><td valign="top" width="20%">
-combined offset of server relative to this host
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>sys_jitter</code>
-</td><td valign="top" width="20%">
-combined system jitter
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>frequency</code>
-</td><td valign="top" width="20%">
-frequency offset (PPM) relative to hardware clock
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>clk_wander</code>
-</td><td valign="top" width="20%">
-clock frequency wander (PPM)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>clk_jitter</code>
-</td><td valign="top" width="20%">
-clock jitter
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>tai</code>
-</td><td valign="top" width="20%">
-TAI-UTC offset (s)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>leapsec</code>
-</td><td valign="top" width="20%">
-NTP seconds when the next leap second is/was inserted
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>expire</code>
-</td><td valign="top" width="20%">
-NTP seconds when the NIST leapseconds file expires
-
- <br></td></tr></table>
-
- <p>The jitter and wander statistics are exponentially-weighted RMS averages.
+</p>
+<table>
+<thead><tr><th width="10%">Variable</th><th width="20%">Description</th></tr></thead>
+<tr><td width="10%"><code>status</code></td><td width="20%"><a href="decode.html#sys">system status word</a></td></tr>
+<tr><td width="10%"><code>version</code></td><td width="20%">NTP software version and build time</td></tr>
+<tr><td width="10%"><code>processor</code></td><td width="20%">hardware platform and version</td></tr>
+<tr><td width="10%"><code>system</code></td><td width="20%">operating system and version</td></tr>
+<tr><td width="10%"><code>leap</code></td><td width="20%">leap warning indicator (0-3)</td></tr>
+<tr><td width="10%"><code>stratum</code></td><td width="20%">stratum (1-15)</td></tr>
+<tr><td width="10%"><code>precision</code></td><td width="20%">precision (log(2) s)</td></tr>
+<tr><td width="10%"><code>rootdelay</code></td><td width="20%">total roundtrip delay to the primary reference clock</td></tr>
+<tr><td width="10%"><code>rootdisp</code></td><td width="20%">total dispersion to the primary reference clock</td></tr>
+<tr><td width="10%"><code>peer</code></td><td width="20%">system peer association ID</td></tr>
+<tr><td width="10%"><code>tc</code>
+time constant and poll exponent (log(2) s) (3-17)</td></tr>
+<tr><td width="10%"><code>mintc</code>
+minimum time constant (log(2) s) (3-10)</td></tr>
+<tr><td width="10%"><code>clock</code></td><td width="20%">date and time of day</td></tr>
+<tr><td width="10%"><code>refid</code>
+reference ID or <a href="decode.html#kiss">kiss code</a></td></tr>
+<tr><td width="10%"><code>reftime</code></td><td width="20%">reference time</td></tr>
+<tr><td width="10%"><code>offset</code></td><td width="20%">combined offset of server relative to this host</td></tr>
+<tr><td width="10%"><code>sys_jitter</code></td><td width="20%">combined system jitter</td></tr>
+<tr><td width="10%"><code>frequency</code></td><td width="20%">frequency offset (PPM) relative to hardware clock</td></tr>
+<tr><td width="10%"><code>clk_wander</code></td><td width="20%">clock frequency wander (PPM)</td></tr>
+<tr><td width="10%"><code>clk_jitter</code></td><td width="20%">clock jitter</td></tr>
+<tr><td width="10%"><code>tai</code></td><td width="20%">TAI-UTC offset (s)</td></tr>
+<tr><td width="10%"><code>leapsec</code></td><td width="20%">NTP seconds when the next leap second is/was inserted</td></tr>
+<tr><td width="10%"><code>expire</code></td><td width="20%">NTP seconds when the NIST leapseconds file expires</td></tr>
+</table>
+
+<p>The jitter and wander statistics are exponentially-weighted RMS averages.
The system jitter is defined in the NTPv4 specification;
the clock jitter statistic is computed by the clock discipline module.
-
- <p>When the NTPv4 daemon is compiled with the OpenSSL software library,
+</p>
+<p>When the NTPv4 daemon is compiled with the OpenSSL software library,
additional system variables are displayed, including some or all of the
following, depending on the particular Autokey dance:
-
- <p><table summary=""><tr align="left"><th valign="top" width="10%">Variable </th><th valign="top" width="20%">Description
-
-<p><br></th></tr><tr align="left"><td valign="top" width="10%"><code>host</code>
-</td><td valign="top" width="20%">
-Autokey host name for this host
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>ident</code>
-</td><td valign="top" width="20%">
-Autokey group name for this host
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>flags</code>
-</td><td valign="top" width="20%">
-host flags (see Autokey specification)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>digest</code>
-</td><td valign="top" width="20%">
-OpenSSL message digest algorithm
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>signature</code>
-</td><td valign="top" width="20%">
-OpenSSL digest/signature scheme
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>update</code>
-</td><td valign="top" width="20%">
-NTP seconds at last signature update
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>cert</code>
-</td><td valign="top" width="20%">
-certificate subject, issuer and certificate flags
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>until</code>
-</td><td valign="top" width="20%">
-NTP seconds when the certificate expires
-
- <br></td></tr></table>
-
-<div class="node">
-<p><hr>
-<a name="Peer-Variables"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Clock-Variables">Clock Variables</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#System-Variables">System Variables</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+</p>
+<table>
+<thead><tr><th width="10%">Variable</th><th width="20%">Description</th></tr></thead>
+<tr><td width="10%"><code>host</code></td><td width="20%">Autokey host name for this host</td></tr>
+<tr><td width="10%"><code>ident</code></td><td width="20%">Autokey group name for this host</td></tr>
+<tr><td width="10%"><code>flags</code></td><td width="20%">host flags (see Autokey specification)</td></tr>
+<tr><td width="10%"><code>digest</code></td><td width="20%">OpenSSL message digest algorithm</td></tr>
+<tr><td width="10%"><code>signature</code></td><td width="20%">OpenSSL digest/signature scheme</td></tr>
+<tr><td width="10%"><code>update</code></td><td width="20%">NTP seconds at last signature update</td></tr>
+<tr><td width="10%"><code>cert</code></td><td width="20%">certificate subject, issuer and certificate flags</td></tr>
+<tr><td width="10%"><code>until</code></td><td width="20%">NTP seconds when the certificate expires</td></tr>
+</table>
+
+<hr>
+<a name="Peer-Variables"></a>
+<div class="header">
+<p>
+Next: <a href="#Clock-Variables" accesskey="n" rel="next">Clock Variables</a>, Previous: <a href="#System-Variables" accesskey="p" rel="prev">System Variables</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Peer Variables</h3>
+<a name="Peer-Variables-2"></a>
+<h3 class="section">1.7 Peer Variables</h3>
<p>The following peer variables appear in the <code>rv</code> billboard
-for each association.
+for each association.
Not all variables are displayed in some configurations.
-
- <p><table summary=""><tr align="left"><th valign="top" width="10%">Variable </th><th valign="top" width="20%">Description
-
-<p><br></th></tr><tr align="left"><td valign="top" width="10%"><code>associd</code>
-</td><td valign="top" width="20%">
-association ID
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>status</code>
-</td><td valign="top" width="20%">
-<a href="decode.html#peer">peer status word</a>
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>srcadr</code>
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>srcport</code>
-</td><td valign="top" width="20%">
-source (remote) IP address and port
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>dstadr</code>
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>dstport</code>
-</td><td valign="top" width="20%">
-destination (local) IP address and port
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>leap</code>
-</td><td valign="top" width="20%">
-leap indicator (0-3)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>stratum</code>
-</td><td valign="top" width="20%">
-stratum (0-15)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>precision</code>
-</td><td valign="top" width="20%">
-precision (log(2) s)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>rootdelay</code>
-</td><td valign="top" width="20%">
-total roundtrip delay to the primary reference clock
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>rootdisp</code>
-</td><td valign="top" width="20%">total root dispersion to the primary reference clock
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>refid</code>
-</td><td valign="top" width="20%">
-reference ID or <a href="decode.html#kiss">kiss code</a>
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>reftime</code>
-</td><td valign="top" width="20%">
-reference time
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>reach</code>
-</td><td valign="top" width="20%">
-reach register (octal)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>unreach</code>
-</td><td valign="top" width="20%">
-unreach counter
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>hmode</code>
-</td><td valign="top" width="20%">
-host mode (1-6)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>pmode</code>
-</td><td valign="top" width="20%">
-peer mode (1-5)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>hpoll</code>
-</td><td valign="top" width="20%">
-host poll exponent (log(2) s) (3-17)
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>ppoll</code>
-</td><td valign="top" width="20%">
-peer poll exponent (log(2) s) (3-17)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>headway</code>
-</td><td valign="top" width="20%">
-headway (see <a href="rate.html">Rate Management and the Kiss-o'-Death Packet</a>)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>flash</code>
-</td><td valign="top" width="20%">
-<a href="decode.html#flash">flash status word</a>
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>offset</code>
-</td><td valign="top" width="20%">
-filter offset
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>delay</code>
-</td><td valign="top" width="20%">
-filter delay
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>dispersion</code>
-</td><td valign="top" width="20%">
-filter dispersion
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>jitter</code>
-</td><td valign="top" width="20%">
-filter jitter
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>ident</code>
-</td><td valign="top" width="20%">
-Autokey group name for this association
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>bias</code>
-</td><td valign="top" width="20%">
-unicast/broadcast bias
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>xleave</code>
-</td><td valign="top" width="20%">
-interleave delay (see <a href="xleave.html">NTP Interleaved Modes</a>)
-
- <br></td></tr></table>
-
- <p>The bias variable is calculated when the first broadcast packet is received
+</p>
+<table>
+<thead><tr><th width="10%">Variable</th><th width="20%">Description</th></tr></thead>
+<tr><td width="10%"><code>associd</code></td><td width="20%">association ID</td></tr>
+<tr><td width="10%"><code>status</code></td><td width="20%"><a href="decode.html#peer">peer status word</a></td></tr>
+<tr><td width="10%"><code>srcadr</code>
+<p><code>srcport</code>
+</p></td><td width="20%">source (remote) IP address and port</td></tr>
+<tr><td width="10%"><code>dstadr</code>
+<p><code>dstport</code>
+</p></td><td width="20%">destination (local) IP address and port</td></tr>
+<tr><td width="10%"><code>leap</code></td><td width="20%">leap indicator (0-3)</td></tr>
+<tr><td width="10%"><code>stratum</code></td><td width="20%">stratum (0-15)</td></tr>
+<tr><td width="10%"><code>precision</code></td><td width="20%">precision (log(2) s)</td></tr>
+<tr><td width="10%"><code>rootdelay</code></td><td width="20%">total roundtrip delay to the primary reference clock</td></tr>
+<tr><td width="10%"><code>rootdisp</code></td><td width="20%">total root dispersion to the primary reference clock</td></tr>
+<tr><td width="10%"><code>refid</code></td><td width="20%">reference ID or <a href="decode.html#kiss">kiss code</a></td></tr>
+<tr><td width="10%"><code>reftime</code></td><td width="20%">reference time</td></tr>
+<tr><td width="10%"><code>reach</code></td><td width="20%">reach register (octal)</td></tr>
+<tr><td width="10%"><code>unreach</code></td><td width="20%">unreach counter</td></tr>
+<tr><td width="10%"><code>hmode</code></td><td width="20%">host mode (1-6)</td></tr>
+<tr><td width="10%"><code>pmode</code></td><td width="20%">peer mode (1-5)</td></tr>
+<tr><td width="10%"><code>hpoll</code></td><td width="20%">host poll exponent (log(2) s) (3-17)</td></tr>
+<tr><td width="10%"><code>ppoll</code></td><td width="20%">peer poll exponent (log(2) s) (3-17)</td></tr>
+<tr><td width="10%"><code>headway</code></td><td width="20%">headway (see <a href="rate.html">Rate Management and the Kiss-o&rsquo;-Death Packet</a>)</td></tr>
+<tr><td width="10%"><code>flash</code></td><td width="20%"><a href="decode.html#flash">flash status word</a></td></tr>
+<tr><td width="10%"><code>offset</code></td><td width="20%">filter offset</td></tr>
+<tr><td width="10%"><code>delay</code></td><td width="20%">filter delay</td></tr>
+<tr><td width="10%"><code>dispersion</code></td><td width="20%">filter dispersion</td></tr>
+<tr><td width="10%"><code>jitter</code></td><td width="20%">filter jitter</td></tr>
+<tr><td width="10%"><code>ident</code></td><td width="20%">Autokey group name for this association</td></tr>
+<tr><td width="10%"><code>bias</code></td><td width="20%">unicast/broadcast bias</td></tr>
+<tr><td width="10%"><code>xleave</code></td><td width="20%">interleave delay (see <a href="xleave.html">NTP Interleaved Modes</a>)</td></tr>
+</table>
+
+<p>The bias variable is calculated when the first broadcast packet is received
after the calibration volley. It represents the offset of the broadcast
subgraph relative to the unicast subgraph. The xleave variable appears
only the interleaved symmetric and interleaved modes. It represents
the internal queuing, buffering and transmission delays for the preceding
packet.
-
- <p>When the NTPv4 daemon is compiled with the OpenSSL software library,
+</p>
+<p>When the NTPv4 daemon is compiled with the OpenSSL software library,
additional peer variables are displayed, including the following:
-
- <p><table summary=""><tr align="left"><th valign="top" width="10%">Variable </th><th valign="top" width="20%">Description
-
-<p><br></th></tr><tr align="left"><td valign="top" width="10%"><code>flags</code>
-</td><td valign="top" width="20%">
-peer flags (see Autokey specification)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>host</code>
-</td><td valign="top" width="20%">
-Autokey server name
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>flags</code>
-</td><td valign="top" width="20%">
-peer flags (see Autokey specification)
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>signature</code>
-</td><td valign="top" width="20%">
-OpenSSL digest/signature scheme
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>initsequence</code>
-</td><td valign="top" width="20%">
-initial key ID
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>initkey</code>
-</td><td valign="top" width="20%">
-initial key index
-
-<p><br></td></tr><tr align="left"><td valign="top" width="10%"><code>timestamp</code>
-</td><td valign="top" width="20%">
-Autokey signature timestamp
-
- <br></td></tr></table>
-
-<div class="node">
-<p><hr>
-<a name="Clock-Variables"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#Peer-Variables">Peer Variables</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+</p>
+<table>
+<thead><tr><th width="10%">Variable</th><th width="20%">Description</th></tr></thead>
+<tr><td width="10%"><code>flags</code></td><td width="20%">peer flags (see Autokey specification)</td></tr>
+<tr><td width="10%"><code>host</code></td><td width="20%">Autokey server name</td></tr>
+<tr><td width="10%"><code>flags</code></td><td width="20%">peer flags (see Autokey specification)</td></tr>
+<tr><td width="10%"><code>signature</code></td><td width="20%">OpenSSL digest/signature scheme</td></tr>
+<tr><td width="10%"><code>initsequence</code></td><td width="20%">initial key ID</td></tr>
+<tr><td width="10%"><code>initkey</code></td><td width="20%">initial key index</td></tr>
+<tr><td width="10%"><code>timestamp</code></td><td width="20%">Autokey signature timestamp</td></tr>
+</table>
+
+<hr>
+<a name="Clock-Variables"></a>
+<div class="header">
+<p>
+Previous: <a href="#Peer-Variables" accesskey="p" rel="prev">Peer Variables</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Clock Variables</h3>
+<a name="Clock-Variables-2"></a>
+<h3 class="section">1.8 Clock Variables</h3>
<p>The following clock variables appear in the <code>cv</code> billboard for each association with a reference clock. Not all variables are displayed in some configurations.
-
- <p><table summary=""><tr align="left"><th valign="top" width="10%">Variable </th><th valign="top" width="20%">Description
-<br></th></tr><tr align="left"><td valign="top" width="10%"><code>associd</code>
-</td><td valign="top" width="20%">association ID
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>status</code>
-</td><td valign="top" width="20%"><a href="decode.html#clock">clock status word</a>
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>device</code>
-</td><td valign="top" width="20%">device description
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>timecode</code>
-</td><td valign="top" width="20%">ASCII time code string (specific to device)
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>poll</code>
-</td><td valign="top" width="20%">poll messages sent
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>noreply</code>
-</td><td valign="top" width="20%">no reply
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>badformat</code>
-</td><td valign="top" width="20%">bad format
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>baddata</code>
-</td><td valign="top" width="20%">bad date or time
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>fudgetime1</code>
-</td><td valign="top" width="20%">fudge time 1
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>fudgetime2</code>
-</td><td valign="top" width="20%">fudge time 2
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>stratum</code>
-</td><td valign="top" width="20%">driver stratum
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>refid</code>
-</td><td valign="top" width="20%">driver reference ID
-<br></td></tr><tr align="left"><td valign="top" width="10%"><code>flags</code>
-</td><td valign="top" width="20%">driver flags
- <br></td></tr></table>
-
-</body></html>
-
+</p>
+<table>
+<thead><tr><th width="10%">Variable</th><th width="20%">Description</th></tr></thead>
+<tr><td width="10%"><code>associd</code></td><td width="20%">association ID</td></tr>
+<tr><td width="10%"><code>status</code></td><td width="20%"><a href="decode.html#clock">clock status word</a></td></tr>
+<tr><td width="10%"><code>device</code></td><td width="20%">device description</td></tr>
+<tr><td width="10%"><code>timecode</code></td><td width="20%">ASCII time code string (specific to device)</td></tr>
+<tr><td width="10%"><code>poll</code></td><td width="20%">poll messages sent</td></tr>
+<tr><td width="10%"><code>noreply</code></td><td width="20%">no reply</td></tr>
+<tr><td width="10%"><code>badformat</code></td><td width="20%">bad format</td></tr>
+<tr><td width="10%"><code>baddata</code></td><td width="20%">bad date or time</td></tr>
+<tr><td width="10%"><code>fudgetime1</code></td><td width="20%">fudge time 1</td></tr>
+<tr><td width="10%"><code>fudgetime2</code></td><td width="20%">fudge time 2</td></tr>
+<tr><td width="10%"><code>stratum</code></td><td width="20%">driver stratum</td></tr>
+<tr><td width="10%"><code>refid</code></td><td width="20%">driver reference ID</td></tr>
+<tr><td width="10%"><code>flags</code></td><td width="20%">driver flags</td></tr>
+</table>
+<hr>
+
+
+
+</body>
+</html>
diff --git a/contrib/ntp/ntpq/ntpq.man.in b/contrib/ntp/ntpq/ntpq.man.in
index d28d30c..8614603 100644
--- a/contrib/ntp/ntpq/ntpq.man.in
+++ b/contrib/ntp/ntpq/ntpq.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpq @NTPQ_MS@ "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH ntpq @NTPQ_MS@ "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-D4aGRT/ag-Q4ayQT)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:22 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:02 AM by AutoGen 5.18.5
.\" From the definitions ntpq-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/ntpq/ntpq.mdoc.in b/contrib/ntp/ntpq/ntpq.mdoc.in
index e0804f1..d6ebeb5 100644
--- a/contrib/ntp/ntpq/ntpq.mdoc.in
+++ b/contrib/ntp/ntpq/ntpq.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPQ @NTPQ_MS@ User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpq-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:28 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:56:59 AM by AutoGen 5.18.5
.\" From the definitions ntpq-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/ntpq/ntpq.texi b/contrib/ntp/ntpq/ntpq.texi
index 5526178..260a5ab 100644
--- a/contrib/ntp/ntpq/ntpq.texi
+++ b/contrib/ntp/ntpq/ntpq.texi
@@ -186,7 +186,7 @@ Exit @code{ntpq}.
@item @anchor{raw} @code{raw}
Display server messages as received and without reformatting.
-@item @anchor{timeout} @code{timeout @kbd{millseconds}}
+@item @anchor{timeout} @code{timeout @kbd{milliseconds}}
Specify a timeout period for responses to server queries.
The default is about 5000 milliseconds.
Note that since @code{ntpq} retries each query once after a timeout
diff --git a/contrib/ntp/ntpsnmpd/Makefile.in b/contrib/ntp/ntpsnmpd/Makefile.in
index 7a05aa9..5cd0dd2 100644
--- a/contrib/ntp/ntpsnmpd/Makefile.in
+++ b/contrib/ntp/ntpsnmpd/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/ntpsnmpd/invoke-ntpsnmpd.texi b/contrib/ntp/ntpsnmpd/invoke-ntpsnmpd.texi
index 90fd00d..4b537ae 100644
--- a/contrib/ntp/ntpsnmpd/invoke-ntpsnmpd.texi
+++ b/contrib/ntp/ntpsnmpd/invoke-ntpsnmpd.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntpsnmpd.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 05:15:36 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:07 AM by AutoGen 5.18.5
# From the definitions ntpsnmpd-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -47,31 +47,30 @@ with a status code of 0.
@exampleindent 0
@example
-ntpsnmpd - NTP SNMP MIB agent - Ver. 4.2.7p245
-USAGE: ntpsnmpd [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
+ntpsnmpd - NTP SNMP MIB agent - Ver. 4.2.8p13
+Usage: ntpsnmpd [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
Flg Arg Option-Name Description
-n no nofork Do not fork
-p no syslog Log to syslog()
Str agentxsocket The socket address ntpsnmpd uses to connect to net-snmpd
- opt version Output version information and exit
- -? no help Display extended usage information and exit
- -! no more-help Extended usage information passed thru pager
- -> opt save-opts Save the option state to a config file
- -< Str load-opts Load options from a config file
- - disabled as --no-load-opts
+ opt version output version information and exit
+ -? no help display extended usage information and exit
+ -! no more-help extended usage information passed thru pager
+ -> opt save-opts save the option state to a config file
+ -< Str load-opts load options from a config file
+ - disabled as '--no-load-opts'
- may appear multiple times
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-
The following option preset mechanisms are supported:
- reading file $HOME/.ntprc
- reading file ./.ntprc
- examining environment variables named NTPSNMPD_*
-please send bug reports to: http://bugs.ntp.org, bugs@@ntp.org
+Please send bug reports to: <http://bugs.ntp.org, bugs@@ntp.org>
@end example
@exampleindent 4
diff --git a/contrib/ntp/ntpsnmpd/ntpsnmpd-opts.c b/contrib/ntp/ntpsnmpd/ntpsnmpd-opts.c
index 8e957bc..609caff 100644
--- a/contrib/ntp/ntpsnmpd/ntpsnmpd-opts.c
+++ b/contrib/ntp/ntpsnmpd/ntpsnmpd-opts.c
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntpsnmpd-opts.c)
*
- * It has been AutoGen-ed February 27, 2018 at 05:15:31 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:57:03 AM by AutoGen 5.18.5
* From the definitions ntpsnmpd-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This source file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -61,7 +61,7 @@ extern FILE * option_usage_fp;
* static const strings for ntpsnmpd options
*/
static char const ntpsnmpd_opt_strs[1613] =
-/* 0 */ "ntpsnmpd 4.2.8p11\n"
+/* 0 */ "ntpsnmpd 4.2.8p13\n"
"Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n"
"This is free software. It is licensed for use, modification and\n"
"redistribution under the terms of the NTP License, copies of which\n"
@@ -101,14 +101,14 @@ static char const ntpsnmpd_opt_strs[1613] =
/* 1415 */ "no-load-opts\0"
/* 1428 */ "no\0"
/* 1431 */ "NTPSNMPD\0"
-/* 1440 */ "ntpsnmpd - NTP SNMP MIB agent - Ver. 4.2.8p11\n"
+/* 1440 */ "ntpsnmpd - NTP SNMP MIB agent - Ver. 4.2.8p13\n"
"Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\0"
/* 1544 */ "$HOME\0"
/* 1550 */ ".\0"
/* 1552 */ ".ntprc\0"
/* 1559 */ "http://bugs.ntp.org, bugs@ntp.org\0"
/* 1593 */ "\n\0"
-/* 1595 */ "ntpsnmpd 4.2.8p11";
+/* 1595 */ "ntpsnmpd 4.2.8p13";
/**
* nofork option description:
@@ -554,7 +554,7 @@ static void bogus_function(void) {
translate option names.
*/
/* referenced via ntpsnmpdOptions.pzCopyright */
- puts(_("ntpsnmpd 4.2.8p11\n\
+ puts(_("ntpsnmpd 4.2.8p13\n\
Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n\
This is free software. It is licensed for use, modification and\n\
redistribution under the terms of the NTP License, copies of which\n\
@@ -599,14 +599,14 @@ implied warranty.\n"));
puts(_("load options from a config file"));
/* referenced via ntpsnmpdOptions.pzUsageTitle */
- puts(_("ntpsnmpd - NTP SNMP MIB agent - Ver. 4.2.8p11\n\
+ puts(_("ntpsnmpd - NTP SNMP MIB agent - Ver. 4.2.8p13\n\
Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n"));
/* referenced via ntpsnmpdOptions.pzExplain */
puts(_("\n"));
/* referenced via ntpsnmpdOptions.pzFullVersion */
- puts(_("ntpsnmpd 4.2.8p11"));
+ puts(_("ntpsnmpd 4.2.8p13"));
/* referenced via ntpsnmpdOptions.pzFullUsage */
puts(_("<<<NOT-FOUND>>>"));
diff --git a/contrib/ntp/ntpsnmpd/ntpsnmpd-opts.h b/contrib/ntp/ntpsnmpd/ntpsnmpd-opts.h
index 5219659..8b88a51 100644
--- a/contrib/ntp/ntpsnmpd/ntpsnmpd-opts.h
+++ b/contrib/ntp/ntpsnmpd/ntpsnmpd-opts.h
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntpsnmpd-opts.h)
*
- * It has been AutoGen-ed February 27, 2018 at 05:15:31 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:57:03 AM by AutoGen 5.18.5
* From the definitions ntpsnmpd-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This header file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -53,7 +53,7 @@
* tolerable version is at least as old as what was current when the header
* template was released.
*/
-#define AO_TEMPLATE_VERSION 167936
+#define AO_TEMPLATE_VERSION 167937
#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
|| (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
# error option template version mismatches autoopts/options.h header
@@ -76,9 +76,9 @@ typedef enum {
/** count of all options for ntpsnmpd */
#define OPTION_CT 8
/** ntpsnmpd version */
-#define NTPSNMPD_VERSION "4.2.8p11"
+#define NTPSNMPD_VERSION "4.2.8p13"
/** Full ntpsnmpd version text */
-#define NTPSNMPD_FULL_VERSION "ntpsnmpd 4.2.8p11"
+#define NTPSNMPD_FULL_VERSION "ntpsnmpd 4.2.8p13"
/**
* Interface defines for all options. Replace "n" with the UPPER_CASED
diff --git a/contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdman b/contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdman
index 2d50156..f8574d7 100644
--- a/contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdman
+++ b/contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpsnmpd 1ntpsnmpdman "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH ntpsnmpd 1ntpsnmpdman "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-_Ia4FU/ag-lJaWEU)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:33 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:08 AM by AutoGen 5.18.5
.\" From the definitions ntpsnmpd-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc b/contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc
index b7aa23e..fddcb19 100644
--- a/contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc
+++ b/contrib/ntp/ntpsnmpd/ntpsnmpd.1ntpsnmpdmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPSNMPD 1ntpsnmpdmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpsnmpd-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:39 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:05 AM by AutoGen 5.18.5
.\" From the definitions ntpsnmpd-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/ntpsnmpd/ntpsnmpd.html b/contrib/ntp/ntpsnmpd/ntpsnmpd.html
index c12d766..bceab9d 100644
--- a/contrib/ntp/ntpsnmpd/ntpsnmpd.html
+++ b/contrib/ntp/ntpsnmpd/ntpsnmpd.html
@@ -1,79 +1,116 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>ntpsnmpd: Network Time Protocol SNMP Daemon User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="ntpsnmpd: Network Time Protocol SNMP Daemon User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>ntpsnmpd: Network Time Protocol SNMP Daemon User&rsquo;s Manual</title>
+
+<meta name="description" content="ntpsnmpd: Network Time Protocol SNMP Daemon User&rsquo;s Manual">
+<meta name="keywords" content="ntpsnmpd: Network Time Protocol SNMP Daemon User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">ntpsnmpd: Network Time Protocol SNMP Daemon User's Manual</h1>
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">ntpsnmpd: Network Time Protocol Query User Manual</a>
-</ul>
-</div>
+<body lang="en">
+<h1 class="settitle" align="center">ntpsnmpd: Network Time Protocol SNMP Daemon User&rsquo;s Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpsnmpd-Description">ntpsnmpd Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">ntpsnmpd: Network Time Protocol Query User Manual</h2>
-<p>The <code>ntpsnmpd</code> utility program is used to monitor NTP daemon <code>ntpd</code>
-operations and determine performance. It uses the standard NTP mode 6 control
- <p>This document applies to version 4.2.8p11 of <code>ntpsnmpd</code>.
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
-<ul class="menu">
-<li><a accesskey="1" href="#ntpsnmpd-Description">ntpsnmpd Description</a>: Description
-<li><a accesskey="2" href="#ntpsnmpd-Invocation">ntpsnmpd Invocation</a>: Invoking ntpsnmpd
-<li><a accesskey="3" href="#Usage">Usage</a>: Usage
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Description" href="#toc-Description">1 Description</a></li>
</ul>
+</div>
+
-<div class="node">
-<p><hr>
-<a name="ntpsnmpd-Description"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Usage">Usage</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+<a name="Top"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpsnmpd-Description" accesskey="n" rel="next">ntpsnmpd Description</a>, Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
</div>
+<a name="ntpsnmpd_003a-Network-Time-Protocol-Query-User-Manual"></a>
+<h1 class="top">ntpsnmpd: Network Time Protocol Query User Manual</h1>
+
+<p>The <code>ntpsnmpd</code> utility program is used to monitor NTP daemon <code>ntpd</code>
+operations and determine performance. It uses the standard NTP mode 6 control
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntpsnmpd</code>.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpsnmpd-Description" accesskey="1">ntpsnmpd Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; ntpsnmpd Invocation:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking ntpsnmpd
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="3">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+</table>
-<!-- node-name, next, previous, up -->
-<h3 class="section">Description</h3>
+<hr>
+<a name="ntpsnmpd-Description"></a>
+<div class="header">
+<p>
+Next: <a href="#Usage" accesskey="n" rel="next">Usage</a>, Previous: <a href="#Top" accesskey="p" rel="prev">Top</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
+</div>
+<a name="Description"></a>
+<h2 class="chapter">1 Description</h2>
<p>The <code>ntpsnmpd</code> utility program provides an SNMP MIB agent for <code>ntpd</code>.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="1">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
-<div class="node">
-<p><hr>
-<a name="Usage"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpsnmpd-Description">ntpsnmpd Description</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+<hr>
+<a name="Usage"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntpsnmpd-Description" accesskey="p" rel="prev">ntpsnmpd Description</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Usage</h3>
+<a name="Usage-1"></a>
+<h3 class="section">1.1 Usage</h3>
<p>(what should we say here?)
+</p><hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/ntpsnmpd/ntpsnmpd.man.in b/contrib/ntp/ntpsnmpd/ntpsnmpd.man.in
index 4c4a392..5bb4fe4 100644
--- a/contrib/ntp/ntpsnmpd/ntpsnmpd.man.in
+++ b/contrib/ntp/ntpsnmpd/ntpsnmpd.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpsnmpd @NTPSNMPD_MS@ "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH ntpsnmpd @NTPSNMPD_MS@ "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-_Ia4FU/ag-lJaWEU)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:33 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:08 AM by AutoGen 5.18.5
.\" From the definitions ntpsnmpd-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/ntpsnmpd/ntpsnmpd.mdoc.in b/contrib/ntp/ntpsnmpd/ntpsnmpd.mdoc.in
index e383e0c..6a0421d 100644
--- a/contrib/ntp/ntpsnmpd/ntpsnmpd.mdoc.in
+++ b/contrib/ntp/ntpsnmpd/ntpsnmpd.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPSNMPD @NTPSNMPD_MS@ User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpsnmpd-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:39 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:05 AM by AutoGen 5.18.5
.\" From the definitions ntpsnmpd-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/packageinfo.sh b/contrib/ntp/packageinfo.sh
index 0f45fbf..d4fa3fe 100644
--- a/contrib/ntp/packageinfo.sh
+++ b/contrib/ntp/packageinfo.sh
@@ -83,7 +83,7 @@ CLTAG=NTP_4_2_0
# - Numeric values increment
# - empty 'increments' to 1
# - NEW 'increments' to empty
-point=11
+point=13
### betapoint is normally modified by script.
# ntp-stable Beta number (betapoint)
diff --git a/contrib/ntp/parseutil/Makefile.in b/contrib/ntp/parseutil/Makefile.in
index 42a24fd..4bb0e5c 100644
--- a/contrib/ntp/parseutil/Makefile.in
+++ b/contrib/ntp/parseutil/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/Makefile.in b/contrib/ntp/scripts/Makefile.in
index f185b9d..1725b15 100644
--- a/contrib/ntp/scripts/Makefile.in
+++ b/contrib/ntp/scripts/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/build/Makefile.in b/contrib/ntp/scripts/build/Makefile.in
index eb5d28c..44718a8 100644
--- a/contrib/ntp/scripts/build/Makefile.in
+++ b/contrib/ntp/scripts/build/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/build/check--help b/contrib/ntp/scripts/build/check--help
index 1524675..a968fc4 100755
--- a/contrib/ntp/scripts/build/check--help
+++ b/contrib/ntp/scripts/build/check--help
@@ -10,13 +10,13 @@
if test ! -f $1
then
- echo "$0: $1 is not a regular file!" 2>&3
+ echo "$0: $1 is not a regular file!" 1>&2
exit 1
fi
if grep -q 'no --help' $1
then
- echo "$0: $1 contains 'no --help'!" 2>&3
+ echo "$0: $1 contains 'no --help'!" 1>&2
mv ${1} ${1}-
exit 1
fi
diff --git a/contrib/ntp/scripts/calc_tickadj/Makefile.in b/contrib/ntp/scripts/calc_tickadj/Makefile.in
index cd49b68..106f368 100644
--- a/contrib/ntp/scripts/calc_tickadj/Makefile.in
+++ b/contrib/ntp/scripts/calc_tickadj/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjman b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjman
index 33c6a43..14db08a 100644
--- a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjman
+++ b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH calc_tickadj 1calc_tickadjman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH calc_tickadj 1calc_tickadjman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-mfaiQP/ag-zfaqPP)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:49:40 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:23 AM by AutoGen 5.18.5
.\" From the definitions calc_tickadj-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc
index 0755240..dff96f4 100644
--- a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc
+++ b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.1calc_tickadjmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt CALC_TICKADJ 1calc_tickadjmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (calc_tickadj-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:49:43 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:24 AM by AutoGen 5.18.5
.\" From the definitions calc_tickadj-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.html b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.html
index 930d90c..3f65c49 100644
--- a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.html
+++ b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.html
@@ -1,115 +1,156 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>calc_tickadj User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="calc_tickadj User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>calc_tickadj User&rsquo;s Manual</title>
+
+<meta name="description" content="calc_tickadj User&rsquo;s Manual">
+<meta name="keywords" content="calc_tickadj User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">calc_tickadj User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#calc_005ftickadj-Description">calc_tickadj Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">calc_tickadj User's Manual</h2>
+<body lang="en">
+<h1 class="settitle" align="center">calc_tickadj User&rsquo;s Manual</h1>
-<p>This document describes the use of the NTP Project's <code>calc_tickadj</code> program.
-This document applies to version 4.2.8p11 of <code>calc_tickadj</code>.
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">calc_tickadj User's Manual</a>
+
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="calc_005ftickadj-User_0027s-Manual"></a>
+<h1 class="top">calc_tickadj User&rsquo;s Manual</h1>
+
+<p>This document describes the use of the NTP Project&rsquo;s <code>calc_tickadj</code> program.
+This document applies to version 4.2.8p13 of <code>calc_tickadj</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
+
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Invoking-calc_005ftickadj" href="#toc-Invoking-calc_005ftickadj">1 Invoking calc_tickadj</a></li>
</ul>
</div>
-<ul class="menu">
-<li><a accesskey="1" href="#calc_005ftickadj-Description">calc_tickadj Description</a>: Description
-<li><a accesskey="2" href="#calc_005ftickadj-Invocation">calc_tickadj Invocation</a>: Invoking calc_tickadj
-</ul>
-<div class="node">
-<p><hr>
-<a name="calc_005ftickadj-Invocation"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#calc_005ftickadj-Description">calc_tickadj Description</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
-</div>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; calc_tickadj Description:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#calc_005ftickadj-Invocation" accesskey="2">calc_tickadj Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking calc_tickadj
+</td></tr>
+</table>
-<h3 class="section">Invoking calc_tickadj</h3>
+<hr>
+<a name="calc_005ftickadj-Invocation"></a>
+<div class="header">
+<p>
+Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
+</div>
+<a name="Invoking-calc_005ftickadj"></a>
+<h2 class="chapter">1 Invoking calc_tickadj</h2>
+<a name="index-calc_005ftickadj"></a>
+<a name="index-Calculates-_0022optimal_0022-value-for-tick-given-ntp-drift-file_002e"></a>
-<p><a name="index-calc_005ftickadj-1"></a><a name="index-Calculates-_0022optimal_0022-value-for-tick-given-ntp-drift-file_002e-2"></a>
-The <code>calc_tickadj</code> script uses provided ntp drift file to generate optimal
+<p>The <code>calc_tickadj</code> script uses provided ntp drift file to generate optimal
tick value. Generally, ntpd can do better job if the drift value is the
-smallest possible number.
-
- <p>The example output of
-<pre class="example"> $ ./calc_tickadj
- 81.699 (drift)
- 9999 usec; 9999779 nsec
- $ cat /etc/ntp/drift
- -23.159
-</pre>
- <p>means the following. If tick on that box is 10,000, by making the value 9999
-we'll shift the box from its current drift of -23.159 to a drift of 81.699, and
-in doing so we'll speed the clock up a little every second instead of slowing
+smallest possible number.
+</p>
+<p>The example output of
+</p><div class="example">
+<pre class="example">$ ./calc_tickadj
+81.699 (drift)
+9999 usec; 9999779 nsec
+$ cat /etc/ntp/drift
+-23.159
+</pre></div>
+
+<p>means the following. If tick on that box is 10,000, by making the value 9999
+we&rsquo;ll shift the box from its current drift of -23.159 to a drift of 81.699, and
+in doing so we&rsquo;ll speed the clock up a little every second instead of slowing
the clock down a little.
-
- <p>If 'tick' on that box is 10,000,000 then by setting it to 9999779 the drift
+</p>
+<p>If &rsquo;tick&rsquo; on that box is 10,000,000 then by setting it to 9999779 the drift
value will be somewhere around 0.0.
-
- <p><code>calc_tickadj</code> tries to determine the the tick value by using
-<code>tickadj</code> program from ntp package. If this doesn't work you can specify
+</p>
+<p><code>calc_tickadj</code> tries to determine the the tick value by using
+<code>tickadj</code> program from ntp package. If this doesn&rsquo;t work you can specify
current tick manually on command line.
+</p>
- <p>This section was generated by <strong>AutoGen</strong>,
+<p>This section was generated by <strong>AutoGen</strong>,
using the <code>agtexi-cmd</code> template and the option descriptions for the <code>calc_tickadj</code> program.
-
-<ul class="menu">
-<li><a accesskey="1" href="#calc_005ftickadj-usage">calc_tickadj usage</a>: calc_tickadj help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#calc_005ftickadj-drift_002dfile">calc_tickadj drift-file</a>: drift-file option (-d)
-<li><a accesskey="3" href="#calc_005ftickadj-tick">calc_tickadj tick</a>: tick option (-t)
-<li><a accesskey="4" href="#calc_005ftickadj-exit-status">calc_tickadj exit status</a>: exit status
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="calc_005ftickadj-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#calc_005ftickadj-drift_002dfile">calc_tickadj drift-file</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#calc_005ftickadj-Invocation">calc_tickadj Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#calc_005ftickadj-usage" accesskey="1">calc_tickadj usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">calc_tickadj help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#calc_005ftickadj-drift_002dfile" accesskey="2">calc_tickadj drift-file</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">drift-file option (-d)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#calc_005ftickadj-tick" accesskey="3">calc_tickadj tick</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">tick option (-t)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#calc_005ftickadj-exit-status" accesskey="4">calc_tickadj exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+</table>
+
+<hr>
+<a name="calc_005ftickadj-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#calc_005ftickadj-drift_002dfile" accesskey="n" rel="next">calc_tickadj drift-file</a>, Up: <a href="#calc_005ftickadj-Invocation" accesskey="u" rel="up">calc_tickadj Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">calc_tickadj help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-calc_005ftickadj-help-3"></a>
-This is the automatically generated usage text for calc_tickadj.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="calc_005ftickadj-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h3 class="section">1.1 calc_tickadj help/usage (<samp>--help</samp>)</h3>
+<a name="index-calc_005ftickadj-help"></a>
+
+<p>This is the automatically generated usage text for calc_tickadj.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">calc_tickadj - Calculates "optimal" value for tick given ntp drift file. - Ver. 4.2.7p467
-USAGE: calc_tickadj [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
+</p>
+<div class="example">
+<pre class="example">calc_tickadj - Calculates &quot;optimal&quot; value for tick given ntp drift file. - Ver. 4.2.7p467
+USAGE: calc_tickadj [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
-d, --drift-file=str Ntp drift file to use
-t, --tick=num Tick value of this host
@@ -118,49 +159,64 @@ USAGE: calc_tickadj [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-</pre>
- <div class="node">
-<p><hr>
-<a name="calc_005ftickadj-drift_002dfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#calc_005ftickadj-tick">calc_tickadj tick</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#calc_005ftickadj-usage">calc_tickadj usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#calc_005ftickadj-Invocation">calc_tickadj Invocation</a>
-<br>
+</pre></div>
+
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#calc_005ftickadj-drift_002dfile" accesskey="1">calc_tickadj drift-file</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#calc_005ftickadj-tick" accesskey="2">calc_tickadj tick</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#calc_005ftickadj-exit-status" accesskey="3">calc_tickadj exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="calc_005ftickadj-drift_002dfile"></a>
+<div class="header">
+<p>
+Next: <a href="#calc_005ftickadj-tick" accesskey="n" rel="next">calc_tickadj tick</a>, Previous: <a href="#calc_005ftickadj-usage" accesskey="p" rel="prev">calc_tickadj usage</a>, Up: <a href="#calc_005ftickadj-usage" accesskey="u" rel="up">calc_tickadj usage</a> &nbsp; </p>
</div>
+<a name="drift_002dfile-option-_0028_002dd_0029"></a>
+<h4 class="subsection">1.1.1 drift-file option (-d)</h4>
+<a name="index-calc_005ftickadj_002ddrift_002dfile"></a>
-<h4 class="subsection">drift-file option (-d)</h4>
-
-<p><a name="index-calc_005ftickadj_002ddrift_002dfile-4"></a>
-This is the &ldquo;ntp drift file to use&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;ntp drift file to use&rdquo; option.
+This option takes a string argument.
Use the specified drift file for calculations
-<div class="node">
-<p><hr>
-<a name="calc_005ftickadj-tick"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#calc_005ftickadj-exit-status">calc_tickadj exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#calc_005ftickadj-drift_002dfile">calc_tickadj drift-file</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#calc_005ftickadj-Invocation">calc_tickadj Invocation</a>
-<br>
+</p><hr>
+<a name="calc_005ftickadj-tick"></a>
+<div class="header">
+<p>
+Next: <a href="#calc_005ftickadj-exit-status" accesskey="n" rel="next">calc_tickadj exit status</a>, Previous: <a href="#calc_005ftickadj-drift_002dfile" accesskey="p" rel="prev">calc_tickadj drift-file</a>, Up: <a href="#calc_005ftickadj-usage" accesskey="u" rel="up">calc_tickadj usage</a> &nbsp; </p>
</div>
+<a name="tick-option-_0028_002dt_0029"></a>
+<h4 class="subsection">1.1.2 tick option (-t)</h4>
+<a name="index-calc_005ftickadj_002dtick"></a>
-<h4 class="subsection">tick option (-t)</h4>
-
-<p><a name="index-calc_005ftickadj_002dtick-5"></a>
-This is the &ldquo;tick value of this host&rdquo; option.
-This option takes a number argument.
+<p>This is the &ldquo;tick value of this host&rdquo; option.
+This option takes a number argument.
The current tick which to adjustment will be calculated
-<div class="node">
-<p><hr>
-<a name="calc_005ftickadj-exit-status"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#calc_005ftickadj-tick">calc_tickadj tick</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#calc_005ftickadj-Invocation">calc_tickadj Invocation</a>
-<br>
+</p><hr>
+<a name="calc_005ftickadj-exit-status"></a>
+<div class="header">
+<p>
+Previous: <a href="#calc_005ftickadj-tick" accesskey="p" rel="prev">calc_tickadj tick</a>, Up: <a href="#calc_005ftickadj-usage" accesskey="u" rel="up">calc_tickadj usage</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">calc_tickadj exit status</h4>
+<a name="calc_005ftickadj-exit-status-1"></a>
+<h4 class="subsection">1.1.3 calc_tickadj exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
</dl>
+<hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.man.in b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.man.in
index 33c6a43..14db08a 100644
--- a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.man.in
+++ b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH calc_tickadj 1calc_tickadjman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH calc_tickadj 1calc_tickadjman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-mfaiQP/ag-zfaqPP)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:49:40 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:23 AM by AutoGen 5.18.5
.\" From the definitions calc_tickadj-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.mdoc.in b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.mdoc.in
index 0755240..dff96f4 100644
--- a/contrib/ntp/scripts/calc_tickadj/calc_tickadj.mdoc.in
+++ b/contrib/ntp/scripts/calc_tickadj/calc_tickadj.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt CALC_TICKADJ 1calc_tickadjmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (calc_tickadj-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:49:43 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:24 AM by AutoGen 5.18.5
.\" From the definitions calc_tickadj-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/calc_tickadj/invoke-calc_tickadj.texi b/contrib/ntp/scripts/calc_tickadj/invoke-calc_tickadj.texi
index 9c4b7ed..65c738d 100644
--- a/contrib/ntp/scripts/calc_tickadj/invoke-calc_tickadj.texi
+++ b/contrib/ntp/scripts/calc_tickadj/invoke-calc_tickadj.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-calc_tickadj.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 10:49:45 AM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:25 AM by AutoGen 5.18.5
# From the definitions calc_tickadj-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
diff --git a/contrib/ntp/scripts/invoke-plot_summary.texi b/contrib/ntp/scripts/invoke-plot_summary.texi
index e2c7d95..f0b9045 100644
--- a/contrib/ntp/scripts/invoke-plot_summary.texi
+++ b/contrib/ntp/scripts/invoke-plot_summary.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-plot_summary.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 04:55:58 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 05:04:25 PM by AutoGen 5.18.5
# From the definitions plot_summary-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -41,7 +41,7 @@ with a status code of 0.
@exampleindent 0
@example
-plot_summary - plot statistics generated by summary script - Ver. 4.2.8p11
+plot_summary - plot statistics generated by summary script - Ver. 4.2.8p13
USAGE: plot_summary [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
--directory=str Where the summary files are
diff --git a/contrib/ntp/scripts/invoke-summary.texi b/contrib/ntp/scripts/invoke-summary.texi
index 2a6d5a4..08bf305 100644
--- a/contrib/ntp/scripts/invoke-summary.texi
+++ b/contrib/ntp/scripts/invoke-summary.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-summary.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 04:56:04 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 05:04:29 PM by AutoGen 5.18.5
# From the definitions summary-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -42,7 +42,7 @@ with a status code of 0.
@exampleindent 0
@example
-summary - compute various stastics from NTP stat files - Ver. 4.2.8p11
+summary - compute various stastics from NTP stat files - Ver. 4.2.8p13
USAGE: summary [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
--directory=str Directory containing stat files
diff --git a/contrib/ntp/scripts/lib/Makefile.in b/contrib/ntp/scripts/lib/Makefile.in
index 3cafdf8..e2750d2 100644
--- a/contrib/ntp/scripts/lib/Makefile.in
+++ b/contrib/ntp/scripts/lib/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/ntp-wait/Makefile.in b/contrib/ntp/scripts/ntp-wait/Makefile.in
index 9df58c5..5977c52 100644
--- a/contrib/ntp/scripts/ntp-wait/Makefile.in
+++ b/contrib/ntp/scripts/ntp-wait/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/ntp-wait/invoke-ntp-wait.texi b/contrib/ntp/scripts/ntp-wait/invoke-ntp-wait.texi
index 786f3b7..527035a 100644
--- a/contrib/ntp/scripts/ntp-wait/invoke-ntp-wait.texi
+++ b/contrib/ntp/scripts/ntp-wait/invoke-ntp-wait.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntp-wait.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 10:49:53 AM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:28 AM by AutoGen 5.18.5
# From the definitions ntp-wait-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -61,7 +61,7 @@ with a status code of 0.
@exampleindent 0
@example
-ntp-wait - Wait for ntpd to stabilize the system clock - Ver. 4.2.8p11
+ntp-wait - Wait for ntpd to stabilize the system clock - Ver. 4.2.8p13
USAGE: ntp-wait [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
-n, --tries=num Number of times to check ntpd
diff --git a/contrib/ntp/scripts/ntp-wait/ntp-wait-opts b/contrib/ntp/scripts/ntp-wait/ntp-wait-opts
index 4e6c4a0..e81dc0e 100644
--- a/contrib/ntp/scripts/ntp-wait/ntp-wait-opts
+++ b/contrib/ntp/scripts/ntp-wait/ntp-wait-opts
@@ -1,6 +1,6 @@
# EDIT THIS FILE WITH CAUTION (ntp-wait-opts)
#
-# It has been AutoGen-ed February 27, 2018 at 10:49:48 AM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:27 AM by AutoGen 5.18.5
# From the definitions ntp-wait-opts.def
# and the template file perlopt
@@ -40,7 +40,7 @@ sub processOptions {
'help|?', 'more-help'));
$usage = <<'USAGE';
-ntp-wait - Wait for ntpd to stabilize the system clock - Ver. 4.2.8p11
+ntp-wait - Wait for ntpd to stabilize the system clock - Ver. 4.2.8p13
USAGE: ntp-wait [ -<flag> [<val>] | --<name>[{=| }<val>] ]...
-n, --tries=num Number of times to check ntpd
diff --git a/contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitman b/contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitman
index 43158be..90cc4da 100644
--- a/contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitman
+++ b/contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntp-wait 1ntp-waitman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH ntp-wait 1ntp-waitman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-tuay0Q/ag-GuaGZQ)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:49:50 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:30 AM by AutoGen 5.18.5
.\" From the definitions ntp-wait-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitmdoc b/contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitmdoc
index bd33fc9..368b273 100644
--- a/contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitmdoc
+++ b/contrib/ntp/scripts/ntp-wait/ntp-wait.1ntp-waitmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTP_WAIT 1ntp-waitmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp-wait-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:49:55 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:27 AM by AutoGen 5.18.5
.\" From the definitions ntp-wait-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/ntp-wait/ntp-wait.html b/contrib/ntp/scripts/ntp-wait/ntp-wait.html
index ef8e53e..3b33e6d 100644
--- a/contrib/ntp/scripts/ntp-wait/ntp-wait.html
+++ b/contrib/ntp/scripts/ntp-wait/ntp-wait.html
@@ -1,68 +1,105 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>Ntp-wait User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="Ntp-wait User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Ntp-wait User&rsquo;s Manual</title>
+
+<meta name="description" content="Ntp-wait User&rsquo;s Manual">
+<meta name="keywords" content="Ntp-wait User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">Ntp-wait User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dwait-Description">ntp-wait Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
- <p>This document describes the use of the NTP Project's <code>ntp-wait</code> program.
+<body lang="en">
+<h1 class="settitle" align="center">Ntp-wait User&rsquo;s Manual</h1>
+
+
+
+
- <p>If there are time-sensitive applications,
+<a name="Top"></a>
+<div class="header">
+<p>
+Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<h1 class="node-heading">Top</h1>
+
+<p>This document describes the use of the NTP Project&rsquo;s <code>ntp-wait</code> program.
+</p>
+<p>If there are time-sensitive applications,
the proper sequence of events is to
run <code>ntpd -g</code> as early as possible,
then invoke all of the non-time-sensitive process,
run <code>ntp-wait</code> to block
-until the system's time has stabilized and synchronized,
+until the system&rsquo;s time has stabilized and synchronized,
and only then start any applicaitons (like database servers) that require
accurate and stable time.
-
- <p>This document applies to version 4.2.8p11 of <code>ntp-wait</code>.
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntp-wait</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
<div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-</ul>
+<li><a name="stoc-Invoking-ntp_002dwait" href="#toc-Invoking-ntp_002dwait">1 Invoking ntp-wait</a></li>
+
</div>
-<ul class="menu">
-<li><a accesskey="1" href="#ntp_002dwait-Description">ntp-wait Description</a>: Description
-<li><a accesskey="2" href="#ntp_002dwait-Invocation">ntp-wait Invocation</a>: Invoking ntp-wait
-</ul>
-<div class="node">
-<p><hr>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; ntp-wait Description:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dwait-Invocation" accesskey="2">ntp-wait Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking ntp-wait
+</td></tr>
+</table>
+
+<hr>
<a name="ntp_002dwait-Invocation"></a>
-<br>
+<div class="header">
+<p>
+Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
+<a name="Invoking-ntp_002dwait"></a>
+<h3 class="section">1 Invoking ntp-wait</h3>
+<a name="index-ntp_002dwait"></a>
+<a name="index-Wait-for-ntpd-to-stabilize-the-system-clock"></a>
-<h3 class="section">0.1 Invoking ntp-wait</h3>
-<p><a name="index-ntp_002dwait-1"></a><a name="index-Wait-for-ntpd-to-stabilize-the-system-clock-2"></a>
- <p><code>ntp-wait</code>
+<p><code>ntp-wait</code>
will send at most
<kbd>num-tries</kbd>
queries to
@@ -72,50 +109,58 @@ sleeping for
after each status return that says
<code>ntpd(8)</code>
has not yet produced a synchronized and stable system clock.
-
- <p><code>ntp-wait</code>
+</p>
+<p><code>ntp-wait</code>
will do this quietly, unless the
<code>-v</code>
-flag is provided.
+flag is provided.
This can be useful at boot time, to delay the boot sequence until after
<kbd>ntpd</kbd> <kbd>-g</kbd>
has set the time.
-
- <p>This section was generated by <strong>AutoGen</strong>,
+</p>
+<p>This section was generated by <strong>AutoGen</strong>,
using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp-wait</code> program.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntp_002dwait-usage">ntp-wait usage</a>: ntp-wait help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#ntp_002dwait-tries">ntp-wait tries</a>: tries option (-n)
-<li><a accesskey="3" href="#ntp_002dwait-sleep">ntp-wait sleep</a>: sleep option (-s)
-<li><a accesskey="4" href="#ntp_002dwait-verbose">ntp-wait verbose</a>: verbose option (-v)
-<li><a accesskey="5" href="#ntp_002dwait-exit-status">ntp-wait exit status</a>: exit status
-<li><a accesskey="6" href="#ntp_002dwait-Authors">ntp-wait Authors</a>: Authors
-<li><a accesskey="7" href="#ntp_002dwait-Notes">ntp-wait Notes</a>: Notes
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntp_002dwait-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dwait-tries">ntp-wait tries</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dwait-Invocation">ntp-wait Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dwait-usage" accesskey="1">ntp-wait usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntp-wait help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dwait-tries" accesskey="2">ntp-wait tries</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">tries option (-n)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dwait-sleep" accesskey="3">ntp-wait sleep</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">sleep option (-s)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dwait-verbose" accesskey="4">ntp-wait verbose</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">verbose option (-v)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dwait-exit-status" accesskey="5">ntp-wait exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dwait-Authors" accesskey="6">ntp-wait Authors</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Authors
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dwait-Notes" accesskey="7">ntp-wait Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Notes
+</td></tr>
+</table>
+
+<hr>
+<a name="ntp_002dwait-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dwait-tries" accesskey="n" rel="next">ntp-wait tries</a>, Up: <a href="#ntp_002dwait-Invocation" accesskey="u" rel="up">ntp-wait Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.1 ntp-wait help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-ntp_002dwait-help-3"></a>
-This is the automatically generated usage text for ntp-wait.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="ntp_002dwait-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h4 class="subsection">1.1 ntp-wait help/usage (<samp>--help</samp>)</h4>
+<a name="index-ntp_002dwait-help"></a>
+
+<p>This is the automatically generated usage text for ntp-wait.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">ntp-wait - Wait for ntpd to stabilize the system clock - Ver. 4.2.8p11
-USAGE: ntp-wait [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
+</p>
+<div class="example">
+<pre class="example">ntp-wait - Wait for ntpd to stabilize the system clock - Ver. 4.2.8p13
+USAGE: ntp-wait [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
-n, --tries=num Number of times to check ntpd
-s, --sleep=num How long to sleep between tries
@@ -125,84 +170,86 @@ USAGE: ntp-wait [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;]
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-</pre>
- <div class="node">
-<p><hr>
-<a name="ntp_002dwait-tries"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dwait-sleep">ntp-wait sleep</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dwait-usage">ntp-wait usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dwait-Invocation">ntp-wait Invocation</a>
-<br>
-</div>
+</pre></div>
-<h4 class="subsection">0.1.2 tries option (-n)</h4>
+<hr>
+<a name="ntp_002dwait-tries"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dwait-sleep" accesskey="n" rel="next">ntp-wait sleep</a>, Previous: <a href="#ntp_002dwait-usage" accesskey="p" rel="prev">ntp-wait usage</a>, Up: <a href="#ntp_002dwait-Invocation" accesskey="u" rel="up">ntp-wait Invocation</a> &nbsp; </p>
+</div>
+<a name="tries-option-_0028_002dn_0029"></a>
+<h4 class="subsection">1.2 tries option (-n)</h4>
+<a name="index-ntp_002dwait_002dtries"></a>
-<p><a name="index-ntp_002dwait_002dtries-4"></a>
-This is the &ldquo;number of times to check ntpd&rdquo; option.
-This option takes a number argument.
+<p>This is the &ldquo;number of times to check ntpd&rdquo; option.
+This option takes a number argument.
The maximum number of times we will check <code>ntpd</code> to see if
- it has been able to synchronize and stabilize the system clock.
-<div class="node">
-<p><hr>
-<a name="ntp_002dwait-sleep"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dwait-verbose">ntp-wait verbose</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dwait-tries">ntp-wait tries</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dwait-Invocation">ntp-wait Invocation</a>
-<br>
+ it has been able to synchronize and stabilize the system clock.
+</p><hr>
+<a name="ntp_002dwait-sleep"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dwait-verbose" accesskey="n" rel="next">ntp-wait verbose</a>, Previous: <a href="#ntp_002dwait-tries" accesskey="p" rel="prev">ntp-wait tries</a>, Up: <a href="#ntp_002dwait-Invocation" accesskey="u" rel="up">ntp-wait Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.3 sleep option (-s)</h4>
-
-<p><a name="index-ntp_002dwait_002dsleep-5"></a>
-This is the &ldquo;how long to sleep between tries&rdquo; option.
-This option takes a number argument <span class="file">secs-between-tries</span>.
- We will sleep for <span class="file">secs-between-tries</span> after each query
- of <code>ntpd</code> that returns "the time is not yet stable".
-<div class="node">
-<p><hr>
-<a name="ntp_002dwait-verbose"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dwait-exit-status">ntp-wait exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dwait-sleep">ntp-wait sleep</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dwait-Invocation">ntp-wait Invocation</a>
-<br>
+<a name="sleep-option-_0028_002ds_0029"></a>
+<h4 class="subsection">1.3 sleep option (-s)</h4>
+<a name="index-ntp_002dwait_002dsleep"></a>
+
+<p>This is the &ldquo;how long to sleep between tries&rdquo; option.
+This option takes a number argument <samp>secs-between-tries</samp>.
+ We will sleep for <samp>secs-between-tries</samp> after each query
+ of <code>ntpd</code> that returns &quot;the time is not yet stable&quot;.
+</p><hr>
+<a name="ntp_002dwait-verbose"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dwait-exit-status" accesskey="n" rel="next">ntp-wait exit status</a>, Previous: <a href="#ntp_002dwait-sleep" accesskey="p" rel="prev">ntp-wait sleep</a>, Up: <a href="#ntp_002dwait-Invocation" accesskey="u" rel="up">ntp-wait Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.4 verbose option (-v)</h4>
-
-<p><a name="index-ntp_002dwait_002dverbose-6"></a>
-This is the &ldquo;be verbose&rdquo; option.
- By default, <code>ntp-wait</code> is silent.
- With this option, <code>ntp-wait</code> will provide status information.
-<div class="node">
-<p><hr>
-<a name="ntp_002dwait-exit-status"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dwait-Authors">ntp-wait Authors</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dwait-verbose">ntp-wait verbose</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dwait-Invocation">ntp-wait Invocation</a>
-<br>
+<a name="verbose-option-_0028_002dv_0029"></a>
+<h4 class="subsection">1.4 verbose option (-v)</h4>
+<a name="index-ntp_002dwait_002dverbose"></a>
+
+<p>This is the &ldquo;be verbose&rdquo; option.
+ By default, <code>ntp-wait</code> is silent.
+ With this option, <code>ntp-wait</code> will provide status information.
+</p><hr>
+<a name="ntp_002dwait-exit-status"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dwait-Authors" accesskey="n" rel="next">ntp-wait Authors</a>, Previous: <a href="#ntp_002dwait-verbose" accesskey="p" rel="prev">ntp-wait verbose</a>, Up: <a href="#ntp_002dwait-Invocation" accesskey="u" rel="up">ntp-wait Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.5 ntp-wait exit status</h4>
+<a name="ntp_002dwait-exit-status-1"></a>
+<h4 class="subsection">1.5 ntp-wait exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
</dl>
- <div class="node">
-<p><hr>
-<a name="ntp_002dwait-Authors"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dwait-Notes">ntp-wait Notes</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dwait-exit-status">ntp-wait exit status</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dwait-Invocation">ntp-wait Invocation</a>
-<br>
+<hr>
+<a name="ntp_002dwait-Authors"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dwait-Notes" accesskey="n" rel="next">ntp-wait Notes</a>, Previous: <a href="#ntp_002dwait-exit-status" accesskey="p" rel="prev">ntp-wait exit status</a>, Up: <a href="#ntp_002dwait-Invocation" accesskey="u" rel="up">ntp-wait Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.6 ntp-wait Authors</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntp_002dwait-Notes"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dwait-Authors">ntp-wait Authors</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dwait-Invocation">ntp-wait Invocation</a>
-<br>
+<a name="ntp_002dwait-Authors-1"></a>
+<h4 class="subsection">1.6 ntp-wait Authors</h4>
+<hr>
+<a name="ntp_002dwait-Notes"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntp_002dwait-Authors" accesskey="p" rel="prev">ntp-wait Authors</a>, Up: <a href="#ntp_002dwait-Invocation" accesskey="u" rel="up">ntp-wait Invocation</a> &nbsp; </p>
</div>
+<a name="ntp_002dwait-Notes-1"></a>
+<h4 class="subsection">1.7 ntp-wait Notes</h4>
+<hr>
-<h4 class="subsection">0.1.7 ntp-wait Notes</h4>
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/scripts/ntp-wait/ntp-wait.man.in b/contrib/ntp/scripts/ntp-wait/ntp-wait.man.in
index c113287..62a4124 100644
--- a/contrib/ntp/scripts/ntp-wait/ntp-wait.man.in
+++ b/contrib/ntp/scripts/ntp-wait/ntp-wait.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntp-wait @NTP_WAIT_MS@ "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH ntp-wait @NTP_WAIT_MS@ "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-tuay0Q/ag-GuaGZQ)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:49:50 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:30 AM by AutoGen 5.18.5
.\" From the definitions ntp-wait-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/ntp-wait/ntp-wait.mdoc.in b/contrib/ntp/scripts/ntp-wait/ntp-wait.mdoc.in
index c792715..ae0195b 100644
--- a/contrib/ntp/scripts/ntp-wait/ntp-wait.mdoc.in
+++ b/contrib/ntp/scripts/ntp-wait/ntp-wait.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTP_WAIT @NTP_WAIT_MS@ User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp-wait-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:49:55 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:27 AM by AutoGen 5.18.5
.\" From the definitions ntp-wait-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/ntpsweep/Makefile.in b/contrib/ntp/scripts/ntpsweep/Makefile.in
index 45c56c0..6db2194 100644
--- a/contrib/ntp/scripts/ntpsweep/Makefile.in
+++ b/contrib/ntp/scripts/ntpsweep/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/ntpsweep/invoke-ntpsweep.texi b/contrib/ntp/scripts/ntpsweep/invoke-ntpsweep.texi
index 17a7b6e..5375dc1 100644
--- a/contrib/ntp/scripts/ntpsweep/invoke-ntpsweep.texi
+++ b/contrib/ntp/scripts/ntpsweep/invoke-ntpsweep.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntpsweep.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 10:49:59 AM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:31 AM by AutoGen 5.18.5
# From the definitions ntpsweep-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -45,7 +45,7 @@ with a status code of 0.
@exampleindent 0
@example
-ntpsweep - Print various informations about given ntp servers - Ver. 4.2.8p11
+ntpsweep - Print various informations about given ntp servers - Ver. 4.2.8p13
USAGE: ntpsweep [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... [hostfile]
-l, --host-list=str Host to execute actions on
diff --git a/contrib/ntp/scripts/ntpsweep/ntpsweep-opts b/contrib/ntp/scripts/ntpsweep/ntpsweep-opts
index 06dc7ce..5bd7126 100644
--- a/contrib/ntp/scripts/ntpsweep/ntpsweep-opts
+++ b/contrib/ntp/scripts/ntpsweep/ntpsweep-opts
@@ -1,6 +1,6 @@
# EDIT THIS FILE WITH CAUTION (ntpsweep-opts)
#
-# It has been AutoGen-ed February 27, 2018 at 10:49:57 AM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:31 AM by AutoGen 5.18.5
# From the definitions ntpsweep-opts.def
# and the template file perlopt
@@ -43,7 +43,7 @@ sub processOptions {
'help|?', 'more-help'));
$usage = <<'USAGE';
-ntpsweep - Print various informations about given ntp servers - Ver. 4.2.8p11
+ntpsweep - Print various informations about given ntp servers - Ver. 4.2.8p13
USAGE: ntpsweep [ -<flag> [<val>] | --<name>[{=| }<val>] ]... [hostfile]
-l, --host-list=str Host to execute actions on
diff --git a/contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepman b/contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepman
index 34a48a8..5d2edee 100644
--- a/contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepman
+++ b/contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpsweep 1ntpsweepman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH ntpsweep 1ntpsweepman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-cfaGaS/ag-pfaO_R)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:01 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:33 AM by AutoGen 5.18.5
.\" From the definitions ntpsweep-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepmdoc b/contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepmdoc
index d3b142f..d958cde 100644
--- a/contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepmdoc
+++ b/contrib/ntp/scripts/ntpsweep/ntpsweep.1ntpsweepmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPSWEEP 1ntpsweepmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpsweep-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:04 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:32 AM by AutoGen 5.18.5
.\" From the definitions ntpsweep-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/ntpsweep/ntpsweep.html b/contrib/ntp/scripts/ntpsweep/ntpsweep.html
index b44457b..61095d4 100644
--- a/contrib/ntp/scripts/ntpsweep/ntpsweep.html
+++ b/contrib/ntp/scripts/ntpsweep/ntpsweep.html
@@ -1,96 +1,140 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>ntpsweep User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="ntpsweep User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>ntpsweep User&rsquo;s Manual</title>
+
+<meta name="description" content="ntpsweep User&rsquo;s Manual">
+<meta name="keywords" content="ntpsweep User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">ntpsweep User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpsweep-Description">ntpsweep Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
+
+<body lang="en">
+<h1 class="settitle" align="center">ntpsweep User&rsquo;s Manual</h1>
+
+
+
+
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
</div>
+<h1 class="node-heading">Top</h1>
- <p>This document describes the use of the NTP Project's <code>ntpsweep</code> program.
+<p>This document describes the use of the NTP Project&rsquo;s <code>ntpsweep</code> program.
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntpsweep</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
- <p>This document applies to version 4.2.8p11 of <code>ntpsweep</code>.
+<div class="shortcontents">
+<li><a name="stoc-Invoking-ntpsweep" href="#toc-Invoking-ntpsweep">1 Invoking ntpsweep</a></li>
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-</ul>
</div>
-<ul class="menu">
-<li><a accesskey="1" href="#ntpsweep-Description">ntpsweep Description</a>: Description
-<li><a accesskey="2" href="#ntpsweep-Invocation">ntpsweep Invocation</a>: Invoking ntpsweep
-</ul>
-<div class="node">
-<p><hr>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; ntpsweep Description:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpsweep-Invocation" accesskey="2">ntpsweep Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking ntpsweep
+</td></tr>
+</table>
+
+<hr>
<a name="ntpsweep-Invocation"></a>
-<br>
+<div class="header">
+<p>
+Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
+<a name="Invoking-ntpsweep"></a>
+<h3 class="section">1 Invoking ntpsweep</h3>
+<a name="index-ntpsweep"></a>
+<a name="index-Print-various-informations-about-given-ntp-servers"></a>
-<h3 class="section">0.1 Invoking ntpsweep</h3>
-
-<p><a name="index-ntpsweep-1"></a><a name="index-Print-various-informations-about-given-ntp-servers-2"></a>
-<code>ntpsweep</code>
+<p><code>ntpsweep</code>
prints per host the NTP stratum level, the clock offset in seconds, the daemon
version, the operating system and the processor. Optionally recursing through
all peers.
-
- <p>This section was generated by <strong>AutoGen</strong>,
+</p>
+<p>This section was generated by <strong>AutoGen</strong>,
using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntpsweep</code> program.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntpsweep-usage">ntpsweep usage</a>: ntpsweep help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#ntpsweep-host_002dlist">ntpsweep host-list</a>: host-list option (-l)
-<li><a accesskey="3" href="#ntpsweep-peers">ntpsweep peers</a>: peers option (-p)
-<li><a accesskey="4" href="#ntpsweep-maxlevel">ntpsweep maxlevel</a>: maxlevel option (-m)
-<li><a accesskey="5" href="#ntpsweep-strip">ntpsweep strip</a>: strip option (-s)
-<li><a accesskey="6" href="#ntpsweep-host">ntpsweep host</a>: host option (-h)
-<li><a accesskey="7" href="#ntpsweep-exit-status">ntpsweep exit status</a>: exit status
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntpsweep-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpsweep-host_002dlist">ntpsweep host-list</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpsweep-Invocation">ntpsweep Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntpsweep-usage" accesskey="1">ntpsweep usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntpsweep help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpsweep-host_002dlist" accesskey="2">ntpsweep host-list</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">host-list option (-l)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpsweep-peers" accesskey="3">ntpsweep peers</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">peers option (-p)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpsweep-maxlevel" accesskey="4">ntpsweep maxlevel</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">maxlevel option (-m)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpsweep-strip" accesskey="5">ntpsweep strip</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">strip option (-s)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpsweep-host" accesskey="6">ntpsweep host</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">host option (-h)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntpsweep-exit-status" accesskey="7">ntpsweep exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+</table>
+
+<hr>
+<a name="ntpsweep-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpsweep-host_002dlist" accesskey="n" rel="next">ntpsweep host-list</a>, Up: <a href="#ntpsweep-Invocation" accesskey="u" rel="up">ntpsweep Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.1 ntpsweep help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-ntpsweep-help-3"></a>
-This is the automatically generated usage text for ntpsweep.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="ntpsweep-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h4 class="subsection">1.1 ntpsweep help/usage (<samp>--help</samp>)</h4>
+<a name="index-ntpsweep-help"></a>
+
+<p>This is the automatically generated usage text for ntpsweep.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">ntpsweep - Print various informations about given ntp servers - Ver. 4.2.8p11
+</p>
+<div class="example">
+<pre class="example">ntpsweep - Print various informations about given ntp servers - Ver. 4.2.8p13
USAGE: ntpsweep [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]... [hostfile]
-l, --host-list=str Host to execute actions on
@@ -103,99 +147,102 @@ USAGE: ntpsweep [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;]
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-</pre>
- <div class="node">
-<p><hr>
-<a name="ntpsweep-host_002dlist"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpsweep-peers">ntpsweep peers</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpsweep-usage">ntpsweep usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpsweep-Invocation">ntpsweep Invocation</a>
-<br>
-</div>
+</pre></div>
-<h4 class="subsection">0.1.2 host-list option (-l)</h4>
+<hr>
+<a name="ntpsweep-host_002dlist"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpsweep-peers" accesskey="n" rel="next">ntpsweep peers</a>, Previous: <a href="#ntpsweep-usage" accesskey="p" rel="prev">ntpsweep usage</a>, Up: <a href="#ntpsweep-Invocation" accesskey="u" rel="up">ntpsweep Invocation</a> &nbsp; </p>
+</div>
+<a name="host_002dlist-option-_0028_002dl_0029"></a>
+<h4 class="subsection">1.2 host-list option (-l)</h4>
+<a name="index-ntpsweep_002dhost_002dlist"></a>
-<p><a name="index-ntpsweep_002dhost_002dlist-4"></a>
-This is the &ldquo;host to execute actions on&rdquo; option.
+<p>This is the &ldquo;host to execute actions on&rdquo; option.
This option takes a string argument.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>Use this option to specify the host on which this script operates.
- May appear multiple times.
-<div class="node">
-<p><hr>
-<a name="ntpsweep-peers"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpsweep-maxlevel">ntpsweep maxlevel</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpsweep-host_002dlist">ntpsweep host-list</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpsweep-Invocation">ntpsweep Invocation</a>
-<br>
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>Use this option to specify the host on which this script operates.
+ May appear multiple times.
+</p><hr>
+<a name="ntpsweep-peers"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpsweep-maxlevel" accesskey="n" rel="next">ntpsweep maxlevel</a>, Previous: <a href="#ntpsweep-host_002dlist" accesskey="p" rel="prev">ntpsweep host-list</a>, Up: <a href="#ntpsweep-Invocation" accesskey="u" rel="up">ntpsweep Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.3 peers option (-p)</h4>
-
-<p><a name="index-ntpsweep_002dpeers-5"></a>
-This is the &ldquo;recursively list all peers a host synchronizes to&rdquo; option.
-This option has no <span class="samp">doc</span> documentation.
-<div class="node">
-<p><hr>
-<a name="ntpsweep-maxlevel"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpsweep-strip">ntpsweep strip</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpsweep-peers">ntpsweep peers</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpsweep-Invocation">ntpsweep Invocation</a>
-<br>
+<a name="peers-option-_0028_002dp_0029"></a>
+<h4 class="subsection">1.3 peers option (-p)</h4>
+<a name="index-ntpsweep_002dpeers"></a>
+
+<p>This is the &ldquo;recursively list all peers a host synchronizes to&rdquo; option.
+This option has no &lsquo;<samp>doc</samp>&rsquo; documentation.
+</p><hr>
+<a name="ntpsweep-maxlevel"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpsweep-strip" accesskey="n" rel="next">ntpsweep strip</a>, Previous: <a href="#ntpsweep-peers" accesskey="p" rel="prev">ntpsweep peers</a>, Up: <a href="#ntpsweep-Invocation" accesskey="u" rel="up">ntpsweep Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.4 maxlevel option (-m)</h4>
-
-<p><a name="index-ntpsweep_002dmaxlevel-6"></a>
-This is the &ldquo;traverse peers up to this level (4 is a reasonable number)&rdquo; option.
-This option takes a number argument.
-This option has no <span class="samp">doc</span> documentation.
-<div class="node">
-<p><hr>
-<a name="ntpsweep-strip"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpsweep-host">ntpsweep host</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpsweep-maxlevel">ntpsweep maxlevel</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpsweep-Invocation">ntpsweep Invocation</a>
-<br>
+<a name="maxlevel-option-_0028_002dm_0029"></a>
+<h4 class="subsection">1.4 maxlevel option (-m)</h4>
+<a name="index-ntpsweep_002dmaxlevel"></a>
+
+<p>This is the &ldquo;traverse peers up to this level (4 is a reasonable number)&rdquo; option.
+This option takes a number argument.
+This option has no &lsquo;<samp>doc</samp>&rsquo; documentation.
+</p><hr>
+<a name="ntpsweep-strip"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpsweep-host" accesskey="n" rel="next">ntpsweep host</a>, Previous: <a href="#ntpsweep-maxlevel" accesskey="p" rel="prev">ntpsweep maxlevel</a>, Up: <a href="#ntpsweep-Invocation" accesskey="u" rel="up">ntpsweep Invocation</a> &nbsp; </p>
</div>
+<a name="strip-option-_0028_002ds_0029"></a>
+<h4 class="subsection">1.5 strip option (-s)</h4>
+<a name="index-ntpsweep_002dstrip"></a>
-<h4 class="subsection">0.1.5 strip option (-s)</h4>
-
-<p><a name="index-ntpsweep_002dstrip-7"></a>
-This is the &ldquo;strip this string from hostnames&rdquo; option.
-This option takes a string argument.
-This option has no <span class="samp">doc</span> documentation.
-<div class="node">
-<p><hr>
-<a name="ntpsweep-host"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntpsweep-exit-status">ntpsweep exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpsweep-strip">ntpsweep strip</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpsweep-Invocation">ntpsweep Invocation</a>
-<br>
+<p>This is the &ldquo;strip this string from hostnames&rdquo; option.
+This option takes a string argument.
+This option has no &lsquo;<samp>doc</samp>&rsquo; documentation.
+</p><hr>
+<a name="ntpsweep-host"></a>
+<div class="header">
+<p>
+Next: <a href="#ntpsweep-exit-status" accesskey="n" rel="next">ntpsweep exit status</a>, Previous: <a href="#ntpsweep-strip" accesskey="p" rel="prev">ntpsweep strip</a>, Up: <a href="#ntpsweep-Invocation" accesskey="u" rel="up">ntpsweep Invocation</a> &nbsp; </p>
</div>
+<a name="host-option-_0028_002dh_0029"></a>
+<h4 class="subsection">1.6 host option (-h)</h4>
+<a name="index-ntpsweep_002dhost"></a>
-<h4 class="subsection">0.1.6 host option (-h)</h4>
-
-<p><a name="index-ntpsweep_002dhost-8"></a>
-This is the &ldquo;specify a single host&rdquo; option.
-This option takes a string argument.
-This option has no <span class="samp">doc</span> documentation.
-
- <p><strong>NOTE</strong><strong>: THIS OPTION IS DEPRECATED</strong>
-<div class="node">
-<p><hr>
-<a name="ntpsweep-exit-status"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntpsweep-host">ntpsweep host</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntpsweep-Invocation">ntpsweep Invocation</a>
-<br>
+<p>This is the &ldquo;specify a single host&rdquo; option.
+This option takes a string argument.
+This option has no &lsquo;<samp>doc</samp>&rsquo; documentation.
+</p>
+<p><strong>NOTE</strong><strong>: THIS OPTION IS DEPRECATED</strong>
+</p><hr>
+<a name="ntpsweep-exit-status"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntpsweep-host" accesskey="p" rel="prev">ntpsweep host</a>, Up: <a href="#ntpsweep-Invocation" accesskey="u" rel="up">ntpsweep Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.7 ntpsweep exit status</h4>
+<a name="ntpsweep-exit-status-1"></a>
+<h4 class="subsection">1.7 ntpsweep exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
</dl>
+<hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/scripts/ntpsweep/ntpsweep.man.in b/contrib/ntp/scripts/ntpsweep/ntpsweep.man.in
index 34a48a8..5d2edee 100644
--- a/contrib/ntp/scripts/ntpsweep/ntpsweep.man.in
+++ b/contrib/ntp/scripts/ntpsweep/ntpsweep.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntpsweep 1ntpsweepman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH ntpsweep 1ntpsweepman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-cfaGaS/ag-pfaO_R)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:01 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:33 AM by AutoGen 5.18.5
.\" From the definitions ntpsweep-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/ntpsweep/ntpsweep.mdoc.in b/contrib/ntp/scripts/ntpsweep/ntpsweep.mdoc.in
index d3b142f..d958cde 100644
--- a/contrib/ntp/scripts/ntpsweep/ntpsweep.mdoc.in
+++ b/contrib/ntp/scripts/ntpsweep/ntpsweep.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPSWEEP 1ntpsweepmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpsweep-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:04 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:32 AM by AutoGen 5.18.5
.\" From the definitions ntpsweep-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/ntptrace/Makefile.in b/contrib/ntp/scripts/ntptrace/Makefile.in
index 7ce2614..9d87e0e 100644
--- a/contrib/ntp/scripts/ntptrace/Makefile.in
+++ b/contrib/ntp/scripts/ntptrace/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/ntptrace/invoke-ntptrace.texi b/contrib/ntp/scripts/ntptrace/invoke-ntptrace.texi
index f10f347..746689e 100644
--- a/contrib/ntp/scripts/ntptrace/invoke-ntptrace.texi
+++ b/contrib/ntp/scripts/ntptrace/invoke-ntptrace.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntptrace.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 10:50:11 AM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:36 AM by AutoGen 5.18.5
# From the definitions ntptrace-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -62,7 +62,7 @@ with a status code of 0.
@exampleindent 0
@example
-ntptrace - Trace peers of an NTP server - Ver. 4.2.8p11
+ntptrace - Trace peers of an NTP server - Ver. 4.2.8p13
USAGE: ntptrace [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... [host]
-n, --numeric Print IP addresses instead of hostnames
diff --git a/contrib/ntp/scripts/ntptrace/ntptrace-opts b/contrib/ntp/scripts/ntptrace/ntptrace-opts
index 17f513a..6545bff 100644
--- a/contrib/ntp/scripts/ntptrace/ntptrace-opts
+++ b/contrib/ntp/scripts/ntptrace/ntptrace-opts
@@ -1,6 +1,6 @@
# EDIT THIS FILE WITH CAUTION (ntptrace-opts)
#
-# It has been AutoGen-ed February 27, 2018 at 10:50:06 AM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:35 AM by AutoGen 5.18.5
# From the definitions ntptrace-opts.def
# and the template file perlopt
@@ -40,7 +40,7 @@ sub processOptions {
'help|?', 'more-help'));
$usage = <<'USAGE';
-ntptrace - Trace peers of an NTP server - Ver. 4.2.8p11
+ntptrace - Trace peers of an NTP server - Ver. 4.2.8p13
USAGE: ntptrace [ -<flag> [<val>] | --<name>[{=| }<val>] ]... [host]
-n, --numeric Print IP addresses instead of hostnames
diff --git a/contrib/ntp/scripts/ntptrace/ntptrace.1ntptraceman b/contrib/ntp/scripts/ntptrace/ntptrace.1ntptraceman
index 2c4e1b0..79864da 100644
--- a/contrib/ntp/scripts/ntptrace/ntptrace.1ntptraceman
+++ b/contrib/ntp/scripts/ntptrace/ntptrace.1ntptraceman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntptrace 1ntptraceman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH ntptrace 1ntptraceman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-wXa4cT/ag-JXaacT)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:08 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:37 AM by AutoGen 5.18.5
.\" From the definitions ntptrace-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/ntptrace/ntptrace.1ntptracemdoc b/contrib/ntp/scripts/ntptrace/ntptrace.1ntptracemdoc
index f4c355c..7a535d0 100644
--- a/contrib/ntp/scripts/ntptrace/ntptrace.1ntptracemdoc
+++ b/contrib/ntp/scripts/ntptrace/ntptrace.1ntptracemdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPTRACE 1ntptracemdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntptrace-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:13 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:35 AM by AutoGen 5.18.5
.\" From the definitions ntptrace-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/ntptrace/ntptrace.html b/contrib/ntp/scripts/ntptrace/ntptrace.html
index 53a16e9..9160de2 100644
--- a/contrib/ntp/scripts/ntptrace/ntptrace.html
+++ b/contrib/ntp/scripts/ntptrace/ntptrace.html
@@ -1,113 +1,156 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>Ntptrace User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="Ntptrace User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Ntptrace User&rsquo;s Manual</title>
+
+<meta name="description" content="Ntptrace User&rsquo;s Manual">
+<meta name="keywords" content="Ntptrace User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">Ntptrace User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntptrace-Description">ntptrace Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">Simple Network Time Protocol User Manual</h2>
+<body lang="en">
+<h1 class="settitle" align="center">Ntptrace User&rsquo;s Manual</h1>
+
+
+
-<p>This document describes the use of the NTP Project's <code>ntptrace</code> program.
-This document applies to version 4.2.8p11 of <code>ntptrace</code>.
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">Simple Network Time Protocol User Manual</a>
+<a name="Top"></a>
+<div class="header">
+<p>
+Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="Simple-Network-Time-Protocol-User-Manual"></a>
+<h1 class="top">Simple Network Time Protocol User Manual</h1>
+
+<p>This document describes the use of the NTP Project&rsquo;s <code>ntptrace</code> program.
+This document applies to version 4.2.8p13 of <code>ntptrace</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
+
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Invoking-ntptrace" href="#toc-Invoking-ntptrace">1 Invoking ntptrace</a></li>
</ul>
</div>
-<ul class="menu">
-<li><a accesskey="1" href="#ntptrace-Description">ntptrace Description</a>: Description
-<li><a accesskey="2" href="#ntptrace-Invocation">ntptrace Invocation</a>: Invoking ntptrace
-</ul>
-<div class="node">
-<p><hr>
-<a name="ntptrace-Invocation"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntptrace-Description">ntptrace Description</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
-</div>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; ntptrace Description:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-Invocation" accesskey="2">ntptrace Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking ntptrace
+</td></tr>
+</table>
-<h3 class="section">Invoking ntptrace</h3>
+<hr>
+<a name="ntptrace-Invocation"></a>
+<div class="header">
+<p>
+Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
+</div>
+<a name="Invoking-ntptrace"></a>
+<h2 class="chapter">1 Invoking ntptrace</h2>
+<a name="index-ntptrace"></a>
+<a name="index-Trace-peers-of-an-NTP-server"></a>
-<p><a name="index-ntptrace-1"></a><a name="index-Trace-peers-of-an-NTP-server-2"></a>
-<code>ntptrace</code> is a perl script that uses the ntpq utility program to follow
+<p><code>ntptrace</code> is a perl script that uses the ntpq utility program to follow
the chain of NTP servers from a given host back to the primary time source. For
ntptrace to work properly, each of these servers must implement the NTP Control
and Monitoring Protocol specified in RFC 1305 and enable NTP Mode 6 packets.
-
- <p>If given no arguments, ntptrace starts with localhost. Here is an example of
+</p>
+<p>If given no arguments, ntptrace starts with localhost. Here is an example of
the output from ntptrace:
-
-<pre class="example"> % ntptrace localhost: stratum 4, offset 0.0019529, synch distance 0.144135
- server2ozo.com: stratum 2, offset 0.0124263, synch distance 0.115784 usndh.edu:
- stratum 1, offset 0.0019298, synch distance 0.011993, refid 'WWVB'
-</pre>
- <p>On each line, the fields are (left to right): the host name, the host stratum,
+</p>
+<div class="example">
+<pre class="example">% ntptrace localhost: stratum 4, offset 0.0019529, synch distance 0.144135
+server2ozo.com: stratum 2, offset 0.0124263, synch distance 0.115784 usndh.edu:
+stratum 1, offset 0.0019298, synch distance 0.011993, refid 'WWVB'
+</pre></div>
+
+<p>On each line, the fields are (left to right): the host name, the host stratum,
the time offset between that host and the local host (as measured by
-<code>ntptrace</code>; this is why it is not always zero for "localhost"), the host
+<code>ntptrace</code>; this is why it is not always zero for &quot;localhost&quot;), the host
synchronization distance, and (only for stratum-1 servers) the reference clock
ID. All times are given in seconds. Note that the stratum is the server hop
count to the primary source, while the synchronization distance is the
estimated error relative to the primary source. These terms are precisely
defined in RFC-1305.
+</p>
- <p>This section was generated by <strong>AutoGen</strong>,
+<p>This section was generated by <strong>AutoGen</strong>,
using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntptrace</code> program.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntptrace-usage">ntptrace usage</a>: ntptrace help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#ntptrace-numeric">ntptrace numeric</a>: numeric option (-n)
-<li><a accesskey="3" href="#ntptrace-max_002dhosts">ntptrace max-hosts</a>: max-hosts option (-m)
-<li><a accesskey="4" href="#ntptrace-host">ntptrace host</a>: host option (-r)
-<li><a accesskey="5" href="#ntptrace-exit-status">ntptrace exit status</a>: exit status
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntptrace-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntptrace-numeric">ntptrace numeric</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntptrace-Invocation">ntptrace Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-usage" accesskey="1">ntptrace usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntptrace help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-numeric" accesskey="2">ntptrace numeric</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">numeric option (-n)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-max_002dhosts" accesskey="3">ntptrace max-hosts</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">max-hosts option (-m)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-host" accesskey="4">ntptrace host</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">host option (-r)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-exit-status" accesskey="5">ntptrace exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+</table>
+
+<hr>
+<a name="ntptrace-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntptrace-numeric" accesskey="n" rel="next">ntptrace numeric</a>, Up: <a href="#ntptrace-Invocation" accesskey="u" rel="up">ntptrace Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntptrace help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-ntptrace-help-3"></a>
-This is the automatically generated usage text for ntptrace.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="ntptrace-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h3 class="section">1.1 ntptrace help/usage (<samp>--help</samp>)</h3>
+<a name="index-ntptrace-help"></a>
+
+<p>This is the automatically generated usage text for ntptrace.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">ntptrace - Trace peers of an NTP server - Ver. 4.2.8p11
+</p>
+<div class="example">
+<pre class="example">ntptrace - Trace peers of an NTP server - Ver. 4.2.8p13
USAGE: ntptrace [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]... [host]
-n, --numeric Print IP addresses instead of hostnames
@@ -118,63 +161,79 @@ USAGE: ntptrace [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;]
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-</pre>
- <div class="node">
-<p><hr>
-<a name="ntptrace-numeric"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntptrace-max_002dhosts">ntptrace max-hosts</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntptrace-usage">ntptrace usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntptrace-Invocation">ntptrace Invocation</a>
-<br>
+</pre></div>
+
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-numeric" accesskey="1">ntptrace numeric</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-max_002dhosts" accesskey="2">ntptrace max-hosts</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-host" accesskey="3">ntptrace host</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntptrace-exit-status" accesskey="4">ntptrace exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="ntptrace-numeric"></a>
+<div class="header">
+<p>
+Next: <a href="#ntptrace-max_002dhosts" accesskey="n" rel="next">ntptrace max-hosts</a>, Previous: <a href="#ntptrace-usage" accesskey="p" rel="prev">ntptrace usage</a>, Up: <a href="#ntptrace-usage" accesskey="u" rel="up">ntptrace usage</a> &nbsp; </p>
</div>
+<a name="numeric-option-_0028_002dn_0029"></a>
+<h4 class="subsection">1.1.1 numeric option (-n)</h4>
+<a name="index-ntptrace_002dnumeric"></a>
-<h4 class="subsection">numeric option (-n)</h4>
-
-<p><a name="index-ntptrace_002dnumeric-4"></a>
-This is the &ldquo;print ip addresses instead of hostnames&rdquo; option.
+<p>This is the &ldquo;print ip addresses instead of hostnames&rdquo; option.
Output hosts as dotted-quad numeric format rather than converting to
-the canonical host names.
-<div class="node">
-<p><hr>
-<a name="ntptrace-max_002dhosts"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntptrace-host">ntptrace host</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntptrace-numeric">ntptrace numeric</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntptrace-Invocation">ntptrace Invocation</a>
-<br>
+the canonical host names.
+</p><hr>
+<a name="ntptrace-max_002dhosts"></a>
+<div class="header">
+<p>
+Next: <a href="#ntptrace-host" accesskey="n" rel="next">ntptrace host</a>, Previous: <a href="#ntptrace-numeric" accesskey="p" rel="prev">ntptrace numeric</a>, Up: <a href="#ntptrace-usage" accesskey="u" rel="up">ntptrace usage</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">max-hosts option (-m)</h4>
-
-<p><a name="index-ntptrace_002dmax_002dhosts-5"></a>
-This is the &ldquo;maximum number of peers to trace&rdquo; option.
-This option takes a number argument.
-This option has no <span class="samp">doc</span> documentation.
-<div class="node">
-<p><hr>
-<a name="ntptrace-host"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntptrace-exit-status">ntptrace exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntptrace-max_002dhosts">ntptrace max-hosts</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntptrace-Invocation">ntptrace Invocation</a>
-<br>
+<a name="max_002dhosts-option-_0028_002dm_0029"></a>
+<h4 class="subsection">1.1.2 max-hosts option (-m)</h4>
+<a name="index-ntptrace_002dmax_002dhosts"></a>
+
+<p>This is the &ldquo;maximum number of peers to trace&rdquo; option.
+This option takes a number argument.
+This option has no &lsquo;<samp>doc</samp>&rsquo; documentation.
+</p><hr>
+<a name="ntptrace-host"></a>
+<div class="header">
+<p>
+Next: <a href="#ntptrace-exit-status" accesskey="n" rel="next">ntptrace exit status</a>, Previous: <a href="#ntptrace-max_002dhosts" accesskey="p" rel="prev">ntptrace max-hosts</a>, Up: <a href="#ntptrace-usage" accesskey="u" rel="up">ntptrace usage</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">host option (-r)</h4>
-
-<p><a name="index-ntptrace_002dhost-6"></a>
-This is the &ldquo;single remote host&rdquo; option.
-This option takes a string argument.
-This option has no <span class="samp">doc</span> documentation.
-<div class="node">
-<p><hr>
-<a name="ntptrace-exit-status"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntptrace-host">ntptrace host</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntptrace-Invocation">ntptrace Invocation</a>
-<br>
+<a name="host-option-_0028_002dr_0029"></a>
+<h4 class="subsection">1.1.3 host option (-r)</h4>
+<a name="index-ntptrace_002dhost"></a>
+
+<p>This is the &ldquo;single remote host&rdquo; option.
+This option takes a string argument.
+This option has no &lsquo;<samp>doc</samp>&rsquo; documentation.
+</p><hr>
+<a name="ntptrace-exit-status"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntptrace-host" accesskey="p" rel="prev">ntptrace host</a>, Up: <a href="#ntptrace-usage" accesskey="u" rel="up">ntptrace usage</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntptrace exit status</h4>
+<a name="ntptrace-exit-status-1"></a>
+<h4 class="subsection">1.1.4 ntptrace exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
</dl>
+<hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/scripts/ntptrace/ntptrace.man.in b/contrib/ntp/scripts/ntptrace/ntptrace.man.in
index 756e60e..2b498a6 100644
--- a/contrib/ntp/scripts/ntptrace/ntptrace.man.in
+++ b/contrib/ntp/scripts/ntptrace/ntptrace.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntptrace @NTPTRACE_MS@ "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH ntptrace @NTPTRACE_MS@ "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-wXa4cT/ag-JXaacT)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:08 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:37 AM by AutoGen 5.18.5
.\" From the definitions ntptrace-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/ntptrace/ntptrace.mdoc.in b/contrib/ntp/scripts/ntptrace/ntptrace.mdoc.in
index 7a50caf..879dcdf 100644
--- a/contrib/ntp/scripts/ntptrace/ntptrace.mdoc.in
+++ b/contrib/ntp/scripts/ntptrace/ntptrace.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTPTRACE @NTPTRACE_MS@ User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntptrace-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:13 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:35 AM by AutoGen 5.18.5
.\" From the definitions ntptrace-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/plot_summary-opts b/contrib/ntp/scripts/plot_summary-opts
index 462150b..2e01262 100644
--- a/contrib/ntp/scripts/plot_summary-opts
+++ b/contrib/ntp/scripts/plot_summary-opts
@@ -1,6 +1,6 @@
# EDIT THIS FILE WITH CAUTION (plot_summary-opts)
#
-# It has been AutoGen-ed February 27, 2018 at 04:55:55 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 05:04:25 PM by AutoGen 5.18.5
# From the definitions plot_summary-opts.def
# and the template file perlopt
@@ -46,7 +46,7 @@ sub processOptions {
'help|?', 'more-help'));
$usage = <<'USAGE';
-plot_summary - plot statistics generated by summary script - Ver. 4.2.8p11
+plot_summary - plot statistics generated by summary script - Ver. 4.2.8p13
USAGE: plot_summary [ -<flag> [<val>] | --<name>[{=| }<val>] ]...
--directory=str Where the summary files are
diff --git a/contrib/ntp/scripts/plot_summary.1plot_summaryman b/contrib/ntp/scripts/plot_summary.1plot_summaryman
index f3a2a8e..d8188c3 100644
--- a/contrib/ntp/scripts/plot_summary.1plot_summaryman
+++ b/contrib/ntp/scripts/plot_summary.1plot_summaryman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH plot_summary 1plot_summaryman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH plot_summary 1plot_summaryman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-NpayvG/ag-0paGuG)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:56:00 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:26 PM by AutoGen 5.18.5
.\" From the definitions plot_summary-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/plot_summary.1plot_summarymdoc b/contrib/ntp/scripts/plot_summary.1plot_summarymdoc
index f2ff40f..d3a9f7b 100644
--- a/contrib/ntp/scripts/plot_summary.1plot_summarymdoc
+++ b/contrib/ntp/scripts/plot_summary.1plot_summarymdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt PLOT_SUMMARY 1plot_summarymdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (plot_summary-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:56:02 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:27 PM by AutoGen 5.18.5
.\" From the definitions plot_summary-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/plot_summary.html b/contrib/ntp/scripts/plot_summary.html
index 6a2fac5..529a761 100644
--- a/contrib/ntp/scripts/plot_summary.html
+++ b/contrib/ntp/scripts/plot_summary.html
@@ -1,96 +1,138 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>Plot_summary User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="Plot_summary User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
-</head>
-<body>
-<h1 class="settitle">Plot_summary User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#plot_005fsummary-Description">plot_summary Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Plot_summary User&rsquo;s Manual</title>
+
+<meta name="description" content="Plot_summary User&rsquo;s Manual">
+<meta name="keywords" content="Plot_summary User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
-<h2 class="unnumbered">Plot_summary User Manual</h2>
-<p>This document describes the use of the NTP Project's <code>plot_summary</code> program.
-This document applies to version 4.2.8p11 of <code>plot_summary</code>.
+</head>
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">Plot_summary User Manual</a>
-</ul>
-</div>
+<body lang="en">
+<h1 class="settitle" align="center">Plot_summary User&rsquo;s Manual</h1>
-<ul class="menu">
-<li><a accesskey="1" href="#plot_005fsummary-Description">plot_summary Description</a>: Description
-<li><a accesskey="2" href="#plot_005fsummary-Invocation">plot_summary Invocation</a>: Invoking plot_summary
-</ul>
-<div class="node">
-<p><hr>
-<a name="plot_005fsummary-Invocation"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#plot_005fsummary-Description">plot_summary Description</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
-</div>
-<h3 class="section">Invoking plot_summary</h3>
-<p><a name="index-plot_005fsummary-1"></a><a name="index-plot-statistics-generated-by-summary-script-2"></a>
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>plot_summary</code> program.
-
-<ul class="menu">
-<li><a accesskey="1" href="#plot_005fsummary-usage">plot_summary usage</a>: plot_summary help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#plot_005fsummary-directory">plot_summary directory</a>: directory option
-<li><a accesskey="3" href="#plot_005fsummary-identifier">plot_summary identifier</a>: identifier option
-<li><a accesskey="4" href="#plot_005fsummary-peer">plot_summary peer</a>: peer option
-<li><a accesskey="5" href="#plot_005fsummary-plot_002dterm">plot_summary plot-term</a>: plot-term option
-<li><a accesskey="6" href="#plot_005fsummary-output_002dfile">plot_summary output-file</a>: output-file option
-<li><a accesskey="7" href="#plot_005fsummary-exit-status">plot_summary exit status</a>: exit status
+<a name="Top"></a>
+<div class="header">
+<p>
+Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="Plot_005fsummary-User-Manual"></a>
+<h1 class="top">Plot_summary User Manual</h1>
+
+<p>This document describes the use of the NTP Project&rsquo;s <code>plot_summary</code> program.
+This document applies to version 4.2.8p13 of <code>plot_summary</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
+
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Invoking-plot_005fsummary" href="#toc-Invoking-plot_005fsummary">1 Invoking plot_summary</a></li>
</ul>
-
-<div class="node">
-<p><hr>
-<a name="plot_005fsummary-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#plot_005fsummary-directory">plot_summary directory</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#plot_005fsummary-Invocation">plot_summary Invocation</a>
-<br>
</div>
-<h4 class="subsection">plot_summary help/usage (<span class="option">--help</span>)</h4>
-<p><a name="index-plot_005fsummary-help-3"></a>
-This is the automatically generated usage text for plot_summary.
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; plot_summary Description:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-Invocation" accesskey="2">plot_summary Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking plot_summary
+</td></tr>
+</table>
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<hr>
+<a name="plot_005fsummary-Invocation"></a>
+<div class="header">
+<p>
+Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
+</div>
+<a name="Invoking-plot_005fsummary"></a>
+<h2 class="chapter">1 Invoking plot_summary</h2>
+<a name="index-plot_005fsummary"></a>
+<a name="index-plot-statistics-generated-by-summary-script"></a>
+
+
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>plot_summary</code> program.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-usage" accesskey="1">plot_summary usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">plot_summary help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-directory" accesskey="2">plot_summary directory</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">directory option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-identifier" accesskey="3">plot_summary identifier</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">identifier option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-peer" accesskey="4">plot_summary peer</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">peer option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-plot_002dterm" accesskey="5">plot_summary plot-term</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">plot-term option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-output_002dfile" accesskey="6">plot_summary output-file</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">output-file option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-exit-status" accesskey="7">plot_summary exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+</table>
+
+<hr>
+<a name="plot_005fsummary-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#plot_005fsummary-directory" accesskey="n" rel="next">plot_summary directory</a>, Up: <a href="#plot_005fsummary-Invocation" accesskey="u" rel="up">plot_summary Invocation</a> &nbsp; </p>
+</div>
+<a name="plot_005fsummary-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h3 class="section">1.1 plot_summary help/usage (<samp>--help</samp>)</h3>
+<a name="index-plot_005fsummary-help"></a>
+
+<p>This is the automatically generated usage text for plot_summary.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">plot_summary - plot statistics generated by summary script - Ver. 4.2.8p11
-USAGE: plot_summary [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
+</p>
+<div class="example">
+<pre class="example">plot_summary - plot statistics generated by summary script - Ver. 4.2.8p13
+USAGE: plot_summary [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
--directory=str Where the summary files are
--identifier=str Origin of the data
@@ -105,103 +147,121 @@ USAGE: plot_summary [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-</pre>
- <div class="node">
-<p><hr>
-<a name="plot_005fsummary-directory"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#plot_005fsummary-identifier">plot_summary identifier</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#plot_005fsummary-usage">plot_summary usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#plot_005fsummary-Invocation">plot_summary Invocation</a>
-<br>
+</pre></div>
+
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-directory" accesskey="1">plot_summary directory</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-identifier" accesskey="2">plot_summary identifier</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-peer" accesskey="3">plot_summary peer</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-plot_002dterm" accesskey="4">plot_summary plot-term</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-output_002dfile" accesskey="5">plot_summary output-file</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#plot_005fsummary-exit-status" accesskey="6">plot_summary exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="plot_005fsummary-directory"></a>
+<div class="header">
+<p>
+Next: <a href="#plot_005fsummary-identifier" accesskey="n" rel="next">plot_summary identifier</a>, Previous: <a href="#plot_005fsummary-usage" accesskey="p" rel="prev">plot_summary usage</a>, Up: <a href="#plot_005fsummary-usage" accesskey="u" rel="up">plot_summary usage</a> &nbsp; </p>
</div>
+<a name="directory-option"></a>
+<h4 class="subsection">1.1.1 directory option</h4>
+<a name="index-plot_005fsummary_002ddirectory"></a>
-<h4 class="subsection">directory option</h4>
-
-<p><a name="index-plot_005fsummary_002ddirectory-4"></a>
-This is the &ldquo;where the summary files are&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;where the summary files are&rdquo; option.
+This option takes a string argument.
The directory where the <code>plot_summary</code> will search for the
- *_summary files generated by <code>summary</code> script.
-<div class="node">
-<p><hr>
-<a name="plot_005fsummary-identifier"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#plot_005fsummary-peer">plot_summary peer</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#plot_005fsummary-directory">plot_summary directory</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#plot_005fsummary-Invocation">plot_summary Invocation</a>
-<br>
+ *_summary files generated by <code>summary</code> script.
+</p><hr>
+<a name="plot_005fsummary-identifier"></a>
+<div class="header">
+<p>
+Next: <a href="#plot_005fsummary-peer" accesskey="n" rel="next">plot_summary peer</a>, Previous: <a href="#plot_005fsummary-directory" accesskey="p" rel="prev">plot_summary directory</a>, Up: <a href="#plot_005fsummary-usage" accesskey="u" rel="up">plot_summary usage</a> &nbsp; </p>
</div>
+<a name="identifier-option"></a>
+<h4 class="subsection">1.1.2 identifier option</h4>
+<a name="index-plot_005fsummary_002didentifier"></a>
-<h4 class="subsection">identifier option</h4>
-
-<p><a name="index-plot_005fsummary_002didentifier-5"></a>
-This is the &ldquo;origin of the data&rdquo; option.
-This option takes a string argument.
- Where does the plotted data come from, default to string "host" plus
+<p>This is the &ldquo;origin of the data&rdquo; option.
+This option takes a string argument.
+ Where does the plotted data come from, default to string &quot;host&quot; plus
current hostname
-<div class="node">
-<p><hr>
-<a name="plot_005fsummary-peer"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#plot_005fsummary-plot_002dterm">plot_summary plot-term</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#plot_005fsummary-identifier">plot_summary identifier</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#plot_005fsummary-Invocation">plot_summary Invocation</a>
-<br>
+</p><hr>
+<a name="plot_005fsummary-peer"></a>
+<div class="header">
+<p>
+Next: <a href="#plot_005fsummary-plot_002dterm" accesskey="n" rel="next">plot_summary plot-term</a>, Previous: <a href="#plot_005fsummary-identifier" accesskey="p" rel="prev">plot_summary identifier</a>, Up: <a href="#plot_005fsummary-usage" accesskey="u" rel="up">plot_summary usage</a> &nbsp; </p>
</div>
+<a name="peer-option"></a>
+<h4 class="subsection">1.1.3 peer option</h4>
+<a name="index-plot_005fsummary_002dpeer"></a>
-<h4 class="subsection">peer option</h4>
-
-<p><a name="index-plot_005fsummary_002dpeer-6"></a>
-This is the &ldquo;peers to generate plots for&rdquo; option.
+<p>This is the &ldquo;peers to generate plots for&rdquo; option.
This option takes a string argument.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>By default the peer_summary plots are not generated. Use this option to
- specify list of peers if you want to generate plots for them.
-<div class="node">
-<p><hr>
-<a name="plot_005fsummary-plot_002dterm"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#plot_005fsummary-output_002dfile">plot_summary output-file</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#plot_005fsummary-peer">plot_summary peer</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#plot_005fsummary-Invocation">plot_summary Invocation</a>
-<br>
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>By default the peer_summary plots are not generated. Use this option to
+ specify list of peers if you want to generate plots for them.
+</p><hr>
+<a name="plot_005fsummary-plot_002dterm"></a>
+<div class="header">
+<p>
+Next: <a href="#plot_005fsummary-output_002dfile" accesskey="n" rel="next">plot_summary output-file</a>, Previous: <a href="#plot_005fsummary-peer" accesskey="p" rel="prev">plot_summary peer</a>, Up: <a href="#plot_005fsummary-usage" accesskey="u" rel="up">plot_summary usage</a> &nbsp; </p>
</div>
+<a name="plot_002dterm-option"></a>
+<h4 class="subsection">1.1.4 plot-term option</h4>
+<a name="index-plot_005fsummary_002dplot_002dterm"></a>
-<h4 class="subsection">plot-term option</h4>
-
-<p><a name="index-plot_005fsummary_002dplot_002dterm-7"></a>
-This is the &ldquo;gnuplot terminal&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;gnuplot terminal&rdquo; option.
+This option takes a string argument.
This is string is passed directly to the <code>gnuplot set terminal</code>
command. Default is <code>x11</code> if <code>DISPLAY</code> is set and
- <code>dumb</code> is it's not'. See output from -e "set
- terminal") for the list of available options.
-<div class="node">
-<p><hr>
-<a name="plot_005fsummary-output_002dfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#plot_005fsummary-exit-status">plot_summary exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#plot_005fsummary-plot_002dterm">plot_summary plot-term</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#plot_005fsummary-Invocation">plot_summary Invocation</a>
-<br>
+ <code>dumb</code> is it&rsquo;s not&rsquo;. See output from (gnuplot -e &quot;set
+ terminal&quot;) for the list of available options.
+</p><hr>
+<a name="plot_005fsummary-output_002dfile"></a>
+<div class="header">
+<p>
+Next: <a href="#plot_005fsummary-exit-status" accesskey="n" rel="next">plot_summary exit status</a>, Previous: <a href="#plot_005fsummary-plot_002dterm" accesskey="p" rel="prev">plot_summary plot-term</a>, Up: <a href="#plot_005fsummary-usage" accesskey="u" rel="up">plot_summary usage</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">output-file option</h4>
-
-<p><a name="index-plot_005fsummary_002doutput_002dfile-8"></a>
-This is the &ldquo;output file&rdquo; option.
-This option takes a str argument.
- Output file for <code>gnuplot</code>, default to stdout.
-<div class="node">
-<p><hr>
-<a name="plot_005fsummary-exit-status"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#plot_005fsummary-output_002dfile">plot_summary output-file</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#plot_005fsummary-Invocation">plot_summary Invocation</a>
-<br>
+<a name="output_002dfile-option"></a>
+<h4 class="subsection">1.1.5 output-file option</h4>
+<a name="index-plot_005fsummary_002doutput_002dfile"></a>
+
+<p>This is the &ldquo;output file&rdquo; option.
+This option takes a str argument.
+ Output file for <code>gnuplot</code>, default to stdout.
+</p><hr>
+<a name="plot_005fsummary-exit-status"></a>
+<div class="header">
+<p>
+Previous: <a href="#plot_005fsummary-output_002dfile" accesskey="p" rel="prev">plot_summary output-file</a>, Up: <a href="#plot_005fsummary-usage" accesskey="u" rel="up">plot_summary usage</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">plot_summary exit status</h4>
+<a name="plot_005fsummary-exit-status-1"></a>
+<h4 class="subsection">1.1.6 plot_summary exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
</dl>
+<hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/scripts/plot_summary.man.in b/contrib/ntp/scripts/plot_summary.man.in
index f3a2a8e..d8188c3 100644
--- a/contrib/ntp/scripts/plot_summary.man.in
+++ b/contrib/ntp/scripts/plot_summary.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH plot_summary 1plot_summaryman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH plot_summary 1plot_summaryman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-NpayvG/ag-0paGuG)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:56:00 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:26 PM by AutoGen 5.18.5
.\" From the definitions plot_summary-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/plot_summary.mdoc.in b/contrib/ntp/scripts/plot_summary.mdoc.in
index f2ff40f..d3a9f7b 100644
--- a/contrib/ntp/scripts/plot_summary.mdoc.in
+++ b/contrib/ntp/scripts/plot_summary.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt PLOT_SUMMARY 1plot_summarymdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (plot_summary-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:56:02 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:27 PM by AutoGen 5.18.5
.\" From the definitions plot_summary-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/summary-opts b/contrib/ntp/scripts/summary-opts
index 08effab..9c3102f 100644
--- a/contrib/ntp/scripts/summary-opts
+++ b/contrib/ntp/scripts/summary-opts
@@ -1,6 +1,6 @@
# EDIT THIS FILE WITH CAUTION (summary-opts)
#
-# It has been AutoGen-ed February 27, 2018 at 04:55:57 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 05:04:25 PM by AutoGen 5.18.5
# From the definitions summary-opts.def
# and the template file perlopt
@@ -44,7 +44,7 @@ sub processOptions {
'help|?', 'more-help'));
$usage = <<'USAGE';
-summary - compute various stastics from NTP stat files - Ver. 4.2.8p11
+summary - compute various stastics from NTP stat files - Ver. 4.2.8p13
USAGE: summary [ -<flag> [<val>] | --<name>[{=| }<val>] ]...
--directory=str Directory containing stat files
diff --git a/contrib/ntp/scripts/summary.1summaryman b/contrib/ntp/scripts/summary.1summaryman
index d4011fb..932c498 100644
--- a/contrib/ntp/scripts/summary.1summaryman
+++ b/contrib/ntp/scripts/summary.1summaryman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH summary 1summaryman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH summary 1summaryman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-AMaaJG/ag-NMaiIG)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:56:06 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:30 PM by AutoGen 5.18.5
.\" From the definitions summary-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/summary.1summarymdoc b/contrib/ntp/scripts/summary.1summarymdoc
index 6c8eee7..198d162 100644
--- a/contrib/ntp/scripts/summary.1summarymdoc
+++ b/contrib/ntp/scripts/summary.1summarymdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt SUMMARY 1summarymdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (summary-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:56:08 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:31 PM by AutoGen 5.18.5
.\" From the definitions summary-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/summary.html b/contrib/ntp/scripts/summary.html
index b6c226c..b6e47e1 100644
--- a/contrib/ntp/scripts/summary.html
+++ b/contrib/ntp/scripts/summary.html
@@ -1,95 +1,138 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>Summary User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="Summary User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
-</head>
-<body>
-<h1 class="settitle">Summary User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#summary-Description">summary Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-
-<h2 class="unnumbered">Summary User Manual</h2>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Summary User&rsquo;s Manual</title>
+
+<meta name="description" content="Summary User&rsquo;s Manual">
+<meta name="keywords" content="Summary User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
-<p>This document describes the use of the NTP Project's <code>summary</code> program.
-This document applies to version 4.2.8p11 of <code>summary</code>.
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">Summary User Manual</a>
-</ul>
-</div>
+</head>
-<ul class="menu">
-<li><a accesskey="1" href="#summary-Description">summary Description</a>: Description
-<li><a accesskey="2" href="#summary-Invocation">summary Invocation</a>: Invoking summary
-</ul>
+<body lang="en">
+<h1 class="settitle" align="center">Summary User&rsquo;s Manual</h1>
-<div class="node">
-<p><hr>
-<a name="summary-Invocation"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#summary-Description">summary Description</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
-</div>
-<h3 class="section">Invoking summary</h3>
-<p><a name="index-summary-1"></a><a name="index-compute-various-stastics-from-NTP-stat-files-2"></a>
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>summary</code> program.
-<ul class="menu">
-<li><a accesskey="1" href="#summary-usage">summary usage</a>: summary help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#summary-directory">summary directory</a>: directory option
-<li><a accesskey="3" href="#summary-end_002ddate">summary end-date</a>: end-date option
-<li><a accesskey="4" href="#summary-output_002ddirectory">summary output-directory</a>: output-directory option
-<li><a accesskey="5" href="#summary-start_002ddate">summary start-date</a>: start-date option
-<li><a accesskey="6" href="#summary-exit-status">summary exit status</a>: exit status
+<a name="Top"></a>
+<div class="header">
+<p>
+Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="Summary-User-Manual"></a>
+<h1 class="top">Summary User Manual</h1>
+
+<p>This document describes the use of the NTP Project&rsquo;s <code>summary</code> program.
+This document applies to version 4.2.8p13 of <code>summary</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
+
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Invoking-summary" href="#toc-Invoking-summary">1 Invoking summary</a></li>
</ul>
+</div>
+
-<div class="node">
-<p><hr>
-<a name="summary-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#summary-directory">summary directory</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#summary-Invocation">summary Invocation</a>
-<br>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; summary Description:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-Invocation" accesskey="2">summary Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking summary
+</td></tr>
+</table>
+
+<hr>
+<a name="summary-Invocation"></a>
+<div class="header">
+<p>
+Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
+<a name="Invoking-summary"></a>
+<h2 class="chapter">1 Invoking summary</h2>
+<a name="index-summary"></a>
+<a name="index-compute-various-stastics-from-NTP-stat-files"></a>
+
-<h4 class="subsection">summary help/usage (<span class="option">--help</span>)</h4>
-<p><a name="index-summary-help-3"></a>
-This is the automatically generated usage text for summary.
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>summary</code> program.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#summary-usage" accesskey="1">summary usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">summary help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-directory" accesskey="2">summary directory</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">directory option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-end_002ddate" accesskey="3">summary end-date</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">end-date option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-output_002ddirectory" accesskey="4">summary output-directory</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">output-directory option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-start_002ddate" accesskey="5">summary start-date</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">start-date option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-exit-status" accesskey="6">summary exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+</table>
+
+<hr>
+<a name="summary-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#summary-directory" accesskey="n" rel="next">summary directory</a>, Up: <a href="#summary-Invocation" accesskey="u" rel="up">summary Invocation</a> &nbsp; </p>
+</div>
+<a name="summary-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h3 class="section">1.1 summary help/usage (<samp>--help</samp>)</h3>
+<a name="index-summary-help"></a>
+
+<p>This is the automatically generated usage text for summary.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">summary - compute various stastics from NTP stat files - Ver. 4.2.8p11
-USAGE: summary [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
+</p>
+<div class="example">
+<pre class="example">summary - compute various stastics from NTP stat files - Ver. 4.2.8p13
+USAGE: summary [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
--directory=str Directory containing stat files
--end-date=num End date
@@ -102,81 +145,98 @@ USAGE: summary [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;]
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-</pre>
- <div class="node">
-<p><hr>
-<a name="summary-directory"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#summary-end_002ddate">summary end-date</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#summary-usage">summary usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#summary-Invocation">summary Invocation</a>
-<br>
+</pre></div>
+
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#summary-directory" accesskey="1">summary directory</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-end_002ddate" accesskey="2">summary end-date</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-output_002ddirectory" accesskey="3">summary output-directory</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-start_002ddate" accesskey="4">summary start-date</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#summary-exit-status" accesskey="5">summary exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="summary-directory"></a>
+<div class="header">
+<p>
+Next: <a href="#summary-end_002ddate" accesskey="n" rel="next">summary end-date</a>, Previous: <a href="#summary-usage" accesskey="p" rel="prev">summary usage</a>, Up: <a href="#summary-usage" accesskey="u" rel="up">summary usage</a> &nbsp; </p>
</div>
+<a name="directory-option"></a>
+<h4 class="subsection">1.1.1 directory option</h4>
+<a name="index-summary_002ddirectory"></a>
-<h4 class="subsection">directory option</h4>
-
-<p><a name="index-summary_002ddirectory-4"></a>
-This is the &ldquo;directory containing stat files&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;directory containing stat files&rdquo; option.
+This option takes a string argument.
The directory where <code>ntpd</code> will search for .stat files generated
- by <code>ntpd</code>.
-<div class="node">
-<p><hr>
-<a name="summary-end_002ddate"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#summary-output_002ddirectory">summary output-directory</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#summary-directory">summary directory</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#summary-Invocation">summary Invocation</a>
-<br>
+ by <code>ntpd</code>.
+</p><hr>
+<a name="summary-end_002ddate"></a>
+<div class="header">
+<p>
+Next: <a href="#summary-output_002ddirectory" accesskey="n" rel="next">summary output-directory</a>, Previous: <a href="#summary-directory" accesskey="p" rel="prev">summary directory</a>, Up: <a href="#summary-usage" accesskey="u" rel="up">summary usage</a> &nbsp; </p>
</div>
+<a name="end_002ddate-option"></a>
+<h4 class="subsection">1.1.2 end-date option</h4>
+<a name="index-summary_002dend_002ddate"></a>
-<h4 class="subsection">end-date option</h4>
-
-<p><a name="index-summary_002dend_002ddate-5"></a>
-This is the &ldquo;end date&rdquo; option.
-This option takes a number argument.
+<p>This is the &ldquo;end date&rdquo; option.
+This option takes a number argument.
Process all files with the date suffix less or equal to value of this
option. Defaults to today minus one day (Use <code>date -u +%Y%m%d</code>)
- to get the timestamp.
-<div class="node">
-<p><hr>
-<a name="summary-output_002ddirectory"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#summary-start_002ddate">summary start-date</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#summary-end_002ddate">summary end-date</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#summary-Invocation">summary Invocation</a>
-<br>
+ to get the timestamp.
+</p><hr>
+<a name="summary-output_002ddirectory"></a>
+<div class="header">
+<p>
+Next: <a href="#summary-start_002ddate" accesskey="n" rel="next">summary start-date</a>, Previous: <a href="#summary-end_002ddate" accesskey="p" rel="prev">summary end-date</a>, Up: <a href="#summary-usage" accesskey="u" rel="up">summary usage</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">output-directory option</h4>
-
-<p><a name="index-summary_002doutput_002ddirectory-6"></a>
-This is the &ldquo;output directory&rdquo; option.
-This option takes a str argument.
- The output directory <code>summary</code> will write all output files to.
-<div class="node">
-<p><hr>
-<a name="summary-start_002ddate"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#summary-exit-status">summary exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#summary-output_002ddirectory">summary output-directory</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#summary-Invocation">summary Invocation</a>
-<br>
+<a name="output_002ddirectory-option"></a>
+<h4 class="subsection">1.1.3 output-directory option</h4>
+<a name="index-summary_002doutput_002ddirectory"></a>
+
+<p>This is the &ldquo;output directory&rdquo; option.
+This option takes a str argument.
+ The output directory <code>summary</code> will write all output files to.
+</p><hr>
+<a name="summary-start_002ddate"></a>
+<div class="header">
+<p>
+Next: <a href="#summary-exit-status" accesskey="n" rel="next">summary exit status</a>, Previous: <a href="#summary-output_002ddirectory" accesskey="p" rel="prev">summary output-directory</a>, Up: <a href="#summary-usage" accesskey="u" rel="up">summary usage</a> &nbsp; </p>
</div>
+<a name="start_002ddate-option"></a>
+<h4 class="subsection">1.1.4 start-date option</h4>
+<a name="index-summary_002dstart_002ddate"></a>
-<h4 class="subsection">start-date option</h4>
-
-<p><a name="index-summary_002dstart_002ddate-7"></a>
-This is the &ldquo;start date&rdquo; option.
-This option takes a num argument.
+<p>This is the &ldquo;start date&rdquo; option.
+This option takes a num argument.
Process all files with the date suffix more or equal to value of
- this option. Defaults to 197000101.
-<div class="node">
-<p><hr>
-<a name="summary-exit-status"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#summary-start_002ddate">summary start-date</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#summary-Invocation">summary Invocation</a>
-<br>
+ this option. Defaults to 197000101.
+</p><hr>
+<a name="summary-exit-status"></a>
+<div class="header">
+<p>
+Previous: <a href="#summary-start_002ddate" accesskey="p" rel="prev">summary start-date</a>, Up: <a href="#summary-usage" accesskey="u" rel="up">summary usage</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">summary exit status</h4>
+<a name="summary-exit-status-1"></a>
+<h4 class="subsection">1.1.5 summary exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
</dl>
+<hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/scripts/summary.man.in b/contrib/ntp/scripts/summary.man.in
index d4011fb..932c498 100644
--- a/contrib/ntp/scripts/summary.man.in
+++ b/contrib/ntp/scripts/summary.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH summary 1summaryman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH summary 1summaryman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-AMaaJG/ag-NMaiIG)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:56:06 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:30 PM by AutoGen 5.18.5
.\" From the definitions summary-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/summary.mdoc.in b/contrib/ntp/scripts/summary.mdoc.in
index 6c8eee7..198d162 100644
--- a/contrib/ntp/scripts/summary.mdoc.in
+++ b/contrib/ntp/scripts/summary.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt SUMMARY 1summarymdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (summary-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:56:08 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:31 PM by AutoGen 5.18.5
.\" From the definitions summary-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/update-leap/Makefile.in b/contrib/ntp/scripts/update-leap/Makefile.in
index 3a42d80..3302eee 100644
--- a/contrib/ntp/scripts/update-leap/Makefile.in
+++ b/contrib/ntp/scripts/update-leap/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/scripts/update-leap/invoke-update-leap.texi b/contrib/ntp/scripts/update-leap/invoke-update-leap.texi
index 002193a..0d0fbbe 100644
--- a/contrib/ntp/scripts/update-leap/invoke-update-leap.texi
+++ b/contrib/ntp/scripts/update-leap/invoke-update-leap.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-update-leap.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 04:55:50 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 05:04:22 PM by AutoGen 5.18.5
# From the definitions update-leap-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
diff --git a/contrib/ntp/scripts/update-leap/update-leap-opts b/contrib/ntp/scripts/update-leap/update-leap-opts
index ef461c3..6074aa7 100644
--- a/contrib/ntp/scripts/update-leap/update-leap-opts
+++ b/contrib/ntp/scripts/update-leap/update-leap-opts
@@ -1,6 +1,6 @@
# EDIT THIS FILE WITH CAUTION (update-leap-opts)
#
-# It has been AutoGen-ed February 27, 2018 at 04:32:15 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 05:04:25 PM by AutoGen 5.18.5
# From the definitions update-leap-opts.def
# and the template file perlopt
@@ -46,7 +46,7 @@ sub processOptions {
'help|?', 'more-help'));
$usage = <<'USAGE';
-update-leap - leap-seconds file manager/updater - Ver. 4.2.8p11
+update-leap - leap-seconds file manager/updater - Ver. 4.2.8p13
USAGE: update-leap [ -<flag> [<val>] | --<name>[{=| }<val>] ]...
-s, --source-url=str The URL of the master copy of the leapseconds file
diff --git a/contrib/ntp/scripts/update-leap/update-leap.1update-leapman b/contrib/ntp/scripts/update-leap/update-leap.1update-leapman
index 380774a..33aa4f6 100644
--- a/contrib/ntp/scripts/update-leap/update-leap.1update-leapman
+++ b/contrib/ntp/scripts/update-leap/update-leap.1update-leapman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH update-leap 1update-leapman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH update-leap 1update-leapman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-cKaOWT/ag-pKaWVT)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:15 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:24 PM by AutoGen 5.18.5
.\" From the definitions update-leap-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/update-leap/update-leap.1update-leapmdoc b/contrib/ntp/scripts/update-leap/update-leap.1update-leapmdoc
index 1af0cd3..fe1a164 100644
--- a/contrib/ntp/scripts/update-leap/update-leap.1update-leapmdoc
+++ b/contrib/ntp/scripts/update-leap/update-leap.1update-leapmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt UPDATE_LEAP 1update-leapmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (update-leap-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:55:53 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:38 AM by AutoGen 5.18.5
.\" From the definitions update-leap-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/scripts/update-leap/update-leap.html b/contrib/ntp/scripts/update-leap/update-leap.html
index 0303530..becb668 100644
--- a/contrib/ntp/scripts/update-leap/update-leap.html
+++ b/contrib/ntp/scripts/update-leap/update-leap.html
@@ -1,274 +1,396 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>update-leap User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="update-leap User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>update-leap User&rsquo;s Manual</title>
+
+<meta name="description" content="update-leap User&rsquo;s Manual">
+<meta name="keywords" content="update-leap User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">update-leap User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-Description">update-leap Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
- <p>This document describes the use of the NTP Project's <code>update-leap</code> program.
+<body lang="en">
+<h1 class="settitle" align="center">update-leap User&rsquo;s Manual</h1>
+
+
+
+
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<h1 class="node-heading">Top</h1>
- <p>This document applies to version 4.2.8p11 of <code>update-leap</code>.
+<p>This document describes the use of the NTP Project&rsquo;s <code>update-leap</code> program.
+</p>
+<p>This document applies to version 4.2.8p13 of <code>update-leap</code>.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
<div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-</ul>
+<li><a name="stoc-Invoking-update_002dleap" href="#toc-Invoking-update_002dleap">1 Invoking update-leap</a></li>
+
</div>
-<ul class="menu">
-<li><a accesskey="1" href="#update_002dleap-Description">update-leap Description</a>: Description
-<li><a accesskey="2" href="#update_002dleap-Invocation">update-leap Invocation</a>: Invoking update-leap
-</ul>
-<div class="node">
-<p><hr>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; update-leap Description:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-Invocation" accesskey="2">update-leap Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking update-leap
+</td></tr>
+</table>
+
+<hr>
<a name="update_002dleap-Invocation"></a>
-<br>
+<div class="header">
+<p>
+Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
+<a name="Invoking-update_002dleap"></a>
+<h3 class="section">1 Invoking update-leap</h3>
+<a name="index-update_002dleap"></a>
+<a name="index-leap_002dseconds-file-manager_002fupdater"></a>
-<h3 class="section">0.1 Invoking update-leap</h3>
-<p><a name="index-update_002dleap-1"></a><a name="index-leap_002dseconds-file-manager_002fupdater-2"></a>
- <p><code>update-leap</code>
+<p><code>update-leap</code>
will validate the file currently on the local system
and if necessary, updates leap-second definition file.
-
- <p>Ordinarily, the file is found using the "leapfile" directive in
-<code>ntp.conf(5)</code>.
+</p>
+<p>Ordinarily, the file is found using the &quot;leapfile&quot; directive in
+<code>ntp.conf(5)</code>.
However, an alternate location can be specified on the command line.
-
- <p>If the file does not exist, is not valid, has expired, or is expiring soon,
+</p>
+<p>If the file does not exist, is not valid, has expired, or is expiring soon,
a new copy will be downloaded. If the new copy validates, it is installed and
NTP is (optionally) restarted.
-
- <p>If the current file is acceptable, no download or restart occurs.
-
- <p>-c can also be used to invoke another script to perform administrative
-functions, e.g. to copy the file to other local systems.
+</p>
+<p>If the current file is acceptable, no download or restart occurs.
+</p>
+<p>-c can also be used to invoke another script to perform administrative
+functions, e.g. to copy the file to other local systems.
.PP
This can be run as a cron job. As the file is rarely updated, and leap
seconds are announced at least one month in advance (usually longer), it
-need not be run more frequently than about once every three weeks.
+need not be run more frequently than about once every three weeks.
.PP
-For cron-friendly behavior, define CRONJOB=1 in the crontab.
+For cron-friendly behavior, define CRONJOB=1 in the crontab.
.PP
This script depends on$REQUIREDCMDS
-
- <p>This section was generated by <strong>AutoGen</strong>,
+</p>
+<p>This section was generated by <strong>AutoGen</strong>,
using the <code>agtexi-cmd</code> template and the option descriptions for the <code>update-leap</code> program.
-
-<ul class="menu">
-<li><a accesskey="1" href="#update_002dleap-usage">update-leap usage</a>: update-leap help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#update_002dleap-source_002durl">update-leap source-url</a>: source-url option (-s)
-<li><a accesskey="3" href="#update_002dleap-ipv4">update-leap ipv4</a>: ipv4 option (-4)
-<li><a accesskey="4" href="#update_002dleap-destination">update-leap destination</a>: destination option (-d)
-<li><a accesskey="5" href="#update_002dleap-expiration">update-leap expiration</a>: expiration option (-e)
-<li><a accesskey="6" href="#update_002dleap-ntp_002dconf_002dfile">update-leap ntp-conf-file</a>: ntp-conf-file option (-f)
-<li><a accesskey="7" href="#update_002dleap-force_002dupdate">update-leap force-update</a>: force-update option (-F)
-<li><a accesskey="8" href="#update_002dleap-exit-status">update-leap exit status</a>: exit status
-<li><a accesskey="9" href="#update_002dleap-Usage">update-leap Usage</a>: Usage
-<li><a href="#update_002dleap-Authors">update-leap Authors</a>: Authors
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="update_002dleap-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-source_002durl">update-leap source-url</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-usage" accesskey="1">update-leap usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">update-leap help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-source_002durl" accesskey="2">update-leap source-url</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">source-url option (-s)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-ipv4" accesskey="3">update-leap ipv4</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv4 option (-4)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-destination" accesskey="4">update-leap destination</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">destination option (-d)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-expiration" accesskey="5">update-leap expiration</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">expiration option (-e)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-ntp_002dconf_002dfile" accesskey="6">update-leap ntp-conf-file</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntp-conf-file option (-f)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-force_002dupdate" accesskey="7">update-leap force-update</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">force-update option (-F)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-exit-status" accesskey="8">update-leap exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-Usage" accesskey="9">update-leap Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#update_002dleap-Authors">update-leap Authors</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Authors
+</td></tr>
+</table>
+
+<hr>
+<a name="update_002dleap-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-source_002durl" accesskey="n" rel="next">update-leap source-url</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.1 update-leap help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-update_002dleap-help-3"></a>
-This is the automatically generated usage text for update-leap.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="update_002dleap-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h4 class="subsection">1.1 update-leap help/usage (<samp>--help</samp>)</h4>
+<a name="index-update_002dleap-help"></a>
+
+<p>This is the automatically generated usage text for update-leap.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
+</p>
+<div class="example">
<pre class="example">
-</pre>
- <div class="node">
-<p><hr>
-<a name="update_002dleap-source_002durl"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-ipv4">update-leap ipv4</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-usage">update-leap usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
-</div>
-<h4 class="subsection">0.1.2 source-url option (-s)</h4>
+Usage: update-leap [options]
+
+Verifies and if necessary, updates leap-second definition file
+
+All arguments are optional: Default (or current value) shown:
+ -C Absolute path to CA Cert (see SSL/TLS Considerations)
+ -D Path to a CAdir (see SSL/TLS Considerations)
+ -e Specify how long (in days) before expiration the file is to be
+ refreshed. Note that larger values imply more frequent refreshes.
+ 60
+ -F Force update even if current file is OK and not close to expiring.
+ -f Absolute path ntp.conf file (default /etc/ntp.conf)
+ /etc/ntp.conf
+ -h show help
+ -i Specify number of minutes between retries
+ 10
+ -L Absolute path to leapfile on the local system
+ (overrides value in ntp.conf)
+ -l Specify the syslog(3) facility for logging
+ LOG_USER
+ -q Only report errors (cannot be used with -v)
+ -r Specify number of attempts to retrieve file
+ 6
+ -s Send output to syslog(3) - implied if STDOUT has no tty or redirected
+ -t Send output to terminal - implied if STDOUT attached to terminal
+ -u Specify the URL of the master copy to download
+ https://www.ietf.org/timezones/data/leap-seconds.list
+ -v Verbose - show debug messages (cannot be used with -q)
+
+The following options are not (yet) implemented in the perl version:
+ -4 Use only IPv4
+ -6 Use only IPv6
+ -c Command to restart NTP after installing a new file
+ &lt;none&gt; - ntpd checks file daily
+ -p 4|6
+ Prefer IPv4 or IPv6 (as specified) addresses, but use either
+
+update-leap will validate the file currently on the local system.
+
+Ordinarily, the leapfile is found using the 'leapfile' directive in
+/etc/ntp.conf. However, an alternate location can be specified on the
+command line with the -L flag.
+
+If the leapfile does not exist, is not valid, has expired, or is
+expiring soon, a new copy will be downloaded. If the new copy is
+valid, it is installed.
+
+If the current file is acceptable, no download or restart occurs.
+
+This can be run as a cron job. As the file is rarely updated, and
+leap seconds are announced at least one month in advance (usually
+longer), it need not be run more frequently than about once every
+three weeks.
+
+SSL/TLS Considerations
+-----------------------
+The perl modules can usually locate the CA certificate used to verify
+the peer's identity.
+
+On BSDs, the default is typically the file /etc/ssl/certs.pem. On
+Linux, the location is typically a path to a CAdir - a directory of
+symlinks named according to a hash of the certificates' subject names.
+
+The -C or -D options are available to pass in a location if no CA cert
+is found in the default location.
+
+External Dependencies
+---------------------
+The following perl modules are required:
+HTTP::Tiny - version &gt;= 0.056
+IO::Socket::SSL - version &gt;= 1.56
+NET::SSLeay - version &gt;= 1.49
+
+Version: 1.004
+</pre></div>
+
+<hr>
+<a name="update_002dleap-source_002durl"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-ipv4" accesskey="n" rel="next">update-leap ipv4</a>, Previous: <a href="#update_002dleap-usage" accesskey="p" rel="prev">update-leap usage</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
+</div>
+<a name="source_002durl-option-_0028_002ds_0029"></a>
+<h4 class="subsection">1.2 source-url option (-s)</h4>
+<a name="index-update_002dleap_002dsource_002durl"></a>
-<p><a name="index-update_002dleap_002dsource_002durl-4"></a>
-This is the &ldquo;the url of the master copy of the leapseconds file&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;the url of the master copy of the leapseconds file&rdquo; option.
+This option takes a string argument.
Specify the URL of the master copy to download
$LEAPSRC
-<div class="node">
-<p><hr>
-<a name="update_002dleap-ipv4"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-destination">update-leap destination</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-source_002durl">update-leap source-url</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+</p><hr>
+<a name="update_002dleap-ipv4"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-destination" accesskey="n" rel="next">update-leap destination</a>, Previous: <a href="#update_002dleap-source_002durl" accesskey="p" rel="prev">update-leap source-url</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.3 ipv4 option (-4)</h4>
-
-<p><a name="index-update_002dleap_002dipv4-5"></a>
-This is the &ldquo;use only ipv4 addresses for dns name resolution&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv6.
-</ul>
-
- <p>Force DNS resolution of following host names on the command line
- to the IPv4 namespace.
+<a name="ipv4-option-_0028_002d4_0029"></a>
+<h4 class="subsection">1.3 ipv4 option (-4)</h4>
+<a name="index-update_002dleap_002dipv4"></a>
+
+<p>This is the &ldquo;use only ipv4 addresses for dns name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv6.
+</li></ul>
+
+<p>Force DNS resolution of following host names on the command line
+ to the IPv4 namespace.
_EndOfDoc_;
;
-
- <p>flag =
+</p>
+<p>flag =
name = ipv6;
flags-cant = ipv4, prefer;
value = 6;
- descrip = "Use only IPv6 addresses for DNS name resolution";
+ descrip = &quot;Use only IPv6 addresses for DNS name resolution&quot;;
doc = &lt;&lt;- _EndOfDoc_
Force DNS resolution of following host names on the command line
- to the IPv6 namespace.
+ to the IPv6 namespace.
_EndOfDoc_;
;
-
- <p>flag =
+</p>
+<p>flag =
name = prefer;
flags-cant = ipv4, ipv6;
value = p;
arg-type = keyword;
keyword = 4, 6;
- descrip = 'Prefer IPv4 or IPv6 (as specified) addresses, but use either';
+ descrip = &rsquo;Prefer IPv4 or IPv6 (as specified) addresses, but use either&rsquo;;
doc = &lt;&lt;- _EndOfDoc_
-Prefer IPv4 or IPv6 (as specified) addresses, but use either.
-<div class="node">
-<p><hr>
-<a name="update_002dleap-destination"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-expiration">update-leap expiration</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-ipv4">update-leap ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+Prefer IPv4 or IPv6 (as specified) addresses, but use either.
+</p><hr>
+<a name="update_002dleap-destination"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-expiration" accesskey="n" rel="next">update-leap expiration</a>, Previous: <a href="#update_002dleap-ipv4" accesskey="p" rel="prev">update-leap ipv4</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
+<a name="destination-option-_0028_002dd_0029"></a>
+<h4 class="subsection">1.4 destination option (-d)</h4>
+<a name="index-update_002dleap_002ddestination"></a>
-<h4 class="subsection">0.1.4 destination option (-d)</h4>
-
-<p><a name="index-update_002dleap_002ddestination-6"></a>
-This is the &ldquo;filename on the local system&rdquo; option.
-This option takes a string argument <span class="file">float</span>.
-The name to use to store the leapfile on the local system.
+<p>This is the &ldquo;filename on the local system&rdquo; option.
+This option takes a string argument <samp>float</samp>.
+The name to use to store the leapfile on the local system.
$LEAPFILE
-<div class="node">
-<p><hr>
-<a name="update_002dleap-expiration"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-ntp_002dconf_002dfile">update-leap ntp-conf-file</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-destination">update-leap destination</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+</p><hr>
+<a name="update_002dleap-expiration"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-ntp_002dconf_002dfile" accesskey="n" rel="next">update-leap ntp-conf-file</a>, Previous: <a href="#update_002dleap-destination" accesskey="p" rel="prev">update-leap destination</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
+<a name="expiration-option-_0028_002de_0029"></a>
+<h4 class="subsection">1.5 expiration option (-e)</h4>
+<a name="index-update_002dleap_002dexpiration"></a>
-<h4 class="subsection">0.1.5 expiration option (-e)</h4>
-
-<p><a name="index-update_002dleap_002dexpiration-7"></a>
-This is the &ldquo;refresh the leapfile this long before it expires&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;refresh the leapfile this long before it expires&rdquo; option.
+This option takes a string argument.
Specify how long before expiration the file is to be refreshed
-Units are required, e.g. "-e 60 days" Note that larger values
-imply more frequent refreshes.
-"$PREFETCH"
-<div class="node">
-<p><hr>
-<a name="update_002dleap-ntp_002dconf_002dfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-force_002dupdate">update-leap force-update</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-expiration">update-leap expiration</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+Units are required, e.g. &quot;-e 60 days&quot; Note that larger values
+imply more frequent refreshes.
+&quot;$PREFETCH&quot;
+</p><hr>
+<a name="update_002dleap-ntp_002dconf_002dfile"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-force_002dupdate" accesskey="n" rel="next">update-leap force-update</a>, Previous: <a href="#update_002dleap-expiration" accesskey="p" rel="prev">update-leap expiration</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
+<a name="ntp_002dconf_002dfile-option-_0028_002df_0029"></a>
+<h4 class="subsection">1.6 ntp-conf-file option (-f)</h4>
+<a name="index-update_002dleap_002dntp_002dconf_002dfile"></a>
-<h4 class="subsection">0.1.6 ntp-conf-file option (-f)</h4>
-
-<p><a name="index-update_002dleap_002dntp_002dconf_002dfile-8"></a>
-This is the &ldquo;location of the ntp.conf file&rdquo; option.
-This option takes a string argument.
+<p>This is the &ldquo;location of the ntp.conf file&rdquo; option.
+This option takes a string argument.
Specify location of ntp.conf (used to make sure leapfile directive is
present and to default leapfile)
/etc/ntp.conf
-<div class="node">
-<p><hr>
-<a name="update_002dleap-force_002dupdate"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-exit-status">update-leap exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-ntp_002dconf_002dfile">update-leap ntp-conf-file</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+</p><hr>
+<a name="update_002dleap-force_002dupdate"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-exit-status" accesskey="n" rel="next">update-leap exit status</a>, Previous: <a href="#update_002dleap-ntp_002dconf_002dfile" accesskey="p" rel="prev">update-leap ntp-conf-file</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.7 force-update option (-F)</h4>
-
-<p><a name="index-update_002dleap_002dforce_002dupdate-9"></a>
-This is the &ldquo;force update of the leapfile&rdquo; option.
-Force update even if current file is OK and not close to expiring.
-<div class="node">
-<p><hr>
-<a name="update_002dleap-exit-status"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-Usage">update-leap Usage</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-force_002dupdate">update-leap force-update</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+<a name="force_002dupdate-option-_0028_002dF_0029"></a>
+<h4 class="subsection">1.7 force-update option (-F)</h4>
+<a name="index-update_002dleap_002dforce_002dupdate"></a>
+
+<p>This is the &ldquo;force update of the leapfile&rdquo; option.
+Force update even if current file is OK and not close to expiring.
+</p><hr>
+<a name="update_002dleap-exit-status"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-Usage" accesskey="n" rel="next">update-leap Usage</a>, Previous: <a href="#update_002dleap-force_002dupdate" accesskey="p" rel="prev">update-leap force-update</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.8 update-leap exit status</h4>
+<a name="update_002dleap-exit-status-1"></a>
+<h4 class="subsection">1.8 update-leap exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
</dl>
- <div class="node">
-<p><hr>
-<a name="update_002dleap-Usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#update_002dleap-Authors">update-leap Authors</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-exit-status">update-leap exit status</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+<hr>
+<a name="update_002dleap-Usage"></a>
+<div class="header">
+<p>
+Next: <a href="#update_002dleap-Authors" accesskey="n" rel="next">update-leap Authors</a>, Previous: <a href="#update_002dleap-exit-status" accesskey="p" rel="prev">update-leap exit status</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">0.1.9 update-leap Usage</h4>
-
-<div class="node">
-<p><hr>
-<a name="update_002dleap-Authors"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#update_002dleap-Usage">update-leap Usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#update_002dleap-Invocation">update-leap Invocation</a>
-<br>
+<a name="update_002dleap-Usage-1"></a>
+<h4 class="subsection">1.9 update-leap Usage</h4>
+<hr>
+<a name="update_002dleap-Authors"></a>
+<div class="header">
+<p>
+Previous: <a href="#update_002dleap-Usage" accesskey="p" rel="prev">update-leap Usage</a>, Up: <a href="#update_002dleap-Invocation" accesskey="u" rel="up">update-leap Invocation</a> &nbsp; </p>
</div>
+<a name="update_002dleap-Authors-1"></a>
+<h4 class="subsection">1.10 update-leap Authors</h4>
+<hr>
-<h4 class="subsection">0.1.10 update-leap Authors</h4>
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/scripts/update-leap/update-leap.man.in b/contrib/ntp/scripts/update-leap/update-leap.man.in
index 380774a..33aa4f6 100644
--- a/contrib/ntp/scripts/update-leap/update-leap.man.in
+++ b/contrib/ntp/scripts/update-leap/update-leap.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH update-leap 1update-leapman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH update-leap 1update-leapman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-cKaOWT/ag-pKaWVT)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 10:50:15 AM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 05:04:24 PM by AutoGen 5.18.5
.\" From the definitions update-leap-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/scripts/update-leap/update-leap.mdoc.in b/contrib/ntp/scripts/update-leap/update-leap.mdoc.in
index 1af0cd3..fe1a164 100644
--- a/contrib/ntp/scripts/update-leap/update-leap.mdoc.in
+++ b/contrib/ntp/scripts/update-leap/update-leap.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt UPDATE_LEAP 1update-leapmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (update-leap-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 04:55:53 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:38 AM by AutoGen 5.18.5
.\" From the definitions update-leap-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/sntp/COPYRIGHT b/contrib/ntp/sntp/COPYRIGHT
index 935d574..f38933c 100644
--- a/contrib/ntp/sntp/COPYRIGHT
+++ b/contrib/ntp/sntp/COPYRIGHT
@@ -1,16 +1,15 @@
This file is automatically generated from html/copyright.html
-
Copyright Notice
-
+
jpg "Clone me," says Dolly sheepishly.
-
+
Last update: 2-Jan-2017 11:58 UTC
- _________________________________________________________________
-
- The following copyright notice applies to all files collectively
- called the Network Time Protocol Version 4 Distribution. Unless
- specifically declared otherwise in an individual file, this entire
- notice applies as if the text was explicitly included in the file.
+ __________________________________________________________________
+
+ The following copyright notice applies to all files collectively called
+ the Network Time Protocol Version 4 Distribution. Unless specifically
+ declared otherwise in an individual file, this entire notice applies as
+ if the text was explicitly included in the file.
***********************************************************************
* *
* Copyright (c) University of Delaware 1992-2015 *
@@ -62,13 +61,13 @@ This file is automatically generated from html/copyright.html
***********************************************************************
The following individuals contributed in part to the Network Time
- Protocol Distribution Version 4 and are acknowledged as authors of
- this work.
+ Protocol Distribution Version 4 and are acknowledged as authors of this
+ work.
1. [1]Takao Abe <takao_abe@xurb.jp> Clock driver for JJY receivers
2. [2]Mark Andrews <mark_andrews@isc.org> Leitch atomic clock
controller
- 3. [3]Bernd Altmeier <altmeier@atlsoft.de> hopf Elektronik serial
- line and PCI-bus devices
+ 3. [3]Bernd Altmeier <altmeier@atlsoft.de> hopf Elektronik serial line
+ and PCI-bus devices
4. [4]Viraj Bais <vbais@mailman1.intel.com> and [5]Clayton Kirkwood
<kirkwood@striderfm.intel.com> port to WindowsNT 3.5
5. [6]Michael Barone <michael,barone@lmco.com> GPSVME fixes
@@ -84,13 +83,12 @@ This file is automatically generated from html/copyright.html
<Jean-Francois.Boudreault@viagenie.qc.ca> IPv6 support
12. [13]Reg Clemens <reg@dwf.com> Oncore driver (Current maintainer)
13. [14]Steve Clift <clift@ml.csiro.au> OMEGA clock driver
- 14. [15]Casey Crellin <casey@csc.co.za> vxWorks (Tornado) port and
- help with target configuration
+ 14. [15]Casey Crellin <casey@csc.co.za> vxWorks (Tornado) port and help
+ with target configuration
15. [16]Sven Dietrich <sven_dietrich@trimble.com> Palisade reference
clock driver, NT adj. residuals, integrated Greg's Winnt port.
16. [17]John A. Dundas III <dundas@salt.jpl.nasa.gov> Apple A/UX port
- 17. [18]Torsten Duwe <duwe@immd4.informatik.uni-erlangen.de> Linux
- port
+ 17. [18]Torsten Duwe <duwe@immd4.informatik.uni-erlangen.de> Linux port
18. [19]Dennis Ferguson <dennis@mrbill.canet.ca> foundation code for
NTP Version 2 as specified in RFC-1119
19. [20]John Hay <jhay@icomtek.csir.co.za> IPv6 support and testing
@@ -122,9 +120,8 @@ This file is automatically generated from html/copyright.html
code for Version 3 as specified in RFC-1305
36. [39]Danny Mayer <mayer@ntp.org>Network I/O, Windows Port, Code
Maintenance
- 37. [40]David L. Mills <mills@udel.edu> Version 4 foundation,
- precision kernel; clock drivers: 1, 3, 4, 6, 7, 11, 13, 18, 19,
- 22, 36
+ 37. [40]David L. Mills <mills@udel.edu> Version 4 foundation, precision
+ kernel; clock drivers: 1, 3, 4, 6, 7, 11, 13, 18, 19, 22, 36
38. [41]Wolfgang Moeller <moeller@gwdgv1.dnet.gwdg.de> VMS port
39. [42]Jeffrey Mogul <mogul@pa.dec.com> ntptrace utility
40. [43]Tom Moore <tmoore@fievel.daytonoh.ncr.com> i386 svr4 port
@@ -136,22 +133,18 @@ This file is automatically generated from html/copyright.html
44. [48]Rainer Pruy <Rainer.Pruy@informatik.uni-erlangen.de>
monitoring/trap scripts, statistics file handling
45. [49]Dirce Richards <dirce@zk3.dec.com> Digital UNIX V4.0 port
- 46. [50]Wilfredo Sánchez <wsanchez@apple.com> added support for
- NetInfo
+ 46. [50]Wilfredo Sánchez <wsanchez@apple.com> added support for NetInfo
47. [51]Nick Sayer <mrapple@quack.kfu.com> SunOS streams modules
48. [52]Jack Sasportas <jack@innovativeinternet.com> Saved a Lot of
space on the stuff in the html/pic/ subdirectory
49. [53]Ray Schnitzler <schnitz@unipress.com> Unixware1 port
50. [54]Michael Shields <shields@tembel.org> USNO clock driver
- 51. [55]Jeff Steinman <jss@pebbles.jpl.nasa.gov> Datum PTS clock
- driver
+ 51. [55]Jeff Steinman <jss@pebbles.jpl.nasa.gov> Datum PTS clock driver
52. [56]Harlan Stenn <harlan@pfcs.com> GNU automake/autoconfigure
makeover, various other bits (see the ChangeLog)
53. [57]Kenneth Stone <ken@sdd.hp.com> HP-UX port
- 54. [58]Ajit Thyagarajan <ajit@ee.udel.edu>IP multicast/anycast
- support
- 55. [59]Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp>TRAK clock
- driver
+ 54. [58]Ajit Thyagarajan <ajit@ee.udel.edu>IP multicast/anycast support
+ 55. [59]Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp>TRAK clock driver
56. [60]Brian Utterback <brian.utterback@oracle.com> General codebase,
Solaris issues
57. [61]Loganaden Velvindron <loganaden@gmail.com> Sandboxing
@@ -160,7 +153,7 @@ This file is automatically generated from html/copyright.html
TrueTime clock driver
59. [63]Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> corrected and
validated HTML documents according to the HTML DTD
- _________________________________________________________________
+ __________________________________________________________________
References
diff --git a/contrib/ntp/sntp/Makefile.in b/contrib/ntp/sntp/Makefile.in
index 2085ace..3b5156c 100644
--- a/contrib/ntp/sntp/Makefile.in
+++ b/contrib/ntp/sntp/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1211,7 +1211,7 @@ distdir: $(DISTFILES)
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r "$(distdir)"
dist-gzip: distdir
- tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
$(am__post_remove_distdir)
dist-bzip2: distdir
@@ -1237,7 +1237,7 @@ dist-shar: distdir
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
- shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
$(am__post_remove_distdir)
dist-zip: distdir
@@ -1255,7 +1255,7 @@ dist dist-all:
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
- GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lz*) \
@@ -1265,7 +1265,7 @@ distcheck: dist
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
- GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
diff --git a/contrib/ntp/sntp/aclocal.m4 b/contrib/ntp/sntp/aclocal.m4
index ac10938..a22e4e1 100644
--- a/contrib/ntp/sntp/aclocal.m4
+++ b/contrib/ntp/sntp/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -20,126 +20,121 @@ You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
-# serial 9 -*- Autoconf -*-
-# Enable extensions on systems that normally disable them.
+# longlong.m4 serial 17
+dnl Copyright (C) 1999-2007, 2009-2016 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
-# Copyright (C) 2003, 2006-2010 Free Software Foundation, Inc.
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+dnl From Paul Eggert.
-# This definition of AC_USE_SYSTEM_EXTENSIONS is stolen from CVS
-# Autoconf. Perhaps we can remove this once we can assume Autoconf
-# 2.62 or later everywhere, but since CVS Autoconf mutates rapidly
-# enough in this area it's likely we'll need to redefine
-# AC_USE_SYSTEM_EXTENSIONS for quite some time.
-
-# If autoconf reports a warning
-# warning: AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS
-# or warning: AC_RUN_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS
-# the fix is
-# 1) to ensure that AC_USE_SYSTEM_EXTENSIONS is never directly invoked
-# but always AC_REQUIREd,
-# 2) to ensure that for each occurrence of
-# AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
-# or
-# AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
-# the corresponding gnulib module description has 'extensions' among
-# its dependencies. This will ensure that the gl_USE_SYSTEM_EXTENSIONS
-# invocation occurs in gl_EARLY, not in gl_INIT.
-
-# AC_USE_SYSTEM_EXTENSIONS
-# ------------------------
-# Enable extensions on systems that normally disable them,
-# typically due to standards-conformance issues.
-# Remember that #undef in AH_VERBATIM gets replaced with #define by
-# AC_DEFINE. The goal here is to define all known feature-enabling
-# macros, then, if reports of conflicts are made, disable macros that
-# cause problems on some platforms (such as __EXTENSIONS__).
-AC_DEFUN_ONCE([AC_USE_SYSTEM_EXTENSIONS],
-[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
-AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
-
- AC_REQUIRE([AC_CANONICAL_HOST])
-
- AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=])
- if test "$MINIX" = yes; then
- AC_DEFINE([_POSIX_SOURCE], [1],
- [Define to 1 if you need to in order for `stat' and other
- things to work.])
- AC_DEFINE([_POSIX_1_SOURCE], [2],
- [Define to 2 if the system does not provide POSIX.1 features
- except with this defined.])
- AC_DEFINE([_MINIX], [1],
- [Define to 1 if on MINIX.])
+# Define HAVE_LONG_LONG_INT if 'long long int' works.
+# This fixes a bug in Autoconf 2.61, and can be faster
+# than what's in Autoconf 2.62 through 2.68.
+
+# Note: If the type 'long long int' exists but is only 32 bits large
+# (as on some very old compilers), HAVE_LONG_LONG_INT will not be
+# defined. In this case you can treat 'long long int' like 'long int'.
+
+AC_DEFUN([AC_TYPE_LONG_LONG_INT],
+[
+ AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
+ AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int],
+ [ac_cv_type_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+ if test $ac_cv_type_long_long_int = yes; then
+ dnl Catch a bug in Tandem NonStop Kernel (OSS) cc -O circa 2004.
+ dnl If cross compiling, assume the bug is not important, since
+ dnl nobody cross compiles for this platform as far as we know.
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[@%:@include <limits.h>
+ @%:@ifndef LLONG_MAX
+ @%:@ define HALF \
+ (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+ @%:@ define LLONG_MAX (HALF - 1 + HALF)
+ @%:@endif]],
+ [[long long int n = 1;
+ int i;
+ for (i = 0; ; i++)
+ {
+ long long int m = n << i;
+ if (m >> i != n)
+ return 1;
+ if (LLONG_MAX / 2 < m)
+ break;
+ }
+ return 0;]])],
+ [],
+ [ac_cv_type_long_long_int=no],
+ [:])
+ fi
+ fi])
+ if test $ac_cv_type_long_long_int = yes; then
+ AC_DEFINE([HAVE_LONG_LONG_INT], [1],
+ [Define to 1 if the system has the type 'long long int'.])
fi
+])
- dnl HP-UX 11.11 defines mbstate_t only if _XOPEN_SOURCE is defined to 500,
- dnl regardless of whether the flags -Ae or _D_HPUX_SOURCE=1 are already
- dnl provided.
- case "$host_os" in
- hpux*)
- AC_DEFINE([_XOPEN_SOURCE], [500],
- [Define to 500 only on HP-UX.])
- ;;
- esac
+# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works.
+# This fixes a bug in Autoconf 2.61, and can be faster
+# than what's in Autoconf 2.62 through 2.68.
+
+# Note: If the type 'unsigned long long int' exists but is only 32 bits
+# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT
+# will not be defined. In this case you can treat 'unsigned long long int'
+# like 'unsigned long int'.
- AH_VERBATIM([__EXTENSIONS__],
-[/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# undef _ALL_SOURCE
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
+AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT],
+[
+ AC_CACHE_CHECK([for unsigned long long int],
+ [ac_cv_type_unsigned_long_long_int],
+ [ac_cv_type_unsigned_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ AC_LINK_IFELSE(
+ [_AC_TYPE_LONG_LONG_SNIPPET],
+ [],
+ [ac_cv_type_unsigned_long_long_int=no])
+ fi])
+ if test $ac_cv_type_unsigned_long_long_int = yes; then
+ AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], [1],
+ [Define to 1 if the system has the type 'unsigned long long int'.])
+ fi
])
- AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
- [ac_cv_safe_to_define___extensions__],
- [AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM([[
-# define __EXTENSIONS__ 1
- ]AC_INCLUDES_DEFAULT])],
- [ac_cv_safe_to_define___extensions__=yes],
- [ac_cv_safe_to_define___extensions__=no])])
- test $ac_cv_safe_to_define___extensions__ = yes &&
- AC_DEFINE([__EXTENSIONS__])
- AC_DEFINE([_ALL_SOURCE])
- AC_DEFINE([_GNU_SOURCE])
- AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
- AC_DEFINE([_TANDEM_SOURCE])
-])# AC_USE_SYSTEM_EXTENSIONS
-
-# gl_USE_SYSTEM_EXTENSIONS
-# ------------------------
-# Enable extensions on systems that normally disable them,
-# typically due to standards-conformance issues.
-AC_DEFUN_ONCE([gl_USE_SYSTEM_EXTENSIONS],
+
+# Expands to a C program that can be used to test for simultaneous support
+# of 'long long' and 'unsigned long long'. We don't want to say that
+# 'long long' is available if 'unsigned long long' is not, or vice versa,
+# because too many programs rely on the symmetry between signed and unsigned
+# integer types (excluding 'bool').
+AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET],
[
- dnl Require this macro before AC_USE_SYSTEM_EXTENSIONS.
- dnl gnulib does not need it. But if it gets required by third-party macros
- dnl after AC_USE_SYSTEM_EXTENSIONS is required, autoconf 2.62..2.63 emit a
- dnl warning: "AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS".
- dnl Note: We can do this only for one of the macros AC_AIX, AC_GNU_SOURCE,
- dnl AC_MINIX. If people still use AC_AIX or AC_MINIX, they are out of luck.
- AC_REQUIRE([AC_GNU_SOURCE])
-
- AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+ AC_LANG_PROGRAM(
+ [[/* For now, do not test the preprocessor; as of 2007 there are too many
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
+ /* Test literals. */
+ long long int ll = 9223372036854775807ll;
+ long long int nll = -9223372036854775807LL;
+ unsigned long long int ull = 18446744073709551615ULL;
+ /* Test constant expressions. */
+ typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
+ ? 1 : -1)];
+ typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
+ ? 1 : -1)];
+ int i = 63;]],
+ [[/* Test availability of runtime routines for shift and division. */
+ long long int llmax = 9223372036854775807ll;
+ unsigned long long int ullmax = 18446744073709551615ull;
+ return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));]])
])
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -154,7 +149,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.15'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
-m4_if([$1], [1.15], [],
+m4_if([$1], [1.15.1], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@@ -170,12 +165,12 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
-# Copyright (C) 2011-2014 Free Software Foundation, Inc.
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -237,7 +232,7 @@ AC_SUBST([AR])dnl
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -289,7 +284,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd`
# AM_CONDITIONAL -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -320,7 +315,7 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -511,7 +506,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
# Generate code to set up dependency tracking. -*- Autoconf -*-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -587,7 +582,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -784,7 +779,7 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -805,7 +800,7 @@ if test x"${install_sh+set}" != xset; then
fi
AC_SUBST([install_sh])])
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -826,7 +821,7 @@ AC_SUBST([am__leading_dot])])
# Check to see how 'make' treats includes. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -876,7 +871,7 @@ rm -f confinc confmf
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -915,7 +910,7 @@ fi
# Helper functions for option handling. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -944,7 +939,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -991,7 +986,7 @@ AC_LANG_POP([C])])
# For backward compatibility.
AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1010,7 +1005,7 @@ AC_DEFUN([AM_RUN_LOG],
# Check to make sure that the build environment is sane. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1091,7 +1086,7 @@ AC_CONFIG_COMMANDS_PRE(
rm -f conftest.file
])
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1151,7 +1146,7 @@ AC_SUBST([AM_BACKSLASH])dnl
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1179,7 +1174,7 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1198,7 +1193,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/sntp/config.h.in b/contrib/ntp/sntp/config.h.in
index 78d95f1..84a8cb9 100644
--- a/contrib/ntp/sntp/config.h.in
+++ b/contrib/ntp/sntp/config.h.in
@@ -194,7 +194,7 @@
/* Define to 1 if the system has the type `long long'. */
#undef HAVE_LONG_LONG
-/* Define to 1 if the system has the type `long long int'. */
+/* Define to 1 if the system has the type 'long long int'. */
#undef HAVE_LONG_LONG_INT
/* if you have SunOS LWP package */
@@ -260,6 +260,12 @@
/* if you have NT Threads */
#undef HAVE_NT_THREADS
+/* Define to 1 if you have the <openssl/cmac.h> header file. */
+#undef HAVE_OPENSSL_CMAC_H
+
+/* Define to 1 if you have the <openssl/hmac.h> header file. */
+#undef HAVE_OPENSSL_HMAC_H
+
/* Define this if pathfind(3) works */
#undef HAVE_PATHFIND
@@ -477,6 +483,9 @@
/* Define to 1 if you have the <sys/limits.h> header file. */
#undef HAVE_SYS_LIMITS_H
+/* Define to 1 if you have the <sys/mac.h> header file. */
+#undef HAVE_SYS_MAC_H
+
/* Define to 1 if you have the <sys/mman.h> header file. */
#undef HAVE_SYS_MMAN_H
@@ -556,6 +565,9 @@
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
+/* Are TrustedBSD MAC policy privileges available? */
+#undef HAVE_TRUSTEDBSD_MAC
+
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
@@ -580,7 +592,7 @@
/* deviant sigwait? */
#undef HAVE_UNIXWARE_SIGWAIT
-/* Define to 1 if the system has the type `unsigned long long int'. */
+/* Define to 1 if the system has the type 'unsigned long long int'. */
#undef HAVE_UNSIGNED_LONG_LONG_INT
/* Define to 1 if you have the <utime.h> header file. */
@@ -840,6 +852,28 @@ typedef unsigned int uintptr_t;
/* OK to use snprintb()? */
#undef USE_SNPRINTB
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
/* Can we use SIGPOLL for tty IO? */
#undef USE_TTY_SIGPOLL
@@ -892,9 +926,6 @@ typedef unsigned int uintptr_t;
/* enable thread safety */
#undef _THREAD_SAFE
-/* Define to 500 only on HP-UX. */
-#undef _XOPEN_SOURCE
-
/* Are we _special_? */
#undef __APPLE_USE_RFC_3542
@@ -903,28 +934,6 @@ typedef unsigned int uintptr_t;
# undef __CHAR_UNSIGNED__
#endif
-/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# undef _ALL_SOURCE
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-
-
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
diff --git a/contrib/ntp/sntp/configure b/contrib/ntp/sntp/configure
index d9e02fa..aa665af 100755
--- a/contrib/ntp/sntp/configure
+++ b/contrib/ntp/sntp/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sntp 4.2.8p11.
+# Generated by GNU Autoconf 2.69 for sntp 4.2.8p13.
#
# Report bugs to <http://bugs.ntp.org./>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sntp'
PACKAGE_TARNAME='sntp'
-PACKAGE_VERSION='4.2.8p11'
-PACKAGE_STRING='sntp 4.2.8p11'
+PACKAGE_VERSION='4.2.8p13'
+PACKAGE_STRING='sntp 4.2.8p13'
PACKAGE_BUGREPORT='http://bugs.ntp.org./'
PACKAGE_URL='http://www.ntp.org./'
@@ -907,6 +907,8 @@ enable_c99_snprintf
enable_clockctl
enable_linuxcaps
enable_solarisprivs
+enable_trustedbsd_mac
+enable_signalled_io
enable_shared
enable_static
with_pic
@@ -1484,7 +1486,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sntp 4.2.8p11 to adapt to many kinds of systems.
+\`configure' configures sntp 4.2.8p13 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1554,7 +1556,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sntp 4.2.8p11:";;
+ short | recursive ) echo "Configuration of sntp 4.2.8p13:";;
esac
cat <<\_ACEOF
@@ -1575,6 +1577,9 @@ Optional Features:
--enable-clockctl s Use /dev/clockctl for non-root clock control
--enable-linuxcaps + Use Linux capabilities for non-root clock control
--enable-solarisprivs + Use Solaris privileges for non-root clock control
+ --enable-trustedbsd-mac s Use TrustedBSD MAC policy for non-root clock
+ control
+ --enable-signalled-io s Use signalled IO if we can
--enable-shared[=PKGS] build shared libraries [default=no]
--enable-static[=PKGS] build static libraries [default=yes]
--enable-fast-install[=PKGS]
@@ -1702,7 +1707,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sntp configure 4.2.8p11
+sntp configure 4.2.8p13
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2411,7 +2416,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sntp $as_me 4.2.8p11, which was
+It was created by sntp $as_me 4.2.8p13, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3408,7 +3413,7 @@ fi
# Define the identity of the package.
PACKAGE='sntp'
- VERSION='4.2.8p11'
+ VERSION='4.2.8p13'
cat >>confdefs.h <<_ACEOF
@@ -4881,8 +4886,6 @@ done
-
-
ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
if test "x$ac_cv_header_minix_config_h" = xyes; then :
MINIX=yes
@@ -4903,14 +4906,6 @@ $as_echo "#define _MINIX 1" >>confdefs.h
fi
- case "$host_os" in
- hpux*)
-
-$as_echo "#define _XOPEN_SOURCE 500" >>confdefs.h
-
- ;;
- esac
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
@@ -6762,18 +6757,18 @@ else
/* end confdefs.h. */
/* For now, do not test the preprocessor; as of 2007 there are too many
- implementations with broken preprocessors. Perhaps this can
- be revisited in 2012. In the meantime, code should not expect
- #if to work with literals wider than 32 bits. */
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
/* Test literals. */
long long int ll = 9223372036854775807ll;
long long int nll = -9223372036854775807LL;
unsigned long long int ull = 18446744073709551615ULL;
/* Test constant expressions. */
typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
- ? 1 : -1)];
+ ? 1 : -1)];
typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
- ? 1 : -1)];
+ ? 1 : -1)];
int i = 63;
int
main ()
@@ -6782,9 +6777,9 @@ main ()
long long int llmax = 9223372036854775807ll;
unsigned long long int ullmax = 18446744073709551615ull;
return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
- | (llmax / ll) | (llmax % ll)
- | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
- | (ullmax / ull) | (ullmax % ull));
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));
;
return 0;
}
@@ -6972,33 +6967,33 @@ if ${ac_cv_type_long_long_int+:} false; then :
else
ac_cv_type_long_long_int=yes
if test "x${ac_cv_prog_cc_c99-no}" = xno; then
- ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
- if test $ac_cv_type_long_long_int = yes; then
- if test "$cross_compiling" = yes; then :
+ ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+ if test $ac_cv_type_long_long_int = yes; then
+ if test "$cross_compiling" = yes; then :
:
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <limits.h>
- #ifndef LLONG_MAX
- # define HALF \
- (1LL << (sizeof (long long int) * CHAR_BIT - 2))
- # define LLONG_MAX (HALF - 1 + HALF)
- #endif
+ #ifndef LLONG_MAX
+ # define HALF \
+ (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+ # define LLONG_MAX (HALF - 1 + HALF)
+ #endif
int
main ()
{
long long int n = 1;
- int i;
- for (i = 0; ; i++)
- {
- long long int m = n << i;
- if (m >> i != n)
- return 1;
- if (LLONG_MAX / 2 < m)
- break;
- }
- return 0;
+ int i;
+ for (i = 0; ; i++)
+ {
+ long long int m = n << i;
+ if (m >> i != n)
+ return 1;
+ if (LLONG_MAX / 2 < m)
+ break;
+ }
+ return 0;
;
return 0;
}
@@ -7012,7 +7007,7 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
- fi
+ fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5
@@ -7035,18 +7030,18 @@ else
/* end confdefs.h. */
/* For now, do not test the preprocessor; as of 2007 there are too many
- implementations with broken preprocessors. Perhaps this can
- be revisited in 2012. In the meantime, code should not expect
- #if to work with literals wider than 32 bits. */
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
/* Test literals. */
long long int ll = 9223372036854775807ll;
long long int nll = -9223372036854775807LL;
unsigned long long int ull = 18446744073709551615ULL;
/* Test constant expressions. */
typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
- ? 1 : -1)];
+ ? 1 : -1)];
typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
- ? 1 : -1)];
+ ? 1 : -1)];
int i = 63;
int
main ()
@@ -7055,9 +7050,9 @@ main ()
long long int llmax = 9223372036854775807ll;
unsigned long long int ullmax = 18446744073709551615ull;
return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
- | (llmax / ll) | (llmax % ll)
- | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
- | (ullmax / ull) | (ullmax % ull));
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));
;
return 0;
}
@@ -14696,12 +14691,51 @@ case "$ntp_have_solarisprivs" in
$as_echo "#define HAVE_SOLARIS_PRIVS 1" >>confdefs.h
+ ;;
+ '') ntp_have_solarisprivs="no"
+ ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ntp_have_solarisprivs" >&5
$as_echo "$ntp_have_solarisprivs" >&6; }
-case "$ntp_use_dev_clockctl$ntp_have_linuxcaps$ntp_have_solarisprivs" in
+for ac_header in sys/mac.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/mac.h" "ac_cv_header_sys_mac_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mac_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_MAC_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# Check whether --enable-trustedbsd_mac was given.
+if test "${enable_trustedbsd_mac+set}" = set; then :
+ enableval=$enable_trustedbsd_mac; ntp_use_trustedbsd_mac=$enableval
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we should use TrustedBSD MAC privileges" >&5
+$as_echo_n "checking if we should use TrustedBSD MAC privileges... " >&6; }
+
+case "$ntp_use_trustedbsd_mac$ac_cv_header_sys_mac_h" in
+ yesyes)
+
+$as_echo "#define HAVE_TRUSTEDBSD_MAC 1" >>confdefs.h
+
+ ;;
+ *) ntp_use_trustedbsd_mac="no";
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ntp_use_trustedbsd_mac" >&5
+$as_echo "$ntp_use_trustedbsd_mac" >&6; }
+
+case "$ntp_use_dev_clockctl$ntp_have_linuxcaps$ntp_have_solarisprivs$ntp_use_trustedbsd_mac" in
*yes*)
$as_echo "#define HAVE_DROPROOT 1" >>confdefs.h
@@ -15215,6 +15249,16 @@ fi
done
+# HMS: does this need to be a cached variable?
+# Check whether --enable-signalled-io was given.
+if test "${enable_signalled_io+set}" = set; then :
+ enableval=$enable_signalled_io; use_signalled_io=$enableval
+else
+ use_signalled_io=yes
+
+fi
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SIGIO" >&5
$as_echo_n "checking for SIGIO... " >&6; }
if ${ntp_cv_hdr_def_sigio+:} false; then :
@@ -15289,13 +15333,24 @@ case "$ntp_cv_hdr_def_sigio" in
ans=no
;;
esac
+ case "$ans" in
+ no)
+ ans="Possible for $host but disabled because of reported problems"
+ ;;
+ esac
;;
esac
case "$ans" in
yes)
+ case "$use_signalled_io" in
+ yes)
$as_echo "#define HAVE_SIGNALED_IO 1" >>confdefs.h
+ ;;
+ *) ans="Allowed for $host but --disable-signalled-io was given"
+ ;;
+ esac
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ans" >&5
$as_echo "$ans" >&6; }
@@ -25297,6 +25352,19 @@ $as_echo "$ntp_openssl" >&6; }
case "$ntp_openssl" in
yes)
+ for ac_header in openssl/cmac.h openssl/hmac.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
$as_echo "#define OPENSSL /**/" >>confdefs.h
@@ -27078,7 +27146,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sntp $as_me 4.2.8p11, which was
+This file was extended by sntp $as_me 4.2.8p13, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -27145,7 +27213,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-sntp config.status 4.2.8p11
+sntp config.status 4.2.8p13
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/contrib/ntp/sntp/crypto.c b/contrib/ntp/sntp/crypto.c
index ce5d136..be94ed5 100644
--- a/contrib/ntp/sntp/crypto.c
+++ b/contrib/ntp/sntp/crypto.c
@@ -12,13 +12,6 @@
#include "isc/string.h"
#include "ntp_md5.h"
-/* HMS: We may not have OpenSSL, but we have our own AES-128-CMAC */
-#define CMAC "AES128CMAC"
-#ifdef OPENSSL
-# include "openssl/cmac.h"
-# define AES_128_KEY_SIZE 16
-#endif /* OPENSSL */
-
#ifndef EVP_MAX_MD_SIZE
# define EVP_MAX_MD_SIZE 32
#endif
@@ -45,7 +38,7 @@ compute_mac(
INIT_SSL();
key_type = keytype_from_text(macname, NULL);
-#ifdef OPENSSL
+#if defined(OPENSSL) && defined(ENABLE_CMAC)
/* Check if CMAC key type specific code required */
if (key_type == NID_cmac) {
CMAC_CTX * ctx = NULL;
diff --git a/contrib/ntp/sntp/include/Makefile.in b/contrib/ntp/sntp/include/Makefile.in
index 403fdd6..b66440c 100644
--- a/contrib/ntp/sntp/include/Makefile.in
+++ b/contrib/ntp/sntp/include/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/sntp/include/version.def b/contrib/ntp/sntp/include/version.def
index 22657d4..eee2240 100644
--- a/contrib/ntp/sntp/include/version.def
+++ b/contrib/ntp/sntp/include/version.def
@@ -1 +1 @@
-version = '4.2.8p11';
+version = '4.2.8p13';
diff --git a/contrib/ntp/sntp/include/version.texi b/contrib/ntp/sntp/include/version.texi
index ba520bf..1f30a3a 100644
--- a/contrib/ntp/sntp/include/version.texi
+++ b/contrib/ntp/sntp/include/version.texi
@@ -1,3 +1,3 @@
-@set UPDATED 27 February 2018
-@set EDITION 4.2.8p11
-@set VERSION 4.2.8p11
+@set UPDATED 20 February 2019
+@set EDITION 4.2.8p13
+@set VERSION 4.2.8p13
diff --git a/contrib/ntp/sntp/invoke-sntp.texi b/contrib/ntp/sntp/invoke-sntp.texi
index a79b62f..4448653 100644
--- a/contrib/ntp/sntp/invoke-sntp.texi
+++ b/contrib/ntp/sntp/invoke-sntp.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-sntp.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 05:13:11 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:55:49 AM by AutoGen 5.18.5
# From the definitions sntp-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -101,62 +101,58 @@ with a status code of 0.
@exampleindent 0
@example
-sntp - standard Simple Network Time Protocol client program - Ver. 4.2.7p245
-USAGE: sntp [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... \
+sntp - standard Simple Network Time Protocol client program - Ver. 4.2.8p13
+Usage: sntp [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... \
[ hostname-or-IP ...]
Flg Arg Option-Name Description
-4 no ipv4 Force IPv4 DNS name resolution
- - prohibits these options:
- ipv6
+ - prohibits the option 'ipv6'
-6 no ipv6 Force IPv6 DNS name resolution
- - prohibits these options:
- ipv4
- -a Num authentication Enable authentication with the key @@var@{auth-keynumber@}
- -B Num bctimeout The number of seconds to wait for broadcasts
+ - prohibits the option 'ipv4'
+ -a Num authentication Enable authentication with the key auth-keynumber
-b Str broadcast Listen to the address specified for broadcast time sync
- may appear multiple times
-c Str concurrent Concurrently query all IPs returned for host-name
- may appear multiple times
-d no debug-level Increase debug verbosity level
- may appear multiple times
- -D Str set-debug-level Set the debug verbosity level
+ -D Num set-debug-level Set the debug verbosity level
- may appear multiple times
-g Num gap The gap (in milliseconds) between time requests
-K Fil kod KoD history filename
- -k Fil keyfile Look in this file for the key specified with @@option@{-a@}
+ -k Fil keyfile Look in this file for the key specified with -a
-l Fil logfile Log to specified logfile
- -M Num steplimit Adjustments less than @@var@{steplimit@} msec will be slewed
- - It must be in the range:
+ -M Num steplimit Adjustments less than steplimit msec will be slewed
+ - it must be in the range:
greater than or equal to 0
- -o Num ntpversion Send @@var@{int@} as our NTP version
- - It must be in the range:
+ -o Num ntpversion Send int as our NTP protocol version
+ - it must be in the range:
0 to 7
-r no usereservedport Use the NTP Reserved Port (port 123)
- -S no step OK to 'step' the time with @@command@{settimeofday(2)@}
- -s no slew OK to 'slew' the time with @@command@{adjtime(2)@}
- -u Num uctimeout The number of seconds to wait for unicast responses
+ -S no step OK to 'step' the time with settimeofday(2)
+ -s no slew OK to 'slew' the time with adjtime(2)
+ -t Num timeout The number of seconds to wait for responses
no wait Wait for pending replies (if not setting the time)
- - disabled as --no-wait
+ - disabled as '--no-wait'
- enabled by default
- opt version Output version information and exit
- -? no help Display extended usage information and exit
- -! no more-help Extended usage information passed thru pager
- -> opt save-opts Save the option state to a config file
- -< Str load-opts Load options from a config file
- - disabled as --no-load-opts
+ opt version output version information and exit
+ -? no help display extended usage information and exit
+ -! no more-help extended usage information passed thru pager
+ -> opt save-opts save the option state to a config file
+ -< Str load-opts load options from a config file
+ - disabled as '--no-load-opts'
- may appear multiple times
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-
The following option preset mechanisms are supported:
- reading file $HOME/.ntprc
- reading file ./.ntprc
- examining environment variables named SNTP_*
-please send bug reports to: http://bugs.ntp.org, bugs@@ntp.org
+Please send bug reports to: <http://bugs.ntp.org, bugs@@ntp.org>
@end example
@exampleindent 4
diff --git a/contrib/ntp/sntp/libevent/Makefile.in b/contrib/ntp/sntp/libevent/Makefile.in
index 5fb8c02..a608569 100644
--- a/contrib/ntp/sntp/libevent/Makefile.in
+++ b/contrib/ntp/sntp/libevent/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -2168,7 +2168,7 @@ distdir: $(DISTFILES)
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r "$(distdir)"
dist-gzip: distdir
- tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
$(am__post_remove_distdir)
dist-bzip2: distdir
@@ -2194,7 +2194,7 @@ dist-shar: distdir
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
- shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
$(am__post_remove_distdir)
dist-zip: distdir
@@ -2212,7 +2212,7 @@ dist dist-all:
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
- GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lz*) \
@@ -2222,7 +2222,7 @@ distcheck: dist
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
- GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
diff --git a/contrib/ntp/sntp/libevent/aclocal.m4 b/contrib/ntp/sntp/libevent/aclocal.m4
index 3d29497..f869b92 100644
--- a/contrib/ntp/sntp/libevent/aclocal.m4
+++ b/contrib/ntp/sntp/libevent/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -20,126 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
-# serial 9 -*- Autoconf -*-
-# Enable extensions on systems that normally disable them.
-
-# Copyright (C) 2003, 2006-2010 Free Software Foundation, Inc.
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This definition of AC_USE_SYSTEM_EXTENSIONS is stolen from CVS
-# Autoconf. Perhaps we can remove this once we can assume Autoconf
-# 2.62 or later everywhere, but since CVS Autoconf mutates rapidly
-# enough in this area it's likely we'll need to redefine
-# AC_USE_SYSTEM_EXTENSIONS for quite some time.
-
-# If autoconf reports a warning
-# warning: AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS
-# or warning: AC_RUN_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS
-# the fix is
-# 1) to ensure that AC_USE_SYSTEM_EXTENSIONS is never directly invoked
-# but always AC_REQUIREd,
-# 2) to ensure that for each occurrence of
-# AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
-# or
-# AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
-# the corresponding gnulib module description has 'extensions' among
-# its dependencies. This will ensure that the gl_USE_SYSTEM_EXTENSIONS
-# invocation occurs in gl_EARLY, not in gl_INIT.
-
-# AC_USE_SYSTEM_EXTENSIONS
-# ------------------------
-# Enable extensions on systems that normally disable them,
-# typically due to standards-conformance issues.
-# Remember that #undef in AH_VERBATIM gets replaced with #define by
-# AC_DEFINE. The goal here is to define all known feature-enabling
-# macros, then, if reports of conflicts are made, disable macros that
-# cause problems on some platforms (such as __EXTENSIONS__).
-AC_DEFUN_ONCE([AC_USE_SYSTEM_EXTENSIONS],
-[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
-AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
-
- AC_REQUIRE([AC_CANONICAL_HOST])
-
- AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=])
- if test "$MINIX" = yes; then
- AC_DEFINE([_POSIX_SOURCE], [1],
- [Define to 1 if you need to in order for `stat' and other
- things to work.])
- AC_DEFINE([_POSIX_1_SOURCE], [2],
- [Define to 2 if the system does not provide POSIX.1 features
- except with this defined.])
- AC_DEFINE([_MINIX], [1],
- [Define to 1 if on MINIX.])
- fi
-
- dnl HP-UX 11.11 defines mbstate_t only if _XOPEN_SOURCE is defined to 500,
- dnl regardless of whether the flags -Ae or _D_HPUX_SOURCE=1 are already
- dnl provided.
- case "$host_os" in
- hpux*)
- AC_DEFINE([_XOPEN_SOURCE], [500],
- [Define to 500 only on HP-UX.])
- ;;
- esac
-
- AH_VERBATIM([__EXTENSIONS__],
-[/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# undef _ALL_SOURCE
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-])
- AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
- [ac_cv_safe_to_define___extensions__],
- [AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM([[
-# define __EXTENSIONS__ 1
- ]AC_INCLUDES_DEFAULT])],
- [ac_cv_safe_to_define___extensions__=yes],
- [ac_cv_safe_to_define___extensions__=no])])
- test $ac_cv_safe_to_define___extensions__ = yes &&
- AC_DEFINE([__EXTENSIONS__])
- AC_DEFINE([_ALL_SOURCE])
- AC_DEFINE([_GNU_SOURCE])
- AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
- AC_DEFINE([_TANDEM_SOURCE])
-])# AC_USE_SYSTEM_EXTENSIONS
-
-# gl_USE_SYSTEM_EXTENSIONS
-# ------------------------
-# Enable extensions on systems that normally disable them,
-# typically due to standards-conformance issues.
-AC_DEFUN_ONCE([gl_USE_SYSTEM_EXTENSIONS],
-[
- dnl Require this macro before AC_USE_SYSTEM_EXTENSIONS.
- dnl gnulib does not need it. But if it gets required by third-party macros
- dnl after AC_USE_SYSTEM_EXTENSIONS is required, autoconf 2.62..2.63 emit a
- dnl warning: "AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS".
- dnl Note: We can do this only for one of the macros AC_AIX, AC_GNU_SOURCE,
- dnl AC_MINIX. If people still use AC_AIX or AC_MINIX, they are out of luck.
- AC_REQUIRE([AC_GNU_SOURCE])
-
- AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
-])
-
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -154,7 +35,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.15'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
-m4_if([$1], [1.15], [],
+m4_if([$1], [1.15.1], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@@ -170,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -229,7 +110,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd`
# AM_CONDITIONAL -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -260,7 +141,7 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -451,7 +332,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
# Generate code to set up dependency tracking. -*- Autoconf -*-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -527,7 +408,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -724,7 +605,7 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -745,7 +626,7 @@ if test x"${install_sh+set}" != xset; then
fi
AC_SUBST([install_sh])])
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -766,7 +647,7 @@ AC_SUBST([am__leading_dot])])
# Check to see how 'make' treats includes. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -816,7 +697,7 @@ rm -f confinc confmf
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -855,7 +736,7 @@ fi
# Helper functions for option handling. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -884,7 +765,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -931,7 +812,7 @@ AC_LANG_POP([C])])
# For backward compatibility.
AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -950,7 +831,7 @@ AC_DEFUN([AM_RUN_LOG],
# Check to make sure that the build environment is sane. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1031,7 +912,7 @@ AC_CONFIG_COMMANDS_PRE(
rm -f conftest.file
])
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1091,7 +972,7 @@ AC_SUBST([AM_BACKSLASH])dnl
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1119,7 +1000,7 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1138,7 +1019,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/sntp/libevent/build-aux/ar-lib b/contrib/ntp/sntp/libevent/build-aux/ar-lib
index 463b9ec..05094d3 100755
--- a/contrib/ntp/sntp/libevent/build-aux/ar-lib
+++ b/contrib/ntp/sntp/libevent/build-aux/ar-lib
@@ -4,7 +4,7 @@
me=ar-lib
scriptversion=2012-03-01.08; # UTC
-# Copyright (C) 2010-2014 Free Software Foundation, Inc.
+# Copyright (C) 2010-2017 Free Software Foundation, Inc.
# Written by Peter Rosin <peda@lysator.liu.se>.
#
# This program is free software; you can redistribute it and/or modify
diff --git a/contrib/ntp/sntp/libevent/build-aux/compile b/contrib/ntp/sntp/libevent/build-aux/compile
index a85b723..2ab71e4 100755
--- a/contrib/ntp/sntp/libevent/build-aux/compile
+++ b/contrib/ntp/sntp/libevent/build-aux/compile
@@ -1,9 +1,9 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
-scriptversion=2012-10-14.11; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
@@ -255,7 +255,8 @@ EOF
echo "compile $scriptversion"
exit $?
;;
- cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
@@ -342,6 +343,6 @@ exit $ret
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/contrib/ntp/sntp/libevent/build-aux/config.guess b/contrib/ntp/sntp/libevent/build-aux/config.guess
index 6c32c86..0bb53ae 100755
--- a/contrib/ntp/sntp/libevent/build-aux/config.guess
+++ b/contrib/ntp/sntp/libevent/build-aux/config.guess
@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2014 Free Software Foundation, Inc.
+# Copyright 1992-2015 Free Software Foundation, Inc.
-timestamp='2014-11-04'
+timestamp='2015-03-04'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -168,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
- /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ /sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || \
+ echo unknown)`
case "${UNAME_MACHINE_ARCH}" in
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine=${arch}${endian}-unknown
+ ;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently, or will in the future.
case "${UNAME_MACHINE_ARCH}" in
- arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
@@ -197,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
os=netbsd
;;
esac
+ # Determine ABI tags.
+ case "${UNAME_MACHINE_ARCH}" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+ ;;
+ esac
# The OS release
# Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need
@@ -213,7 +227,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "${machine}-${os}${release}"
+ echo "${machine}-${os}${release}${abi}"
exit ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
@@ -811,12 +825,7 @@ EOF
exit ;;
*:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p`
- case ${UNAME_PROCESSOR} in
- amd64)
- echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- esac
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
@@ -933,6 +942,9 @@ EOF
crisv32:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
+ e2k:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
frv:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
diff --git a/contrib/ntp/sntp/libevent/build-aux/config.sub b/contrib/ntp/sntp/libevent/build-aux/config.sub
index 7ffe373..3580aaf 100755
--- a/contrib/ntp/sntp/libevent/build-aux/config.sub
+++ b/contrib/ntp/sntp/libevent/build-aux/config.sub
@@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2014 Free Software Foundation, Inc.
+# Copyright 1992-2015 Free Software Foundation, Inc.
-timestamp='2014-12-03'
+timestamp='2015-03-08'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,7 +117,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
- knetbsd*-gnu* | netbsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
@@ -259,8 +259,8 @@ case $basic_machine in
| bfin \
| c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \
- | epiphany \
- | fido | fr30 | frv \
+ | e2k | epiphany \
+ | fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
| i370 | i860 | i960 | ia64 \
@@ -300,7 +300,7 @@ case $basic_machine in
| ns16k | ns32k \
| open8 | or1k | or1knd | or32 \
| pdp10 | pdp11 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
| pyramid \
| riscv32 | riscv64 \
| rl78 | rx \
@@ -373,7 +373,7 @@ case $basic_machine in
| aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | amd64-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| be32-* | be64-* \
@@ -381,7 +381,7 @@ case $basic_machine in
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
- | elxsi-* \
+ | e2k-* | elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
@@ -426,7 +426,7 @@ case $basic_machine in
| or1k*-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | powerpcspe-* \
| pyramid-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
@@ -485,12 +485,6 @@ case $basic_machine in
basic_machine=a29k-none
os=-bsd
;;
- amd64)
- basic_machine=x86_64-pc
- ;;
- amd64-*)
- basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
amdahl)
basic_machine=580-amdahl
os=-sysv
@@ -518,6 +512,9 @@ case $basic_machine in
basic_machine=i386-pc
os=-aros
;;
+ asmjs)
+ basic_machine=asmjs-unknown
+ ;;
aux)
basic_machine=m68k-apple
os=-aux
@@ -1373,7 +1370,7 @@ case $os in
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* | -aros* \
+ | -aos* | -aros* | -cloudabi* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
diff --git a/contrib/ntp/sntp/libevent/build-aux/depcomp b/contrib/ntp/sntp/libevent/build-aux/depcomp
index fc98710..b39f98f 100755
--- a/contrib/ntp/sntp/libevent/build-aux/depcomp
+++ b/contrib/ntp/sntp/libevent/build-aux/depcomp
@@ -1,9 +1,9 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
-scriptversion=2013-05-30.07; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
# 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
@@ -786,6 +786,6 @@ exit 0
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/contrib/ntp/sntp/libevent/build-aux/install-sh b/contrib/ntp/sntp/libevent/build-aux/install-sh
index 0b0fdcb..0360b79 100755
--- a/contrib/ntp/sntp/libevent/build-aux/install-sh
+++ b/contrib/ntp/sntp/libevent/build-aux/install-sh
@@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
-scriptversion=2013-12-25.23; # UTC
+scriptversion=2016-01-11.22; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -496,6 +496,6 @@ done
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/contrib/ntp/sntp/libevent/build-aux/missing b/contrib/ntp/sntp/libevent/build-aux/missing
index f62bbae..c6e3795 100755
--- a/contrib/ntp/sntp/libevent/build-aux/missing
+++ b/contrib/ntp/sntp/libevent/build-aux/missing
@@ -1,9 +1,9 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
-scriptversion=2013-10-28.13; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
@@ -210,6 +210,6 @@ exit $st
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/contrib/ntp/sntp/libevent/build-aux/test-driver b/contrib/ntp/sntp/libevent/build-aux/test-driver
index 8e575b0..0218a01 100755
--- a/contrib/ntp/sntp/libevent/build-aux/test-driver
+++ b/contrib/ntp/sntp/libevent/build-aux/test-driver
@@ -1,9 +1,9 @@
#! /bin/sh
# test-driver - basic testsuite driver script.
-scriptversion=2013-07-13.22; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 2011-2014 Free Software Foundation, Inc.
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
#
# 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
@@ -143,6 +143,6 @@ echo ":copy-in-global-log: $gcopy" >> $trs_file
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/contrib/ntp/sntp/libevent/build-aux/ylwrap b/contrib/ntp/sntp/libevent/build-aux/ylwrap
index 7c2d927..d788f2d 100755
--- a/contrib/ntp/sntp/libevent/build-aux/ylwrap
+++ b/contrib/ntp/sntp/libevent/build-aux/ylwrap
@@ -1,9 +1,9 @@
#! /bin/sh
# ylwrap - wrapper for lex/yacc invocations.
-scriptversion=2013-01-12.17; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# Written by Tom Tromey <tromey@cygnus.com>.
#
@@ -242,6 +242,6 @@ exit $ret
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/contrib/ntp/sntp/libevent/config.h.in b/contrib/ntp/sntp/libevent/config.h.in
index 64bb3f2..e425aa1 100644
--- a/contrib/ntp/sntp/libevent/config.h.in
+++ b/contrib/ntp/sntp/libevent/config.h.in
@@ -449,6 +449,28 @@
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
/* Version number of package */
#undef VERSION
@@ -473,31 +495,6 @@
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE
-/* Define to 500 only on HP-UX. */
-#undef _XOPEN_SOURCE
-
-/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# undef _ALL_SOURCE
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-
-
/* Define to appropriate substitue if compiler doesnt have __func__ */
#undef __func__
diff --git a/contrib/ntp/sntp/libevent/configure b/contrib/ntp/sntp/libevent/configure
index 486a7d3..0d9dcdd 100755
--- a/contrib/ntp/sntp/libevent/configure
+++ b/contrib/ntp/sntp/libevent/configure
@@ -703,6 +703,14 @@ FGREP
LIBTOOL
SED
LN_S
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
EGREP
GREP
CPP
@@ -723,14 +731,6 @@ CPPFLAGS
LDFLAGS
CFLAGS
CC
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
AM_BACKSLASH
AM_DEFAULT_VERBOSITY
AM_DEFAULT_V
@@ -3287,77 +3287,6 @@ if test "$prefix" = "NONE"; then
fi
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
- ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
- as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "x$host_alias" = x; then
- ac_cv_host=$ac_cv_build
-else
- ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
DEPDIR="${am__leading_dot}deps"
ac_config_commands="$ac_config_commands depfiles"
@@ -4796,8 +4725,6 @@ done
-
-
ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
if test "x$ac_cv_header_minix_config_h" = xyes; then :
MINIX=yes
@@ -4818,14 +4745,6 @@ $as_echo "#define _MINIX 1" >>confdefs.h
fi
- case "$host_os" in
- hpux*)
-
-$as_echo "#define _XOPEN_SOURCE 500" >>confdefs.h
-
- ;;
- esac
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
@@ -4868,6 +4787,75 @@ $as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
diff --git a/contrib/ntp/sntp/libevent/evconfig-private.h b/contrib/ntp/sntp/libevent/evconfig-private.h
index ea4940d..f6b08e3 100644
--- a/contrib/ntp/sntp/libevent/evconfig-private.h
+++ b/contrib/ntp/sntp/libevent/evconfig-private.h
@@ -26,7 +26,7 @@
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
-#define _FILE_OFFSET_BITS 64
+/* #undef _FILE_OFFSET_BITS */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
diff --git a/contrib/ntp/sntp/libevent/test/regress.gen.c b/contrib/ntp/sntp/libevent/test/regress.gen.c
index 8d1c8b6..9ec9258 100644
--- a/contrib/ntp/sntp/libevent/test/regress.gen.c
+++ b/contrib/ntp/sntp/libevent/test/regress.gen.c
@@ -1 +1,1225 @@
-
+/*
+ * Automatically generated from ../../../sntp/libevent/test/regress.rpc
+ * by event_rpcgen.py/0.1. DO NOT EDIT THIS FILE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <event2/event-config.h>
+#include <event2/event.h>
+#include <event2/buffer.h>
+#include <event2/tag.h>
+
+#ifdef EVENT____func__
+#define __func__ EVENT____func__
+#endif
+
+
+#include "regress.gen.h"
+
+void event_warn(const char *fmt, ...);
+void event_warnx(const char *fmt, ...);
+
+
+/*
+ * Implementation of msg
+ */
+
+static struct msg_access_ msg_base__ = {
+ msg_from_name_assign,
+ msg_from_name_get,
+ msg_to_name_assign,
+ msg_to_name_get,
+ msg_attack_assign,
+ msg_attack_get,
+ msg_run_assign,
+ msg_run_get,
+ msg_run_add,
+};
+
+struct msg *
+msg_new(void)
+{
+ return msg_new_with_arg(NULL);
+}
+
+struct msg *
+msg_new_with_arg(void *unused)
+{
+ struct msg *tmp;
+ if ((tmp = malloc(sizeof(struct msg))) == NULL) {
+ event_warn("%s: malloc", __func__);
+ return (NULL);
+ }
+ tmp->base = &msg_base__;
+
+ tmp->from_name_data = NULL;
+ tmp->from_name_set = 0;
+
+ tmp->to_name_data = NULL;
+ tmp->to_name_set = 0;
+
+ tmp->attack_data = NULL;
+ tmp->attack_set = 0;
+
+ tmp->run_data = NULL;
+ tmp->run_length = 0;
+ tmp->run_num_allocated = 0;
+ tmp->run_set = 0;
+
+ return (tmp);
+}
+
+
+
+
+static int
+msg_run_expand_to_hold_more(struct msg *msg)
+{
+ int tobe_allocated = msg->run_num_allocated;
+ struct run** new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (struct run**) realloc(msg->run_data,
+ tobe_allocated * sizeof(struct run*));
+ if (new_data == NULL)
+ return -1;
+ msg->run_data = new_data;
+ msg->run_num_allocated = tobe_allocated;
+ return 0;}
+
+struct run*
+msg_run_add(struct msg *msg)
+{
+ if (++msg->run_length >= msg->run_num_allocated) {
+ if (msg_run_expand_to_hold_more(msg)<0)
+ goto error;
+ }
+ msg->run_data[msg->run_length - 1] = run_new();
+ if (msg->run_data[msg->run_length - 1] == NULL)
+ goto error;
+ msg->run_set = 1;
+ return (msg->run_data[msg->run_length - 1]);
+error:
+ --msg->run_length;
+ return (NULL);
+}
+
+int
+msg_from_name_assign(struct msg *msg,
+ const char * value)
+{
+ if (msg->from_name_data != NULL)
+ free(msg->from_name_data);
+ if ((msg->from_name_data = strdup(value)) == NULL)
+ return (-1);
+ msg->from_name_set = 1;
+ return (0);
+}
+
+int
+msg_to_name_assign(struct msg *msg,
+ const char * value)
+{
+ if (msg->to_name_data != NULL)
+ free(msg->to_name_data);
+ if ((msg->to_name_data = strdup(value)) == NULL)
+ return (-1);
+ msg->to_name_set = 1;
+ return (0);
+}
+
+int
+msg_attack_assign(struct msg *msg,
+ const struct kill* value)
+{
+ struct evbuffer *tmp = NULL;
+ if (msg->attack_set) {
+ kill_clear(msg->attack_data);
+ msg->attack_set = 0;
+ } else {
+ msg->attack_data = kill_new();
+ if (msg->attack_data == NULL) {
+ event_warn("%s: kill_new()", __func__);
+ goto error;
+ }
+ }
+ if ((tmp = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new()", __func__);
+ goto error;
+ }
+ kill_marshal(tmp, value);
+ if (kill_unmarshal(msg->attack_data, tmp) == -1) {
+ event_warnx("%s: kill_unmarshal", __func__);
+ goto error;
+ }
+ msg->attack_set = 1;
+ evbuffer_free(tmp);
+ return (0);
+ error:
+ if (tmp != NULL)
+ evbuffer_free(tmp);
+ if (msg->attack_data != NULL) {
+ kill_free(msg->attack_data);
+ msg->attack_data = NULL;
+ }
+ return (-1);
+}
+
+int
+msg_run_assign(struct msg *msg, int off,
+ const struct run* value)
+{
+ if (!msg->run_set || off < 0 || off >= msg->run_length)
+ return (-1);
+
+ {
+ int had_error = 0;
+ struct evbuffer *tmp = NULL;
+ run_clear(msg->run_data[off]);
+ if ((tmp = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new()", __func__);
+ had_error = 1;
+ goto done;
+ }
+ run_marshal(tmp, value);
+ if (run_unmarshal(msg->run_data[off], tmp) == -1) {
+ event_warnx("%s: run_unmarshal", __func__);
+ had_error = 1;
+ goto done;
+ }
+ done:if (tmp != NULL)
+ evbuffer_free(tmp);
+ if (had_error) {
+ run_clear(msg->run_data[off]);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+int
+msg_from_name_get(struct msg *msg, char * *value)
+{
+ if (msg->from_name_set != 1)
+ return (-1);
+ *value = msg->from_name_data;
+ return (0);
+}
+
+int
+msg_to_name_get(struct msg *msg, char * *value)
+{
+ if (msg->to_name_set != 1)
+ return (-1);
+ *value = msg->to_name_data;
+ return (0);
+}
+
+int
+msg_attack_get(struct msg *msg, struct kill* *value)
+{
+ if (msg->attack_set != 1) {
+ msg->attack_data = kill_new();
+ if (msg->attack_data == NULL)
+ return (-1);
+ msg->attack_set = 1;
+ }
+ *value = msg->attack_data;
+ return (0);
+}
+
+int
+msg_run_get(struct msg *msg, int offset,
+ struct run* *value)
+{
+ if (!msg->run_set || offset < 0 || offset >= msg->run_length)
+ return (-1);
+ *value = msg->run_data[offset];
+ return (0);
+}
+
+void
+msg_clear(struct msg *tmp)
+{
+ if (tmp->from_name_set == 1) {
+ free(tmp->from_name_data);
+ tmp->from_name_data = NULL;
+ tmp->from_name_set = 0;
+ }
+ if (tmp->to_name_set == 1) {
+ free(tmp->to_name_data);
+ tmp->to_name_data = NULL;
+ tmp->to_name_set = 0;
+ }
+ if (tmp->attack_set == 1) {
+ kill_free(tmp->attack_data);
+ tmp->attack_data = NULL;
+ tmp->attack_set = 0;
+ }
+ if (tmp->run_set == 1) {
+ int i;
+ for (i = 0; i < tmp->run_length; ++i) {
+ run_free(tmp->run_data[i]);
+ }
+ free(tmp->run_data);
+ tmp->run_data = NULL;
+ tmp->run_set = 0;
+ tmp->run_length = 0;
+ tmp->run_num_allocated = 0;
+ }
+}
+
+void
+msg_free(struct msg *tmp)
+{
+ if (tmp->from_name_data != NULL)
+ free (tmp->from_name_data);
+ if (tmp->to_name_data != NULL)
+ free (tmp->to_name_data);
+ if (tmp->attack_data != NULL)
+ kill_free(tmp->attack_data);
+ if (tmp->run_set == 1) {
+ int i;
+ for (i = 0; i < tmp->run_length; ++i) {
+ run_free(tmp->run_data[i]);
+ }
+ free(tmp->run_data);
+ tmp->run_data = NULL;
+ tmp->run_set = 0;
+ tmp->run_length = 0;
+ tmp->run_num_allocated = 0;
+ }
+ free(tmp->run_data);
+ free(tmp);
+}
+
+void
+msg_marshal(struct evbuffer *evbuf, const struct msg *tmp){
+ evtag_marshal_string(evbuf, MSG_FROM_NAME, tmp->from_name_data);
+ evtag_marshal_string(evbuf, MSG_TO_NAME, tmp->to_name_data);
+ if (tmp->attack_set) {
+ evtag_marshal_kill(evbuf, MSG_ATTACK, tmp->attack_data);
+ }
+ if (tmp->run_set) {
+ {
+ int i;
+ for (i = 0; i < tmp->run_length; ++i) {
+ evtag_marshal_run(evbuf, MSG_RUN, tmp->run_data[i]);
+ }
+ }
+ }
+}
+
+int
+msg_unmarshal(struct msg *tmp, struct evbuffer *evbuf)
+{
+ ev_uint32_t tag;
+ while (evbuffer_get_length(evbuf) > 0) {
+ if (evtag_peek(evbuf, &tag) == -1)
+ return (-1);
+ switch (tag) {
+
+ case MSG_FROM_NAME:
+
+ if (tmp->from_name_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, MSG_FROM_NAME, &tmp->from_name_data) == -1) {
+ event_warnx("%s: failed to unmarshal from_name", __func__);
+ return (-1);
+ }
+ tmp->from_name_set = 1;
+ break;
+
+ case MSG_TO_NAME:
+
+ if (tmp->to_name_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, MSG_TO_NAME, &tmp->to_name_data) == -1) {
+ event_warnx("%s: failed to unmarshal to_name", __func__);
+ return (-1);
+ }
+ tmp->to_name_set = 1;
+ break;
+
+ case MSG_ATTACK:
+
+ if (tmp->attack_set)
+ return (-1);
+ tmp->attack_data = kill_new();
+ if (tmp->attack_data == NULL)
+ return (-1);
+ if (evtag_unmarshal_kill(evbuf, MSG_ATTACK, tmp->attack_data) == -1) {
+ event_warnx("%s: failed to unmarshal attack", __func__);
+ return (-1);
+ }
+ tmp->attack_set = 1;
+ break;
+
+ case MSG_RUN:
+
+ if (tmp->run_length >= tmp->run_num_allocated &&
+ msg_run_expand_to_hold_more(tmp) < 0) {
+ puts("HEY NOW");
+ return (-1);
+ }
+ tmp->run_data[tmp->run_length] = run_new();
+ if (tmp->run_data[tmp->run_length] == NULL)
+ return (-1);
+ if (evtag_unmarshal_run(evbuf, MSG_RUN, tmp->run_data[tmp->run_length]) == -1) {
+ event_warnx("%s: failed to unmarshal run", __func__);
+ return (-1);
+ }
+ ++tmp->run_length;
+ tmp->run_set = 1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ if (msg_complete(tmp) == -1)
+ return (-1);
+ return (0);
+}
+
+int
+msg_complete(struct msg *msg)
+{
+ if (!msg->from_name_set)
+ return (-1);
+ if (!msg->to_name_set)
+ return (-1);
+ if (msg->attack_set && kill_complete(msg->attack_data) == -1)
+ return (-1);
+ {
+ int i;
+ for (i = 0; i < msg->run_length; ++i) {
+ if (msg->run_set && run_complete(msg->run_data[i]) == -1)
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+int
+evtag_unmarshal_msg(struct evbuffer *evbuf, ev_uint32_t need_tag, struct msg *msg)
+{
+ ev_uint32_t tag;
+ int res = -1;
+
+ struct evbuffer *tmp = evbuffer_new();
+
+ if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+ goto error;
+
+ if (msg_unmarshal(msg, tmp) == -1)
+ goto error;
+
+ res = 0;
+
+ error:
+ evbuffer_free(tmp);
+ return (res);
+}
+
+void
+evtag_marshal_msg(struct evbuffer *evbuf, ev_uint32_t tag, const struct msg *msg)
+{
+ struct evbuffer *buf_ = evbuffer_new();
+ assert(buf_ != NULL);
+ msg_marshal(buf_, msg);
+ evtag_marshal_buffer(evbuf, tag, buf_);
+ evbuffer_free(buf_);
+}
+
+/*
+ * Implementation of kill
+ */
+
+static struct kill_access_ kill_base__ = {
+ kill_weapon_assign,
+ kill_weapon_get,
+ kill_action_assign,
+ kill_action_get,
+ kill_how_often_assign,
+ kill_how_often_get,
+ kill_how_often_add,
+};
+
+struct kill *
+kill_new(void)
+{
+ return kill_new_with_arg(NULL);
+}
+
+struct kill *
+kill_new_with_arg(void *unused)
+{
+ struct kill *tmp;
+ if ((tmp = malloc(sizeof(struct kill))) == NULL) {
+ event_warn("%s: malloc", __func__);
+ return (NULL);
+ }
+ tmp->base = &kill_base__;
+
+ tmp->weapon_data = NULL;
+ tmp->weapon_set = 0;
+
+ tmp->action_data = NULL;
+ tmp->action_set = 0;
+
+ tmp->how_often_data = NULL;
+ tmp->how_often_length = 0;
+ tmp->how_often_num_allocated = 0;
+ tmp->how_often_set = 0;
+
+ return (tmp);
+}
+
+
+
+static int
+kill_how_often_expand_to_hold_more(struct kill *msg)
+{
+ int tobe_allocated = msg->how_often_num_allocated;
+ ev_uint32_t* new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (ev_uint32_t*) realloc(msg->how_often_data,
+ tobe_allocated * sizeof(ev_uint32_t));
+ if (new_data == NULL)
+ return -1;
+ msg->how_often_data = new_data;
+ msg->how_often_num_allocated = tobe_allocated;
+ return 0;}
+
+ev_uint32_t *
+kill_how_often_add(struct kill *msg, const ev_uint32_t value)
+{
+ if (++msg->how_often_length >= msg->how_often_num_allocated) {
+ if (kill_how_often_expand_to_hold_more(msg)<0)
+ goto error;
+ }
+ msg->how_often_data[msg->how_often_length - 1] = value;
+ msg->how_often_set = 1;
+ return &(msg->how_often_data[msg->how_often_length - 1]);
+error:
+ --msg->how_often_length;
+ return (NULL);
+}
+
+int
+kill_weapon_assign(struct kill *msg,
+ const char * value)
+{
+ if (msg->weapon_data != NULL)
+ free(msg->weapon_data);
+ if ((msg->weapon_data = strdup(value)) == NULL)
+ return (-1);
+ msg->weapon_set = 1;
+ return (0);
+}
+
+int
+kill_action_assign(struct kill *msg,
+ const char * value)
+{
+ if (msg->action_data != NULL)
+ free(msg->action_data);
+ if ((msg->action_data = strdup(value)) == NULL)
+ return (-1);
+ msg->action_set = 1;
+ return (0);
+}
+
+int
+kill_how_often_assign(struct kill *msg, int off,
+ const ev_uint32_t value)
+{
+ if (!msg->how_often_set || off < 0 || off >= msg->how_often_length)
+ return (-1);
+
+ {
+ msg->how_often_data[off] = value;
+ }
+ return (0);
+}
+
+int
+kill_weapon_get(struct kill *msg, char * *value)
+{
+ if (msg->weapon_set != 1)
+ return (-1);
+ *value = msg->weapon_data;
+ return (0);
+}
+
+int
+kill_action_get(struct kill *msg, char * *value)
+{
+ if (msg->action_set != 1)
+ return (-1);
+ *value = msg->action_data;
+ return (0);
+}
+
+int
+kill_how_often_get(struct kill *msg, int offset,
+ ev_uint32_t *value)
+{
+ if (!msg->how_often_set || offset < 0 || offset >= msg->how_often_length)
+ return (-1);
+ *value = msg->how_often_data[offset];
+ return (0);
+}
+
+void
+kill_clear(struct kill *tmp)
+{
+ if (tmp->weapon_set == 1) {
+ free(tmp->weapon_data);
+ tmp->weapon_data = NULL;
+ tmp->weapon_set = 0;
+ }
+ if (tmp->action_set == 1) {
+ free(tmp->action_data);
+ tmp->action_data = NULL;
+ tmp->action_set = 0;
+ }
+ if (tmp->how_often_set == 1) {
+ free(tmp->how_often_data);
+ tmp->how_often_data = NULL;
+ tmp->how_often_set = 0;
+ tmp->how_often_length = 0;
+ tmp->how_often_num_allocated = 0;
+ }
+}
+
+void
+kill_free(struct kill *tmp)
+{
+ if (tmp->weapon_data != NULL)
+ free (tmp->weapon_data);
+ if (tmp->action_data != NULL)
+ free (tmp->action_data);
+ if (tmp->how_often_set == 1) {
+ free(tmp->how_often_data);
+ tmp->how_often_data = NULL;
+ tmp->how_often_set = 0;
+ tmp->how_often_length = 0;
+ tmp->how_often_num_allocated = 0;
+ }
+ free(tmp->how_often_data);
+ free(tmp);
+}
+
+void
+kill_marshal(struct evbuffer *evbuf, const struct kill *tmp){
+ evtag_marshal_string(evbuf, KILL_WEAPON, tmp->weapon_data);
+ evtag_marshal_string(evbuf, KILL_ACTION, tmp->action_data);
+ if (tmp->how_often_set) {
+ {
+ int i;
+ for (i = 0; i < tmp->how_often_length; ++i) {
+ evtag_marshal_int(evbuf, KILL_HOW_OFTEN, tmp->how_often_data[i]);
+ }
+ }
+ }
+}
+
+int
+kill_unmarshal(struct kill *tmp, struct evbuffer *evbuf)
+{
+ ev_uint32_t tag;
+ while (evbuffer_get_length(evbuf) > 0) {
+ if (evtag_peek(evbuf, &tag) == -1)
+ return (-1);
+ switch (tag) {
+
+ case KILL_WEAPON:
+
+ if (tmp->weapon_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, KILL_WEAPON, &tmp->weapon_data) == -1) {
+ event_warnx("%s: failed to unmarshal weapon", __func__);
+ return (-1);
+ }
+ tmp->weapon_set = 1;
+ break;
+
+ case KILL_ACTION:
+
+ if (tmp->action_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, KILL_ACTION, &tmp->action_data) == -1) {
+ event_warnx("%s: failed to unmarshal action", __func__);
+ return (-1);
+ }
+ tmp->action_set = 1;
+ break;
+
+ case KILL_HOW_OFTEN:
+
+ if (tmp->how_often_length >= tmp->how_often_num_allocated &&
+ kill_how_often_expand_to_hold_more(tmp) < 0) {
+ puts("HEY NOW");
+ return (-1);
+ }
+ if (evtag_unmarshal_int(evbuf, KILL_HOW_OFTEN, &tmp->how_often_data[tmp->how_often_length]) == -1) {
+ event_warnx("%s: failed to unmarshal how_often", __func__);
+ return (-1);
+ }
+ ++tmp->how_often_length;
+ tmp->how_often_set = 1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ if (kill_complete(tmp) == -1)
+ return (-1);
+ return (0);
+}
+
+int
+kill_complete(struct kill *msg)
+{
+ if (!msg->weapon_set)
+ return (-1);
+ if (!msg->action_set)
+ return (-1);
+ return (0);
+}
+
+int
+evtag_unmarshal_kill(struct evbuffer *evbuf, ev_uint32_t need_tag, struct kill *msg)
+{
+ ev_uint32_t tag;
+ int res = -1;
+
+ struct evbuffer *tmp = evbuffer_new();
+
+ if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+ goto error;
+
+ if (kill_unmarshal(msg, tmp) == -1)
+ goto error;
+
+ res = 0;
+
+ error:
+ evbuffer_free(tmp);
+ return (res);
+}
+
+void
+evtag_marshal_kill(struct evbuffer *evbuf, ev_uint32_t tag, const struct kill *msg)
+{
+ struct evbuffer *buf_ = evbuffer_new();
+ assert(buf_ != NULL);
+ kill_marshal(buf_, msg);
+ evtag_marshal_buffer(evbuf, tag, buf_);
+ evbuffer_free(buf_);
+}
+
+/*
+ * Implementation of run
+ */
+
+static struct run_access_ run_base__ = {
+ run_how_assign,
+ run_how_get,
+ run_some_bytes_assign,
+ run_some_bytes_get,
+ run_fixed_bytes_assign,
+ run_fixed_bytes_get,
+ run_notes_assign,
+ run_notes_get,
+ run_notes_add,
+ run_large_number_assign,
+ run_large_number_get,
+ run_other_numbers_assign,
+ run_other_numbers_get,
+ run_other_numbers_add,
+};
+
+struct run *
+run_new(void)
+{
+ return run_new_with_arg(NULL);
+}
+
+struct run *
+run_new_with_arg(void *unused)
+{
+ struct run *tmp;
+ if ((tmp = malloc(sizeof(struct run))) == NULL) {
+ event_warn("%s: malloc", __func__);
+ return (NULL);
+ }
+ tmp->base = &run_base__;
+
+ tmp->how_data = NULL;
+ tmp->how_set = 0;
+
+ tmp->some_bytes_data = NULL;
+ tmp->some_bytes_length = 0;
+ tmp->some_bytes_set = 0;
+
+ memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data));
+ tmp->fixed_bytes_set = 0;
+
+ tmp->notes_data = NULL;
+ tmp->notes_length = 0;
+ tmp->notes_num_allocated = 0;
+ tmp->notes_set = 0;
+
+ tmp->large_number_data = 0;
+ tmp->large_number_set = 0;
+
+ tmp->other_numbers_data = NULL;
+ tmp->other_numbers_length = 0;
+ tmp->other_numbers_num_allocated = 0;
+ tmp->other_numbers_set = 0;
+
+ return (tmp);
+}
+
+
+
+
+static int
+run_notes_expand_to_hold_more(struct run *msg)
+{
+ int tobe_allocated = msg->notes_num_allocated;
+ char ** new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (char **) realloc(msg->notes_data,
+ tobe_allocated * sizeof(char *));
+ if (new_data == NULL)
+ return -1;
+ msg->notes_data = new_data;
+ msg->notes_num_allocated = tobe_allocated;
+ return 0;}
+
+char * *
+run_notes_add(struct run *msg, const char * value)
+{
+ if (++msg->notes_length >= msg->notes_num_allocated) {
+ if (run_notes_expand_to_hold_more(msg)<0)
+ goto error;
+ }
+ if (value != NULL) {
+ msg->notes_data[msg->notes_length - 1] = strdup(value);
+ if (msg->notes_data[msg->notes_length - 1] == NULL) {
+ goto error;
+ }
+ } else {
+ msg->notes_data[msg->notes_length - 1] = NULL;
+ }
+ msg->notes_set = 1;
+ return &(msg->notes_data[msg->notes_length - 1]);
+error:
+ --msg->notes_length;
+ return (NULL);
+}
+
+
+static int
+run_other_numbers_expand_to_hold_more(struct run *msg)
+{
+ int tobe_allocated = msg->other_numbers_num_allocated;
+ ev_uint32_t* new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (ev_uint32_t*) realloc(msg->other_numbers_data,
+ tobe_allocated * sizeof(ev_uint32_t));
+ if (new_data == NULL)
+ return -1;
+ msg->other_numbers_data = new_data;
+ msg->other_numbers_num_allocated = tobe_allocated;
+ return 0;}
+
+ev_uint32_t *
+run_other_numbers_add(struct run *msg, const ev_uint32_t value)
+{
+ if (++msg->other_numbers_length >= msg->other_numbers_num_allocated) {
+ if (run_other_numbers_expand_to_hold_more(msg)<0)
+ goto error;
+ }
+ msg->other_numbers_data[msg->other_numbers_length - 1] = value;
+ msg->other_numbers_set = 1;
+ return &(msg->other_numbers_data[msg->other_numbers_length - 1]);
+error:
+ --msg->other_numbers_length;
+ return (NULL);
+}
+
+int
+run_how_assign(struct run *msg,
+ const char * value)
+{
+ if (msg->how_data != NULL)
+ free(msg->how_data);
+ if ((msg->how_data = strdup(value)) == NULL)
+ return (-1);
+ msg->how_set = 1;
+ return (0);
+}
+
+int
+run_some_bytes_assign(struct run *msg, const ev_uint8_t * value, ev_uint32_t len)
+{
+ if (msg->some_bytes_data != NULL)
+ free (msg->some_bytes_data);
+ msg->some_bytes_data = malloc(len);
+ if (msg->some_bytes_data == NULL)
+ return (-1);
+ msg->some_bytes_set = 1;
+ msg->some_bytes_length = len;
+ memcpy(msg->some_bytes_data, value, len);
+ return (0);
+}
+
+int
+run_fixed_bytes_assign(struct run *msg, const ev_uint8_t *value)
+{
+ msg->fixed_bytes_set = 1;
+ memcpy(msg->fixed_bytes_data, value, 24);
+ return (0);
+}
+
+int
+run_notes_assign(struct run *msg, int off,
+ const char * value)
+{
+ if (!msg->notes_set || off < 0 || off >= msg->notes_length)
+ return (-1);
+
+ {
+ if (msg->notes_data[off] != NULL)
+ free(msg->notes_data[off]);
+ msg->notes_data[off] = strdup(value);
+ if (msg->notes_data[off] == NULL) {
+ event_warnx("%s: strdup", __func__);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+int
+run_large_number_assign(struct run *msg, const ev_uint64_t value)
+{
+ msg->large_number_set = 1;
+ msg->large_number_data = value;
+ return (0);
+}
+
+int
+run_other_numbers_assign(struct run *msg, int off,
+ const ev_uint32_t value)
+{
+ if (!msg->other_numbers_set || off < 0 || off >= msg->other_numbers_length)
+ return (-1);
+
+ {
+ msg->other_numbers_data[off] = value;
+ }
+ return (0);
+}
+
+int
+run_how_get(struct run *msg, char * *value)
+{
+ if (msg->how_set != 1)
+ return (-1);
+ *value = msg->how_data;
+ return (0);
+}
+
+int
+run_some_bytes_get(struct run *msg, ev_uint8_t * *value, ev_uint32_t *plen)
+{
+ if (msg->some_bytes_set != 1)
+ return (-1);
+ *value = msg->some_bytes_data;
+ *plen = msg->some_bytes_length;
+ return (0);
+}
+
+int
+run_fixed_bytes_get(struct run *msg, ev_uint8_t **value)
+{
+ if (msg->fixed_bytes_set != 1)
+ return (-1);
+ *value = msg->fixed_bytes_data;
+ return (0);
+}
+
+int
+run_notes_get(struct run *msg, int offset,
+ char * *value)
+{
+ if (!msg->notes_set || offset < 0 || offset >= msg->notes_length)
+ return (-1);
+ *value = msg->notes_data[offset];
+ return (0);
+}
+
+int
+run_large_number_get(struct run *msg, ev_uint64_t *value)
+{
+ if (msg->large_number_set != 1)
+ return (-1);
+ *value = msg->large_number_data;
+ return (0);
+}
+
+int
+run_other_numbers_get(struct run *msg, int offset,
+ ev_uint32_t *value)
+{
+ if (!msg->other_numbers_set || offset < 0 || offset >= msg->other_numbers_length)
+ return (-1);
+ *value = msg->other_numbers_data[offset];
+ return (0);
+}
+
+void
+run_clear(struct run *tmp)
+{
+ if (tmp->how_set == 1) {
+ free(tmp->how_data);
+ tmp->how_data = NULL;
+ tmp->how_set = 0;
+ }
+ if (tmp->some_bytes_set == 1) {
+ free (tmp->some_bytes_data);
+ tmp->some_bytes_data = NULL;
+ tmp->some_bytes_length = 0;
+ tmp->some_bytes_set = 0;
+ }
+ tmp->fixed_bytes_set = 0;
+ memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data));
+ if (tmp->notes_set == 1) {
+ int i;
+ for (i = 0; i < tmp->notes_length; ++i) {
+ if (tmp->notes_data[i] != NULL) free(tmp->notes_data[i]);
+ }
+ free(tmp->notes_data);
+ tmp->notes_data = NULL;
+ tmp->notes_set = 0;
+ tmp->notes_length = 0;
+ tmp->notes_num_allocated = 0;
+ }
+ tmp->large_number_set = 0;
+ if (tmp->other_numbers_set == 1) {
+ free(tmp->other_numbers_data);
+ tmp->other_numbers_data = NULL;
+ tmp->other_numbers_set = 0;
+ tmp->other_numbers_length = 0;
+ tmp->other_numbers_num_allocated = 0;
+ }
+}
+
+void
+run_free(struct run *tmp)
+{
+ if (tmp->how_data != NULL)
+ free (tmp->how_data);
+ if (tmp->some_bytes_data != NULL)
+ free(tmp->some_bytes_data);
+ if (tmp->notes_set == 1) {
+ int i;
+ for (i = 0; i < tmp->notes_length; ++i) {
+ if (tmp->notes_data[i] != NULL) free(tmp->notes_data[i]);
+ }
+ free(tmp->notes_data);
+ tmp->notes_data = NULL;
+ tmp->notes_set = 0;
+ tmp->notes_length = 0;
+ tmp->notes_num_allocated = 0;
+ }
+ free(tmp->notes_data);
+ if (tmp->other_numbers_set == 1) {
+ free(tmp->other_numbers_data);
+ tmp->other_numbers_data = NULL;
+ tmp->other_numbers_set = 0;
+ tmp->other_numbers_length = 0;
+ tmp->other_numbers_num_allocated = 0;
+ }
+ free(tmp->other_numbers_data);
+ free(tmp);
+}
+
+void
+run_marshal(struct evbuffer *evbuf, const struct run *tmp){
+ evtag_marshal_string(evbuf, RUN_HOW, tmp->how_data);
+ if (tmp->some_bytes_set) {
+ evtag_marshal(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length);
+ }
+ evtag_marshal(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, (24));
+ if (tmp->notes_set) {
+ {
+ int i;
+ for (i = 0; i < tmp->notes_length; ++i) {
+ evtag_marshal_string(evbuf, RUN_NOTES, tmp->notes_data[i]);
+ }
+ }
+ }
+ if (tmp->large_number_set) {
+ evtag_marshal_int64(evbuf, RUN_LARGE_NUMBER, tmp->large_number_data);
+ }
+ if (tmp->other_numbers_set) {
+ {
+ int i;
+ for (i = 0; i < tmp->other_numbers_length; ++i) {
+ evtag_marshal_int(evbuf, RUN_OTHER_NUMBERS, tmp->other_numbers_data[i]);
+ }
+ }
+ }
+}
+
+int
+run_unmarshal(struct run *tmp, struct evbuffer *evbuf)
+{
+ ev_uint32_t tag;
+ while (evbuffer_get_length(evbuf) > 0) {
+ if (evtag_peek(evbuf, &tag) == -1)
+ return (-1);
+ switch (tag) {
+
+ case RUN_HOW:
+
+ if (tmp->how_set)
+ return (-1);
+ if (evtag_unmarshal_string(evbuf, RUN_HOW, &tmp->how_data) == -1) {
+ event_warnx("%s: failed to unmarshal how", __func__);
+ return (-1);
+ }
+ tmp->how_set = 1;
+ break;
+
+ case RUN_SOME_BYTES:
+
+ if (tmp->some_bytes_set)
+ return (-1);
+ if (evtag_payload_length(evbuf, &tmp->some_bytes_length) == -1)
+ return (-1);
+ if (tmp->some_bytes_length > evbuffer_get_length(evbuf))
+ return (-1);
+ if ((tmp->some_bytes_data = malloc(tmp->some_bytes_length)) == NULL)
+ return (-1);
+ if (evtag_unmarshal_fixed(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length) == -1) {
+ event_warnx("%s: failed to unmarshal some_bytes", __func__);
+ return (-1);
+ }
+ tmp->some_bytes_set = 1;
+ break;
+
+ case RUN_FIXED_BYTES:
+
+ if (tmp->fixed_bytes_set)
+ return (-1);
+ if (evtag_unmarshal_fixed(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, (24)) == -1) {
+ event_warnx("%s: failed to unmarshal fixed_bytes", __func__);
+ return (-1);
+ }
+ tmp->fixed_bytes_set = 1;
+ break;
+
+ case RUN_NOTES:
+
+ if (tmp->notes_length >= tmp->notes_num_allocated &&
+ run_notes_expand_to_hold_more(tmp) < 0) {
+ puts("HEY NOW");
+ return (-1);
+ }
+ if (evtag_unmarshal_string(evbuf, RUN_NOTES, &tmp->notes_data[tmp->notes_length]) == -1) {
+ event_warnx("%s: failed to unmarshal notes", __func__);
+ return (-1);
+ }
+ ++tmp->notes_length;
+ tmp->notes_set = 1;
+ break;
+
+ case RUN_LARGE_NUMBER:
+
+ if (tmp->large_number_set)
+ return (-1);
+ if (evtag_unmarshal_int64(evbuf, RUN_LARGE_NUMBER, &tmp->large_number_data) == -1) {
+ event_warnx("%s: failed to unmarshal large_number", __func__);
+ return (-1);
+ }
+ tmp->large_number_set = 1;
+ break;
+
+ case RUN_OTHER_NUMBERS:
+
+ if (tmp->other_numbers_length >= tmp->other_numbers_num_allocated &&
+ run_other_numbers_expand_to_hold_more(tmp) < 0) {
+ puts("HEY NOW");
+ return (-1);
+ }
+ if (evtag_unmarshal_int(evbuf, RUN_OTHER_NUMBERS, &tmp->other_numbers_data[tmp->other_numbers_length]) == -1) {
+ event_warnx("%s: failed to unmarshal other_numbers", __func__);
+ return (-1);
+ }
+ ++tmp->other_numbers_length;
+ tmp->other_numbers_set = 1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ if (run_complete(tmp) == -1)
+ return (-1);
+ return (0);
+}
+
+int
+run_complete(struct run *msg)
+{
+ if (!msg->how_set)
+ return (-1);
+ if (!msg->fixed_bytes_set)
+ return (-1);
+ return (0);
+}
+
+int
+evtag_unmarshal_run(struct evbuffer *evbuf, ev_uint32_t need_tag, struct run *msg)
+{
+ ev_uint32_t tag;
+ int res = -1;
+
+ struct evbuffer *tmp = evbuffer_new();
+
+ if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+ goto error;
+
+ if (run_unmarshal(msg, tmp) == -1)
+ goto error;
+
+ res = 0;
+
+ error:
+ evbuffer_free(tmp);
+ return (res);
+}
+
+void
+evtag_marshal_run(struct evbuffer *evbuf, ev_uint32_t tag, const struct run *msg)
+{
+ struct evbuffer *buf_ = evbuffer_new();
+ assert(buf_ != NULL);
+ run_marshal(buf_, msg);
+ evtag_marshal_buffer(evbuf, tag, buf_);
+ evbuffer_free(buf_);
+}
+
diff --git a/contrib/ntp/sntp/libevent/test/regress.gen.h b/contrib/ntp/sntp/libevent/test/regress.gen.h
index 7130984..3546f62 100644
--- a/contrib/ntp/sntp/libevent/test/regress.gen.h
+++ b/contrib/ntp/sntp/libevent/test/regress.gen.h
@@ -1 +1,207 @@
-#define NO_PYTHON_EXISTS
+/*
+ * Automatically generated from ../../../sntp/libevent/test/regress.rpc
+ */
+
+#ifndef EVENT_RPCOUT__________SNTP_LIBEVENT_TEST_REGRESS_RPC_
+#define EVENT_RPCOUT__________SNTP_LIBEVENT_TEST_REGRESS_RPC_
+
+#include <event2/util.h> /* for ev_uint*_t */
+#include <event2/rpc.h>
+
+struct msg;
+struct kill;
+struct run;
+
+/* Tag definition for msg */
+enum msg_ {
+ MSG_FROM_NAME=1,
+ MSG_TO_NAME=2,
+ MSG_ATTACK=3,
+ MSG_RUN=4,
+ MSG_MAX_TAGS
+};
+
+/* Structure declaration for msg */
+struct msg_access_ {
+ int (*from_name_assign)(struct msg *, const char *);
+ int (*from_name_get)(struct msg *, char * *);
+ int (*to_name_assign)(struct msg *, const char *);
+ int (*to_name_get)(struct msg *, char * *);
+ int (*attack_assign)(struct msg *, const struct kill*);
+ int (*attack_get)(struct msg *, struct kill* *);
+ int (*run_assign)(struct msg *, int, const struct run*);
+ int (*run_get)(struct msg *, int, struct run* *);
+ struct run* (*run_add)(struct msg *msg);
+};
+
+struct msg {
+ struct msg_access_ *base;
+
+ char *from_name_data;
+ char *to_name_data;
+ struct kill* attack_data;
+ struct run* *run_data;
+ int run_length;
+ int run_num_allocated;
+
+ ev_uint8_t from_name_set;
+ ev_uint8_t to_name_set;
+ ev_uint8_t attack_set;
+ ev_uint8_t run_set;
+};
+
+struct msg *msg_new(void);
+struct msg *msg_new_with_arg(void *);
+void msg_free(struct msg *);
+void msg_clear(struct msg *);
+void msg_marshal(struct evbuffer *, const struct msg *);
+int msg_unmarshal(struct msg *, struct evbuffer *);
+int msg_complete(struct msg *);
+void evtag_marshal_msg(struct evbuffer *, ev_uint32_t,
+ const struct msg *);
+int evtag_unmarshal_msg(struct evbuffer *, ev_uint32_t,
+ struct msg *);
+int msg_from_name_assign(struct msg *, const char *);
+int msg_from_name_get(struct msg *, char * *);
+int msg_to_name_assign(struct msg *, const char *);
+int msg_to_name_get(struct msg *, char * *);
+int msg_attack_assign(struct msg *, const struct kill*);
+int msg_attack_get(struct msg *, struct kill* *);
+int msg_run_assign(struct msg *, int, const struct run*);
+int msg_run_get(struct msg *, int, struct run* *);
+struct run* msg_run_add(struct msg *msg);
+/* --- msg done --- */
+
+/* Tag definition for kill */
+enum kill_ {
+ KILL_WEAPON=65825,
+ KILL_ACTION=2,
+ KILL_HOW_OFTEN=3,
+ KILL_MAX_TAGS
+};
+
+/* Structure declaration for kill */
+struct kill_access_ {
+ int (*weapon_assign)(struct kill *, const char *);
+ int (*weapon_get)(struct kill *, char * *);
+ int (*action_assign)(struct kill *, const char *);
+ int (*action_get)(struct kill *, char * *);
+ int (*how_often_assign)(struct kill *, int, const ev_uint32_t);
+ int (*how_often_get)(struct kill *, int, ev_uint32_t *);
+ ev_uint32_t * (*how_often_add)(struct kill *msg, const ev_uint32_t value);
+};
+
+struct kill {
+ struct kill_access_ *base;
+
+ char *weapon_data;
+ char *action_data;
+ ev_uint32_t *how_often_data;
+ int how_often_length;
+ int how_often_num_allocated;
+
+ ev_uint8_t weapon_set;
+ ev_uint8_t action_set;
+ ev_uint8_t how_often_set;
+};
+
+struct kill *kill_new(void);
+struct kill *kill_new_with_arg(void *);
+void kill_free(struct kill *);
+void kill_clear(struct kill *);
+void kill_marshal(struct evbuffer *, const struct kill *);
+int kill_unmarshal(struct kill *, struct evbuffer *);
+int kill_complete(struct kill *);
+void evtag_marshal_kill(struct evbuffer *, ev_uint32_t,
+ const struct kill *);
+int evtag_unmarshal_kill(struct evbuffer *, ev_uint32_t,
+ struct kill *);
+int kill_weapon_assign(struct kill *, const char *);
+int kill_weapon_get(struct kill *, char * *);
+int kill_action_assign(struct kill *, const char *);
+int kill_action_get(struct kill *, char * *);
+int kill_how_often_assign(struct kill *, int, const ev_uint32_t);
+int kill_how_often_get(struct kill *, int, ev_uint32_t *);
+ev_uint32_t * kill_how_often_add(struct kill *msg, const ev_uint32_t value);
+/* --- kill done --- */
+
+/* Tag definition for run */
+enum run_ {
+ RUN_HOW=1,
+ RUN_SOME_BYTES=2,
+ RUN_FIXED_BYTES=3,
+ RUN_NOTES=4,
+ RUN_LARGE_NUMBER=5,
+ RUN_OTHER_NUMBERS=6,
+ RUN_MAX_TAGS
+};
+
+/* Structure declaration for run */
+struct run_access_ {
+ int (*how_assign)(struct run *, const char *);
+ int (*how_get)(struct run *, char * *);
+ int (*some_bytes_assign)(struct run *, const ev_uint8_t *, ev_uint32_t);
+ int (*some_bytes_get)(struct run *, ev_uint8_t * *, ev_uint32_t *);
+ int (*fixed_bytes_assign)(struct run *, const ev_uint8_t *);
+ int (*fixed_bytes_get)(struct run *, ev_uint8_t **);
+ int (*notes_assign)(struct run *, int, const char *);
+ int (*notes_get)(struct run *, int, char * *);
+ char * * (*notes_add)(struct run *msg, const char * value);
+ int (*large_number_assign)(struct run *, const ev_uint64_t);
+ int (*large_number_get)(struct run *, ev_uint64_t *);
+ int (*other_numbers_assign)(struct run *, int, const ev_uint32_t);
+ int (*other_numbers_get)(struct run *, int, ev_uint32_t *);
+ ev_uint32_t * (*other_numbers_add)(struct run *msg, const ev_uint32_t value);
+};
+
+struct run {
+ struct run_access_ *base;
+
+ char *how_data;
+ ev_uint8_t *some_bytes_data;
+ ev_uint32_t some_bytes_length;
+ ev_uint8_t fixed_bytes_data[24];
+ char * *notes_data;
+ int notes_length;
+ int notes_num_allocated;
+ ev_uint64_t large_number_data;
+ ev_uint32_t *other_numbers_data;
+ int other_numbers_length;
+ int other_numbers_num_allocated;
+
+ ev_uint8_t how_set;
+ ev_uint8_t some_bytes_set;
+ ev_uint8_t fixed_bytes_set;
+ ev_uint8_t notes_set;
+ ev_uint8_t large_number_set;
+ ev_uint8_t other_numbers_set;
+};
+
+struct run *run_new(void);
+struct run *run_new_with_arg(void *);
+void run_free(struct run *);
+void run_clear(struct run *);
+void run_marshal(struct evbuffer *, const struct run *);
+int run_unmarshal(struct run *, struct evbuffer *);
+int run_complete(struct run *);
+void evtag_marshal_run(struct evbuffer *, ev_uint32_t,
+ const struct run *);
+int evtag_unmarshal_run(struct evbuffer *, ev_uint32_t,
+ struct run *);
+int run_how_assign(struct run *, const char *);
+int run_how_get(struct run *, char * *);
+int run_some_bytes_assign(struct run *, const ev_uint8_t *, ev_uint32_t);
+int run_some_bytes_get(struct run *, ev_uint8_t * *, ev_uint32_t *);
+int run_fixed_bytes_assign(struct run *, const ev_uint8_t *);
+int run_fixed_bytes_get(struct run *, ev_uint8_t **);
+int run_notes_assign(struct run *, int, const char *);
+int run_notes_get(struct run *, int, char * *);
+char * * run_notes_add(struct run *msg, const char * value);
+int run_large_number_assign(struct run *, const ev_uint64_t);
+int run_large_number_get(struct run *, ev_uint64_t *);
+int run_other_numbers_assign(struct run *, int, const ev_uint32_t);
+int run_other_numbers_get(struct run *, int, ev_uint32_t *);
+ev_uint32_t * run_other_numbers_add(struct run *msg, const ev_uint32_t value);
+/* --- run done --- */
+
+#endif /* EVENT_RPCOUT__________SNTP_LIBEVENT_TEST_REGRESS_RPC_ */
diff --git a/contrib/ntp/sntp/libopts/Makefile.in b/contrib/ntp/sntp/libopts/Makefile.in
index 8550a37..f7b7d4e 100644
--- a/contrib/ntp/sntp/libopts/Makefile.in
+++ b/contrib/ntp/sntp/libopts/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/sntp/libopts/autoopts/options.h b/contrib/ntp/sntp/libopts/autoopts/options.h
index f92cd0e..09aac10 100644
--- a/contrib/ntp/sntp/libopts/autoopts/options.h
+++ b/contrib/ntp/sntp/libopts/autoopts/options.h
@@ -109,7 +109,7 @@
* @{
*/
/// autoopts structure version
-#define OPTIONS_STRUCT_VERSION 167936
+#define OPTIONS_STRUCT_VERSION 167937
/// autoopts structure version string
#define OPTIONS_VERSION_STRING "41:0:16"
/// minimum version the autoopts library supports
diff --git a/contrib/ntp/sntp/libopts/genshell.h b/contrib/ntp/sntp/libopts/genshell.h
index 1c18735..4482556 100644
--- a/contrib/ntp/sntp/libopts/genshell.h
+++ b/contrib/ntp/sntp/libopts/genshell.h
@@ -55,7 +55,7 @@
* tolerable version is at least as old as what was current when the header
* template was released.
*/
-#define AO_TEMPLATE_VERSION 167936
+#define AO_TEMPLATE_VERSION 167937
#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
|| (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
# error option template version mismatches autoopts/options.h header
diff --git a/contrib/ntp/sntp/m4/ntp_libntp.m4 b/contrib/ntp/sntp/m4/ntp_libntp.m4
index 3f35a92..21d0cff 100644
--- a/contrib/ntp/sntp/m4/ntp_libntp.m4
+++ b/contrib/ntp/sntp/m4/ntp_libntp.m4
@@ -689,11 +689,38 @@ case "$ntp_have_solarisprivs" in
yes)
AC_DEFINE([HAVE_SOLARIS_PRIVS], [1],
[Are Solaris privileges available?])
+ ;;
+ '') ntp_have_solarisprivs="no"
+ ;;
esac
AC_MSG_RESULT([$ntp_have_solarisprivs])
-case "$ntp_use_dev_clockctl$ntp_have_linuxcaps$ntp_have_solarisprivs" in
+AC_CHECK_HEADERS([sys/mac.h])
+
+AC_ARG_ENABLE(
+ [trustedbsd_mac],
+ [AS_HELP_STRING(
+ [--enable-trustedbsd-mac],
+ [s Use TrustedBSD MAC policy for non-root clock control]
+ )],
+ [ntp_use_trustedbsd_mac=$enableval]
+)
+
+AC_MSG_CHECKING([if we should use TrustedBSD MAC privileges])
+
+case "$ntp_use_trustedbsd_mac$ac_cv_header_sys_mac_h" in
+ yesyes)
+ AC_DEFINE([HAVE_TRUSTEDBSD_MAC], [1],
+ [Are TrustedBSD MAC policy privileges available?])
+ ;;
+ *) ntp_use_trustedbsd_mac="no";
+ ;;
+esac
+
+AC_MSG_RESULT([$ntp_use_trustedbsd_mac])
+
+case "$ntp_use_dev_clockctl$ntp_have_linuxcaps$ntp_have_solarisprivs$ntp_use_trustedbsd_mac" in
*yes*)
AC_DEFINE([HAVE_DROPROOT], [1],
[Can we drop root privileges?])
@@ -862,6 +889,14 @@ AC_CHECK_HEADERS(
AC_SEARCH_LIBS([MD5Init], [md5 md])
AC_CHECK_FUNCS([MD5Init sysconf getdtablesize sigaction sigset sigvec])
+# HMS: does this need to be a cached variable?
+AC_ARG_ENABLE(
+ [signalled-io],
+ [AS_HELP_STRING([--enable-signalled-io], [s Use signalled IO if we can])],
+ [use_signalled_io=$enableval],
+ [use_signalled_io=yes]
+ )
+
AC_CACHE_CHECK(
[for SIGIO],
[ntp_cv_hdr_def_sigio],
@@ -925,12 +960,23 @@ case "$ntp_cv_hdr_def_sigio" in
ans=no
;;
esac
+ case "$ans" in
+ no)
+ ans="Possible for $host but disabled because of reported problems"
+ ;;
+ esac
;;
esac
case "$ans" in
yes)
- AC_DEFINE([HAVE_SIGNALED_IO], [1],
- [Can we use SIGIO for tcp and udp IO?])
+ case "$use_signalled_io" in
+ yes)
+ AC_DEFINE([HAVE_SIGNALED_IO], [1],
+ [Can we use SIGIO for tcp and udp IO?])
+ ;;
+ *) ans="Allowed for $host but --disable-signalled-io was given"
+ ;;
+ esac
esac
AC_MSG_RESULT([$ans])
diff --git a/contrib/ntp/sntp/m4/ntp_openssl.m4 b/contrib/ntp/sntp/m4/ntp_openssl.m4
index 112b7a2..2f9d6c4 100644
--- a/contrib/ntp/sntp/m4/ntp_openssl.m4
+++ b/contrib/ntp/sntp/m4/ntp_openssl.m4
@@ -242,6 +242,7 @@ AC_MSG_RESULT([$ntp_openssl])
case "$ntp_openssl" in
yes)
+ AC_CHECK_HEADERS([openssl/cmac.h openssl/hmac.h])
AC_DEFINE([OPENSSL], [], [Use OpenSSL?])
case "$VER_SUFFIX" in
*o*) ;;
diff --git a/contrib/ntp/sntp/m4/version.m4 b/contrib/ntp/sntp/m4/version.m4
index 4ebd02c..48b635c 100644
--- a/contrib/ntp/sntp/m4/version.m4
+++ b/contrib/ntp/sntp/m4/version.m4
@@ -1 +1 @@
-m4_define([VERSION_NUMBER],[4.2.8p11])
+m4_define([VERSION_NUMBER],[4.2.8p13])
diff --git a/contrib/ntp/sntp/main.c b/contrib/ntp/sntp/main.c
index 098a696..204d6a8 100644
--- a/contrib/ntp/sntp/main.c
+++ b/contrib/ntp/sntp/main.c
@@ -1608,3 +1608,9 @@ gettimeofday_cached(
#endif
}
+/* Dummy function to satisfy libntp/work_fork.c */
+extern int set_user_group_ids(void);
+int set_user_group_ids(void)
+{
+ return 1;
+}
diff --git a/contrib/ntp/sntp/networking.c b/contrib/ntp/sntp/networking.c
index ecac15c..040395e 100644
--- a/contrib/ntp/sntp/networking.c
+++ b/contrib/ntp/sntp/networking.c
@@ -78,7 +78,8 @@ skip_efields(
u_int nlen; /* next extension length */
while ((tail - head) > 6) {
- nlen = ntohl(*head++) & 0xffff;
+ nlen = ntohl(*head) & 0xffff;
+ ++head;
nlen = (nlen + 3) >> 2;
if (nlen > (u_int)(tail - head) || nlen < 4)
return NULL; /* Blooper! Inconsistent! */
diff --git a/contrib/ntp/sntp/scm-rev b/contrib/ntp/sntp/scm-rev
index fe53b4f..4410181 100644
--- a/contrib/ntp/sntp/scm-rev
+++ b/contrib/ntp/sntp/scm-rev
@@ -1 +1 @@
-1.3728
+1.3847
diff --git a/contrib/ntp/sntp/scripts/Makefile.in b/contrib/ntp/sntp/scripts/Makefile.in
index 0c44543..2e8e3df 100644
--- a/contrib/ntp/sntp/scripts/Makefile.in
+++ b/contrib/ntp/sntp/scripts/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/sntp/sntp-opts.c b/contrib/ntp/sntp/sntp-opts.c
index 404068a..9f6ee32 100644
--- a/contrib/ntp/sntp/sntp-opts.c
+++ b/contrib/ntp/sntp/sntp-opts.c
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (sntp-opts.c)
*
- * It has been AutoGen-ed February 27, 2018 at 10:25:32 AM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:55:45 AM by AutoGen 5.18.5
* From the definitions sntp-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This source file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -70,7 +70,7 @@ extern FILE * option_usage_fp;
* static const strings for sntp options
*/
static char const sntp_opt_strs[2566] =
-/* 0 */ "sntp 4.2.8p11\n"
+/* 0 */ "sntp 4.2.8p13\n"
"Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n"
"This is free software. It is licensed for use, modification and\n"
"redistribution under the terms of the NTP License, copies of which\n"
@@ -156,7 +156,7 @@ static char const sntp_opt_strs[2566] =
/* 2313 */ "LOAD_OPTS\0"
/* 2323 */ "no-load-opts\0"
/* 2336 */ "SNTP\0"
-/* 2341 */ "sntp - standard Simple Network Time Protocol client program - Ver. 4.2.8p11\n"
+/* 2341 */ "sntp - standard Simple Network Time Protocol client program - Ver. 4.2.8p13\n"
"Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \\\n"
"\t\t[ hostname-or-IP ...]\n\0"
/* 2501 */ "$HOME\0"
@@ -164,7 +164,7 @@ static char const sntp_opt_strs[2566] =
/* 2509 */ ".ntprc\0"
/* 2516 */ "http://bugs.ntp.org, bugs@ntp.org\0"
/* 2550 */ "\n\0"
-/* 2552 */ "sntp 4.2.8p11";
+/* 2552 */ "sntp 4.2.8p13";
/**
* ipv4 option description with
@@ -1176,7 +1176,7 @@ static void bogus_function(void) {
translate option names.
*/
/* referenced via sntpOptions.pzCopyright */
- puts(_("sntp 4.2.8p11\n\
+ puts(_("sntp 4.2.8p13\n\
Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n\
This is free software. It is licensed for use, modification and\n\
redistribution under the terms of the NTP License, copies of which\n\
@@ -1266,7 +1266,7 @@ implied warranty.\n"));
puts(_("load options from a config file"));
/* referenced via sntpOptions.pzUsageTitle */
- puts(_("sntp - standard Simple Network Time Protocol client program - Ver. 4.2.8p11\n\
+ puts(_("sntp - standard Simple Network Time Protocol client program - Ver. 4.2.8p13\n\
Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \\\n\
\t\t[ hostname-or-IP ...]\n"));
@@ -1274,7 +1274,7 @@ Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]... \\\n\
puts(_("\n"));
/* referenced via sntpOptions.pzFullVersion */
- puts(_("sntp 4.2.8p11"));
+ puts(_("sntp 4.2.8p13"));
/* referenced via sntpOptions.pzFullUsage */
puts(_("<<<NOT-FOUND>>>"));
diff --git a/contrib/ntp/sntp/sntp-opts.h b/contrib/ntp/sntp/sntp-opts.h
index 25e2fe8..cf17a27 100644
--- a/contrib/ntp/sntp/sntp-opts.h
+++ b/contrib/ntp/sntp/sntp-opts.h
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (sntp-opts.h)
*
- * It has been AutoGen-ed February 27, 2018 at 10:25:31 AM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:55:45 AM by AutoGen 5.18.5
* From the definitions sntp-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This header file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -53,7 +53,7 @@
* tolerable version is at least as old as what was current when the header
* template was released.
*/
-#define AO_TEMPLATE_VERSION 167936
+#define AO_TEMPLATE_VERSION 167937
#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
|| (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
# error option template version mismatches autoopts/options.h header
@@ -91,9 +91,9 @@ typedef enum {
/** count of all options for sntp */
#define OPTION_CT 23
/** sntp version */
-#define SNTP_VERSION "4.2.8p11"
+#define SNTP_VERSION "4.2.8p13"
/** Full sntp version text */
-#define SNTP_FULL_VERSION "sntp 4.2.8p11"
+#define SNTP_FULL_VERSION "sntp 4.2.8p13"
/**
* Interface defines for all options. Replace "n" with the UPPER_CASED
diff --git a/contrib/ntp/sntp/sntp.1sntpman b/contrib/ntp/sntp/sntp.1sntpman
index 8378d45..732b0b4 100644
--- a/contrib/ntp/sntp/sntp.1sntpman
+++ b/contrib/ntp/sntp/sntp.1sntpman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH sntp 1sntpman "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH sntp 1sntpman "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-eaayfN/ag-qaaqeN)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:13:07 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:55:51 AM by AutoGen 5.18.5
.\" From the definitions sntp-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/sntp/sntp.1sntpmdoc b/contrib/ntp/sntp/sntp.1sntpmdoc
index 8c9f1a5..36f5270 100644
--- a/contrib/ntp/sntp/sntp.1sntpmdoc
+++ b/contrib/ntp/sntp/sntp.1sntpmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt SNTP 1sntpmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (sntp-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:13:14 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:55:48 AM by AutoGen 5.18.5
.\" From the definitions sntp-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/sntp/sntp.html b/contrib/ntp/sntp/sntp.html
index 9121504..884553b 100644
--- a/contrib/ntp/sntp/sntp.html
+++ b/contrib/ntp/sntp/sntp.html
@@ -1,628 +1,702 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>Sntp User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="Sntp User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Sntp User&rsquo;s Manual</title>
+
+<meta name="description" content="Sntp User&rsquo;s Manual">
+<meta name="keywords" content="Sntp User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">Sntp User's Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-Description">sntp Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">Simple Network Time Protocol User Manual</h2>
+<body lang="en">
+<h1 class="settitle" align="center">Sntp User&rsquo;s Manual</h1>
+
+
-<p>This document describes the use of the NTP Project's <code>sntp</code> program,
+
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-Description" accesskey="n" rel="next">sntp Description</a>, Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="Simple-Network-Time-Protocol-User-Manual"></a>
+<h1 class="top">Simple Network Time Protocol User Manual</h1>
+
+<p>This document describes the use of the NTP Project&rsquo;s <code>sntp</code> program,
that can be used to query a Network Time Protocol (NTP) server and
display the time offset of the system clock relative to the server
clock. Run as root, it can correct the system clock to this offset as
well. It can be run as an interactive command or from a cron job.
-
- <p>This document applies to version 4.2.8p11 of <code>sntp</code>.
-
- <p>The program implements the SNTP protocol as defined by RFC 5905, the NTPv4
+</p>
+<p>This document applies to version 4.2.8p13 of <code>sntp</code>.
+</p>
+<p>The program implements the SNTP protocol as defined by RFC 5905, the NTPv4
IETF specification.
+</p>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">Simple Network Time Protocol User Manual</a>
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Description" href="#toc-Description">1 Description</a></li>
</ul>
</div>
-<ul class="menu">
-<li><a accesskey="1" href="#sntp-Description">sntp Description</a>: Description
-<li><a accesskey="2" href="#sntp-Invocation">sntp Invocation</a>: Invoking sntp
-<li><a accesskey="3" href="#Usage">Usage</a>: Usage
-</ul>
-<div class="node">
-<p><hr>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#sntp-Description" accesskey="1">sntp Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Description
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-Invocation" accesskey="2">sntp Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking sntp
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="3">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+</table>
+
+<hr>
<a name="sntp-Description"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#sntp-Invocation" accesskey="n" rel="next">sntp Invocation</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Description</h3>
+<a name="Description"></a>
+<h2 class="chapter">1 Description</h2>
<p>By default, <code>sntp</code> writes the local data and time (i.e., not UTC) to the
standard output in the format:
+</p>
+<div class="example">
+<pre class="example">1996-10-15 20:17:25.123 (+0800) +4.567 +/- 0.089 secs
+</pre></div>
-<pre class="example"> 1996-10-15 20:17:25.123 (+0800) +4.567 +/- 0.089 secs
-</pre>
- <p>where
+<p>where
YYYY-MM-DD HH:MM:SS.SUBSEC is the local date and time,
(+0800) is the local timezone adjustment (so we would add 8 hours and 0 minutes to convert the reported local time to UTC),
and
the +4.567 +/- 0.089 secs indicates the time offset and
error bound of the system clock relative to the server clock.
-
-<div class="node">
-<p><hr>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#sntp-Invocation" accesskey="1">sntp Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Usage" accesskey="2">Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
<a name="sntp-Invocation"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Usage" accesskey="n" rel="next">Usage</a>, Previous: <a href="#sntp-Description" accesskey="p" rel="prev">sntp Description</a>, Up: <a href="#sntp-Description" accesskey="u" rel="up">sntp Description</a> &nbsp; </p>
</div>
+<a name="Invoking-sntp"></a>
+<h3 class="section">1.1 Invoking sntp</h3>
+<a name="index-sntp"></a>
+<a name="index-standard-Simple-Network-Time-Protocol-client-program"></a>
-<h3 class="section">Invoking sntp</h3>
-<p><a name="index-sntp-1"></a><a name="index-standard-Simple-Network-Time-Protocol-client-program-2"></a>
- <p><code>sntp</code>
+<p><code>sntp</code>
can be used as an SNTP client to query a NTP or SNTP server and either display
-the time or set the local system's time (given suitable privilege). It can be
+the time or set the local system&rsquo;s time (given suitable privilege). It can be
run as an interactive command or from a
<code>cron</code>
job.
-
- <p>NTP (the Network Time Protocol) and SNTP (the Simple Network Time Protocol)
+</p>
+<p>NTP (the Network Time Protocol) and SNTP (the Simple Network Time Protocol)
are defined and described by RFC 5905.
+</p>
- <p>The default is to write the estimated correct local date and time (i.e. not
+<p>The default is to write the estimated correct local date and time (i.e. not
UTC) to the standard output in a format like:
-
- <p><code>'1996-10-15 20:17:25.123 (+0800) +4.567 +/- 0.089 [host] IP sN'</code>
-
- <p>where the
+</p>
+<p><code>'1996-10-15 20:17:25.123 (+0800) +4.567 +/- 0.089 [host] IP sN'</code>
+</p>
+<p>where the
<code>'(+0800)'</code>
means that to get to UTC from the reported local time one must
add 8 hours and 0 minutes,
the
<code>'+4.567'</code>
indicates the local clock is 4.567 seconds behind the correct time
-(so 4.567 seconds must be added to the local clock to get it to be correct).
+(so 4.567 seconds must be added to the local clock to get it to be correct).
Note that the number of decimals printed for this value will change
-based on the reported precision of the server.
+based on the reported precision of the server.
<code>'+/- 0.089'</code>
is the reported
<em>synchronization</em> <em>distance</em>
-(in seconds), which represents the maximum error due to all causes.
+(in seconds), which represents the maximum error due to all causes.
If the server does not report valid data needed to calculate the
synchronization distance, this will be reported as
-<code>'+/- ?'</code>.
+<code>'+/- ?'</code>.
If the
<em>host</em>
is different from the
<em>IP</em>,
-both will be displayed.
-Otherwise, only the
+both will be displayed.
+Otherwise, only the
<em>IP</em>
-is displayed.
+is displayed.
Finally, the
<em>stratum</em>
of the host is reported
and the leap indicator is decoded and displayed.
-
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>sntp</code> program.
+</p>
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>sntp</code> program.
This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
-
-<ul class="menu">
-<li><a accesskey="1" href="#sntp-usage">sntp usage</a>: sntp help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#sntp-ipv4">sntp ipv4</a>: ipv4 option (-4)
-<li><a accesskey="3" href="#sntp-ipv6">sntp ipv6</a>: ipv6 option (-6)
-<li><a accesskey="4" href="#sntp-authentication">sntp authentication</a>: authentication option (-a)
-<li><a accesskey="5" href="#sntp-broadcast">sntp broadcast</a>: broadcast option (-b)
-<li><a accesskey="6" href="#sntp-concurrent">sntp concurrent</a>: concurrent option (-c)
-<li><a accesskey="7" href="#sntp-gap">sntp gap</a>: gap option (-g)
-<li><a accesskey="8" href="#sntp-kod">sntp kod</a>: kod option (-K)
-<li><a accesskey="9" href="#sntp-keyfile">sntp keyfile</a>: keyfile option (-k)
-<li><a href="#sntp-logfile">sntp logfile</a>: logfile option (-l)
-<li><a href="#sntp-steplimit">sntp steplimit</a>: steplimit option (-M)
-<li><a href="#sntp-ntpversion">sntp ntpversion</a>: ntpversion option (-o)
-<li><a href="#sntp-usereservedport">sntp usereservedport</a>: usereservedport option (-r)
-<li><a href="#sntp-timeout">sntp timeout</a>: timeout option (-t)
-<li><a href="#sntp-wait">sntp wait</a>: wait option
-<li><a href="#sntp-config">sntp config</a>: presetting/configuring sntp
-<li><a href="#sntp-exit-status">sntp exit status</a>: exit status
-<li><a href="#sntp-Usage">sntp Usage</a>: Usage
-<li><a href="#sntp-Authors">sntp Authors</a>: Authors
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="sntp-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-ipv4">sntp ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#sntp-usage" accesskey="1">sntp usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">sntp help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-ipv4" accesskey="2">sntp ipv4</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv4 option (-4)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-ipv6" accesskey="3">sntp ipv6</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ipv6 option (-6)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-authentication" accesskey="4">sntp authentication</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">authentication option (-a)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-broadcast" accesskey="5">sntp broadcast</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">broadcast option (-b)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-concurrent" accesskey="6">sntp concurrent</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">concurrent option (-c)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-gap" accesskey="7">sntp gap</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">gap option (-g)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-kod" accesskey="8">sntp kod</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">kod option (-K)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-keyfile" accesskey="9">sntp keyfile</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">keyfile option (-k)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-logfile">sntp logfile</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">logfile option (-l)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-steplimit">sntp steplimit</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">steplimit option (-M)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-ntpversion">sntp ntpversion</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntpversion option (-o)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-usereservedport">sntp usereservedport</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">usereservedport option (-r)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-timeout">sntp timeout</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">timeout option (-t)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-wait">sntp wait</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">wait option
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-config">sntp config</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">presetting/configuring sntp
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-exit-status">sntp exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-Usage">sntp Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#sntp-Authors">sntp Authors</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Authors
+</td></tr>
+</table>
+
+<hr>
+<a name="sntp-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-ipv4" accesskey="n" rel="next">sntp ipv4</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">sntp help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-sntp-help-3"></a>
-This is the automatically generated usage text for sntp.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="sntp-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h4 class="subsection">1.1.1 sntp help/usage (<samp>--help</samp>)</h4>
+<a name="index-sntp-help"></a>
+
+<p>This is the automatically generated usage text for sntp.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">sntp - standard Simple Network Time Protocol client program - Ver. 4.2.7p245
-USAGE: sntp [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]... \
+</p>
+<div class="example">
+<pre class="example">sntp - standard Simple Network Time Protocol client program - Ver. 4.2.8p13
+Usage: sntp [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]... \
[ hostname-or-IP ...]
Flg Arg Option-Name Description
-4 no ipv4 Force IPv4 DNS name resolution
- - prohibits these options:
- ipv6
+ - prohibits the option 'ipv6'
-6 no ipv6 Force IPv6 DNS name resolution
- - prohibits these options:
- ipv4
- -a Num authentication Enable authentication with the key @var{auth-keynumber}
- -B Num bctimeout The number of seconds to wait for broadcasts
+ - prohibits the option 'ipv4'
+ -a Num authentication Enable authentication with the key auth-keynumber
-b Str broadcast Listen to the address specified for broadcast time sync
- may appear multiple times
-c Str concurrent Concurrently query all IPs returned for host-name
- may appear multiple times
-d no debug-level Increase debug verbosity level
- may appear multiple times
- -D Str set-debug-level Set the debug verbosity level
+ -D Num set-debug-level Set the debug verbosity level
- may appear multiple times
-g Num gap The gap (in milliseconds) between time requests
-K Fil kod KoD history filename
- -k Fil keyfile Look in this file for the key specified with @option{-a}
+ -k Fil keyfile Look in this file for the key specified with -a
-l Fil logfile Log to specified logfile
- -M Num steplimit Adjustments less than @var{steplimit} msec will be slewed
- - It must be in the range:
+ -M Num steplimit Adjustments less than steplimit msec will be slewed
+ - it must be in the range:
greater than or equal to 0
- -o Num ntpversion Send @var{int} as our NTP version
- - It must be in the range:
+ -o Num ntpversion Send int as our NTP protocol version
+ - it must be in the range:
0 to 7
-r no usereservedport Use the NTP Reserved Port (port 123)
- -S no step OK to 'step' the time with @command{settimeofday(2)}
- -s no slew OK to 'slew' the time with @command{adjtime(2)}
- -u Num uctimeout The number of seconds to wait for unicast responses
+ -S no step OK to 'step' the time with settimeofday(2)
+ -s no slew OK to 'slew' the time with adjtime(2)
+ -t Num timeout The number of seconds to wait for responses
no wait Wait for pending replies (if not setting the time)
- - disabled as --no-wait
+ - disabled as '--no-wait'
- enabled by default
- opt version Output version information and exit
- -? no help Display extended usage information and exit
- -! no more-help Extended usage information passed thru pager
- -&gt; opt save-opts Save the option state to a config file
- -&lt; Str load-opts Load options from a config file
- - disabled as --no-load-opts
+ opt version output version information and exit
+ -? no help display extended usage information and exit
+ -! no more-help extended usage information passed thru pager
+ -&gt; opt save-opts save the option state to a config file
+ -&lt; Str load-opts load options from a config file
+ - disabled as '--no-load-opts'
- may appear multiple times
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-
The following option preset mechanisms are supported:
- reading file $HOME/.ntprc
- reading file ./.ntprc
- examining environment variables named SNTP_*
-please send bug reports to: http://bugs.ntp.org, bugs@ntp.org
-</pre>
- <div class="node">
-<p><hr>
-<a name="sntp-ipv4"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-ipv6">sntp ipv6</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-usage">sntp usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">ipv4 option (-4)</h4>
-
-<p><a name="index-sntp_002dipv4-4"></a>
-This is the &ldquo;force ipv4 dns name resolution&rdquo; option.
+Please send bug reports to: &lt;http://bugs.ntp.org, bugs@ntp.org&gt;
+</pre></div>
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv6.
-</ul>
-
- <p>Force DNS resolution of the following host names on the command line
-to the IPv4 namespace.
-<div class="node">
-<p><hr>
-<a name="sntp-ipv6"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-authentication">sntp authentication</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-ipv4">sntp ipv4</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<hr>
+<a name="sntp-ipv4"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-ipv6" accesskey="n" rel="next">sntp ipv6</a>, Previous: <a href="#sntp-usage" accesskey="p" rel="prev">sntp usage</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ipv6 option (-6)</h4>
-
-<p><a name="index-sntp_002dipv6-5"></a>
-This is the &ldquo;force ipv6 dns name resolution&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must not appear in combination with any of the following options:
-ipv4.
-</ul>
-
- <p>Force DNS resolution of the following host names on the command line
-to the IPv6 namespace.
-<div class="node">
-<p><hr>
-<a name="sntp-authentication"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-broadcast">sntp broadcast</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-ipv6">sntp ipv6</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<a name="ipv4-option-_0028_002d4_0029"></a>
+<h4 class="subsection">1.1.2 ipv4 option (-4)</h4>
+<a name="index-sntp_002dipv4"></a>
+
+<p>This is the &ldquo;force ipv4 dns name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv6.
+</li></ul>
+
+<p>Force DNS resolution of the following host names on the command line
+to the IPv4 namespace.
+</p><hr>
+<a name="sntp-ipv6"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-authentication" accesskey="n" rel="next">sntp authentication</a>, Previous: <a href="#sntp-ipv4" accesskey="p" rel="prev">sntp ipv4</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">authentication option (-a)</h4>
-
-<p><a name="index-sntp_002dauthentication-6"></a>
-This is the &ldquo;enable authentication with the key <var>auth-keynumber</var>&rdquo; option.
-This option takes a number argument <span class="file">auth-keynumber</span>.
-Enable authentication using the key specified in this option's
-argument. The argument of this option is the <span class="option">keyid</span>, a
-number specified in the <span class="option">keyfile</span> as this key's identifier.
-See the <span class="option">keyfile</span> option (<span class="option">-k</span>) for more details.
-<div class="node">
-<p><hr>
-<a name="sntp-broadcast"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-concurrent">sntp concurrent</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-authentication">sntp authentication</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<a name="ipv6-option-_0028_002d6_0029"></a>
+<h4 class="subsection">1.1.3 ipv6 option (-6)</h4>
+<a name="index-sntp_002dipv6"></a>
+
+<p>This is the &ldquo;force ipv6 dns name resolution&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must not appear in combination with any of the following options:
+ipv4.
+</li></ul>
+
+<p>Force DNS resolution of the following host names on the command line
+to the IPv6 namespace.
+</p><hr>
+<a name="sntp-authentication"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-broadcast" accesskey="n" rel="next">sntp broadcast</a>, Previous: <a href="#sntp-ipv6" accesskey="p" rel="prev">sntp ipv6</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">broadcast option (-b)</h4>
-
-<p><a name="index-sntp_002dbroadcast-7"></a>
-This is the &ldquo;listen to the address specified for broadcast time sync&rdquo; option.
-This option takes a string argument <span class="file">broadcast-address</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>If specified <code>sntp</code> will listen to the specified address
+<a name="authentication-option-_0028_002da_0029"></a>
+<h4 class="subsection">1.1.4 authentication option (-a)</h4>
+<a name="index-sntp_002dauthentication"></a>
+
+<p>This is the &ldquo;enable authentication with the key <var>auth-keynumber</var>&rdquo; option.
+This option takes a number argument <samp>auth-keynumber</samp>.
+Enable authentication using the key specified in this option&rsquo;s
+argument. The argument of this option is the <samp>keyid</samp>, a
+number specified in the <samp>keyfile</samp> as this key&rsquo;s identifier.
+See the <samp>keyfile</samp> option (<samp>-k</samp>) for more details.
+</p><hr>
+<a name="sntp-broadcast"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-concurrent" accesskey="n" rel="next">sntp concurrent</a>, Previous: <a href="#sntp-authentication" accesskey="p" rel="prev">sntp authentication</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
+</div>
+<a name="broadcast-option-_0028_002db_0029"></a>
+<h4 class="subsection">1.1.5 broadcast option (-b)</h4>
+<a name="index-sntp_002dbroadcast"></a>
+
+<p>This is the &ldquo;listen to the address specified for broadcast time sync&rdquo; option.
+This option takes a string argument <samp>broadcast-address</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>If specified <code>sntp</code> will listen to the specified address
for NTP broadcasts. The default maximum wait time
-can (and probably should) be modified with <span class="option">-t</span>.
-<div class="node">
-<p><hr>
-<a name="sntp-concurrent"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-gap">sntp gap</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-broadcast">sntp broadcast</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+can (and probably should) be modified with <samp>-t</samp>.
+</p><hr>
+<a name="sntp-concurrent"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-gap" accesskey="n" rel="next">sntp gap</a>, Previous: <a href="#sntp-broadcast" accesskey="p" rel="prev">sntp broadcast</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">concurrent option (-c)</h4>
-
-<p><a name="index-sntp_002dconcurrent-8"></a>
-This is the &ldquo;concurrently query all ips returned for host-name&rdquo; option.
-This option takes a string argument <span class="file">host-name</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>may appear an unlimited number of times.
-</ul>
-
- <p>Requests from an NTP "client" to a "server" should never be sent
+<a name="concurrent-option-_0028_002dc_0029"></a>
+<h4 class="subsection">1.1.6 concurrent option (-c)</h4>
+<a name="index-sntp_002dconcurrent"></a>
+
+<p>This is the &ldquo;concurrently query all ips returned for host-name&rdquo; option.
+This option takes a string argument <samp>host-name</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> may appear an unlimited number of times.
+</li></ul>
+
+<p>Requests from an NTP &quot;client&quot; to a &quot;server&quot; should never be sent
more rapidly than one every 2 seconds. By default, any IPs returned
as part of a DNS lookup are assumed to be for a single instance of
<code>ntpd</code>, and therefore <code>sntp</code> will send queries to these IPs
one after another, with a 2-second gap in between each query.
-
- <p>The <span class="option">-c</span> or <span class="option">--concurrent</span> flag says that any IPs
+</p>
+<p>The <samp>-c</samp> or <samp>--concurrent</samp> flag says that any IPs
returned for the DNS lookup of the supplied host-name are on
-different machines, so we can send concurrent queries.
-<div class="node">
-<p><hr>
-<a name="sntp-gap"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-kod">sntp kod</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-concurrent">sntp concurrent</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+different machines, so we can send concurrent queries.
+</p><hr>
+<a name="sntp-gap"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-kod" accesskey="n" rel="next">sntp kod</a>, Previous: <a href="#sntp-concurrent" accesskey="p" rel="prev">sntp concurrent</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
+<a name="gap-option-_0028_002dg_0029"></a>
+<h4 class="subsection">1.1.7 gap option (-g)</h4>
+<a name="index-sntp_002dgap"></a>
-<h4 class="subsection">gap option (-g)</h4>
-
-<p><a name="index-sntp_002dgap-9"></a>
-This is the &ldquo;the gap (in milliseconds) between time requests&rdquo; option.
-This option takes a number argument <span class="file">milliseconds</span>.
-Since we're only going to use the first valid response we get and
+<p>This is the &ldquo;the gap (in milliseconds) between time requests&rdquo; option.
+This option takes a number argument <samp>milliseconds</samp>.
+Since we&rsquo;re only going to use the first valid response we get and
there is benefit to specifying a good number of servers to query,
separate the queries we send out by the specified number of
-milliseconds.
-<div class="node">
-<p><hr>
-<a name="sntp-kod"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-keyfile">sntp keyfile</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-gap">sntp gap</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+milliseconds.
+</p><hr>
+<a name="sntp-kod"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-keyfile" accesskey="n" rel="next">sntp keyfile</a>, Previous: <a href="#sntp-gap" accesskey="p" rel="prev">sntp gap</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
+<a name="kod-option-_0028_002dK_0029"></a>
+<h4 class="subsection">1.1.8 kod option (-K)</h4>
+<a name="index-sntp_002dkod"></a>
-<h4 class="subsection">kod option (-K)</h4>
-
-<p><a name="index-sntp_002dkod-10"></a>
-This is the &ldquo;kod history filename&rdquo; option.
-This option takes a file argument <span class="file">file-name</span>.
+<p>This is the &ldquo;kod history filename&rdquo; option.
+This option takes a file argument <samp>file-name</samp>.
Specifies the filename to be used for the persistent history of KoD
responses received from servers. If the file does not exist, a
-warning message will be displayed. The file will not be created.
-<div class="node">
-<p><hr>
-<a name="sntp-keyfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-logfile">sntp logfile</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-kod">sntp kod</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+warning message will be displayed. The file will not be created.
+</p><hr>
+<a name="sntp-keyfile"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-logfile" accesskey="n" rel="next">sntp logfile</a>, Previous: <a href="#sntp-kod" accesskey="p" rel="prev">sntp kod</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">keyfile option (-k)</h4>
-
-<p><a name="index-sntp_002dkeyfile-11"></a>
-This is the &ldquo;look in this file for the key specified with <span class="option">-a</span>&rdquo; option.
-This option takes a file argument <span class="file">file-name</span>.
-This option specifies the keyfile.
-<code>sntp</code> will search for the key specified with <span class="option">-a</span>
-<span class="file">keyno</span> in this file. See <span class="command">ntp.keys(5)</span> for more
-information.
-<div class="node">
-<p><hr>
-<a name="sntp-logfile"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-steplimit">sntp steplimit</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-keyfile">sntp keyfile</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<a name="keyfile-option-_0028_002dk_0029"></a>
+<h4 class="subsection">1.1.9 keyfile option (-k)</h4>
+<a name="index-sntp_002dkeyfile"></a>
+
+<p>This is the &ldquo;look in this file for the key specified with <samp>-a</samp>&rdquo; option.
+This option takes a file argument <samp>file-name</samp>.
+This option specifies the keyfile.
+<code>sntp</code> will search for the key specified with <samp>-a</samp>
+<samp>keyno</samp> in this file. See <code>ntp.keys(5)</code> for more
+information.
+</p><hr>
+<a name="sntp-logfile"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-steplimit" accesskey="n" rel="next">sntp steplimit</a>, Previous: <a href="#sntp-keyfile" accesskey="p" rel="prev">sntp keyfile</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
+<a name="logfile-option-_0028_002dl_0029"></a>
+<h4 class="subsection">1.1.10 logfile option (-l)</h4>
+<a name="index-sntp_002dlogfile"></a>
-<h4 class="subsection">logfile option (-l)</h4>
-
-<p><a name="index-sntp_002dlogfile-12"></a>
-This is the &ldquo;log to specified logfile&rdquo; option.
-This option takes a file argument <span class="file">file-name</span>.
+<p>This is the &ldquo;log to specified logfile&rdquo; option.
+This option takes a file argument <samp>file-name</samp>.
This option causes the client to write log messages to the specified
-<span class="file">logfile</span>.
-<div class="node">
-<p><hr>
-<a name="sntp-steplimit"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-ntpversion">sntp ntpversion</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-logfile">sntp logfile</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<samp>logfile</samp>.
+</p><hr>
+<a name="sntp-steplimit"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-ntpversion" accesskey="n" rel="next">sntp ntpversion</a>, Previous: <a href="#sntp-logfile" accesskey="p" rel="prev">sntp logfile</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">steplimit option (-M)</h4>
-
-<p><a name="index-sntp_002dsteplimit-13"></a>
-This is the &ldquo;adjustments less than <var>steplimit</var> msec will be slewed&rdquo; option.
-This option takes a number argument.
-If the time adjustment is less than <span class="file">steplimit</span> milliseconds,
-slew the amount using <span class="command">adjtime(2)</span>. Otherwise, step the
-correction using <span class="command">settimeofday(2)</span>. The default value is 0,
+<a name="steplimit-option-_0028_002dM_0029"></a>
+<h4 class="subsection">1.1.11 steplimit option (-M)</h4>
+<a name="index-sntp_002dsteplimit"></a>
+
+<p>This is the &ldquo;adjustments less than <var>steplimit</var> msec will be slewed&rdquo; option.
+This option takes a number argument.
+If the time adjustment is less than <samp>steplimit</samp> milliseconds,
+slew the amount using <code>adjtime(2)</code>. Otherwise, step the
+correction using <code>settimeofday(2)</code>. The default value is 0,
which means all adjustments will be stepped. This is a feature, as
-different situations demand different values.
-<div class="node">
-<p><hr>
-<a name="sntp-ntpversion"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-usereservedport">sntp usereservedport</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-steplimit">sntp steplimit</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+different situations demand different values.
+</p><hr>
+<a name="sntp-ntpversion"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-usereservedport" accesskey="n" rel="next">sntp usereservedport</a>, Previous: <a href="#sntp-steplimit" accesskey="p" rel="prev">sntp steplimit</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
+<a name="ntpversion-option-_0028_002do_0029"></a>
+<h4 class="subsection">1.1.12 ntpversion option (-o)</h4>
+<a name="index-sntp_002dntpversion"></a>
-<h4 class="subsection">ntpversion option (-o)</h4>
-
-<p><a name="index-sntp_002dntpversion-14"></a>
-This is the &ldquo;send <var>int</var> as our ntp protocol version&rdquo; option.
-This option takes a number argument.
+<p>This is the &ldquo;send <var>int</var> as our ntp protocol version&rdquo; option.
+This option takes a number argument.
When sending requests to a remote server, tell them we are running
-NTP protocol version <span class="file">ntpversion</span> .
-<div class="node">
-<p><hr>
-<a name="sntp-usereservedport"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-timeout">sntp timeout</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-ntpversion">sntp ntpversion</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+NTP protocol version <samp>ntpversion</samp> .
+</p><hr>
+<a name="sntp-usereservedport"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-timeout" accesskey="n" rel="next">sntp timeout</a>, Previous: <a href="#sntp-ntpversion" accesskey="p" rel="prev">sntp ntpversion</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
+<a name="usereservedport-option-_0028_002dr_0029"></a>
+<h4 class="subsection">1.1.13 usereservedport option (-r)</h4>
+<a name="index-sntp_002dusereservedport"></a>
-<h4 class="subsection">usereservedport option (-r)</h4>
-
-<p><a name="index-sntp_002dusereservedport-15"></a>
-This is the &ldquo;use the ntp reserved port (port 123)&rdquo; option.
+<p>This is the &ldquo;use the ntp reserved port (port 123)&rdquo; option.
Use port 123, which is reserved for NTP, for our network
-communications.
-<div class="node">
-<p><hr>
-<a name="sntp-timeout"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-wait">sntp wait</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-usereservedport">sntp usereservedport</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+communications.
+</p><hr>
+<a name="sntp-timeout"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-wait" accesskey="n" rel="next">sntp wait</a>, Previous: <a href="#sntp-usereservedport" accesskey="p" rel="prev">sntp usereservedport</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
+<a name="timeout-option-_0028_002dt_0029"></a>
+<h4 class="subsection">1.1.14 timeout option (-t)</h4>
+<a name="index-sntp_002dtimeout"></a>
-<h4 class="subsection">timeout option (-t)</h4>
-
-<p><a name="index-sntp_002dtimeout-16"></a>
-This is the &ldquo;the number of seconds to wait for responses&rdquo; option.
-This option takes a number argument <span class="file">seconds</span>.
+<p>This is the &ldquo;the number of seconds to wait for responses&rdquo; option.
+This option takes a number argument <samp>seconds</samp>.
When waiting for a reply, <code>sntp</code> will wait the number
of seconds specified before giving up. The default should be
more than enough for a unicast response. If <code>sntp</code> is
only waiting for a broadcast response a longer timeout is
-likely needed.
-<div class="node">
-<p><hr>
-<a name="sntp-wait"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-config">sntp config</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-timeout">sntp timeout</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+likely needed.
+</p><hr>
+<a name="sntp-wait"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-config" accesskey="n" rel="next">sntp config</a>, Previous: <a href="#sntp-timeout" accesskey="p" rel="prev">sntp timeout</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">wait option</h4>
-
-<p><a name="index-sntp_002dwait-17"></a>
-This is the &ldquo;wait for pending replies (if not setting the time)&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>can be disabled with &ndash;no-wait.
-<li>It is enabled by default.
-</ul>
-
- <p>If we are not setting the time, wait for all pending responses.
-
-<div class="node">
-<p><hr>
-<a name="sntp-config"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-exit-status">sntp exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-wait">sntp wait</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<a name="wait-option"></a>
+<h4 class="subsection">1.1.15 wait option</h4>
+<a name="index-sntp_002dwait"></a>
+
+<p>This is the &ldquo;wait for pending replies (if not setting the time)&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> can be disabled with &ndash;no-wait.
+</li><li> It is enabled by default.
+</li></ul>
+
+<p>If we are not setting the time, wait for all pending responses.
+</p>
+
+<hr>
+<a name="sntp-config"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-exit-status" accesskey="n" rel="next">sntp exit status</a>, Previous: <a href="#sntp-wait" accesskey="p" rel="prev">sntp wait</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">presetting/configuring sntp</h4>
+<a name="presetting_002fconfiguring-sntp"></a>
+<h4 class="subsection">1.1.16 presetting/configuring sntp</h4>
<p>Any option that is not marked as <i>not presettable</i> may be preset by
-loading values from configuration ("rc" or "ini") files, and values from environment variables named <code>SNTP</code> and <code>SNTP_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
-the options listed above in upper case and segmented with underscores.
+loading values from configuration (&quot;rc&quot; or &quot;ini&quot;) files, and values from environment variables named <code>SNTP</code> and <code>SNTP_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
+the options listed above in upper case and segmented with underscores.
The <code>SNTP</code> variable will be tokenized and parsed like
the command line. The remaining variables are tested for existence and their
values are treated like option arguments.
-
-<p class="noindent"><code>libopts</code> will search in 2 places for configuration files:
- <ul>
-<li>$HOME
-<li>$PWD
-</ul>
- The environment variables <code>HOME</code>, and <code>PWD</code>
-are expanded and replaced when <span class="file">sntp</span> runs.
-For any of these that are plain files, they are simply processed.
-For any that are directories, then a file named <span class="file">.ntprc</span> is searched for
+</p>
+
+<p><code>libopts</code> will search in 2 places for configuration files:
+</p><ul>
+<li> $HOME
+</li><li> $PWD
+</li></ul>
+<p>The environment variables <code>HOME</code>, and <code>PWD</code>
+are expanded and replaced when <samp>sntp</samp> runs.
+For any of these that are plain files, they are simply processed.
+For any that are directories, then a file named <samp>.ntprc</samp> is searched for
within that directory and processed.
-
- <p>Configuration files may be in a wide variety of formats.
+</p>
+<p>Configuration files may be in a wide variety of formats.
The basic format is an option name followed by a value (argument) on the
same line. Values may be separated from the option name with a colon,
equal sign or simply white space. Values may be continued across multiple
lines by escaping the newline with a backslash.
-
- <p>Multiple programs may also share the same initialization file.
+</p>
+<p>Multiple programs may also share the same initialization file.
Common options are collected at the top, followed by program specific
segments. The segments are separated by lines like:
-<pre class="example"> [SNTP]
-</pre>
- <p class="noindent">or by
-<pre class="example"> &lt;?program sntp&gt;
-</pre>
- <p class="noindent">Do not mix these styles within one configuration file.
-
- <p>Compound values and carefully constructed string values may also be
+</p><div class="example">
+<pre class="example">[SNTP]
+</pre></div>
+<p>or by
+</p><div class="example">
+<pre class="example">&lt;?program sntp&gt;
+</pre></div>
+<p>Do not mix these styles within one configuration file.
+</p>
+<p>Compound values and carefully constructed string values may also be
specified using XML syntax:
-<pre class="example"> &lt;option-name&gt;
- &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
- &lt;/option-name&gt;
-</pre>
- <p class="noindent">yielding an <code>option-name.sub-opt</code> string value of
-<pre class="example"> "...&lt;...&gt;..."
-</pre>
- <p><code>AutoOpts</code> does not track suboptions. You simply note that it is a
+</p><div class="example">
+<pre class="example">&lt;option-name&gt;
+ &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
+&lt;/option-name&gt;
+</pre></div>
+<p>yielding an <code>option-name.sub-opt</code> string value of
+</p><div class="example">
+<pre class="example">&quot;...&lt;...&gt;...&quot;
+</pre></div>
+<p><code>AutoOpts</code> does not track suboptions. You simply note that it is a
hierarchicly valued option. <code>AutoOpts</code> does provide a means for searching
the associated name/value pair list (see: optionFindValue).
-
- <p>The command line options relating to configuration and/or usage help are:
-
-<h5 class="subsubheading">version (-)</h5>
+</p>
+<p>The command line options relating to configuration and/or usage help are:
+</p>
+<a name="version-_0028_002d_0029"></a>
+<h4 class="subsubheading">version (-)</h4>
<p>Print the program version to standard out, optionally with licensing
information, then exit 0. The optional argument specifies how much licensing
-detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
+detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
Only the first letter of the argument is examined:
-
- <dl>
-<dt><span class="samp">version</span><dd>Only print the version. This is the default.
-<br><dt><span class="samp">copyright</span><dd>Name the copyright usage licensing terms.
-<br><dt><span class="samp">verbose</span><dd>Print the full copyright usage licensing terms.
+</p>
+<dl compact="compact">
+<dt>&lsquo;<samp>version</samp>&rsquo;</dt>
+<dd><p>Only print the version. This is the default.
+</p></dd>
+<dt>&lsquo;<samp>copyright</samp>&rsquo;</dt>
+<dd><p>Name the copyright usage licensing terms.
+</p></dd>
+<dt>&lsquo;<samp>verbose</samp>&rsquo;</dt>
+<dd><p>Print the full copyright usage licensing terms.
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
-<a name="sntp-exit-status"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-Usage">sntp Usage</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-config">sntp config</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<hr>
+<a name="sntp-exit-status"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-Usage" accesskey="n" rel="next">sntp Usage</a>, Previous: <a href="#sntp-config" accesskey="p" rel="prev">sntp config</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">sntp exit status</h4>
+<a name="sntp-exit-status-1"></a>
+<h4 class="subsection">1.1.17 sntp exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
-<br><dt><span class="samp">66 (EX_NOINPUT)</span><dd>A specified configuration file could not be loaded.
-<br><dt><span class="samp">70 (EX_SOFTWARE)</span><dd>libopts had an internal operational error. Please report
-it to autogen-users@lists.sourceforge.net. Thank you.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
+<dt>&lsquo;<samp>66 (EX_NOINPUT)</samp>&rsquo;</dt>
+<dd><p>A specified configuration file could not be loaded.
+</p></dd>
+<dt>&lsquo;<samp>70 (EX_SOFTWARE)</samp>&rsquo;</dt>
+<dd><p>libopts had an internal operational error. Please report
+it to autogen-users@lists.sourceforge.net. Thank you.
+</p></dd>
</dl>
- <div class="node">
-<p><hr>
-<a name="sntp-Usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#sntp-Authors">sntp Authors</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-exit-status">sntp exit status</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<hr>
+<a name="sntp-Usage"></a>
+<div class="header">
+<p>
+Next: <a href="#sntp-Authors" accesskey="n" rel="next">sntp Authors</a>, Previous: <a href="#sntp-exit-status" accesskey="p" rel="prev">sntp exit status</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">sntp Usage</h4>
-
-<div class="node">
-<p><hr>
-<a name="sntp-Authors"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#sntp-Usage">sntp Usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#sntp-Invocation">sntp Invocation</a>
-<br>
+<a name="sntp-Usage-1"></a>
+<h4 class="subsection">1.1.18 sntp Usage</h4>
+<hr>
+<a name="sntp-Authors"></a>
+<div class="header">
+<p>
+Previous: <a href="#sntp-Usage" accesskey="p" rel="prev">sntp Usage</a>, Up: <a href="#sntp-Invocation" accesskey="u" rel="up">sntp Invocation</a> &nbsp; </p>
</div>
+<a name="sntp-Authors-1"></a>
+<h4 class="subsection">1.1.19 sntp Authors</h4>
-<h4 class="subsection">sntp Authors</h4>
-
-<div class="node">
-<p><hr>
+<hr>
<a name="Usage"></a>
-<br>
+<div class="header">
+<p>
+Previous: <a href="#sntp-Invocation" accesskey="p" rel="prev">sntp Invocation</a>, Up: <a href="#sntp-Description" accesskey="u" rel="up">sntp Description</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Usage</h3>
+<a name="Usage-1"></a>
+<h3 class="section">1.2 Usage</h3>
<p>The simplest use of this program is as an unprivileged command to
-check the current time, offset, and error in the local clock.
+check the current time, offset, and error in the local clock.
For example:
+</p>
+<div class="example">
+<pre class="example">sntp ntpserver.somewhere
+</pre></div>
-<pre class="example"> sntp ntpserver.somewhere
-</pre>
- <p>With suitable privilege, it can be run as a command or in a
+<p>With suitable privilege, it can be run as a command or in a
<code>crom</code> job to reset the local clock from a reliable server, like
-the <code>ntpdate</code> and <code>rdate</code> commands.
+the <code>ntpdate</code> and <code>rdate</code> commands.
For example:
+</p>
+<div class="example">
+<pre class="example">sntp -a ntpserver.somewhere
+</pre></div>
+<hr>
+
-<pre class="example"> sntp -a ntpserver.somewhere
-</pre>
- </body></html>
+</body>
+</html>
diff --git a/contrib/ntp/sntp/sntp.man.in b/contrib/ntp/sntp/sntp.man.in
index 9156d05..b94a3cd 100644
--- a/contrib/ntp/sntp/sntp.man.in
+++ b/contrib/ntp/sntp/sntp.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH sntp @SNTP_MS@ "27 Feb 2018" "4.2.8p11" "User Commands"
+.TH sntp @SNTP_MS@ "20 Feb 2019" "4.2.8p13" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-eaayfN/ag-qaaqeN)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:13:07 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:55:51 AM by AutoGen 5.18.5
.\" From the definitions sntp-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
diff --git a/contrib/ntp/sntp/sntp.mdoc.in b/contrib/ntp/sntp/sntp.mdoc.in
index a5f9095..89eb68c 100644
--- a/contrib/ntp/sntp/sntp.mdoc.in
+++ b/contrib/ntp/sntp/sntp.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt SNTP @SNTP_MS@ User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (sntp-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:13:14 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:55:48 AM by AutoGen 5.18.5
.\" From the definitions sntp-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/contrib/ntp/sntp/tests/Makefile.in b/contrib/ntp/sntp/tests/Makefile.in
index bd776d8..a3fc69e 100644
--- a/contrib/ntp/sntp/tests/Makefile.in
+++ b/contrib/ntp/sntp/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/sntp/tests/crypto.c b/contrib/ntp/sntp/tests/crypto.c
index 64c784d..8ecd743 100644
--- a/contrib/ntp/sntp/tests/crypto.c
+++ b/contrib/ntp/sntp/tests/crypto.c
@@ -85,7 +85,7 @@ test_MakeSHA1Mac(void)
void
test_MakeCMac(void)
{
-#ifdef OPENSSL
+#if defined(OPENSSL) && defined(ENABLE_CMAC)
const char* PKT_DATA = "abcdefgh0123";
const int PKT_LEN = strlen(PKT_DATA);
@@ -191,7 +191,7 @@ test_VerifyCMAC(void)
void
VerifyOpenSSLCMAC(struct key *cmac)
{
-#ifdef OPENSSL
+#if defined(OPENSSL) && defined(ENABLE_CMAC)
/* XXX: HMS: auth_md5 must be renamed/incorrect. */
// TEST_ASSERT_TRUE(auth_md5(PKT_DATA, PKT_LEN, CMAC_LENGTH, cmac));
diff --git a/contrib/ntp/sntp/tests/packetProcessing.c b/contrib/ntp/sntp/tests/packetProcessing.c
index 910c561..9c9f061 100644
--- a/contrib/ntp/sntp/tests/packetProcessing.c
+++ b/contrib/ntp/sntp/tests/packetProcessing.c
@@ -464,6 +464,8 @@ test_CorrectAuthenticatedPacketSHA1(void)
void
test_CorrectAuthenticatedPacketCMAC(void)
{
+#if defined(OPENSSL) && defined(ENABLE_CMAC)
+
PrepareAuthenticationTest(30, CMAC_LENGTH, CMAC, "abcdefghijklmnop");
TEST_ASSERT_TRUE(ENABLED_OPT(AUTHENTICATION));
@@ -480,5 +482,11 @@ test_CorrectAuthenticatedPacketCMAC(void)
TEST_ASSERT_EQUAL(pkt_len,
process_pkt(&testpkt.p, &testsock, pkt_len,
MODE_SERVER, &testspkt.p, "UnitTest"));
+
+#else
+
+ TEST_IGNORE_MESSAGE("OpenSSL CMAC not used, skipping...");
+
+#endif /* OPENSSL */
}
diff --git a/contrib/ntp/sntp/unity/Makefile.in b/contrib/ntp/sntp/unity/Makefile.in
index be1866c..0923192 100644
--- a/contrib/ntp/sntp/unity/Makefile.in
+++ b/contrib/ntp/sntp/unity/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/sntp/version.c b/contrib/ntp/sntp/version.c
index 25d4b14..77ce223 100644
--- a/contrib/ntp/sntp/version.c
+++ b/contrib/ntp/sntp/version.c
@@ -2,4 +2,4 @@
* version file for sntp
*/
#include <config.h>
-const char * Version = "sntp 4.2.8p11@1.3728-o Tue Feb 27 22:59:12 UTC 2018 (50)";
+const char * Version = "sntp 4.2.8p13@1.3847-o Thu Feb 21 01:04:54 UTC 2019 (1)";
diff --git a/contrib/ntp/util/Makefile.in b/contrib/ntp/util/Makefile.in
index a7ab7ee..099e270 100644
--- a/contrib/ntp/util/Makefile.in
+++ b/contrib/ntp/util/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/contrib/ntp/util/invoke-ntp-keygen.texi b/contrib/ntp/util/invoke-ntp-keygen.texi
index 2a8d401..cb0d891 100644
--- a/contrib/ntp/util/invoke-ntp-keygen.texi
+++ b/contrib/ntp/util/invoke-ntp-keygen.texi
@@ -6,7 +6,7 @@
#
# EDIT THIS FILE WITH CAUTION (invoke-ntp-keygen.texi)
#
-# It has been AutoGen-ed February 27, 2018 at 05:15:57 PM by AutoGen 5.18.5
+# It has been AutoGen-ed February 20, 2019 at 09:57:13 AM by AutoGen 5.18.5
# From the definitions ntp-keygen-opts.def
# and the template file agtexi-cmd.tpl
@end ignore
@@ -948,7 +948,7 @@ Following the header the keys are entered one per line in the format
@end example
where
@kbd{keyno}
-is a positive integer in the range 1-65534;
+is a positive integer in the range 1-65535;
@kbd{type}
is the key type for the message digest algorithm, which in the absence of the
OpenSSL library must be
@@ -1056,14 +1056,17 @@ with a status code of 0.
@exampleindent 0
@example
-ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.7p245
-USAGE: ntp-keygen [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
+ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.8p13
+Usage: ntp-keygen [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
Flg Arg Option-Name Description
+ -b Num imbits identity modulus bits
+ - it must be in the range:
+ 256 to 2048
-c Str certificate certificate scheme
-C Str cipher privatekey cipher
-d no debug-level Increase debug verbosity level
- may appear multiple times
- -D Str set-debug-level Set the debug verbosity level
+ -D Num set-debug-level Set the debug verbosity level
- may appear multiple times
-e no id-key Write IFF or GQ identity keys
-G no gq-params Generate GQ parameters and keys
@@ -1071,37 +1074,36 @@ USAGE: ntp-keygen [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]...
-I no iffkey generate IFF parameters
-i Str ident set Autokey group name
-l Num lifetime set certificate lifetime
- -M no md5key generate MD5 keys
- -m Num modulus modulus
- - It must be in the range:
+ -m Num modulus prime modulus
+ - it must be in the range:
256 to 2048
+ -M no md5key generate symmetric keys
-P no pvt-cert generate PC private certificate
- -p Str pvt-passwd output private password
- -q Str get-pvt-passwd input private password
- -S Str sign-key generate sign key (RSA or DSA)
+ -p Str password local private password
+ -q Str export-passwd export IFF or GQ group keys with password
-s Str subject-name set host and optionally group name
+ -S Str sign-key generate sign key (RSA or DSA)
-T no trusted-cert trusted certificate (TC scheme)
-V Num mv-params generate <num> MV parameters
-v Num mv-keys update <num> MV keys
- opt version Output version information and exit
- -? no help Display extended usage information and exit
- -! no more-help Extended usage information passed thru pager
- -> opt save-opts Save the option state to a config file
- -< Str load-opts Load options from a config file
- - disabled as --no-load-opts
+ opt version output version information and exit
+ -? no help display extended usage information and exit
+ -! no more-help extended usage information passed thru pager
+ -> opt save-opts save the option state to a config file
+ -< Str load-opts load options from a config file
+ - disabled as '--no-load-opts'
- may appear multiple times
Options are specified by doubled hyphens and their name or by a single
hyphen and the flag character.
-
The following option preset mechanisms are supported:
- reading file $HOME/.ntprc
- reading file ./.ntprc
- examining environment variables named NTP_KEYGEN_*
-please send bug reports to: http://bugs.ntp.org, bugs@@ntp.org
+Please send bug reports to: <http://bugs.ntp.org, bugs@@ntp.org>
@end example
@exampleindent 4
diff --git a/contrib/ntp/util/ntp-keygen-opts.c b/contrib/ntp/util/ntp-keygen-opts.c
index 6c07f97..e47d7ce 100644
--- a/contrib/ntp/util/ntp-keygen-opts.c
+++ b/contrib/ntp/util/ntp-keygen-opts.c
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.c)
*
- * It has been AutoGen-ed February 27, 2018 at 05:15:44 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:57:09 AM by AutoGen 5.18.5
* From the definitions ntp-keygen-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This source file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -72,7 +72,7 @@ extern FILE * option_usage_fp;
* static const strings for ntp-keygen options
*/
static char const ntp_keygen_opt_strs[2442] =
-/* 0 */ "ntp-keygen (ntp) 4.2.8p11\n"
+/* 0 */ "ntp-keygen (ntp) 4.2.8p13\n"
"Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n"
"This is free software. It is licensed for use, modification and\n"
"redistribution under the terms of the NTP License, copies of which\n"
@@ -165,14 +165,14 @@ static char const ntp_keygen_opt_strs[2442] =
/* 2223 */ "no-load-opts\0"
/* 2236 */ "no\0"
/* 2239 */ "NTP_KEYGEN\0"
-/* 2250 */ "ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.8p11\n"
+/* 2250 */ "ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.8p13\n"
"Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\0"
/* 2365 */ "$HOME\0"
/* 2371 */ ".\0"
/* 2373 */ ".ntprc\0"
/* 2380 */ "http://bugs.ntp.org, bugs@ntp.org\0"
/* 2414 */ "\n\0"
-/* 2416 */ "ntp-keygen (ntp) 4.2.8p11";
+/* 2416 */ "ntp-keygen (ntp) 4.2.8p13";
/**
* imbits option description:
@@ -1310,7 +1310,7 @@ static void bogus_function(void) {
translate option names.
*/
/* referenced via ntp_keygenOptions.pzCopyright */
- puts(_("ntp-keygen (ntp) 4.2.8p11\n\
+ puts(_("ntp-keygen (ntp) 4.2.8p13\n\
Copyright (C) 1992-2017 The University of Delaware and Network Time Foundation, all rights reserved.\n\
This is free software. It is licensed for use, modification and\n\
redistribution under the terms of the NTP License, copies of which\n\
@@ -1409,14 +1409,14 @@ implied warranty.\n"));
puts(_("load options from a config file"));
/* referenced via ntp_keygenOptions.pzUsageTitle */
- puts(_("ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.8p11\n\
+ puts(_("ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.8p13\n\
Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n"));
/* referenced via ntp_keygenOptions.pzExplain */
puts(_("\n"));
/* referenced via ntp_keygenOptions.pzFullVersion */
- puts(_("ntp-keygen (ntp) 4.2.8p11"));
+ puts(_("ntp-keygen (ntp) 4.2.8p13"));
/* referenced via ntp_keygenOptions.pzFullUsage */
puts(_("<<<NOT-FOUND>>>"));
diff --git a/contrib/ntp/util/ntp-keygen-opts.def b/contrib/ntp/util/ntp-keygen-opts.def
index f8c39c4..f89ee33 100644
--- a/contrib/ntp/util/ntp-keygen-opts.def
+++ b/contrib/ntp/util/ntp-keygen-opts.def
@@ -1210,7 +1210,7 @@ Following the header the keys are entered one per line in the format
.D1 Ar keyno Ar type Ar key
where
.Ar keyno
-is a positive integer in the range 1-65534;
+is a positive integer in the range 1-65535;
.Ar type
is the key type for the message digest algorithm, which in the absence of the
OpenSSL library must be
diff --git a/contrib/ntp/util/ntp-keygen-opts.h b/contrib/ntp/util/ntp-keygen-opts.h
index ab9e8ca..5af994d 100644
--- a/contrib/ntp/util/ntp-keygen-opts.h
+++ b/contrib/ntp/util/ntp-keygen-opts.h
@@ -1,11 +1,11 @@
/*
* EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.h)
*
- * It has been AutoGen-ed February 27, 2018 at 05:15:43 PM by AutoGen 5.18.5
+ * It has been AutoGen-ed February 20, 2019 at 09:57:09 AM by AutoGen 5.18.5
* From the definitions ntp-keygen-opts.def
* and the template file options
*
- * Generated from AutoOpts 41:0:16 templates.
+ * Generated from AutoOpts 41:1:16 templates.
*
* AutoOpts is a copyrighted work. This header file is not encumbered
* by AutoOpts licensing, but is provided under the licensing terms chosen
@@ -53,7 +53,7 @@
* tolerable version is at least as old as what was current when the header
* template was released.
*/
-#define AO_TEMPLATE_VERSION 167936
+#define AO_TEMPLATE_VERSION 167937
#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \
|| (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION)
# error option template version mismatches autoopts/options.h header
@@ -94,9 +94,9 @@ typedef enum {
/** count of all options for ntp-keygen */
#define OPTION_CT 26
/** ntp-keygen version */
-#define NTP_KEYGEN_VERSION "4.2.8p11"
+#define NTP_KEYGEN_VERSION "4.2.8p13"
/** Full ntp-keygen version text */
-#define NTP_KEYGEN_FULL_VERSION "ntp-keygen (ntp) 4.2.8p11"
+#define NTP_KEYGEN_FULL_VERSION "ntp-keygen (ntp) 4.2.8p13"
/**
* Interface defines for all options. Replace "n" with the UPPER_CASED
diff --git a/contrib/ntp/util/ntp-keygen.1ntp-keygenman b/contrib/ntp/util/ntp-keygen.1ntp-keygenman
index 5b942d8..0d5e443 100644
--- a/contrib/ntp/util/ntp-keygen.1ntp-keygenman
+++ b/contrib/ntp/util/ntp-keygen.1ntp-keygenman
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntp-keygen 1ntp-keygenman "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH ntp-keygen 1ntp-keygenman "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-bBa46V/ag-nBaW5V)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:53 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:14 AM by AutoGen 5.18.5
.\" From the definitions ntp-keygen-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
@@ -1054,7 +1054,7 @@ Following the header the keys are entered one per line in the format
.in -4
where
\f\*[I-Font]keyno\f[]
-is a positive integer in the range 1-65534;
+is a positive integer in the range 1-65535;
\f\*[I-Font]type\f[]
is the key type for the message digest algorithm, which in the absence of the
OpenSSL library must be
diff --git a/contrib/ntp/util/ntp-keygen.1ntp-keygenmdoc b/contrib/ntp/util/ntp-keygen.1ntp-keygenmdoc
index ba21087..602dae8 100644
--- a/contrib/ntp/util/ntp-keygen.1ntp-keygenmdoc
+++ b/contrib/ntp/util/ntp-keygen.1ntp-keygenmdoc
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTP_KEYGEN 1ntp-keygenmdoc User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:16:00 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:11 AM by AutoGen 5.18.5
.\" From the definitions ntp-keygen-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -943,7 +943,7 @@ Following the header the keys are entered one per line in the format
.D1 Ar keyno Ar type Ar key
where
.Ar keyno
-is a positive integer in the range 1\-65534;
+is a positive integer in the range 1\-65535;
.Ar type
is the key type for the message digest algorithm, which in the absence of the
OpenSSL library must be
diff --git a/contrib/ntp/util/ntp-keygen.html b/contrib/ntp/util/ntp-keygen.html
index 854d055..07ac9c2 100644
--- a/contrib/ntp/util/ntp-keygen.html
+++ b/contrib/ntp/util/ntp-keygen.html
@@ -1,87 +1,115 @@
-<html lang="en">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<head>
-<title>Ntp-keygen User's Manual</title>
-<meta http-equiv="Content-Type" content="text/html">
-<meta name="description" content="Ntp-keygen User's Manual">
-<meta name="generator" content="makeinfo 4.7">
-<link title="Top" rel="top" href="#Top">
-<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
-<meta http-equiv="Content-Style-Type" content="text/css">
-<style type="text/css"><!--
- pre.display { font-family:inherit }
- pre.format { font-family:inherit }
- pre.smalldisplay { font-family:inherit; font-size:smaller }
- pre.smallformat { font-family:inherit; font-size:smaller }
- pre.smallexample { font-size:smaller }
- pre.smalllisp { font-size:smaller }
- span.sc { font-variant:small-caps }
- span.roman { font-family: serif; font-weight: normal; }
---></style>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Ntp-keygen User&rsquo;s Manual</title>
+
+<meta name="description" content="Ntp-keygen User&rsquo;s Manual">
+<meta name="keywords" content="Ntp-keygen User&rsquo;s Manual">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="makeinfo">
+<link href="#Top" rel="start" title="Top">
+<link href="dir.html#Top" rel="up" title="(dir)">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+blockquote.indentedblock {margin-right: 0em}
+blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
+blockquote.smallquotation {font-size: smaller}
+div.display {margin-left: 3.2em}
+div.example {margin-left: 3.2em}
+div.lisp {margin-left: 3.2em}
+div.smalldisplay {margin-left: 3.2em}
+div.smallexample {margin-left: 3.2em}
+div.smalllisp {margin-left: 3.2em}
+kbd {font-style: oblique}
+pre.display {font-family: inherit}
+pre.format {font-family: inherit}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: inherit; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: inherit; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.nolinebreak {white-space: nowrap}
+span.roman {font-family: initial; font-weight: normal}
+span.sansserif {font-family: sans-serif; font-weight: normal}
+ul.no-bullet {list-style: none}
+-->
+</style>
+
+
</head>
-<body>
-<h1 class="settitle">Ntp-keygen User's Manual</h1>
- <div class="shortcontents">
-<h2>Short Contents</h2>
-<ul>
-<a href="#Top">Top</a>
-<a href="#Top">NTP Key Generation Program User Manual</a>
-</ul>
-</div>
+<body lang="en">
+<h1 class="settitle" align="center">Ntp-keygen User&rsquo;s Manual</h1>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
-</div>
-<h2 class="unnumbered">Top</h2>
-<ul class="menu">
-<li><a accesskey="1" href="#Description">Description</a>
-<li><a accesskey="2" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>: Invoking ntp-keygen
-<li><a accesskey="3" href="#Running-the-Program">Running the Program</a>
-<li><a accesskey="4" href="#Random-Seed-File">Random Seed File</a>
-<li><a accesskey="5" href="#Cryptographic-Data-Files">Cryptographic Data Files</a>
-</ul>
-<div class="node">
-<p><hr>
-<a name="Top"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Description">Description</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
-<br>
+<a name="SEC_Overview"></a>
+<h2 class="shortcontents-heading">Short Table of Contents</h2>
+
+<div class="shortcontents">
+<ul class="no-bullet">
+<li><a name="stoc-Description-1" href="#toc-Description-1">1 Description</a></li>
+</ul>
</div>
-<h2 class="unnumbered">NTP Key Generation Program User Manual</h2>
-<p>This document describes the use of the NTP Project's <code>ntp-keygen</code>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#Description" accesskey="1">Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-Invocation" accesskey="2">ntp-keygen Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Invoking ntp-keygen
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Running-the-Program" accesskey="3">Running the Program</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Random-Seed-File" accesskey="4">Random Seed File</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Cryptographic-Data-Files" accesskey="5">Cryptographic Data Files</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<a name="Top"></a>
+<div class="header">
+<p>
+Next: <a href="#Description" accesskey="n" rel="next">Description</a>, Previous: <a href="dir.html#Top" accesskey="p" rel="prev">(dir)</a>, Up: <a href="dir.html#Top" accesskey="u" rel="up">(dir)</a> &nbsp; </p>
+</div>
+<a name="NTP-Key-Generation-Program-User-Manual"></a>
+<h1 class="top">NTP Key Generation Program User Manual</h1>
+
+<p>This document describes the use of the NTP Project&rsquo;s <code>ntp-keygen</code>
program, that generates cryptographic data files used by the NTPv4
-authentication and identity schemes.
+authentication and identity schemes.
It can generate message digest keys used in symmetric key cryptography and,
if the OpenSSL software
library has been installed, it can generate host keys, sign keys,
certificates, and identity keys and parameters used by the Autokey
-public key cryptography.
+public key cryptography.
The message digest keys file is generated in a
-format compatible with NTPv3.
+format compatible with NTPv3.
All other files are in PEM-encoded
printable ASCII format so they can be embedded as MIME attachments in
mail to other sites.
-
- <p>This document applies to version 4.2.8p11 of <code>ntp-keygen</code>.
-
-<div class="node">
-<p><hr>
-<a name="Description"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Running-the-Program">Running the Program</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+</p>
+<p>This document applies to version 4.2.8p13 of <code>ntp-keygen</code>.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#Description" accesskey="1">Description</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="Description"></a>
+<div class="header">
+<p>
+Next: <a href="#Running-the-Program" accesskey="n" rel="next">Running the Program</a>, Previous: <a href="#Top" accesskey="p" rel="prev">Top</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Description</h3>
+<a name="Description-1"></a>
+<h2 class="chapter">1 Description</h2>
<p>This program generates cryptographic data files used by the NTPv4
authentication and identity schemes. It can generate message digest
@@ -92,255 +120,320 @@ public key cryptography. The message digest keys file is generated in a
format compatible with NTPv3. All other files are in PEM-encoded
printable ASCII format so they can be embedded as MIME attachments in
mail to other sites.
-
- <p>When used to generate message digest keys, the program produces a file
+</p>
+<p>When used to generate message digest keys, the program produces a file
containing ten pseudo-random printable ASCII strings suitable for the
-MD5 message digest algorithm included in the distribution.
+MD5 message digest algorithm included in the distribution.
If the
OpenSSL library is installed, it produces an additional ten hex-encoded
random bit strings suitable for the SHA1 and other message digest
-algorithms.
+algorithms.
The message digest keys file must be distributed and stored
-using secure means beyond the scope of NTP itself.
+using secure means beyond the scope of NTP itself.
Besides the keys
used for ordinary NTP associations, additional keys can be defined as
passwords for the ntpq and ntpdc utility programs.
-
- <p>The remaining generated files are compatible with other OpenSSL
-applications and other Public Key Infrastructure (PKI) resources.
+</p>
+<p>The remaining generated files are compatible with other OpenSSL
+applications and other Public Key Infrastructure (PKI) resources.
Certificates generated by this program are compatible with extant
industry practice, although some users might find the interpretation of
-X509v3 extension fields somewhat liberal.
+X509v3 extension fields somewhat liberal.
However, the identity keys
are probably not compatible with anything other than Autokey.
-
- <p>Some files used by this program are encrypted using a private password.
+</p>
+<p>Some files used by this program are encrypted using a private password.
The <code>-p</code> option specifies the password for local encrypted files and the
-<code>-q</code> option the password for encrypted files sent to remote sites.
+<code>-q</code> option the password for encrypted files sent to remote sites.
If no password is specified, the host name returned by the Unix
<code>gethostname()</code> function, normally the DNS name of the host, is used.
-
- <p>The <kbd>pw</kbd> option of the <code>crypto</code> configuration command
-specifies the read password for previously encrypted local files.
-This must match the local password used by this program.
-If not specified, the host name is used.
+</p>
+<p>The <kbd>pw</kbd> option of the <code>crypto</code> configuration command
+specifies the read password for previously encrypted local files.
+This must match the local password used by this program.
+If not specified, the host name is used.
Thus, if files are generated by this program without password,
they can be read back by ntpd without password, but only on the same
host.
-
- <p>Normally, encrypted files for each host are generated by that host and
+</p>
+<p>Normally, encrypted files for each host are generated by that host and
used only by that host, although exceptions exist as noted later on
-this page.
+this page.
The symmetric keys file, normally called <code>ntp.keys</code>, is
-usually installed in <code>/etc</code>.
+usually installed in <code>/etc</code>.
Other files and links are usually installed
in <code>/usr/local/etc</code>, which is normally in a shared filesystem in
-NFS-mounted networks and cannot be changed by shared clients.
+NFS-mounted networks and cannot be changed by shared clients.
The location of the keys directory can be changed by the keysdir
-configuration command in such cases.
+configuration command in such cases.
Normally, this is in <code>/etc</code>.
-
- <p>This program directs commentary and error messages to the standard
+</p>
+<p>This program directs commentary and error messages to the standard
error stream <code>stderr</code> and remote files to the standard output stream
<code>stdout</code> where they can be piped to other applications or redirected to
-files.
+files.
The names used for generated files and links all begin with the
string <code>ntpkey</code> and include the file type,
generating host and filestamp,
as described in the <a href="#Cryptographic-Data-Files">Cryptographic Data Files</a> section below.
-
-<div class="node">
-<p><hr>
-<a name="Running-the-Program"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Random-Seed-File">Random Seed File</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Description">Description</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#Running-the-Program" accesskey="1">Running the Program</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-Invocation" accesskey="2">ntp-keygen Invocation</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Random-Seed-File" accesskey="3">Random Seed File</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#Cryptographic-Data-Files" accesskey="4">Cryptographic Data Files</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<hr>
+<a name="Running-the-Program"></a>
+<div class="header">
+<p>
+Next: <a href="#Random-Seed-File" accesskey="n" rel="next">Random Seed File</a>, Previous: <a href="#Description" accesskey="p" rel="prev">Description</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Running the Program</h3>
+<a name="Running-the-Program-1"></a>
+<h3 class="section">1.1 Running the Program</h3>
<p>To test and gain experience with Autokey concepts, log in as root and
-change to the keys directory, usually <code>/usr/local/etc</code>.
+change to the keys directory, usually <code>/usr/local/etc</code>.
When run for the
first time, or if all files with names beginning <code>ntpkey</code>] have been
removed, use the <code>ntp-keygen</code> command without arguments to generate a
default RSA host key and matching RSA-MD5 certificate with expiration
-date one year hence.
+date one year hence.
If run again without options, the program uses the
existing keys and parameters and generates only a new certificate with
new expiration date one year hence.
-
- <p>Run the command on as many hosts as necessary.
+</p>
+<p>Run the command on as many hosts as necessary.
Designate one of them as the trusted host (TH) using <code>ntp-keygen</code>
with the <code>-T</code> option and configure
-it to synchronize from reliable Internet servers.
-Then configure the other hosts to synchronize to the TH directly or indirectly.
+it to synchronize from reliable Internet servers.
+Then configure the other hosts to synchronize to the TH directly or indirectly.
A certificate trail is created when Autokey asks the immediately
ascendant host towards the TH to sign its certificate, which is then
-provided to the immediately descendant host on request.
+provided to the immediately descendant host on request.
All group hosts should have acyclic certificate trails ending on the TH.
-
- <p>The host key is used to encrypt the cookie when required and so must be
-RSA type.
-By default, the host key is also the sign key used to encrypt signatures.
+</p>
+<p>The host key is used to encrypt the cookie when required and so must be
+RSA type.
+By default, the host key is also the sign key used to encrypt signatures.
A different sign key can be assigned using the <code>-S</code> option
-and this can be either RSA or DSA type.
+and this can be either RSA or DSA type.
By default, the signature
message digest type is MD5, but any combination of sign key type and
message digest type supported by the OpenSSL library can be specified
using the <code>-c</code> option.
-
- <p>The rules say cryptographic media should be generated with proventic
+</p>
+<p>The rules say cryptographic media should be generated with proventic
filestamps, which means the host should already be synchronized before
-this program is run.
+this program is run.
This of course creates a chicken-and-egg problem
-when the host is started for the first time.
+when the host is started for the first time.
Accordingly, the host time
should be set by some other means, such as eyeball-and-wristwatch, at
-least so that the certificate lifetime is within the current year.
+least so that the certificate lifetime is within the current year.
After that and when the host is synchronized to a proventic source, the
certificate should be re-generated.
-
- <p>Additional information on trusted groups and identity schemes is on the
+</p>
+<p>Additional information on trusted groups and identity schemes is on the
Autokey Public-Key Authentication page.
-
-<div class="node">
-<p><hr>
+</p>
+<hr>
<a name="ntp_002dkeygen-Invocation"></a>
-<br>
+<div class="header">
+<p>
+Next: <a href="#Random-Seed-File" accesskey="n" rel="next">Random Seed File</a>, Previous: <a href="#Running-the-Program" accesskey="p" rel="prev">Running the Program</a>, Up: <a href="#Description" accesskey="u" rel="up">Description</a> &nbsp; </p>
</div>
+<a name="Invoking-ntp_002dkeygen"></a>
+<h3 class="section">1.2 Invoking ntp-keygen</h3>
+<a name="index-ntp_002dkeygen"></a>
+<a name="index-Create-a-NTP-host-key"></a>
-<h3 class="section">Invoking ntp-keygen</h3>
-<p><a name="index-ntp_002dkeygen-1"></a><a name="index-Create-a-NTP-host-key-2"></a>
- <p>This program generates cryptographic data files used by the NTPv4
-authentication and identification schemes.
+<p>This program generates cryptographic data files used by the NTPv4
+authentication and identification schemes.
It can generate message digest keys used in symmetric key cryptography and,
if the OpenSSL software library has been installed, it can generate host keys,
signing keys, certificates, and identity keys and parameters used in Autokey
-public key cryptography.
+public key cryptography.
These files are used for cookie encryption,
digital signature, and challenge/response identification algorithms
compatible with the Internet standard security infrastructure.
-
- <p>The message digest symmetric keys file is generated in a format
-compatible with NTPv3.
+</p>
+<p>The message digest symmetric keys file is generated in a format
+compatible with NTPv3.
All other files are in PEM-encoded printable ASCII format,
so they can be embedded as MIME attachments in email to other sites
-and certificate authorities.
+and certificate authorities.
By default, files are not encrypted.
-
- <p>When used to generate message digest symmetric keys, the program
+</p>
+<p>When used to generate message digest symmetric keys, the program
produces a file containing ten pseudo-random printable ASCII strings
suitable for the MD5 message digest algorithm included in the
-distribution.
+distribution.
If the OpenSSL library is installed, it produces an additional ten
hex-encoded random bit strings suitable for SHA1, AES-128-CMAC, and
-other message digest algorithms.
+other message digest algorithms.
The message digest symmetric keys file must be distributed and stored
-using secure means beyond the scope of NTP itself.
+using secure means beyond the scope of NTP itself.
Besides the keys used for ordinary NTP associations, additional keys
can be defined as passwords for the
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
utility programs.
-
- <p>The remaining generated files are compatible with other OpenSSL
-applications and other Public Key Infrastructure (PKI) resources.
+</p>
+<p>The remaining generated files are compatible with other OpenSSL
+applications and other Public Key Infrastructure (PKI) resources.
Certificates generated by this program are compatible with extant
industry practice, although some users might find the interpretation of
-X509v3 extension fields somewhat liberal.
+X509v3 extension fields somewhat liberal.
However, the identity keys are probably not compatible with anything
other than Autokey.
-
- <p>Some files used by this program are encrypted using a private password.
+</p>
+<p>Some files used by this program are encrypted using a private password.
The
<code>-p</code>
option specifies the read password for local encrypted files and the
<code>-q</code>
-option the write password for encrypted files sent to remote sites.
+option the write password for encrypted files sent to remote sites.
If no password is specified, the host name returned by the Unix
<code>hostname(1)</code>
command, normally the DNS name of the host, is used as the the default read
-password, for convenience.
+password, for convenience.
The
<code>ntp-keygen</code>
program prompts for the password if it reads an encrypted file
-and the password is missing or incorrect.
+and the password is missing or incorrect.
If an encrypted file is read successfully and
no write password is specified, the read password is used
as the write password by default.
-
- <p>The
+</p>
+<p>The
<code>pw</code>
option of the
<code>crypto</code>
<code>ntpd(1ntpdmdoc)</code>
configuration command specifies the read
-password for previously encrypted local files.
-This must match the local read password used by this program.
-If not specified, the host name is used.
+password for previously encrypted local files.
+This must match the local read password used by this program.
+If not specified, the host name is used.
Thus, if files are generated by this program without an explicit password,
they can be read back by
<code>ntpd(1ntpdmdoc)</code>
-without specifying an explicit password but only on the same host.
+without specifying an explicit password but only on the same host.
If the write password used for encryption is specified as the host name,
these files can be read by that host with no explicit password.
-
- <p>Normally, encrypted files for each host are generated by that host and
+</p>
+<p>Normally, encrypted files for each host are generated by that host and
used only by that host, although exceptions exist as noted later on
-this page.
+this page.
The symmetric keys file, normally called
-<span class="file">ntp.keys</span>,
+<samp>ntp.keys</samp>,
is usually installed in
-<span class="file">/etc</span>.
+<samp>/etc</samp>.
Other files and links are usually installed in
-<span class="file">/usr/local/etc</span>,
+<samp>/usr/local/etc</samp>,
which is normally in a shared filesystem in
-NFS-mounted networks and cannot be changed by shared clients.
+NFS-mounted networks and cannot be changed by shared clients.
In these cases, NFS clients can specify the files in another
directory such as
-<span class="file">/etc</span>
+<samp>/etc</samp>
using the
<code>keysdir</code>
<code>ntpd(1ntpdmdoc)</code>
configuration file command.
-
- <p>This program directs commentary and error messages to the standard
+</p>
+<p>This program directs commentary and error messages to the standard
error stream
-<span class="file">stderr</span>
+<samp>stderr</samp>
and remote files to the standard output stream
-<span class="file">stdout</span>
-where they can be piped to other applications or redirected to files.
+<samp>stdout</samp>
+where they can be piped to other applications or redirected to files.
The names used for generated files and links all begin with the
string
-<span class="file">ntpkey*</span>
+<samp>ntpkey*</samp>
and include the file type, generating host and filestamp,
as described in the
<a href="#Cryptographic-Data-Files">Cryptographic Data Files</a>
section below.
-
-<h5 class="subsubsection">Running the Program</h5>
-
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-usage" accesskey="1">ntp-keygen usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-imbits" accesskey="2">ntp-keygen imbits</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-certificate" accesskey="3">ntp-keygen certificate</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-cipher" accesskey="4">ntp-keygen cipher</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-id_002dkey" accesskey="5">ntp-keygen id-key</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-gq_002dparams" accesskey="6">ntp-keygen gq-params</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-host_002dkey" accesskey="7">ntp-keygen host-key</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-iffkey" accesskey="8">ntp-keygen iffkey</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-ident" accesskey="9">ntp-keygen ident</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-password">ntp-keygen password</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-config">ntp-keygen config</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-Bugs">ntp-keygen Bugs</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">
+</td></tr>
+</table>
+
+<a name="Running-the-Program-2"></a>
+<h4 class="subsection">1.2.1 Running the Program</h4>
<p>The safest way to run the
<code>ntp-keygen</code>
-program is logged in directly as root.
+program is logged in directly as root.
The recommended procedure is change to the
<kbd>keys</kbd>
directory, usually
-<span class="file">/usr/local/etc</span>,
+<samp>/usr/local/etc</samp>,
then run the program.
-
- <p>To test and gain experience with Autokey concepts, log in as root and
+</p>
+<p>To test and gain experience with Autokey concepts, log in as root and
change to the
<kbd>keys</kbd>
directory, usually
-<span class="file">/usr/local/etc</span>.
+<samp>/usr/local/etc</samp>.
When run for the first time, or if all files with names beginning with
-<span class="file">ntpkey*</span>
+<samp>ntpkey*</samp>
have been removed, use the
<code>ntp-keygen</code>
command without arguments to generate a default
@@ -348,23 +441,23 @@ command without arguments to generate a default
host key and matching
<code>RSA-MD5</code>
certificate file with expiration date one year hence,
-which is all that is necessary in many cases.
+which is all that is necessary in many cases.
The program also generates soft links from the generic names
-to the respective files.
+to the respective files.
If run again without options, the program uses the
existing keys and parameters and generates a new certificate file with
new expiration date one year hence, and soft link.
-
- <p>The host key is used to encrypt the cookie when required and so must be
+</p>
+<p>The host key is used to encrypt the cookie when required and so must be
<code>RSA</code>
-type.
-By default, the host key is also the sign key used to encrypt signatures.
+type.
+By default, the host key is also the sign key used to encrypt signatures.
When necessary, a different sign key can be specified and this can be
either
<code>RSA</code>
or
<code>DSA</code>
-type.
+type.
By default, the message digest type is
<code>MD5</code>,
but any combination
@@ -373,9 +466,9 @@ can be specified, including those using the
<code>AES128CMAC</code>, <code>MD2</code>, <code>MD5</code>, <code>MDC2</code>, <code>SHA</code>, <code>SHA1</code>
and
<code>RIPE160</code>
-message digest algorithms.
+message digest algorithms.
However, the scheme specified in the certificate must be compatible
-with the sign key.
+with the sign key.
Certificates using any digest algorithm are compatible with
<code>RSA</code>
sign keys;
@@ -386,96 +479,96 @@ and
certificates are compatible with
<code>DSA</code>
sign keys.
-
- <p>Private/public key files and certificates are compatible with
-other OpenSSL applications and very likely other libraries as well.
+</p>
+<p>Private/public key files and certificates are compatible with
+other OpenSSL applications and very likely other libraries as well.
Certificates or certificate requests derived from them should be compatible
with extant industry practice, although some users might find
-the interpretation of X509v3 extension fields somewhat liberal.
+the interpretation of X509v3 extension fields somewhat liberal.
However, the identification parameter files, although encoded
as the other files, are probably not compatible with anything other than Autokey.
-
- <p>Running the program as other than root and using the Unix
+</p>
+<p>Running the program as other than root and using the Unix
<code>su(1)</code>
command
to assume root may not work properly, since by default the OpenSSL library
looks for the random seed file
-<span class="file">.rnd</span>
-in the user home directory.
+<samp>.rnd</samp>
+in the user home directory.
However, there should be only one
-<span class="file">.rnd</span>,
+<samp>.rnd</samp>,
most conveniently
in the root directory, so it is convenient to define the
.Ev RANDFILE
environment variable used by the OpenSSL library as the path to
-<span class="file">.rnd</span>.
-
- <p>Installing the keys as root might not work in NFS-mounted
+<samp>.rnd</samp>.
+</p>
+<p>Installing the keys as root might not work in NFS-mounted
shared file systems, as NFS clients may not be able to write
-to the shared keys directory, even as root.
+to the shared keys directory, even as root.
In this case, NFS clients can specify the files in another
directory such as
-<span class="file">/etc</span>
+<samp>/etc</samp>
using the
<code>keysdir</code>
<code>ntpd(1ntpdmdoc)</code>
-configuration file command.
+configuration file command.
There is no need for one client to read the keys and certificates
of other clients or servers, as these data are obtained automatically
by the Autokey protocol.
-
- <p>Ordinarily, cryptographic files are generated by the host that uses them,
+</p>
+<p>Ordinarily, cryptographic files are generated by the host that uses them,
but it is possible for a trusted agent (TA) to generate these files
-for other hosts; however, in such cases files should always be encrypted.
+for other hosts; however, in such cases files should always be encrypted.
The subject name and trusted name default to the hostname
-of the host generating the files, but can be changed by command line options.
+of the host generating the files, but can be changed by command line options.
It is convenient to designate the owner name and trusted name
-as the subject and issuer fields, respectively, of the certificate.
+as the subject and issuer fields, respectively, of the certificate.
The owner name is also used for the host and sign key files,
while the trusted name is used for the identity files.
-
- <p>All files are installed by default in the keys directory
-<span class="file">/usr/local/etc</span>,
+</p>
+<p>All files are installed by default in the keys directory
+<samp>/usr/local/etc</samp>,
which is normally in a shared filesystem
-in NFS-mounted networks.
+in NFS-mounted networks.
The actual location of the keys directory
and each file can be overridden by configuration commands,
-but this is not recommended.
+but this is not recommended.
Normally, the files for each host are generated by that host
and used only by that host, although exceptions exist
as noted later on this page.
-
- <p>Normally, files containing private values,
+</p>
+<p>Normally, files containing private values,
including the host key, sign key and identification parameters,
are permitted root read/write-only;
-while others containing public values are permitted world readable.
+while others containing public values are permitted world readable.
Alternatively, files containing private values can be encrypted
and these files permitted world readable,
-which simplifies maintenance in shared file systems.
+which simplifies maintenance in shared file systems.
Since uniqueness is insured by the
<kbd>hostname</kbd>
and
<kbd>filestamp</kbd>
file name extensions, the files for an NTP server and
dependent clients can all be installed in the same shared directory.
-
- <p>The recommended practice is to keep the file name extensions
+</p>
+<p>The recommended practice is to keep the file name extensions
when installing a file and to install a soft link
from the generic names specified elsewhere on this page
-to the generated files.
+to the generated files.
This allows new file generations to be activated simply
-by changing the link.
+by changing the link.
If a link is present,
<code>ntpd(1ntpdmdoc)</code>
follows it to the file name to extract the
-<kbd>filestamp</kbd>.
+<kbd>filestamp</kbd>.
If a link is not present,
<code>ntpd(1ntpdmdoc)</code>
extracts the
<kbd>filestamp</kbd>
-from the file itself.
+from the file itself.
This allows clients to verify that the file and generation times
-are always current.
+are always current.
The
<code>ntp-keygen</code>
program uses the same
@@ -483,31 +576,31 @@ program uses the same
extension for all files generated
at one time, so each generation is distinct and can be readily
recognized in monitoring data.
-
- <p>Run the command on as many hosts as necessary.
+</p>
+<p>Run the command on as many hosts as necessary.
Designate one of them as the trusted host (TH) using
<code>ntp-keygen</code>
with the
<code>-T</code>
-option and configure it to synchronize from reliable Internet servers.
+option and configure it to synchronize from reliable Internet servers.
Then configure the other hosts to synchronize to the TH directly or
-indirectly.
+indirectly.
A certificate trail is created when Autokey asks the immediately
ascendant host towards the TH to sign its certificate, which is then
-provided to the immediately descendant host on request.
+provided to the immediately descendant host on request.
All group hosts should have acyclic certificate trails ending on the TH.
-
- <p>The host key is used to encrypt the cookie when required and so must be
-RSA type.
+</p>
+<p>The host key is used to encrypt the cookie when required and so must be
+RSA type.
By default, the host key is also the sign key used to encrypt
-signatures.
+signatures.
A different sign key can be assigned using the
<code>-S</code>
option and this can be either
<code>RSA</code>
or
<code>DSA</code>
-type.
+type.
By default, the signature
message digest type is
<code>MD5</code>,
@@ -516,26 +609,26 @@ message digest type supported by the OpenSSL library can be specified
using the
<code>-c</code>
option.
-
- <p>The rules say cryptographic media should be generated with proventic
+</p>
+<p>The rules say cryptographic media should be generated with proventic
filestamps, which means the host should already be synchronized before
-this program is run.
+this program is run.
This of course creates a chicken-and-egg problem
-when the host is started for the first time.
+when the host is started for the first time.
Accordingly, the host time
should be set by some other means, such as eyeball-and-wristwatch, at
-least so that the certificate lifetime is within the current year.
+least so that the certificate lifetime is within the current year.
After that and when the host is synchronized to a proventic source, the
certificate should be re-generated.
-
- <p>Additional information on trusted groups and identity schemes is on the
-Autokey Public-Key Authentication
+</p>
+<p>Additional information on trusted groups and identity schemes is on the
+&ldquo;Autokey Public-Key Authentication&rdquo;
page.
-
- <p>File names begin with the prefix
-<span class="file">ntpkey</span>_
+</p>
+<p>File names begin with the prefix
+<samp>ntpkey</samp>_
and end with the suffix
-<span class="file">_</span><kbd>hostname</kbd>. <kbd>filestamp</kbd>,
+<samp>_</samp><kbd>hostname</kbd>. <kbd>filestamp</kbd>,
where
<kbd>hostname</kbd>
is the owner name, usually the string returned
@@ -543,27 +636,27 @@ by the Unix
<code>hostname(1)</code>
command, and
<kbd>filestamp</kbd>
-is the NTP seconds when the file was generated, in decimal digits.
+is the NTP seconds when the file was generated, in decimal digits.
This both guarantees uniqueness and simplifies maintenance
procedures, since all files can be quickly removed
by a
-<code>rm</code> <span class="file">ntpkey*</span>
+<code>rm</code> <samp>ntpkey*</samp>
command or all files generated
at a specific time can be removed by a
-<code>rm</code> <span class="file">*</span><kbd>filestamp</kbd>
-command.
+<code>rm</code> <samp>*</samp><kbd>filestamp</kbd>
+command.
To further reduce the risk of misconfiguration,
the first two lines of a file contain the file name
and generation date and time as comments.
-
-<h5 class="subsubsection">Trusted Hosts and Groups</h5>
-
+</p>
+<a name="Trusted-Hosts-and-Groups"></a>
+<h4 class="subsubsection">1.2.1.1 Trusted Hosts and Groups</h4>
<p>Each cryptographic configuration involves selection of a signature scheme
and identification scheme, called a cryptotype,
as explained in the
-<a href="#Authentication-Options">Authentication Options</a>
+&lsquo;Authentication Options&rsquo;
section of
-<code>ntp.conf(5)</code>.
+<code>ntp.conf(5)</code>.
The default cryptotype uses
<code>RSA</code>
encryption,
@@ -571,39 +664,39 @@ encryption,
message digest
and
<code>TC</code>
-identification.
+identification.
First, configure a NTP subnet including one or more low-stratum
trusted hosts from which all other hosts derive synchronization
-directly or indirectly.
+directly or indirectly.
Trusted hosts have trusted certificates;
-all other hosts have nontrusted certificates.
+all other hosts have nontrusted certificates.
These hosts will automatically and dynamically build authoritative
-certificate trails to one or more trusted hosts.
+certificate trails to one or more trusted hosts.
A trusted group is the set of all hosts that have, directly or indirectly,
-a certificate trail ending at a trusted host.
+a certificate trail ending at a trusted host.
The trail is defined by static configuration file entries
or dynamic means described on the
-<a href="#Automatic-NTP-Configuration-Options">Automatic NTP Configuration Options</a>
+&lsquo;Automatic NTP Configuration Options&rsquo;
section of
<code>ntp.conf(5)</code>.
-
- <p>On each trusted host as root, change to the keys directory.
+</p>
+<p>On each trusted host as root, change to the keys directory.
To insure a fresh fileset, remove all
-<span class="file">ntpkey</span>
-files.
+<samp>ntpkey</samp>
+files.
Then run
<code>ntp-keygen</code>
<code>-T</code>
-to generate keys and a trusted certificate.
+to generate keys and a trusted certificate.
On all other hosts do the same, but leave off the
<code>-T</code>
-flag to generate keys and nontrusted certificates.
+flag to generate keys and nontrusted certificates.
When complete, start the NTP daemons beginning at the lowest stratum
-and working up the tree.
+and working up the tree.
It may take some time for Autokey to instantiate the certificate trails
throughout the subnet, but setting up the environment is completely automatic.
-
- <p>If it is necessary to use a different sign key or different digest/signature
+</p>
+<p>If it is necessary to use a different sign key or different digest/signature
scheme than the default, run
<code>ntp-keygen</code>
with the
@@ -613,10 +706,10 @@ option, where
is either
<code>RSA</code>
or
-<code>DSA</code>.
+<code>DSA</code>.
The most frequent need to do this is when a
<code>DSA</code>-signed
-certificate is used.
+certificate is used.
If it is necessary to use a different certificate scheme than the default,
run
<code>ntp-keygen</code>
@@ -624,83 +717,83 @@ with the
<code>-c</code> <kbd>scheme</kbd>
option and selected
<kbd>scheme</kbd>
-as needed.
+as needed.
If
<code>ntp-keygen</code>
is run again without these options, it generates a new certificate
using the same scheme and sign key, and soft link.
-
- <p>After setting up the environment it is advisable to update certificates
-from time to time, if only to extend the validity interval.
+</p>
+<p>After setting up the environment it is advisable to update certificates
+from time to time, if only to extend the validity interval.
Simply run
<code>ntp-keygen</code>
with the same flags as before to generate new certificates
-using existing keys, and soft links.
+using existing keys, and soft links.
However, if the host or sign key is changed,
<code>ntpd(1ntpdmdoc)</code>
-should be restarted.
+should be restarted.
When
<code>ntpd(1ntpdmdoc)</code>
-is restarted, it loads any new files and restarts the protocol.
+is restarted, it loads any new files and restarts the protocol.
Other dependent hosts will continue as usual until signatures are refreshed,
at which time the protocol is restarted.
-
-<h5 class="subsubsection">Identity Schemes</h5>
-
+</p>
+<a name="Identity-Schemes"></a>
+<h4 class="subsubsection">1.2.1.2 Identity Schemes</h4>
<p>As mentioned on the Autonomous Authentication page,
the default
<code>TC</code>
-identity scheme is vulnerable to a middleman attack.
+identity scheme is vulnerable to a middleman attack.
However, there are more secure identity schemes available,
including
<code>PC</code>, <code>IFF</code>, <code>GQ</code>
and
<code>MV</code>
-schemes described below.
+schemes described below.
These schemes are based on a TA, one or more trusted hosts
-and some number of nontrusted hosts.
+and some number of nontrusted hosts.
Trusted hosts prove identity using values provided by the TA,
while the remaining hosts prove identity using values provided
-by a trusted host and certificate trails that end on that host.
+by a trusted host and certificate trails that end on that host.
The name of a trusted host is also the name of its sugroup
-and also the subject and issuer name on its trusted certificate.
+and also the subject and issuer name on its trusted certificate.
The TA is not necessarily a trusted host in this sense, but often is.
-
- <p>In some schemes there are separate keys for servers and clients.
+</p>
+<p>In some schemes there are separate keys for servers and clients.
A server can also be a client of another server,
-but a client can never be a server for another client.
+but a client can never be a server for another client.
In general, trusted hosts and nontrusted hosts that operate
as both server and client have parameter files that contain
-both server and client keys.
+both server and client keys.
Hosts that operate
only as clients have key files that contain only client keys.
-
- <p>The PC scheme supports only one trusted host in the group.
+</p>
+<p>The PC scheme supports only one trusted host in the group.
On trusted host alice run
<code>ntp-keygen</code>
<code>-P</code>
<code>-p</code> <kbd>password</kbd>
to generate the host key file
-<span class="file">ntpkey</span>_ <code>RSA</code> <span class="file">key_alice.</span> <kbd>filestamp</kbd>
+<samp>ntpkey</samp>_ <code>RSA</code> <samp>key_alice.</samp> <kbd>filestamp</kbd>
and trusted private certificate file
-<span class="file">ntpkey</span>_ <code>RSA-MD5</code> <code>_</code> <span class="file">cert_alice.</span> <kbd>filestamp</kbd>,
-and soft links.
+<samp>ntpkey</samp>_ <code>RSA-MD5</code> <code>_</code> <samp>cert_alice.</samp> <kbd>filestamp</kbd>,
+and soft links.
Copy both files to all group hosts;
-they replace the files which would be generated in other schemes.
+they replace the files which would be generated in other schemes.
On each host
<kbd>bob</kbd>
install a soft link from the generic name
-<span class="file">ntpkey_host_</span><kbd>bob</kbd>
+<samp>ntpkey_host_</samp><kbd>bob</kbd>
to the host key file and soft link
-<span class="file">ntpkey_cert_</span><kbd>bob</kbd>
-to the private certificate file.
+<samp>ntpkey_cert_</samp><kbd>bob</kbd>
+to the private certificate file.
Note the generic links are on bob, but point to files generated
-by trusted host alice.
+by trusted host alice.
In this scheme it is not possible to refresh
either the keys or certificates without copying them
to all other hosts in the group, and recreating the soft links.
-
- <p>For the
+</p>
+<p>For the
<code>IFF</code>
scheme proceed as in the
<code>TC</code>
@@ -708,42 +801,42 @@ scheme to generate keys
and certificates for all group hosts, then for every trusted host in the group,
generate the
<code>IFF</code>
-parameter file.
+parameter file.
On trusted host alice run
<code>ntp-keygen</code>
<code>-T</code>
<code>-I</code>
<code>-p</code> <kbd>password</kbd>
to produce her parameter file
-<span class="file">ntpkey_IFFpar_alice.</span><kbd>filestamp</kbd>,
-which includes both server and client keys.
+<samp>ntpkey_IFFpar_alice.</samp><kbd>filestamp</kbd>,
+which includes both server and client keys.
Copy this file to all group hosts that operate as both servers
and clients and install a soft link from the generic
-<span class="file">ntpkey_iff_alice</span>
-to this file.
+<samp>ntpkey_iff_alice</samp>
+to this file.
If there are no hosts restricted to operate only as clients,
-there is nothing further to do.
+there is nothing further to do.
As the
<code>IFF</code>
scheme is independent
of keys and certificates, these files can be refreshed as needed.
-
- <p>If a rogue client has the parameter file, it could masquerade
-as a legitimate server and present a middleman threat.
+</p>
+<p>If a rogue client has the parameter file, it could masquerade
+as a legitimate server and present a middleman threat.
To eliminate this threat, the client keys can be extracted
-from the parameter file and distributed to all restricted clients.
+from the parameter file and distributed to all restricted clients.
After generating the parameter file, on alice run
<code>ntp-keygen</code>
<code>-e</code>
-and pipe the output to a file or email program.
-Copy or email this file to all restricted clients.
+and pipe the output to a file or email program.
+Copy or email this file to all restricted clients.
On these clients install a soft link from the generic
-<span class="file">ntpkey_iff_alice</span>
-to this file.
+<samp>ntpkey_iff_alice</samp>
+to this file.
To further protect the integrity of the keys,
each file can be encrypted with a secret password.
-
- <p>For the
+</p>
+<p>For the
<code>GQ</code>
scheme proceed as in the
<code>TC</code>
@@ -751,40 +844,40 @@ scheme to generate keys
and certificates for all group hosts, then for every trusted host
in the group, generate the
<code>IFF</code>
-parameter file.
+parameter file.
On trusted host alice run
<code>ntp-keygen</code>
<code>-T</code>
<code>-G</code>
<code>-p</code> <kbd>password</kbd>
to produce her parameter file
-<span class="file">ntpkey_GQpar_alice.</span><kbd>filestamp</kbd>,
-which includes both server and client keys.
+<samp>ntpkey_GQpar_alice.</samp><kbd>filestamp</kbd>,
+which includes both server and client keys.
Copy this file to all group hosts and install a soft link
from the generic
-<span class="file">ntpkey_gq_alice</span>
-to this file.
+<samp>ntpkey_gq_alice</samp>
+to this file.
In addition, on each host
<kbd>bob</kbd>
install a soft link
from generic
-<span class="file">ntpkey_gq_</span><kbd>bob</kbd>
-to this file.
+<samp>ntpkey_gq_</samp><kbd>bob</kbd>
+to this file.
As the
<code>GQ</code>
scheme updates the
<code>GQ</code>
parameters file and certificate
at the same time, keys and certificates can be regenerated as needed.
-
- <p>For the
+</p>
+<p>For the
<code>MV</code>
scheme, proceed as in the
<code>TC</code>
scheme to generate keys
-and certificates for all group hosts.
+and certificates for all group hosts.
For illustration assume trish is the TA, alice one of several trusted hosts
-and bob one of her clients.
+and bob one of her clients.
On TA trish run
<code>ntp-keygen</code>
<code>-V</code> <kbd>n</kbd>
@@ -793,49 +886,52 @@ where
<kbd>n</kbd>
is the number of revokable keys (typically 5) to produce
the parameter file
-<span class="file">ntpkeys_MVpar_trish.</span><kbd>filestamp</kbd>
+<samp>ntpkeys_MVpar_trish.</samp><kbd>filestamp</kbd>
and client key files
-<span class="file">ntpkeys_MVkey</span><kbd>d</kbd> <kbd>_</kbd> <span class="file">trish.</span> <kbd>filestamp</kbd>
+<samp>ntpkeys_MVkey</samp><kbd>d</kbd> <kbd>_</kbd> <samp>trish.</samp> <kbd>filestamp</kbd>
where
<kbd>d</kbd>
is the key number (0 &lt;
<kbd>d</kbd>
&lt;
-<kbd>n</kbd>).
+<kbd>n</kbd>).
Copy the parameter file to alice and install a soft link
from the generic
-<span class="file">ntpkey_mv_alice</span>
-to this file.
+<samp>ntpkey_mv_alice</samp>
+to this file.
Copy one of the client key files to alice for later distribution
-to her clients.
+to her clients.
It does not matter which client key file goes to alice,
-since they all work the same way.
-Alice copies the client key file to all of her clients.
+since they all work the same way.
+Alice copies the client key file to all of her clients.
On client bob install a soft link from generic
-<span class="file">ntpkey_mvkey_bob</span>
-to the client key file.
+<samp>ntpkey_mvkey_bob</samp>
+to the client key file.
As the
<code>MV</code>
scheme is independent of keys and certificates,
these files can be refreshed as needed.
-
-<h5 class="subsubsection">Command Line Options</h5>
-
- <dl>
-<dt><code>-b</code> <code>--imbits</code>= <kbd>modulus</kbd><dd>Set the number of bits in the identity modulus for generating identity keys to
+</p>
+<a name="Command-Line-Options"></a>
+<h4 class="subsubsection">1.2.1.3 Command Line Options</h4>
+<dl compact="compact">
+<dt><code>-b</code> <code>--imbits</code>= <kbd>modulus</kbd></dt>
+<dd><p>Set the number of bits in the identity modulus for generating identity keys to
<kbd>modulus</kbd>
-bits.
+bits.
The number of bits in the identity modulus defaults to 256, but can be set to
-values from 256 to 2048 (32 to 256 octets).
+values from 256 to 2048 (32 to 256 octets).
Use the larger moduli with caution, as this can consume considerable computing
-resources and increases the size of authenticated packets.
-<br><dt><code>-c</code> <code>--certificate</code>= <kbd>scheme</kbd><dd>Select certificate signature encryption/message digest scheme.
+resources and increases the size of authenticated packets.
+</p></dd>
+<dt><code>-c</code> <code>--certificate</code>= <kbd>scheme</kbd></dt>
+<dd><p>Select certificate signature encryption/message digest scheme.
The
<kbd>scheme</kbd>
can be one of the following:
<code>RSA-MD2</code>, <code>RSA-MD5</code>, <code>RSA-MDC2</code>, <code>RSA-SHA</code>, <code>RSA-SHA1</code>, <code>RSA-RIPEMD160</code>, <code>DSA-SHA</code>,
or
-<code>DSA-SHA1</code>.
+<code>DSA-SHA1</code>.
Note that
<code>RSA</code>
schemes must be used with an
@@ -844,26 +940,34 @@ sign key and
<code>DSA</code>
schemes must be used with a
<code>DSA</code>
-sign key.
+sign key.
The default without this option is
-<code>RSA-MD5</code>.
+<code>RSA-MD5</code>.
If compatibility with FIPS 140-2 is required, either the
<code>DSA-SHA</code>
or
<code>DSA-SHA1</code>
-scheme must be used.
-<br><dt><code>-C</code> <code>--cipher</code>= <kbd>cipher</kbd><dd>Select the OpenSSL cipher to encrypt the files containing private keys.
+scheme must be used.
+</p></dd>
+<dt><code>-C</code> <code>--cipher</code>= <kbd>cipher</kbd></dt>
+<dd><p>Select the OpenSSL cipher to encrypt the files containing private keys.
The default without this option is three-key triple DES in CBC mode,
-<code>des-ede3-cbc</code>.
+<code>des-ede3-cbc</code>.
The
<code>openssl</code> <code>-h</code>
-command provided with OpenSSL displays available ciphers.
-<br><dt><code>-d</code> <code>--debug-level</code><dd>Increase debugging verbosity level.
-This option displays the cryptographic data produced in eye-friendly billboards.
-<br><dt><code>-D</code> <code>--set-debug-level</code>= <kbd>level</kbd><dd>Set the debugging verbosity to
-<kbd>level</kbd>.
-This option displays the cryptographic data produced in eye-friendly billboards.
-<br><dt><code>-e</code> <code>--id-key</code><dd>Write the
+command provided with OpenSSL displays available ciphers.
+</p></dd>
+<dt><code>-d</code> <code>--debug-level</code></dt>
+<dd><p>Increase debugging verbosity level.
+This option displays the cryptographic data produced in eye-friendly billboards.
+</p></dd>
+<dt><code>-D</code> <code>--set-debug-level</code>= <kbd>level</kbd></dt>
+<dd><p>Set the debugging verbosity to
+<kbd>level</kbd>.
+This option displays the cryptographic data produced in eye-friendly billboards.
+</p></dd>
+<dt><code>-e</code> <code>--id-key</code></dt>
+<dd><p>Write the
<code>IFF</code>
or
<code>GQ</code>
@@ -871,168 +975,197 @@ public parameters from the
<kbd>IFFkey</kbd> <kbd>or</kbd> <kbd>GQkey</kbd>
client keys file previously specified
as unencrypted data to the standard output stream
-<span class="file">stdout</span>.
-This is intended for automatic key distribution by email.
-<br><dt><code>-G</code> <code>--gq-params</code><dd>Generate a new encrypted
+<samp>stdout</samp>.
+This is intended for automatic key distribution by email.
+</p></dd>
+<dt><code>-G</code> <code>--gq-params</code></dt>
+<dd><p>Generate a new encrypted
<code>GQ</code>
-parameters and key file for the Guillou-Quisquater (GQ) identity scheme.
+parameters and key file for the Guillou-Quisquater (GQ) identity scheme.
This option is mutually exclusive with the
<code>-I</code>
and
<code>-V</code>
-options.
-<br><dt><code>-H</code> <code>--host-key</code><dd>Generate a new encrypted
+options.
+</p></dd>
+<dt><code>-H</code> <code>--host-key</code></dt>
+<dd><p>Generate a new encrypted
<code>RSA</code>
-public/private host key file.
-<br><dt><code>-I</code> <code>--iffkey</code><dd>Generate a new encrypted
+public/private host key file.
+</p></dd>
+<dt><code>-I</code> <code>--iffkey</code></dt>
+<dd><p>Generate a new encrypted
<code>IFF</code>
-key file for the Schnorr (IFF) identity scheme.
+key file for the Schnorr (IFF) identity scheme.
This option is mutually exclusive with the
<code>-G</code>
and
Fl V
-options.
-<br><dt><code>-i</code> <code>--ident</code>= <kbd>group</kbd><dd>Set the optional Autokey group name to
-<kbd>group</kbd>.
+options.
+</p></dd>
+<dt><code>-i</code> <code>--ident</code>= <kbd>group</kbd></dt>
+<dd><p>Set the optional Autokey group name to
+<kbd>group</kbd>.
This is used in the identity scheme parameter file names of
<code>IFF</code>, <code>GQ</code>,
and
<code>MV</code>
-client parameters files.
-In that role, the default is the host name if no group is provided.
+client parameters files.
+In that role, the default is the host name if no group is provided.
The group name, if specified using
<code>-i</code>
or
<code>-s</code>
following an
-@
+&lsquo;@&rsquo;
character, is also used in certificate subject and issuer names in the form
<kbd>host</kbd> <kbd>@</kbd> <kbd>group</kbd>
and should match the group specified via
<code>crypto</code> <code>ident</code>
or
<code>server</code> <code>ident</code>
-in the ntpd configuration file.
-<br><dt><code>-l</code> <code>--lifetime</code>= <kbd>days</kbd><dd>Set the lifetime for certificate expiration to
-<kbd>days</kbd>.
-The default lifetime is one year (365 days).
-<br><dt><code>-m</code> <code>--modulus</code>= <kbd>bits</kbd><dd>Set the number of bits in the prime modulus for generating files to
-<kbd>bits</kbd>.
-The modulus defaults to 512, but can be set from 256 to 2048 (32 to 256 octets).
+in the ntpd configuration file.
+</p></dd>
+<dt><code>-l</code> <code>--lifetime</code>= <kbd>days</kbd></dt>
+<dd><p>Set the lifetime for certificate expiration to
+<kbd>days</kbd>.
+The default lifetime is one year (365 days).
+</p></dd>
+<dt><code>-m</code> <code>--modulus</code>= <kbd>bits</kbd></dt>
+<dd><p>Set the number of bits in the prime modulus for generating files to
+<kbd>bits</kbd>.
+The modulus defaults to 512, but can be set from 256 to 2048 (32 to 256 octets).
Use the larger moduli with caution, as this can consume considerable computing
-resources and increases the size of authenticated packets.
-<br><dt><code>-M</code> <code>--md5key</code><dd>Generate a new symmetric keys file containing 10
+resources and increases the size of authenticated packets.
+</p></dd>
+<dt><code>-M</code> <code>--md5key</code></dt>
+<dd><p>Generate a new symmetric keys file containing 10
<code>MD5</code>
keys, and if OpenSSL is available, 10
<code>SHA</code>
-keys.
+keys.
An
<code>MD5</code>
key is a string of 20 random printable ASCII characters, while a
<code>SHA</code>
-key is a string of 40 random hex digits.
-The file can be edited using a text editor to change the key type or key content.
-This option is mutually exclusive with all other options.
-<br><dt><code>-p</code> <code>--password</code>= <kbd>passwd</kbd><dd>Set the password for reading and writing encrypted files to
-<kbd>passwd</kbd>.
-These include the host, sign and identify key files.
+key is a string of 40 random hex digits.
+The file can be edited using a text editor to change the key type or key content.
+This option is mutually exclusive with all other options.
+</p></dd>
+<dt><code>-p</code> <code>--password</code>= <kbd>passwd</kbd></dt>
+<dd><p>Set the password for reading and writing encrypted files to
+<kbd>passwd</kbd>.
+These include the host, sign and identify key files.
By default, the password is the string returned by the Unix
<code>hostname</code>
-command.
-<br><dt><code>-P</code> <code>--pvt-cert</code><dd>Generate a new private certificate used by the
+command.
+</p></dd>
+<dt><code>-P</code> <code>--pvt-cert</code></dt>
+<dd><p>Generate a new private certificate used by the
<code>PC</code>
-identity scheme.
-By default, the program generates public certificates.
-Note: the PC identity scheme is not recommended for new installations.
-<br><dt><code>-q</code> <code>--export-passwd</code>= <kbd>passwd</kbd><dd>Set the password for writing encrypted
+identity scheme.
+By default, the program generates public certificates.
+Note: the PC identity scheme is not recommended for new installations.
+</p></dd>
+<dt><code>-q</code> <code>--export-passwd</code>= <kbd>passwd</kbd></dt>
+<dd><p>Set the password for writing encrypted
<code>IFF</code>, <code>GQ</code> <code>and</code> <code>MV</code>
identity files redirected to
-<span class="file">stdout</span>
+<samp>stdout</samp>
to
-<kbd>passwd</kbd>.
+<kbd>passwd</kbd>.
In effect, these files are decrypted with the
<code>-p</code>
password, then encrypted with the
<code>-q</code>
-password.
+password.
By default, the password is the string returned by the Unix
<code>hostname</code>
-command.
-<br><dt><code>-s</code> <code>--subject-key</code>= <code>[host]</code> <code>[@ </code><kbd>group</kbd><code>]</code><dd>Specify the Autokey host name, where
+command.
+</p></dd>
+<dt><code>-s</code> <code>--subject-key</code>= <code>[host]</code> <code>[@ <kbd>group</kbd>]</code></dt>
+<dd><p>Specify the Autokey host name, where
<kbd>host</kbd>
is the optional host name and
<kbd>group</kbd>
-is the optional group name.
+is the optional group name.
The host name, and if provided, group name are used in
<kbd>host</kbd> <kbd>@</kbd> <kbd>group</kbd>
-form as certificate subject and issuer.
+form as certificate subject and issuer.
Specifying
<code>-s</code> <code>-@</code> <kbd>group</kbd>
is allowed, and results in leaving the host name unchanged, as with
-<code>-i</code> <kbd>group</kbd>.
+<code>-i</code> <kbd>group</kbd>.
The group name, or if no group is provided, the host name are also used in the
file names of
<code>IFF</code>, <code>GQ</code>,
and
<code>MV</code>
-identity scheme client parameter files.
+identity scheme client parameter files.
If
<kbd>host</kbd>
is not specified, the default host name is the string returned by the Unix
<code>hostname</code>
-command.
-<br><dt><code>-S</code> <code>--sign-key</code>= <code>[RSA | DSA]</code><dd>Generate a new encrypted public/private sign key file of the specified type.
-By default, the sign key is the host key and has the same type.
+command.
+</p></dd>
+<dt><code>-S</code> <code>--sign-key</code>= <code>[<code>RSA</code> | <code>DSA</code>]</code></dt>
+<dd><p>Generate a new encrypted public/private sign key file of the specified type.
+By default, the sign key is the host key and has the same type.
If compatibility with FIPS 140-2 is required, the sign key type must be
-<code>DSA</code>.
-<br><dt><code>-T</code> <code>--trusted-cert</code><dd>Generate a trusted certificate.
-By default, the program generates a non-trusted certificate.
-<br><dt><code>-V</code> <code>--mv-params</code> <kbd>nkeys</kbd><dd>Generate
+<code>DSA</code>.
+</p></dd>
+<dt><code>-T</code> <code>--trusted-cert</code></dt>
+<dd><p>Generate a trusted certificate.
+By default, the program generates a non-trusted certificate.
+</p></dd>
+<dt><code>-V</code> <code>--mv-params</code> <kbd>nkeys</kbd></dt>
+<dd><p>Generate
<kbd>nkeys</kbd>
encrypted server keys and parameters for the Mu-Varadharajan (MV)
-identity scheme.
+identity scheme.
This option is mutually exclusive with the
<code>-I</code>
and
<code>-G</code>
-options.
-Note: support for this option should be considered a work in progress.
+options.
+Note: support for this option should be considered a work in progress.
+</p></dd>
</dl>
-<h5 class="subsubsection">Random Seed File</h5>
-
+<a name="Random-Seed-File-1"></a>
+<h4 class="subsubsection">1.2.1.4 Random Seed File</h4>
<p>All cryptographically sound key generation schemes must have means
to randomize the entropy seed used to initialize
the internal pseudo-random number generator used
-by the library routines.
-The OpenSSL library uses a designated random seed file for this purpose.
+by the library routines.
+The OpenSSL library uses a designated random seed file for this purpose.
The file must be available when starting the NTP daemon and
<code>ntp-keygen</code>
-program.
+program.
If a site supports OpenSSL or its companion OpenSSH,
it is very likely that means to do this are already available.
-
- <p>It is important to understand that entropy must be evolved
+</p>
+<p>It is important to understand that entropy must be evolved
for each generation, for otherwise the random number sequence
-would be predictable.
+would be predictable.
Various means dependent on external events, such as keystroke intervals,
-can be used to do this and some systems have built-in entropy sources.
+can be used to do this and some systems have built-in entropy sources.
Suitable means are described in the OpenSSL software documentation,
but are outside the scope of this page.
-
- <p>The entropy seed used by the OpenSSL library is contained in a file,
+</p>
+<p>The entropy seed used by the OpenSSL library is contained in a file,
usually called
-<span class="file">.rnd</span>,
+<samp>.rnd</samp>,
which must be available when starting the NTP daemon
or the
<code>ntp-keygen</code>
-program.
+program.
The NTP daemon will first look for the file
using the path specified by the
<code>randfile</code>
subcommand of the
<code>crypto</code>
-configuration command.
+configuration command.
If not specified in this way, or when starting the
<code>ntp-keygen</code>
program,
@@ -1040,77 +1173,76 @@ the OpenSSL library will look for the file using the path specified
by the
.Ev RANDFILE
environment variable in the user home directory,
-whether root or some other user.
+whether root or some other user.
If the
.Ev RANDFILE
environment variable is not present,
the library will look for the
-<span class="file">.rnd</span>
-file in the user home directory.
+<samp>.rnd</samp>
+file in the user home directory.
Since both the
<code>ntp-keygen</code>
program and
<code>ntpd(1ntpdmdoc)</code>
daemon must run as root, the logical place to put this file is in
-<span class="file">/.rnd</span>
+<samp>/.rnd</samp>
or
-<span class="file">/root/.rnd</span>.
+<samp>/root/.rnd</samp>.
If the file is not available or cannot be written,
the daemon exits with a message to the system log and the program
exits with a suitable error message.
-
-<h5 class="subsubsection">Cryptographic Data Files</h5>
-
-<p>All file formats begin with two nonencrypted lines.
+</p>
+<a name="Cryptographic-Data-Files-1"></a>
+<h4 class="subsubsection">1.2.1.5 Cryptographic Data Files</h4>
+<p>All file formats begin with two nonencrypted lines.
The first line contains the file name, including the generated host name
and filestamp, in the format
-<span class="file">ntpkey_</span><kbd>key</kbd> <kbd>_</kbd> <kbd>name</kbd>. <kbd>filestamp</kbd>,
+<samp>ntpkey_</samp><kbd>key</kbd> <kbd>_</kbd> <kbd>name</kbd>. <kbd>filestamp</kbd>,
where
<kbd>key</kbd>
is the key or parameter type,
<kbd>name</kbd>
is the host or group name and
<kbd>filestamp</kbd>
-is the filestamp (NTP seconds) when the file was created.
+is the filestamp (NTP seconds) when the file was created.
By convention,
<kbd>key</kbd>
names in generated file names include both upper and lower case
characters, while
<kbd>key</kbd>
-names in generated link names include only lower case characters.
-The filestamp is not used in generated link names.
+names in generated link names include only lower case characters.
+The filestamp is not used in generated link names.
The second line contains the datestamp in conventional Unix
-<span class="file">date</span>
-format.
+<samp>date</samp>
+format.
Lines beginning with
-#
+&lsquo;#&rsquo;
are considered comments and ignored by the
<code>ntp-keygen</code>
program and
<code>ntpd(1ntpdmdoc)</code>
daemon.
-
- <p>The remainder of the file contains cryptographic data, encoded first using ASN.1
+</p>
+<p>The remainder of the file contains cryptographic data, encoded first using ASN.1
rules, then encrypted if necessary, and finally written in PEM-encoded
printable ASCII text, preceded and followed by MIME content identifier lines.
-
- <p>The format of the symmetric keys file, ordinarily named
-<span class="file">ntp.keys</span>,
-is somewhat different than the other files in the interest of backward compatibility.
+</p>
+<p>The format of the symmetric keys file, ordinarily named
+<samp>ntp.keys</samp>,
+is somewhat different than the other files in the interest of backward compatibility.
Ordinarily, the file is generated by this program, but it can be constructed
and edited using an ordinary text editor.
-<pre class="verbatim">
-# ntpkey_MD5key_bk.ntp.org.3595864945
+</p><pre class="verbatim"># ntpkey_MD5key_bk.ntp.org.3595864945
# Thu Dec 12 19:22:25 2013
-1 MD5 L";Nw&lt;\`.I&lt;f4U0)247"i # MD5 key
-2 MD5 &amp;>l0%XXK9O'51VwV&lt;xq~ # MD5 key
+1 MD5 L&quot;;Nw&lt;\`.I&lt;f4U0)247&quot;i # MD5 key
+2 MD5 &amp;&gt;l0%XXK9O'51VwV&lt;xq~ # MD5 key
3 MD5 lb4zLW~d^!K:]RsD'qb6 # MD5 key
4 MD5 Yue:tL[+vR)M\`n~bY,'? # MD5 key
5 MD5 B;fx'Kgr/&amp;4ZTbL6=RxA # MD5 key
6 MD5 4eYwa\`o@}3i@@@@V@@..R9!l # MD5 key
7 MD5 \`A.([h+;wTQ|xfi%Sn_! # MD5 key
-8 MD5 45:V,r4]l6y^JH6"Sh?F # MD5 key
+8 MD5 45:V,r4]l6y^JH6&quot;Sh?F # MD5 key
9 MD5 3-5vcn*6l29DS?Xdsg)* # MD5 key
10 MD5 2late4Me # MD5 key
11 SHA1 a27872d3030a9025b8446c751b4551a7629af65c # SHA1 key
@@ -1123,17 +1255,19 @@ and edited using an ordinary text editor.
18 MDC2 a8d5e2315c025bf3a79174c87fbd10477de2eabc # MDC2 key
19 RIPEMD160 77ca332cafb30e3cafb174dcd5b80ded7ba9b3d2 # RIPEMD160 key
20 AES128CMAC f92ff73eee86c1e7dc638d6489a04e4e555af878 # AES128CMAC key
-</pre>
-<pre class="example"> Figure 1. Typical Symmetric Key File
-</pre>
- <p>Figure 1 shows a typical symmetric keys file used by the reference
-implementation.
+</pre><div class="example">
+<pre class="example">Figure 1. Typical Symmetric Key File
+</pre></div>
+
+<p>Figure 1 shows a typical symmetric keys file used by the reference
+implementation.
Following the header the keys are entered one per line in the format
-<pre class="example"> <kbd>keyno</kbd> <kbd>type</kbd> <kbd>key</kbd>
-</pre>
- <p>where
+</p><div class="example">
+<pre class="example"><kbd>keyno</kbd> <kbd>type</kbd> <kbd>key</kbd>
+</pre></div>
+<p>where
<kbd>keyno</kbd>
-is a positive integer in the range 1-65534;
+is a positive integer in the range 1-65535;
<kbd>type</kbd>
is the key type for the message digest algorithm, which in the absence of the
OpenSSL library must be
@@ -1151,18 +1285,18 @@ is the key itself,
which is a printable ASCII string 20 characters or less in length:
each character is chosen from the 93 printable characters
in the range 0x21 through 0x7e (
-!
+&lsquo;&rsquo;!
through
-~
+&lsquo;~&rsquo;
) excluding space and the
-#
+&lsquo;#&rsquo;
character, and terminated by whitespace or a
-#
-character.
+&lsquo;#&rsquo;
+character.
An OpenSSL key consists of a hex-encoded ASCII string of 40 characters, which
is truncated as necessary.
-
- <p>Note that the keys used by the
+</p>
+<p>Note that the keys used by the
<code>ntpq(1ntpqmdoc)</code>
and
<code>ntpdc(1ntpdcmdoc)</code>
@@ -1170,21 +1304,21 @@ programs
are checked against passwords requested by the programs
and entered by hand, so it is generally appropriate to specify these keys
in human readable ASCII format.
-
- <p>The
+</p>
+<p>The
<code>ntp-keygen</code>
program generates a symmetric keys file
-<span class="file">ntpkey_MD5key_</span><kbd>hostname</kbd>. <kbd>filestamp</kbd>.
+<samp>ntpkey_MD5key_</samp><kbd>hostname</kbd>. <kbd>filestamp</kbd>.
Since the file contains private shared keys,
it should be visible only to root and distributed by secure means
-to other subnet hosts.
+to other subnet hosts.
The NTP daemon loads the file
-<span class="file">ntp.keys</span>,
+<samp>ntp.keys</samp>,
so
<code>ntp-keygen</code>
-installs a soft link from this name to the generated file.
+installs a soft link from this name to the generated file.
Subsequently, similar soft links must be installed by manual
-or automated means on the other subnet hosts.
+or automated means on the other subnet hosts.
While this file is not used with the Autokey Version 2 protocol,
it is needed to authenticate some remote configuration commands
used by the
@@ -1192,60 +1326,86 @@ used by the
and
<code>ntpdc(1ntpdcmdoc)</code>
utilities.
-
- <p>This section was generated by <strong>AutoGen</strong>,
-using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp-keygen</code> program.
+</p>
+<p>This section was generated by <strong>AutoGen</strong>,
+using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp-keygen</code> program.
This software is released under the NTP license, &lt;http://ntp.org/license&gt;.
-
-<ul class="menu">
-<li><a accesskey="1" href="#ntp_002dkeygen-usage">ntp-keygen usage</a>: ntp-keygen help/usage (<span class="option">--help</span>)
-<li><a accesskey="2" href="#ntp_002dkeygen-imbits">ntp-keygen imbits</a>: imbits option (-b)
-<li><a accesskey="3" href="#ntp_002dkeygen-certificate">ntp-keygen certificate</a>: certificate option (-c)
-<li><a accesskey="4" href="#ntp_002dkeygen-cipher">ntp-keygen cipher</a>: cipher option (-C)
-<li><a accesskey="5" href="#ntp_002dkeygen-id_002dkey">ntp-keygen id-key</a>: id-key option (-e)
-<li><a accesskey="6" href="#ntp_002dkeygen-gq_002dparams">ntp-keygen gq-params</a>: gq-params option (-G)
-<li><a accesskey="7" href="#ntp_002dkeygen-host_002dkey">ntp-keygen host-key</a>: host-key option (-H)
-<li><a accesskey="8" href="#ntp_002dkeygen-iffkey">ntp-keygen iffkey</a>: iffkey option (-I)
-<li><a accesskey="9" href="#ntp_002dkeygen-ident">ntp-keygen ident</a>: ident option (-i)
-<li><a href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>: lifetime option (-l)
-<li><a href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>: modulus option (-m)
-<li><a href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>: md5key option (-M)
-<li><a href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>: pvt-cert option (-P)
-<li><a href="#ntp_002dkeygen-password">ntp-keygen password</a>: password option (-p)
-<li><a href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>: export-passwd option (-q)
-<li><a href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>: subject-name option (-s)
-<li><a href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>: sign-key option (-S)
-<li><a href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>: trusted-cert option (-T)
-<li><a href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>: mv-params option (-V)
-<li><a href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>: mv-keys option (-v)
-<li><a href="#ntp_002dkeygen-config">ntp-keygen config</a>: presetting/configuring ntp-keygen
-<li><a href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>: exit status
-<li><a href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>: Usage
-<li><a href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>: Notes
-<li><a href="#ntp_002dkeygen-Bugs">ntp-keygen Bugs</a>: Bugs
-</ul>
-
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-imbits">ntp-keygen imbits</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-usage" accesskey="1">ntp-keygen usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ntp-keygen help/usage (<samp>--help</samp>)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-imbits" accesskey="2">ntp-keygen imbits</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">imbits option (-b)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-certificate" accesskey="3">ntp-keygen certificate</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">certificate option (-c)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-cipher" accesskey="4">ntp-keygen cipher</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">cipher option (-C)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-id_002dkey" accesskey="5">ntp-keygen id-key</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">id-key option (-e)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-gq_002dparams" accesskey="6">ntp-keygen gq-params</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">gq-params option (-G)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-host_002dkey" accesskey="7">ntp-keygen host-key</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">host-key option (-H)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-iffkey" accesskey="8">ntp-keygen iffkey</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">iffkey option (-I)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-ident" accesskey="9">ntp-keygen ident</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">ident option (-i)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">lifetime option (-l)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">modulus option (-m)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">md5key option (-M)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">pvt-cert option (-P)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-password">ntp-keygen password</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">password option (-p)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">export-passwd option (-q)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">subject-name option (-s)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">sign-key option (-S)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">trusted-cert option (-T)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">mv-params option (-V)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">mv-keys option (-v)
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-config">ntp-keygen config</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">presetting/configuring ntp-keygen
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">exit status
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Usage
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Notes
+</td></tr>
+<tr><td align="left" valign="top">&bull; <a href="#ntp_002dkeygen-Bugs">ntp-keygen Bugs</a>:</td><td>&nbsp;&nbsp;</td><td align="left" valign="top">Bugs
+</td></tr>
+</table>
+
+<hr>
+<a name="ntp_002dkeygen-usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-imbits" accesskey="n" rel="next">ntp-keygen imbits</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp-keygen help/usage (<span class="option">--help</span>)</h4>
-
-<p><a name="index-ntp_002dkeygen-help-3"></a>
-This is the automatically generated usage text for ntp-keygen.
-
- <p>The text printed is the same whether selected with the <code>help</code> option
-(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print
-the usage text by passing it through a pager program.
+<a name="ntp_002dkeygen-help_002fusage-_0028_002d_002dhelp_0029"></a>
+<h4 class="subsection">1.2.2 ntp-keygen help/usage (<samp>--help</samp>)</h4>
+<a name="index-ntp_002dkeygen-help"></a>
+
+<p>This is the automatically generated usage text for ntp-keygen.
+</p>
+<p>The text printed is the same whether selected with the <code>help</code> option
+(<samp>--help</samp>) or the <code>more-help</code> option (<samp>--more-help</samp>). <code>more-help</code> will print
+the usage text by passing it through a pager program.
<code>more-help</code> is disabled on platforms without a working
<code>fork(2)</code> function. The <code>PAGER</code> environment variable is
-used to select the program, defaulting to <span class="file">more</span>. Both will exit
+used to select the program, defaulting to <samp>more</samp>. Both will exit
with a status code of 0.
-
-<pre class="example">ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.8p10
+</p>
+<div class="example">
+<pre class="example">ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.8p12
Usage: ntp-keygen [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
Flg Arg Option-Name Description
-b Num imbits identity modulus bits
@@ -1293,680 +1453,679 @@ The following option preset mechanisms are supported:
- examining environment variables named NTP_KEYGEN_*
Please send bug reports to: &lt;http://bugs.ntp.org, bugs@ntp.org&gt;
-</pre>
- <div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-imbits"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-certificate">ntp-keygen certificate</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-usage">ntp-keygen usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
-</div>
-
-<h4 class="subsection">imbits option (-b)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dimbits-4"></a>
-This is the &ldquo;identity modulus bits&rdquo; option.
-This option takes a number argument <span class="file">imbits</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
+</pre></div>
- <p>The number of bits in the identity modulus. The default is 256.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-certificate"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-cipher">ntp-keygen cipher</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-imbits">ntp-keygen imbits</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<hr>
+<a name="ntp_002dkeygen-imbits"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-certificate" accesskey="n" rel="next">ntp-keygen certificate</a>, Previous: <a href="#ntp_002dkeygen-usage" accesskey="p" rel="prev">ntp-keygen usage</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">certificate option (-c)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dcertificate-5"></a>
-This is the &ldquo;certificate scheme&rdquo; option.
-This option takes a string argument <span class="file">scheme</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>scheme is one of
+<a name="imbits-option-_0028_002db_0029"></a>
+<h4 class="subsection">1.2.3 imbits option (-b)</h4>
+<a name="index-ntp_002dkeygen_002dimbits"></a>
+
+<p>This is the &ldquo;identity modulus bits&rdquo; option.
+This option takes a number argument <samp>imbits</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>The number of bits in the identity modulus. The default is 256.
+</p><hr>
+<a name="ntp_002dkeygen-certificate"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-cipher" accesskey="n" rel="next">ntp-keygen cipher</a>, Previous: <a href="#ntp_002dkeygen-imbits" accesskey="p" rel="prev">ntp-keygen imbits</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
+</div>
+<a name="certificate-option-_0028_002dc_0029"></a>
+<h4 class="subsection">1.2.4 certificate option (-c)</h4>
+<a name="index-ntp_002dkeygen_002dcertificate"></a>
+
+<p>This is the &ldquo;certificate scheme&rdquo; option.
+This option takes a string argument <samp>scheme</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>scheme is one of
RSA-MD2, RSA-MD5, RSA-MDC2, RSA-SHA, RSA-SHA1, RSA-RIPEMD160,
DSA-SHA, or DSA-SHA1.
-
- <p>Select the certificate signature encryption/message digest scheme.
+</p>
+<p>Select the certificate signature encryption/message digest scheme.
Note that RSA schemes must be used with a RSA sign key and DSA
schemes must be used with a DSA sign key. The default without
-this option is RSA-MD5.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-cipher"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-id_002dkey">ntp-keygen id-key</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-certificate">ntp-keygen certificate</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+this option is RSA-MD5.
+</p><hr>
+<a name="ntp_002dkeygen-cipher"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-id_002dkey" accesskey="n" rel="next">ntp-keygen id-key</a>, Previous: <a href="#ntp_002dkeygen-certificate" accesskey="p" rel="prev">ntp-keygen certificate</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">cipher option (-C)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dcipher-6"></a>
-This is the &ldquo;privatekey cipher&rdquo; option.
-This option takes a string argument <span class="file">cipher</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Select the cipher which is used to encrypt the files containing
+<a name="cipher-option-_0028_002dC_0029"></a>
+<h4 class="subsection">1.2.5 cipher option (-C)</h4>
+<a name="index-ntp_002dkeygen_002dcipher"></a>
+
+<p>This is the &ldquo;privatekey cipher&rdquo; option.
+This option takes a string argument <samp>cipher</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Select the cipher which is used to encrypt the files containing
private keys. The default is three-key triple DES in CBC mode,
-equivalent to "<code>-C des-ede3-cbc</code>". The openssl tool lists ciphers
-available in "<code>openssl -h</code>" output.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-id_002dkey"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-gq_002dparams">ntp-keygen gq-params</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-cipher">ntp-keygen cipher</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+equivalent to &quot;<code>-C des-ede3-cbc</code>&quot;. The openssl tool lists ciphers
+available in &quot;<code>openssl -h</code>&quot; output.
+</p><hr>
+<a name="ntp_002dkeygen-id_002dkey"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-gq_002dparams" accesskey="n" rel="next">ntp-keygen gq-params</a>, Previous: <a href="#ntp_002dkeygen-cipher" accesskey="p" rel="prev">ntp-keygen cipher</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">id-key option (-e)</h4>
-
-<p><a name="index-ntp_002dkeygen_002did_002dkey-7"></a>
-This is the &ldquo;write iff or gq identity keys&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Write the public parameters from the IFF or GQ client keys to
-the standard output.
-This is intended for automatic key distribution by email.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-gq_002dparams"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-host_002dkey">ntp-keygen host-key</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-id_002dkey">ntp-keygen id-key</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="id_002dkey-option-_0028_002de_0029"></a>
+<h4 class="subsection">1.2.6 id-key option (-e)</h4>
+<a name="index-ntp_002dkeygen_002did_002dkey"></a>
+
+<p>This is the &ldquo;write iff or gq identity keys&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Write the public parameters from the IFF or GQ client keys to
+the standard output.
+This is intended for automatic key distribution by email.
+</p><hr>
+<a name="ntp_002dkeygen-gq_002dparams"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-host_002dkey" accesskey="n" rel="next">ntp-keygen host-key</a>, Previous: <a href="#ntp_002dkeygen-id_002dkey" accesskey="p" rel="prev">ntp-keygen id-key</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">gq-params option (-G)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dgq_002dparams-8"></a>
-This is the &ldquo;generate gq parameters and keys&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Generate parameters and keys for the GQ identification scheme,
-obsoleting any that may exist.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-host_002dkey"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-iffkey">ntp-keygen iffkey</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-gq_002dparams">ntp-keygen gq-params</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="gq_002dparams-option-_0028_002dG_0029"></a>
+<h4 class="subsection">1.2.7 gq-params option (-G)</h4>
+<a name="index-ntp_002dkeygen_002dgq_002dparams"></a>
+
+<p>This is the &ldquo;generate gq parameters and keys&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Generate parameters and keys for the GQ identification scheme,
+obsoleting any that may exist.
+</p><hr>
+<a name="ntp_002dkeygen-host_002dkey"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-iffkey" accesskey="n" rel="next">ntp-keygen iffkey</a>, Previous: <a href="#ntp_002dkeygen-gq_002dparams" accesskey="p" rel="prev">ntp-keygen gq-params</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">host-key option (-H)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dhost_002dkey-9"></a>
-This is the &ldquo;generate rsa host key&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Generate new host keys, obsoleting any that may exist.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-iffkey"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-ident">ntp-keygen ident</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-host_002dkey">ntp-keygen host-key</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="host_002dkey-option-_0028_002dH_0029"></a>
+<h4 class="subsection">1.2.8 host-key option (-H)</h4>
+<a name="index-ntp_002dkeygen_002dhost_002dkey"></a>
+
+<p>This is the &ldquo;generate rsa host key&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Generate new host keys, obsoleting any that may exist.
+</p><hr>
+<a name="ntp_002dkeygen-iffkey"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-ident" accesskey="n" rel="next">ntp-keygen ident</a>, Previous: <a href="#ntp_002dkeygen-host_002dkey" accesskey="p" rel="prev">ntp-keygen host-key</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">iffkey option (-I)</h4>
-
-<p><a name="index-ntp_002dkeygen_002diffkey-10"></a>
-This is the &ldquo;generate iff parameters&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Generate parameters for the IFF identification scheme, obsoleting
-any that may exist.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-ident"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-iffkey">ntp-keygen iffkey</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="iffkey-option-_0028_002dI_0029"></a>
+<h4 class="subsection">1.2.9 iffkey option (-I)</h4>
+<a name="index-ntp_002dkeygen_002diffkey"></a>
+
+<p>This is the &ldquo;generate iff parameters&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Generate parameters for the IFF identification scheme, obsoleting
+any that may exist.
+</p><hr>
+<a name="ntp_002dkeygen-ident"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-lifetime" accesskey="n" rel="next">ntp-keygen lifetime</a>, Previous: <a href="#ntp_002dkeygen-iffkey" accesskey="p" rel="prev">ntp-keygen iffkey</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ident option (-i)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dident-11"></a>
-This is the &ldquo;set autokey group name&rdquo; option.
-This option takes a string argument <span class="file">group</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Set the optional Autokey group name to name. This is used in
+<a name="ident-option-_0028_002di_0029"></a>
+<h4 class="subsection">1.2.10 ident option (-i)</h4>
+<a name="index-ntp_002dkeygen_002dident"></a>
+
+<p>This is the &ldquo;set autokey group name&rdquo; option.
+This option takes a string argument <samp>group</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Set the optional Autokey group name to name. This is used in
the file name of IFF, GQ, and MV client parameters files. In
that role, the default is the host name if this option is not
provided. The group name, if specified using <code>-i/--ident</code> or
-using <code>-s/--subject-name</code> following an '<code>@</code>' character,
+using <code>-s/--subject-name</code> following an &rsquo;<code>@</code>&rsquo; character,
is also a part of the self-signed host certificate subject and
issuer names in the form <code>host@group</code> and should match the
-'<code>crypto ident</code>' or '<code>server ident</code>' configuration in the
-<code>ntpd</code> configuration file.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-lifetime"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-ident">ntp-keygen ident</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+&rsquo;<code>crypto ident</code>&rsquo; or &rsquo;<code>server ident</code>&rsquo; configuration in the
+<code>ntpd</code> configuration file.
+</p><hr>
+<a name="ntp_002dkeygen-lifetime"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-modulus" accesskey="n" rel="next">ntp-keygen modulus</a>, Previous: <a href="#ntp_002dkeygen-ident" accesskey="p" rel="prev">ntp-keygen ident</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">lifetime option (-l)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dlifetime-12"></a>
-This is the &ldquo;set certificate lifetime&rdquo; option.
-This option takes a number argument <span class="file">lifetime</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Set the certificate expiration to lifetime days from now.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-modulus"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="lifetime-option-_0028_002dl_0029"></a>
+<h4 class="subsection">1.2.11 lifetime option (-l)</h4>
+<a name="index-ntp_002dkeygen_002dlifetime"></a>
+
+<p>This is the &ldquo;set certificate lifetime&rdquo; option.
+This option takes a number argument <samp>lifetime</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Set the certificate expiration to lifetime days from now.
+</p><hr>
+<a name="ntp_002dkeygen-modulus"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-md5key" accesskey="n" rel="next">ntp-keygen md5key</a>, Previous: <a href="#ntp_002dkeygen-lifetime" accesskey="p" rel="prev">ntp-keygen lifetime</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">modulus option (-m)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dmodulus-13"></a>
-This is the &ldquo;prime modulus&rdquo; option.
-This option takes a number argument <span class="file">modulus</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>The number of bits in the prime modulus. The default is 512.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-md5key"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="modulus-option-_0028_002dm_0029"></a>
+<h4 class="subsection">1.2.12 modulus option (-m)</h4>
+<a name="index-ntp_002dkeygen_002dmodulus"></a>
+
+<p>This is the &ldquo;prime modulus&rdquo; option.
+This option takes a number argument <samp>modulus</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>The number of bits in the prime modulus. The default is 512.
+</p><hr>
+<a name="ntp_002dkeygen-md5key"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-pvt_002dcert" accesskey="n" rel="next">ntp-keygen pvt-cert</a>, Previous: <a href="#ntp_002dkeygen-modulus" accesskey="p" rel="prev">ntp-keygen modulus</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">md5key option (-M)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dmd5key-14"></a>
-This is the &ldquo;generate symmetric keys&rdquo; option.
-Generate symmetric keys, obsoleting any that may exist.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-pvt_002dcert"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-password">ntp-keygen password</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="md5key-option-_0028_002dM_0029"></a>
+<h4 class="subsection">1.2.13 md5key option (-M)</h4>
+<a name="index-ntp_002dkeygen_002dmd5key"></a>
+
+<p>This is the &ldquo;generate symmetric keys&rdquo; option.
+Generate symmetric keys, obsoleting any that may exist.
+</p><hr>
+<a name="ntp_002dkeygen-pvt_002dcert"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-password" accesskey="n" rel="next">ntp-keygen password</a>, Previous: <a href="#ntp_002dkeygen-md5key" accesskey="p" rel="prev">ntp-keygen md5key</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">pvt-cert option (-P)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dpvt_002dcert-15"></a>
-This is the &ldquo;generate pc private certificate&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Generate a private certificate. By default, the program generates
-public certificates.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-password"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="pvt_002dcert-option-_0028_002dP_0029"></a>
+<h4 class="subsection">1.2.14 pvt-cert option (-P)</h4>
+<a name="index-ntp_002dkeygen_002dpvt_002dcert"></a>
+
+<p>This is the &ldquo;generate pc private certificate&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Generate a private certificate. By default, the program generates
+public certificates.
+</p><hr>
+<a name="ntp_002dkeygen-password"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-export_002dpasswd" accesskey="n" rel="next">ntp-keygen export-passwd</a>, Previous: <a href="#ntp_002dkeygen-pvt_002dcert" accesskey="p" rel="prev">ntp-keygen pvt-cert</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">password option (-p)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dpassword-16"></a>
-This is the &ldquo;local private password&rdquo; option.
-This option takes a string argument <span class="file">passwd</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Local files containing private data are encrypted with the
+<a name="password-option-_0028_002dp_0029"></a>
+<h4 class="subsection">1.2.15 password option (-p)</h4>
+<a name="index-ntp_002dkeygen_002dpassword"></a>
+
+<p>This is the &ldquo;local private password&rdquo; option.
+This option takes a string argument <samp>passwd</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Local files containing private data are encrypted with the
DES-CBC algorithm and the specified password. The same password
-must be specified to the local ntpd via the "crypto pw password"
+must be specified to the local ntpd via the &quot;crypto pw password&quot;
configuration command. The default password is the local
-hostname.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-export_002dpasswd"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-password">ntp-keygen password</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+hostname.
+</p><hr>
+<a name="ntp_002dkeygen-export_002dpasswd"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-subject_002dname" accesskey="n" rel="next">ntp-keygen subject-name</a>, Previous: <a href="#ntp_002dkeygen-password" accesskey="p" rel="prev">ntp-keygen password</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">export-passwd option (-q)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dexport_002dpasswd-17"></a>
-This is the &ldquo;export iff or gq group keys with password&rdquo; option.
-This option takes a string argument <span class="file">passwd</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Export IFF or GQ identity group keys to the standard output,
-encrypted with the DES-CBC algorithm and the specified password.
+<a name="export_002dpasswd-option-_0028_002dq_0029"></a>
+<h4 class="subsection">1.2.16 export-passwd option (-q)</h4>
+<a name="index-ntp_002dkeygen_002dexport_002dpasswd"></a>
+
+<p>This is the &ldquo;export iff or gq group keys with password&rdquo; option.
+This option takes a string argument <samp>passwd</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Export IFF or GQ identity group keys to the standard output,
+encrypted with the DES-CBC algorithm and the specified password.
The same password must be specified to the remote ntpd via the
-"crypto pw password" configuration command. See also the option
-&ndash;id-key (-e) for unencrypted exports.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-subject_002dname"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+&quot;crypto pw password&quot; configuration command. See also the option
+&ndash;id-key (-e) for unencrypted exports.
+</p><hr>
+<a name="ntp_002dkeygen-subject_002dname"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-sign_002dkey" accesskey="n" rel="next">ntp-keygen sign-key</a>, Previous: <a href="#ntp_002dkeygen-export_002dpasswd" accesskey="p" rel="prev">ntp-keygen export-passwd</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">subject-name option (-s)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dsubject_002dname-18"></a>
-This is the &ldquo;set host and optionally group name&rdquo; option.
-This option takes a string argument <span class="file">host@group</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Set the Autokey host name, and optionally, group name specified
-following an '<code>@</code>' character. The host name is used in the file
+<a name="subject_002dname-option-_0028_002ds_0029"></a>
+<h4 class="subsection">1.2.17 subject-name option (-s)</h4>
+<a name="index-ntp_002dkeygen_002dsubject_002dname"></a>
+
+<p>This is the &ldquo;set host and optionally group name&rdquo; option.
+This option takes a string argument <samp>host@group</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Set the Autokey host name, and optionally, group name specified
+following an &rsquo;<code>@</code>&rsquo; character. The host name is used in the file
name of generated host and signing certificates, without the
group name. The host name, and if provided, group name are used
in <code>host@group</code> form for the host certificate subject and issuer
-fields. Specifying '<code>-s @group</code>' is allowed, and results in
+fields. Specifying &rsquo;<code>-s @group</code>&rsquo; is allowed, and results in
leaving the host name unchanged while appending <code>@group</code> to the
subject and issuer fields, as with <code>-i group</code>. The group name, or
if not provided, the host name are also used in the file names
-of IFF, GQ, and MV client parameter files.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-sign_002dkey"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+of IFF, GQ, and MV client parameter files.
+</p><hr>
+<a name="ntp_002dkeygen-sign_002dkey"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-trusted_002dcert" accesskey="n" rel="next">ntp-keygen trusted-cert</a>, Previous: <a href="#ntp_002dkeygen-subject_002dname" accesskey="p" rel="prev">ntp-keygen subject-name</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">sign-key option (-S)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dsign_002dkey-19"></a>
-This is the &ldquo;generate sign key (rsa or dsa)&rdquo; option.
-This option takes a string argument <span class="file">sign</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Generate a new sign key of the designated type, obsoleting any
+<a name="sign_002dkey-option-_0028_002dS_0029"></a>
+<h4 class="subsection">1.2.18 sign-key option (-S)</h4>
+<a name="index-ntp_002dkeygen_002dsign_002dkey"></a>
+
+<p>This is the &ldquo;generate sign key (rsa or dsa)&rdquo; option.
+This option takes a string argument <samp>sign</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Generate a new sign key of the designated type, obsoleting any
that may exist. By default, the program uses the host key as the
-sign key.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-trusted_002dcert"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+sign key.
+</p><hr>
+<a name="ntp_002dkeygen-trusted_002dcert"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-mv_002dparams" accesskey="n" rel="next">ntp-keygen mv-params</a>, Previous: <a href="#ntp_002dkeygen-sign_002dkey" accesskey="p" rel="prev">ntp-keygen sign-key</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">trusted-cert option (-T)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dtrusted_002dcert-20"></a>
-This is the &ldquo;trusted certificate (tc scheme)&rdquo; option.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Generate a trusted certificate. By default, the program generates
-a non-trusted certificate.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-mv_002dparams"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="trusted_002dcert-option-_0028_002dT_0029"></a>
+<h4 class="subsection">1.2.19 trusted-cert option (-T)</h4>
+<a name="index-ntp_002dkeygen_002dtrusted_002dcert"></a>
+
+<p>This is the &ldquo;trusted certificate (tc scheme)&rdquo; option.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Generate a trusted certificate. By default, the program generates
+a non-trusted certificate.
+</p><hr>
+<a name="ntp_002dkeygen-mv_002dparams"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-mv_002dkeys" accesskey="n" rel="next">ntp-keygen mv-keys</a>, Previous: <a href="#ntp_002dkeygen-trusted_002dcert" accesskey="p" rel="prev">ntp-keygen trusted-cert</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">mv-params option (-V)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dmv_002dparams-21"></a>
-This is the &ldquo;generate &lt;num&gt; mv parameters&rdquo; option.
-This option takes a number argument <span class="file">num</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>Generate parameters and keys for the Mu-Varadharajan (MV)
-identification scheme.
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-mv_002dkeys"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-config">ntp-keygen config</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="mv_002dparams-option-_0028_002dV_0029"></a>
+<h4 class="subsection">1.2.20 mv-params option (-V)</h4>
+<a name="index-ntp_002dkeygen_002dmv_002dparams"></a>
+
+<p>This is the &ldquo;generate &lt;num&gt; mv parameters&rdquo; option.
+This option takes a number argument <samp>num</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>Generate parameters and keys for the Mu-Varadharajan (MV)
+identification scheme.
+</p><hr>
+<a name="ntp_002dkeygen-mv_002dkeys"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-config" accesskey="n" rel="next">ntp-keygen config</a>, Previous: <a href="#ntp_002dkeygen-mv_002dparams" accesskey="p" rel="prev">ntp-keygen mv-params</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">mv-keys option (-v)</h4>
-
-<p><a name="index-ntp_002dkeygen_002dmv_002dkeys-22"></a>
-This is the &ldquo;update &lt;num&gt; mv keys&rdquo; option.
-This option takes a number argument <span class="file">num</span>.
-
-<p class="noindent">This option has some usage constraints. It:
- <ul>
-<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation.
-</ul>
-
- <p>This option has no <span class="samp">doc</span> documentation.
-
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-config"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="mv_002dkeys-option-_0028_002dv_0029"></a>
+<h4 class="subsection">1.2.21 mv-keys option (-v)</h4>
+<a name="index-ntp_002dkeygen_002dmv_002dkeys"></a>
+
+<p>This is the &ldquo;update &lt;num&gt; mv keys&rdquo; option.
+This option takes a number argument <samp>num</samp>.
+</p>
+<p>This option has some usage constraints. It:
+</p><ul>
+<li> must be compiled in by defining <code>AUTOKEY</code> during the compilation.
+</li></ul>
+
+<p>This option has no &lsquo;<samp>doc</samp>&rsquo; documentation.
+</p>
+
+<hr>
+<a name="ntp_002dkeygen-config"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-exit-status" accesskey="n" rel="next">ntp-keygen exit status</a>, Previous: <a href="#ntp_002dkeygen-mv_002dkeys" accesskey="p" rel="prev">ntp-keygen mv-keys</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">presetting/configuring ntp-keygen</h4>
+<a name="presetting_002fconfiguring-ntp_002dkeygen"></a>
+<h4 class="subsection">1.2.22 presetting/configuring ntp-keygen</h4>
<p>Any option that is not marked as <i>not presettable</i> may be preset by
-loading values from configuration ("rc" or "ini") files, and values from environment variables named <code>NTP-KEYGEN</code> and <code>NTP-KEYGEN_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
-the options listed above in upper case and segmented with underscores.
+loading values from configuration (&quot;rc&quot; or &quot;ini&quot;) files, and values from environment variables named <code>NTP-KEYGEN</code> and <code>NTP-KEYGEN_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</code> must be one of
+the options listed above in upper case and segmented with underscores.
The <code>NTP-KEYGEN</code> variable will be tokenized and parsed like
the command line. The remaining variables are tested for existence and their
values are treated like option arguments.
-
-<p class="noindent"><code>libopts</code> will search in 2 places for configuration files:
- <ul>
-<li>$HOME
-<li>$PWD
-</ul>
- The environment variables <code>HOME</code>, and <code>PWD</code>
-are expanded and replaced when <span class="file">ntp-keygen</span> runs.
-For any of these that are plain files, they are simply processed.
-For any that are directories, then a file named <span class="file">.ntprc</span> is searched for
+</p>
+
+<p><code>libopts</code> will search in 2 places for configuration files:
+</p><ul>
+<li> $HOME
+</li><li> $PWD
+</li></ul>
+<p>The environment variables <code>HOME</code>, and <code>PWD</code>
+are expanded and replaced when <samp>ntp-keygen</samp> runs.
+For any of these that are plain files, they are simply processed.
+For any that are directories, then a file named <samp>.ntprc</samp> is searched for
within that directory and processed.
-
- <p>Configuration files may be in a wide variety of formats.
+</p>
+<p>Configuration files may be in a wide variety of formats.
The basic format is an option name followed by a value (argument) on the
same line. Values may be separated from the option name with a colon,
equal sign or simply white space. Values may be continued across multiple
lines by escaping the newline with a backslash.
-
- <p>Multiple programs may also share the same initialization file.
+</p>
+<p>Multiple programs may also share the same initialization file.
Common options are collected at the top, followed by program specific
segments. The segments are separated by lines like:
-<pre class="example"> [NTP-KEYGEN]
-</pre>
- <p class="noindent">or by
-<pre class="example"> &lt;?program ntp-keygen&gt;
-</pre>
- <p class="noindent">Do not mix these styles within one configuration file.
-
- <p>Compound values and carefully constructed string values may also be
+</p><div class="example">
+<pre class="example">[NTP-KEYGEN]
+</pre></div>
+<p>or by
+</p><div class="example">
+<pre class="example">&lt;?program ntp-keygen&gt;
+</pre></div>
+<p>Do not mix these styles within one configuration file.
+</p>
+<p>Compound values and carefully constructed string values may also be
specified using XML syntax:
-<pre class="example"> &lt;option-name&gt;
- &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
- &lt;/option-name&gt;
-</pre>
- <p class="noindent">yielding an <code>option-name.sub-opt</code> string value of
-<pre class="example"> "...&lt;...&gt;..."
-</pre>
- <p><code>AutoOpts</code> does not track suboptions. You simply note that it is a
+</p><div class="example">
+<pre class="example">&lt;option-name&gt;
+ &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
+&lt;/option-name&gt;
+</pre></div>
+<p>yielding an <code>option-name.sub-opt</code> string value of
+</p><div class="example">
+<pre class="example">&quot;...&lt;...&gt;...&quot;
+</pre></div>
+<p><code>AutoOpts</code> does not track suboptions. You simply note that it is a
hierarchicly valued option. <code>AutoOpts</code> does provide a means for searching
the associated name/value pair list (see: optionFindValue).
-
- <p>The command line options relating to configuration and/or usage help are:
-
-<h5 class="subsubheading">version (-)</h5>
+</p>
+<p>The command line options relating to configuration and/or usage help are:
+</p>
+<a name="version-_0028_002d_0029"></a>
+<h4 class="subsubheading">version (-)</h4>
<p>Print the program version to standard out, optionally with licensing
information, then exit 0. The optional argument specifies how much licensing
-detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
+detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument.
Only the first letter of the argument is examined:
-
- <dl>
-<dt><span class="samp">version</span><dd>Only print the version. This is the default.
-<br><dt><span class="samp">copyright</span><dd>Name the copyright usage licensing terms.
-<br><dt><span class="samp">verbose</span><dd>Print the full copyright usage licensing terms.
+</p>
+<dl compact="compact">
+<dt>&lsquo;<samp>version</samp>&rsquo;</dt>
+<dd><p>Only print the version. This is the default.
+</p></dd>
+<dt>&lsquo;<samp>copyright</samp>&rsquo;</dt>
+<dd><p>Name the copyright usage licensing terms.
+</p></dd>
+<dt>&lsquo;<samp>verbose</samp>&rsquo;</dt>
+<dd><p>Print the full copyright usage licensing terms.
+</p></dd>
</dl>
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-exit-status"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-config">ntp-keygen config</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<hr>
+<a name="ntp_002dkeygen-exit-status"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-Usage" accesskey="n" rel="next">ntp-keygen Usage</a>, Previous: <a href="#ntp_002dkeygen-config" accesskey="p" rel="prev">ntp-keygen config</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp-keygen exit status</h4>
+<a name="ntp_002dkeygen-exit-status-1"></a>
+<h4 class="subsection">1.2.23 ntp-keygen exit status</h4>
<p>One of the following exit values will be returned:
- <dl>
-<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution.
-<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid.
-<br><dt><span class="samp">66 (EX_NOINPUT)</span><dd>A specified configuration file could not be loaded.
-<br><dt><span class="samp">70 (EX_SOFTWARE)</span><dd>libopts had an internal operational error. Please report
-it to autogen-users@lists.sourceforge.net. Thank you.
+</p><dl compact="compact">
+<dt>&lsquo;<samp>0 (EXIT_SUCCESS)</samp>&rsquo;</dt>
+<dd><p>Successful program execution.
+</p></dd>
+<dt>&lsquo;<samp>1 (EXIT_FAILURE)</samp>&rsquo;</dt>
+<dd><p>The operation failed or the command syntax was not valid.
+</p></dd>
+<dt>&lsquo;<samp>66 (EX_NOINPUT)</samp>&rsquo;</dt>
+<dd><p>A specified configuration file could not be loaded.
+</p></dd>
+<dt>&lsquo;<samp>70 (EX_SOFTWARE)</samp>&rsquo;</dt>
+<dd><p>libopts had an internal operational error. Please report
+it to autogen-users@lists.sourceforge.net. Thank you.
+</p></dd>
</dl>
- <div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-Usage"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<hr>
+<a name="ntp_002dkeygen-Usage"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-Notes" accesskey="n" rel="next">ntp-keygen Notes</a>, Previous: <a href="#ntp_002dkeygen-exit-status" accesskey="p" rel="prev">ntp-keygen exit status</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp-keygen Usage</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-Notes"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-Bugs">ntp-keygen Bugs</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="ntp_002dkeygen-Usage-1"></a>
+<h4 class="subsection">1.2.24 ntp-keygen Usage</h4>
+<hr>
+<a name="ntp_002dkeygen-Notes"></a>
+<div class="header">
+<p>
+Next: <a href="#ntp_002dkeygen-Bugs" accesskey="n" rel="next">ntp-keygen Bugs</a>, Previous: <a href="#ntp_002dkeygen-Usage" accesskey="p" rel="prev">ntp-keygen Usage</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp-keygen Notes</h4>
-
-<div class="node">
-<p><hr>
-<a name="ntp_002dkeygen-Bugs"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>
-<br>
+<a name="ntp_002dkeygen-Notes-1"></a>
+<h4 class="subsection">1.2.25 ntp-keygen Notes</h4>
+<hr>
+<a name="ntp_002dkeygen-Bugs"></a>
+<div class="header">
+<p>
+Previous: <a href="#ntp_002dkeygen-Notes" accesskey="p" rel="prev">ntp-keygen Notes</a>, Up: <a href="#ntp_002dkeygen-Invocation" accesskey="u" rel="up">ntp-keygen Invocation</a> &nbsp; </p>
</div>
-
-<h4 class="subsection">ntp-keygen Bugs</h4>
-
-<div class="node">
-<p><hr>
-<a name="Random-Seed-File"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#Cryptographic-Data-Files">Cryptographic Data Files</a>,
-Previous:&nbsp;<a rel="previous" accesskey="p" href="#Running-the-Program">Running the Program</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+<a name="ntp_002dkeygen-Bugs-1"></a>
+<h4 class="subsection">1.2.26 ntp-keygen Bugs</h4>
+
+<hr>
+<a name="Random-Seed-File"></a>
+<div class="header">
+<p>
+Next: <a href="#Cryptographic-Data-Files" accesskey="n" rel="next">Cryptographic Data Files</a>, Previous: <a href="#Running-the-Program" accesskey="p" rel="prev">Running the Program</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Random Seed File</h3>
+<a name="Random-Seed-File-2"></a>
+<h3 class="section">1.3 Random Seed File</h3>
<p>All cryptographically sound key generation schemes must have means to
randomize the entropy seed used to initialize the internal
-pseudo-random number generator used by the OpenSSL library routines.
+pseudo-random number generator used by the OpenSSL library routines.
If a site supports ssh, it is very likely that means to do this are
-already available.
+already available.
The entropy seed used by the OpenSSL library is contained in a file,
usually called <code>.rnd</code>, which must be available when
starting the <code>ntp-keygen</code> program or <code>ntpd</code> daemon.
-
- <p>The OpenSSL library looks for the file using the path specified by the
+</p>
+<p>The OpenSSL library looks for the file using the path specified by the
<code>RANDFILE</code> environment variable in the user home directory, whether root
-or some other user.
+or some other user.
If the <code>RANDFILE</code> environment variable is not
present, the library looks for the <code>.rnd</code> file in the user home
-directory.
+directory.
Since both the <code>ntp-keygen</code> program and <code>ntpd</code> daemon must run
as root, the logical place to put this file is in <code>/.rnd</code> or
-<code>/root/.rnd</code>.
+<code>/root/.rnd</code>.
If the file is not available or cannot be written, the program exits
with a message to the system log.
-
-<div class="node">
-<p><hr>
-<a name="Cryptographic-Data-Files"></a>Previous:&nbsp;<a rel="previous" accesskey="p" href="#Random-Seed-File">Random Seed File</a>,
-Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
-<br>
+</p>
+<hr>
+<a name="Cryptographic-Data-Files"></a>
+<div class="header">
+<p>
+Previous: <a href="#Random-Seed-File" accesskey="p" rel="prev">Random Seed File</a>, Up: <a href="#Top" accesskey="u" rel="up">Top</a> &nbsp; </p>
</div>
-
-<!-- node-name, next, previous, up -->
-<h3 class="section">Cryptographic Data Files</h3>
+<a name="Cryptographic-Data-Files-2"></a>
+<h3 class="section">1.4 Cryptographic Data Files</h3>
<p>File and link names are in the <code>form ntpkey_key_name.fstamp</code>,
where <code>key</code> is the key or parameter type,
<code>name</code> is the host or group name and
-<code>fstamp</code> is the filestamp (NTP seconds) when the file was created).
+<code>fstamp</code> is the filestamp (NTP seconds) when the file was created).
By convention, key names in generated file names include both upper and
lower case characters, while key names in generated link names include
only lower case characters. The filestamp is not used in generated link
names.
-
- <p>The key name is a string defining the cryptographic key type.
+</p>
+<p>The key name is a string defining the cryptographic key type.
Key types include public/private keys host and sign, certificate cert
-and several challenge/response key types.
+and several challenge/response key types.
By convention, client files used for
challenges have a par subtype, as in the IFF challenge IFFpar, while
server files for responses have a key subtype, as in the GQ response
GQkey.
-
- <p>All files begin with two nonencrypted lines. The first line contains
-the file name in the format <code>ntpkey_key_host.fstamp</code>.
-The second line contains the datestamp in conventional Unix date format.
+</p>
+<p>All files begin with two nonencrypted lines. The first line contains
+the file name in the format <code>ntpkey_key_host.fstamp</code>.
+The second line contains the datestamp in conventional Unix date format.
Lines beginning with <code>#</code> are ignored.
-
- <p>The remainder of the file contains cryptographic data encoded first
+</p>
+<p>The remainder of the file contains cryptographic data encoded first
using ASN.1 rules, then encrypted using the DES-CBC algorithm with
given password and finally written in PEM-encoded printable ASCII text
preceded and followed by MIME content identifier lines.
-
- <p>The format of the symmetric keys file, ordinarily named <code>ntp.keys</code>,
+</p>
+<p>The format of the symmetric keys file, ordinarily named <code>ntp.keys</code>,
is somewhat different than the other files in the interest of backward
-compatibility.
+compatibility.
Ordinarily, the file is generated by this program, but
it can be constructed and edited using an ordinary text editor.
-
-<pre class="example"> # ntpkey_MD5key_hms.local.3564038757
- # Sun Dec 9 02:45:57 2012
-
- 1 MD5 "]!ghT%O;3)WJ,/Nc:&gt;I # MD5 key
- 2 MD5 lu+H^tF46BKR-6~pV_5 # MD5 key
- 3 MD5 :lnoVsE%Yz*avh%EtNC # MD5 key
- 4 MD5 |fdZrf0sF~^V # MD5 key
- 5 MD5 IyAG&gt;O"y"LmCRS!*bHC # MD5 key
- 6 MD5 "&gt;e\A # MD5 key
- 7 MD5 c9x=M'CfLxax9v)PV-si # MD5 key
- 8 MD5 E|=jvFVov?Bn|Ev=&amp;aK\ # MD5 key
- 9 MD5 T!c4UT&amp;`(m$+m+B6,`Q0 # MD5 key
- 10 MD5 JVF/1=)=IFbHbJQz..Cd # MD5 key
- 11 SHA1 6dea311109529e436c2b4fccae9bc753c16d1b48 # SHA1 key
- 12 SHA1 7076f373d86c4848c59ff8046e49cb7d614ec394 # SHA1 key
- 13 SHA1 5f48b1b60591eb01b7cf1d33b7774f08d20262d3 # SHA1 key
- 14 SHA1 eed5ab9d9497319ec60cf3781d52607e76720178 # SHA1 key
- 15 SHA1 f283562611a04c964da8126296f5f8e58c3f85de # SHA1 key
- 16 SHA1 1930da171297dd63549af50b29449de17dcf341f # SHA1 key
- 17 SHA1 fee892110358cd4382322b889869e750db8e8a8f # SHA1 key
- 18 SHA1 b5520c9fadd7ad3fd8bfa061c8821b65d029bb37 # SHA1 key
- 19 SHA1 8c74fb440ec80f453ec6aaa62b9baed0ab723b92 # SHA1 key
- 20 SHA1 6bc05f734306a189326000970c19b3910f403795 # SHA1 key
-</pre>
- <p>Figure 1. Typical Symmetric Key File
-
- <p>Figure 1 shows a typical symmetric keys file used by the reference
-implementation.
+</p>
+<div class="example">
+<pre class="example"># ntpkey_MD5key_hms.local.3564038757
+# Sun Dec 9 02:45:57 2012
+
+ 1 MD5 &quot;]!ghT%O;3)WJ,/Nc:&gt;I # MD5 key
+ 2 MD5 lu+H^tF46BKR-6~pV_5 # MD5 key
+ 3 MD5 :lnoVsE%Yz*avh%EtNC # MD5 key
+ 4 MD5 |fdZrf0sF~;w-i^V # MD5 key
+ 5 MD5 IyAG&gt;O&quot;y&quot;LmCRS!*bHC # MD5 key
+ 6 MD5 &quot;&gt;e\A&gt;hT/661ri52,,H # MD5 key
+ 7 MD5 c9x=M'CfLxax9v)PV-si # MD5 key
+ 8 MD5 E|=jvFVov?Bn|Ev=&amp;aK\ # MD5 key
+ 9 MD5 T!c4UT&amp;`(m$+m+B6,`Q0 # MD5 key
+10 MD5 JVF/1=)=IFbHbJQz..Cd # MD5 key
+11 SHA1 6dea311109529e436c2b4fccae9bc753c16d1b48 # SHA1 key
+12 SHA1 7076f373d86c4848c59ff8046e49cb7d614ec394 # SHA1 key
+13 SHA1 5f48b1b60591eb01b7cf1d33b7774f08d20262d3 # SHA1 key
+14 SHA1 eed5ab9d9497319ec60cf3781d52607e76720178 # SHA1 key
+15 SHA1 f283562611a04c964da8126296f5f8e58c3f85de # SHA1 key
+16 SHA1 1930da171297dd63549af50b29449de17dcf341f # SHA1 key
+17 SHA1 fee892110358cd4382322b889869e750db8e8a8f # SHA1 key
+18 SHA1 b5520c9fadd7ad3fd8bfa061c8821b65d029bb37 # SHA1 key
+19 SHA1 8c74fb440ec80f453ec6aaa62b9baed0ab723b92 # SHA1 key
+20 SHA1 6bc05f734306a189326000970c19b3910f403795 # SHA1 key
+</pre></div>
+
+<p>Figure 1. Typical Symmetric Key File
+</p>
+<p>Figure 1 shows a typical symmetric keys file used by the reference
+implementation.
Each line of the file contains three fields, first an
-integer between 1 and 65534, inclusive, representing the key identifier
-used in the server and peer configuration commands.
+integer between 1 and 65535, inclusive, representing the key identifier
+used in the server and peer configuration commands.
Next is the key type for the message digest algorithm,
which in the absence of the
OpenSSL library must be MD5 to designate the MD5 message digest
-algorithm.
+algorithm.
If the OpenSSL library is installed, the key type can be any
-message digest algorithm supported by that library.
+message digest algorithm supported by that library.
However, if
compatibility with FIPS 140-2 is required, the key type must be either
-SHA or SHA1.
+SHA or SHA1.
The key type can be changed using an ASCII text editor.
-
- <p>An MD5 key consists of a printable ASCII string less than or equal to
-16 characters and terminated by whitespace or a # character.
+</p>
+<p>An MD5 key consists of a printable ASCII string less than or equal to
+16 characters and terminated by whitespace or a # character.
An OpenSSL
key consists of a hex-encoded ASCII string of 40 characters, which is
truncated as necessary.
-
- <p>Note that the keys used by the <code>ntpq</code> and <code>ntpdc</code> programs are
+</p>
+<p>Note that the keys used by the <code>ntpq</code> and <code>ntpdc</code> programs are
checked against passwords requested by the programs and entered by hand,
so it
is generally appropriate to specify these keys in human readable ASCII
format.
-
- <p>The <code>ntp-keygen</code> program generates a MD5 symmetric keys file
-<code>ntpkey_MD5key_hostname.filestamp</code>.
+</p>
+<p>The <code>ntp-keygen</code> program generates a MD5 symmetric keys file
+<code>ntpkey_MD5key_hostname.filestamp</code>.
Since the file contains private
shared keys, it should be visible only to root and distributed by
-secure means to other subnet hosts.
+secure means to other subnet hosts.
The NTP daemon loads the file <code>ntp.keys</code>, so <code>ntp-keygen</code>
-installs a soft link from this name to the generated file.
+installs a soft link from this name to the generated file.
Subsequently, similar soft links must be installed by
-manual or automated means on the other subnet hosts.
+manual or automated means on the other subnet hosts.
While this file is
not used with the Autokey Version 2 protocol, it is needed to
authenticate some remote configuration commands used by the <code>ntpq</code> and
<code>ntpdc</code> utilities.
+</p><hr>
+
-</body></html>
+</body>
+</html>
diff --git a/contrib/ntp/util/ntp-keygen.man.in b/contrib/ntp/util/ntp-keygen.man.in
index 71dcaa5..13c71ea 100644
--- a/contrib/ntp/util/ntp-keygen.man.in
+++ b/contrib/ntp/util/ntp-keygen.man.in
@@ -10,11 +10,11 @@
.ds B-Font B
.ds I-Font I
.ds R-Font R
-.TH ntp-keygen @NTP_KEYGEN_MS@ "27 Feb 2018" "ntp (4.2.8p11)" "User Commands"
+.TH ntp-keygen @NTP_KEYGEN_MS@ "20 Feb 2019" "ntp (4.2.8p13)" "User Commands"
.\"
-.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-bBa46V/ag-nBaW5V)
+.\" EDIT THIS FILE WITH CAUTION (in-mem file)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:53 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:14 AM by AutoGen 5.18.5
.\" From the definitions ntp-keygen-opts.def
.\" and the template file agman-cmd.tpl
.SH NAME
@@ -1054,7 +1054,7 @@ Following the header the keys are entered one per line in the format
.in -4
where
\f\*[I-Font]keyno\f[]
-is a positive integer in the range 1-65534;
+is a positive integer in the range 1-65535;
\f\*[I-Font]type\f[]
is the key type for the message digest algorithm, which in the absence of the
OpenSSL library must be
diff --git a/contrib/ntp/util/ntp-keygen.mdoc.in b/contrib/ntp/util/ntp-keygen.mdoc.in
index 8ed42c0..a2fcedf 100644
--- a/contrib/ntp/util/ntp-keygen.mdoc.in
+++ b/contrib/ntp/util/ntp-keygen.mdoc.in
@@ -1,9 +1,9 @@
-.Dd February 27 2018
+.Dd February 20 2019
.Dt NTP_KEYGEN @NTP_KEYGEN_MS@ User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.mdoc)
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:16:00 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed February 20, 2019 at 09:57:11 AM by AutoGen 5.18.5
.\" From the definitions ntp-keygen-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -943,7 +943,7 @@ Following the header the keys are entered one per line in the format
.D1 Ar keyno Ar type Ar key
where
.Ar keyno
-is a positive integer in the range 1\-65534;
+is a positive integer in the range 1\-65535;
.Ar type
is the key type for the message digest algorithm, which in the absence of the
OpenSSL library must be
diff --git a/contrib/ntp/util/ntp-keygen.texi b/contrib/ntp/util/ntp-keygen.texi
index 92cec48..34e6aaa 100644
--- a/contrib/ntp/util/ntp-keygen.texi
+++ b/contrib/ntp/util/ntp-keygen.texi
@@ -267,7 +267,7 @@ it can be constructed and edited using an ordinary text editor.
Figure 1 shows a typical symmetric keys file used by the reference
implementation.
Each line of the file contains three fields, first an
-integer between 1 and 65534, inclusive, representing the key identifier
+integer between 1 and 65535, inclusive, representing the key identifier
used in the server and peer configuration commands.
Next is the key type for the message digest algorithm,
which in the absence of the
diff --git a/contrib/ntp/util/ntptime.c b/contrib/ntp/util/ntptime.c
index c47e356..35896e9 100644
--- a/contrib/ntp/util/ntptime.c
+++ b/contrib/ntp/util/ntptime.c
@@ -349,10 +349,6 @@ main(
printf(" status %s,\n", sprintb((u_int)ntx.status, TIMEX_STA_BITS));
ftemp = (double)ntx.tolerance / SCALE_FREQ;
gtemp = (double)ntx.precision;
-#ifdef STA_NANO
- if (flash & STA_NANO)
- gtemp /= 1000.0;
-#endif
printf(
" time constant %lu, precision %.3f us, tolerance %.0f ppm,\n",
(u_long)ntx.constant, gtemp, ftemp);
diff --git a/contrib/ntp/util/sht.c b/contrib/ntp/util/sht.c
index dfd97ff..d0e0721 100644
--- a/contrib/ntp/util/sht.c
+++ b/contrib/ntp/util/sht.c
@@ -196,7 +196,7 @@ again:
* certain jitter!)
*/
time_t clk_sec, rcv_sec;
- uint clk_frc, rcv_frc;
+ u_int clk_frc, rcv_frc;
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
@@ -206,17 +206,17 @@ again:
struct timespec tmptime;
if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) {
rcv_sec = tmptime.tv_sec;
- rcv_frc = (uint)tmptime.tv_nsec;
+ rcv_frc = (u_int)tmptime.tv_nsec;
}
else
#endif
{
time(&rcv_sec);
- rcv_frc = (uint)random() % 1000000000u;
+ rcv_frc = (u_int)random() % 1000000000u;
}
/* add a wobble of ~3.5msec to the clock time */
clk_sec = rcv_sec;
- clk_frc = rcv_frc + (uint)(random()%7094713 - 3547356);
+ clk_frc = rcv_frc + (u_int)(random()%7094713 - 3547356);
/* normalise result -- the SHM driver is picky! */
while ((int)clk_frc < 0) {
clk_frc += 1000000000;
diff --git a/contrib/tzdata/Makefile b/contrib/tzdata/Makefile
index d8d8e21..25f1d35 100644
--- a/contrib/tzdata/Makefile
+++ b/contrib/tzdata/Makefile
@@ -12,7 +12,10 @@ VERSION= unknown
# Email address for bug reports.
BUGEMAIL= tz@iana.org
-# Choose source data features. To get new features right away, use:
+# DATAFORM selects the data format.
+# Available formats represent essentially the same data, albeit
+# possibly with minor discrepancies that users are not likely to notice.
+# To get new features and the best data right away, use:
# DATAFORM= vanguard
# To wait a while before using new features, to give downstream users
# time to upgrade zic (the default), use:
@@ -33,11 +36,11 @@ DATAFORM= main
LOCALTIME= GMT
# If you want something other than Eastern United States time as a template
-# for handling POSIX-style timezone environment variables,
+# for handling ruleless POSIX-style timezone environment variables,
# change the line below (after finding the timezone you want in the
# one of the $(TDATA) source files, or adding it to a source file).
-# When a POSIX-style environment variable is handled, the rules in the
-# template file are used to determine "spring forward" and "fall back" days and
+# A ruleless environment setting like TZ='CST6CDT' uses the rules in the
+# template file to determine "spring forward" and "fall back" days and
# times; the environment variable itself specifies UT offsets of standard and
# daylight saving time.
# Alternatively, if you discover you've got the wrong timezone, you can just
@@ -46,7 +49,6 @@ LOCALTIME= GMT
# Use the command
# make zonenames
# to get a list of the values you can use for POSIXRULES.
-# If you want POSIX compatibility, use "America/New_York".
POSIXRULES= America/New_York
@@ -113,8 +115,8 @@ TIME_T_ALTERNATIVES = $(TIME_T_ALTERNATIVES_HEAD) $(TIME_T_ALTERNATIVES_TAIL)
TIME_T_ALTERNATIVES_HEAD = int64_t
TIME_T_ALTERNATIVES_TAIL = int32_t uint32_t uint64_t
-# What kind of TZif data files to generate.
-# (TZif is the binary time zone data format that zic generates.)
+# What kind of TZif data files to generate. (TZif is the binary time
+# zone data format that zic generates; see Internet RFC 8536.)
# If you want only POSIX time, with time values interpreted as
# seconds since the epoch (not counting leap seconds), use
# REDO= posix_only
@@ -360,6 +362,9 @@ LEAPSECONDS=
zic= ./zic
ZIC= $(zic) $(ZFLAGS)
+# To shrink the size of installed TZif files,
+# append "-r @N" to omit data before N-seconds-after-the-Epoch.
+# See the zic man page for more about -r.
ZFLAGS=
# How to use zic to install TZif files.
@@ -491,7 +496,8 @@ MANTXTS= newctime.3.txt newstrftime.3.txt newtzset.3.txt \
COMMON= calendars CONTRIBUTING LICENSE Makefile \
NEWS README theory.html version
WEB_PAGES= tz-art.html tz-how-to.html tz-link.html
-CHECK_WEB_PAGES=check_tz-art.html check_tz-how-to.html check_tz-link.html
+CHECK_WEB_PAGES=check_theory.html check_tz-art.html \
+ check_tz-how-to.html check_tz-link.html
DOCS= $(MANS) date.1 $(MANTXTS) $(WEB_PAGES)
PRIMARY_YDATA= africa antarctica asia australasia \
europe northamerica southamerica
@@ -804,9 +810,10 @@ check_tzs: $(TZS) $(TZS_NEW)
touch $@
check_web: $(CHECK_WEB_PAGES)
+check_theory.html: theory.html
check_tz-art.html: tz-art.html
check_tz-link.html: tz-link.html
-check_tz-art.html check_tz-link.html:
+check_theory.html check_tz-art.html check_tz-link.html:
$(CURL) -sS --url https://validator.w3.org/nu/ -F out=gnu \
-F file=@$$(expr $@ : 'check_\(.*\)') -o $@.out && \
test ! -s $@.out || { cat $@.out; exit 1; }
@@ -840,11 +847,13 @@ check_zishrink_posix check_zishrink_right: \
touch $@
clean_misc:
+ rm -fr check_*.dir
rm -f *.o *.out $(TIME_T_ALTERNATIVES) \
check_* core typecheck_* \
date tzselect version.h zdump zic yearistype libtz.a
clean: clean_misc
- rm -fr *.dir *.zi tzdb-*/ $(TZS_NEW)
+ rm -fr *.dir tzdb-*/
+ rm -f *.zi $(TZS_NEW)
maintainer-clean: clean
@echo 'This command is intended for maintainers to use; it'
diff --git a/contrib/tzdata/NEWS b/contrib/tzdata/NEWS
index 37f2281..9d0e9c0 100644
--- a/contrib/tzdata/NEWS
+++ b/contrib/tzdata/NEWS
@@ -1,5 +1,53 @@
News for the tz database
+Release 20198 - 2019-03-25 22:01:33 -0700
+
+ Briefly:
+ Palestine "springs forward" on 2019-03-30 instead of 2019-03-23.
+ Metlakatla "fell back" to rejoin Alaska Time on 2019-01-20 at 02:00.
+
+ Changes to past and future timestamps
+
+ Palestine will not start DST until 2019-03-30, instead of 2019-03-23 as
+ previously predicted. Adjust our prediction by guessing that spring
+ transitions will be between 24 and 30 March, which matches recent practice
+ since 2016. (Thanks to Even Scharning and Tim Parenti.)
+
+ Metlakatla ended its observance of Pacific standard time,
+ rejoining Alaska Time, on 2019-01-20 at 02:00. (Thanks to Ryan
+ Stanley and Tim Parenti.)
+
+ Changes to past timestamps
+
+ Israel observed DST in 1980 (08-02/09-13) and 1984 (05-05/08-25).
+ (Thanks to Alois Treindl and Isaac Starkman.)
+
+ Changes to time zone abbreviations
+
+ Etc/UCT is now a backward-compatibility link to Etc/UTC, instead
+ of being a separate zone that generates the abbreviation "UCT",
+ which nowadays is typically a typo. (Problem reported by Isiah
+ Meadows.)
+
+ Changes to code
+
+ zic now has an -r option to limit the time range of output data.
+ For example, 'zic -r @1000000000' limits the output data to
+ timestamps starting 1000000000 seconds after the Epoch.
+ This helps shrink output size and can be useful for applications
+ not needing the full timestamp history, such as TZDIST truncation;
+ see Internet RFC 8536 section 5.1. (Inspired by a feature request
+ from Christopher Wong, helped along by bug reports from Wong and
+ from Tim Parenti.)
+
+ Changes to documentation
+
+ Mention Internet RFC 8536 (February 2019), which documents TZif.
+
+ tz-link.html now cites tzdata-meta
+ <https://tzdata-meta.timtimeonline.com/>.
+
+
Release 2018i - 2018-12-30 11:05:43 -0800
Briefly:
@@ -400,8 +448,9 @@ Release 2018d - 2018-03-22 07:05:46 -0700
downstream parsers do not support it.
* The build procedure constructs three files vanguard.zi, main.zi,
- and rearguard.zi, one for each format. The files represent the
- same data as closely as the formats allow. These three files
+ and rearguard.zi, one for each format. Although the files
+ represent essentially the same data, they may have minor
+ discrepancies that users are not likely to notice. The files
are intended for downstream data consumers and are not
installed. Zoneinfo parsers that do not support negative SAVE values
should start using rearguard.zi, so that they will be unaffected
diff --git a/contrib/tzdata/README b/contrib/tzdata/README
index efe7a17..dd6fcf7 100644
--- a/contrib/tzdata/README
+++ b/contrib/tzdata/README
@@ -1,7 +1,7 @@
README for the tz distribution
-"What time is it?" -- Richard Deacon as The King
-"Any time you want it to be." -- Frank Baxter as The Scientist
+"Where do I set the hands of the clock?" -- Les Tremayne as The King
+"Oh that--you can set them any place you want." -- Frank Baxter as The Scientist
(from the Bell System film "About Time")
The Time Zone Database (called tz, tzdb or zoneinfo) contains code and
diff --git a/contrib/tzdata/africa b/contrib/tzdata/africa
index 0a0f586..a58c11c 100644
--- a/contrib/tzdata/africa
+++ b/contrib/tzdata/africa
@@ -364,6 +364,11 @@ Zone Africa/Cairo 2:05:09 - LMT 1900 Oct
# See Africa/Lagos.
# Eritrea
+# See Africa/Nairobi.
+
+# Eswatini (formerly Swaziland)
+# See Africa/Johannesburg.
+
# Ethiopia
# See Africa/Nairobi.
#
@@ -1188,7 +1193,7 @@ Zone Africa/Johannesburg 1:52:00 - LMT 1892 Feb 8
1:30 - SAST 1903 Mar
2:00 SA SAST
Link Africa/Johannesburg Africa/Maseru # Lesotho
-Link Africa/Johannesburg Africa/Mbabane # Swaziland
+Link Africa/Johannesburg Africa/Mbabane # Eswatini
#
# Marion and Prince Edward Is
# scientific station since 1947
@@ -1230,9 +1235,6 @@ Zone Africa/Juba 2:06:28 - LMT 1931
2:00 Sudan CA%sT 2000 Jan 15 12:00
3:00 - EAT
-# Swaziland
-# See Africa/Johannesburg.
-
# Tanzania
# See Africa/Nairobi.
diff --git a/contrib/tzdata/asia b/contrib/tzdata/asia
index 3165203..d790da5 100644
--- a/contrib/tzdata/asia
+++ b/contrib/tzdata/asia
@@ -1620,6 +1620,24 @@ Rule Zion 1974 only - Jul 7 0:00 1:00 D
Rule Zion 1974 only - Oct 13 0:00 0 S
Rule Zion 1975 only - Apr 20 0:00 1:00 D
Rule Zion 1975 only - Aug 31 0:00 0 S
+
+# From Alois Treindl (2019-03-06):
+# http://www.moin.gov.il/Documents/שעון קיץ/clock-50-years-7-2014.pdf
+# From Isaac Starkman (2019-03-06):
+# Summer time was in that period in 1980 and 1984, see
+# https://www.ynet.co.il/articles/0,7340,L-3951073,00.html
+# You can of course read it in translation.
+# I checked the local newspapers for that years.
+# It started on midnight and end at 01.00 am.
+# From Paul Eggert (2019-03-06):
+# Also see this thread about the moin.gov.il URL:
+# https://mm.icann.org/pipermail/tz/2018-November/027194.html
+Rule Zion 1980 only - Aug 2 0:00 1:00 D
+Rule Zion 1980 only - Sep 13 1:00 0 S
+Rule Zion 1984 only - May 5 0:00 1:00 D
+Rule Zion 1984 only - Aug 25 1:00 0 S
+
+# From Shanks & Pottenger:
Rule Zion 1985 only - Apr 14 0:00 1:00 D
Rule Zion 1985 only - Sep 15 0:00 0 S
Rule Zion 1986 only - May 18 0:00 1:00 D
@@ -3071,9 +3089,15 @@ Zone Asia/Karachi 4:28:12 - LMT 1907
# the official website, though the decree did not specify the exact
# time of the time shift.
# http://www.palestinecabinet.gov.ps/Website/AR/NDecrees/ViewFile.ashx?ID=e7a42ab7-ee23-435a-b9c8-a4f7e81f3817
+
+# From Even Scharning (2019-03-23):
+# DST in Palestine will start on 30 March this year, not 23 March as the time
+# zone database predicted.
+# https://ramallah.news/post/123610
#
-# From Paul Eggert (2018-03-16):
-# For 2016 on, predict spring transitions on March's fourth Saturday at 01:00.
+# From Tim Parenti (2019-03-23):
+# Combining this with the rules observed since 2016, adjust our spring
+# transition guess to Mar Sat>=24.
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule EgyptAsia 1957 only - May 10 0:00 1:00 S
@@ -3104,7 +3128,7 @@ Rule Palestine 2012 only - Sep 21 1:00 0 -
Rule Palestine 2013 only - Sep Fri>=21 0:00 0 -
Rule Palestine 2014 2015 - Oct Fri>=21 0:00 0 -
Rule Palestine 2015 only - Mar lastFri 24:00 1:00 S
-Rule Palestine 2016 max - Mar Sat>=22 1:00 1:00 S
+Rule Palestine 2016 max - Mar Sat>=24 1:00 1:00 S
Rule Palestine 2016 max - Oct lastSat 1:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
@@ -3596,5 +3620,17 @@ Zone Asia/Ho_Chi_Minh 7:06:40 - LMT 1906 Jul 1
8:00 - +08 1975 Jun 13
7:00 - +07
+# From Paul Eggert (2019-02-19):
+#
+# The Ho Chi Minh entry suffices for most purposes as it agrees with all of
+# Vietnam since 1975-06-13. Presumably clocks often changed in south Vietnam
+# in the early 1970s as locations changed hands during the war; however the
+# details are unknown and would likely be too voluminous for this database.
+#
+# For timestamps in north Vietnam back to 1970 (the tzdb cutoff),
+# use Asia/Bangkok; see the VN entries in the file zone1970.tab.
+# For timestamps before 1970, see Asia/Hanoi in the file 'backzone'.
+
+
# Yemen
# See Asia/Riyadh.
diff --git a/contrib/tzdata/backward b/contrib/tzdata/backward
index 51e10f4..b4ae3cf 100644
--- a/contrib/tzdata/backward
+++ b/contrib/tzdata/backward
@@ -77,6 +77,7 @@ Link Pacific/Easter Chile/EasterIsland
Link America/Havana Cuba
Link Africa/Cairo Egypt
Link Europe/Dublin Eire
+Link Etc/UTC Etc/UCT
Link Europe/London Europe/Belfast
Link Europe/Chisinau Europe/Tiraspol
Link Europe/London GB
@@ -111,7 +112,7 @@ Link Asia/Taipei ROC
Link Asia/Seoul ROK
Link Asia/Singapore Singapore
Link Europe/Istanbul Turkey
-Link Etc/UCT UCT
+Link Etc/UTC UCT
Link America/Anchorage US/Alaska
Link America/Adak US/Aleutian
Link America/Phoenix US/Arizona
diff --git a/contrib/tzdata/backzone b/contrib/tzdata/backzone
index 97792b1..380c492 100644
--- a/contrib/tzdata/backzone
+++ b/contrib/tzdata/backzone
@@ -204,7 +204,7 @@ Zone Africa/Maseru 1:50:00 - LMT 1903 Mar
2:00 1:00 SAST 1944 Mar 19 2:00
2:00 - SAST
-# Swaziland
+# Eswatini (formerly Swaziland)
Zone Africa/Mbabane 2:04:24 - LMT 1903 Mar
2:00 - SAST
@@ -625,7 +625,7 @@ Zone Europe/Sarajevo 1:13:40 - LMT 1884
1:00 - CET 1982 Nov 27
1:00 EU CE%sT
-# Macedonia
+# North Macedonia
Zone Europe/Skopje 1:25:44 - LMT 1884
1:00 - CET 1941 Apr 18 23:00
1:00 C-Eur CE%sT 1945 May 8 2:00s
diff --git a/contrib/tzdata/etcetera b/contrib/tzdata/etcetera
index 5d02c44..8b6bed3 100644
--- a/contrib/tzdata/etcetera
+++ b/contrib/tzdata/etcetera
@@ -19,7 +19,6 @@
Zone Etc/GMT 0 - GMT
Zone Etc/UTC 0 - UTC
-Zone Etc/UCT 0 - UCT
# The following link uses older naming conventions,
# but it belongs here, not in the file 'backward',
diff --git a/contrib/tzdata/europe b/contrib/tzdata/europe
index 587f7b0..b735a48 100644
--- a/contrib/tzdata/europe
+++ b/contrib/tzdata/europe
@@ -1855,7 +1855,7 @@ Zone Europe/Luxembourg 0:24:36 - LMT 1904 Jun
1:00 Belgium CE%sT 1977
1:00 EU CE%sT
-# Macedonia
+# North Macedonia
# See Europe/Belgrade.
# Malta
@@ -3359,7 +3359,7 @@ Zone Europe/Belgrade 1:22:00 - LMT 1884
Link Europe/Belgrade Europe/Ljubljana # Slovenia
Link Europe/Belgrade Europe/Podgorica # Montenegro
Link Europe/Belgrade Europe/Sarajevo # Bosnia and Herzegovina
-Link Europe/Belgrade Europe/Skopje # Macedonia
+Link Europe/Belgrade Europe/Skopje # North Macedonia
Link Europe/Belgrade Europe/Zagreb # Croatia
# Slovakia
diff --git a/contrib/tzdata/leap-seconds.list b/contrib/tzdata/leap-seconds.list
index cf54b9a..fd3d192 100644
--- a/contrib/tzdata/leap-seconds.list
+++ b/contrib/tzdata/leap-seconds.list
@@ -204,10 +204,10 @@
# current -- the update time stamp, the data and the name of the file
# will not change.
#
-# Updated through IERS Bulletin C56
-# File expires on: 28 June 2019
+# Updated through IERS Bulletin C57
+# File expires on: 28 December 2019
#
-#@ 3770668800
+#@ 3786480000
#
2272060800 10 # 1 Jan 1972
2287785600 11 # 1 Jul 1972
@@ -252,4 +252,4 @@
# the hash line is also ignored in the
# computation.
#
-#h 62ca19f6 96a4ae0a 3708451c 9f8693f4 016604eb
+#h 83c68138 d3650221 07dbbbcd 11fcc859 ced1106a
diff --git a/contrib/tzdata/leapseconds b/contrib/tzdata/leapseconds
index 325f3a1..886ae27 100644
--- a/contrib/tzdata/leapseconds
+++ b/contrib/tzdata/leapseconds
@@ -63,7 +63,7 @@ Leap 2016 Dec 31 23:59:60 + S
# POSIX timestamps for the data in this file:
#updated 1467936000
-#expires 1561680000
+#expires 1577491200
-# Updated through IERS Bulletin C56
-# File expires on: 28 June 2019
+# Updated through IERS Bulletin C57
+# File expires on: 28 December 2019
diff --git a/contrib/tzdata/northamerica b/contrib/tzdata/northamerica
index faaf979..eee8de0 100644
--- a/contrib/tzdata/northamerica
+++ b/contrib/tzdata/northamerica
@@ -609,6 +609,15 @@ Zone America/Los_Angeles -7:52:58 - LMT 1883 Nov 18 12:07:02
# In a 2018-12-11 special election, Metlakatla voted to go back to
# Alaska time (including daylight saving time) starting next year.
# https://www.krbd.org/2018/12/12/metlakatla-to-follow-alaska-standard-time-allow-liquor-sales/
+#
+# From Ryan Stanley (2019-01-11):
+# The community will be changing back on the 20th of this month...
+# From Tim Parenti (2019-01-11):
+# Per an announcement on the Metlakatla community's official Facebook page, the
+# "fall back" will be on Sunday 2019-01-20 at 02:00:
+# https://www.facebook.com/141055983004923/photos/607150969728753/
+# So they won't be waiting for Alaska to join them on 2019-03-10, but will
+# rather change their clocks twice in seven weeks.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Juneau 15:02:19 - LMT 1867 Oct 19 15:33:32
@@ -637,7 +646,7 @@ Zone America/Metlakatla 15:13:42 - LMT 1867 Oct 19 15:44:55
-8:00 US P%sT 1983 Oct 30 2:00
-8:00 - PST 2015 Nov 1 2:00
-9:00 US AK%sT 2018 Nov 4 2:00
- -8:00 - PST 2019 Mar Sun>=8 3:00
+ -8:00 - PST 2019 Jan 20 2:00
-9:00 US AK%sT
Zone America/Yakutat 14:41:05 - LMT 1867 Oct 19 15:12:18
-9:18:55 - LMT 1900 Aug 20 12:00
diff --git a/contrib/tzdata/theory.html b/contrib/tzdata/theory.html
index a8da065..e373022 100644
--- a/contrib/tzdata/theory.html
+++ b/contrib/tzdata/theory.html
@@ -15,7 +15,7 @@
<ul>
<li><a href="#scope">Scope of the <code><abbr>tz</abbr></code>
database</a></li>
- <li><a href="#naming">Names of timezones</a></li>
+ <li><a href="#naming">Timezone identifiers</a></li>
<li><a href="#abbreviations">Time zone abbreviations</a></li>
<li><a href="#accuracy">Accuracy of the <code><abbr>tz</abbr></code>
database</a></li>
@@ -107,9 +107,9 @@ It does not always make sense to talk about a timezone's
</section>
<section>
- <h2 id="naming">Names of timezones</h2>
+ <h2 id="naming">Timezone identifiers</h2>
<p>
-Each timezone has a unique name.
+Each timezone has a name that uniquely identifies the timezone.
Inexperienced users are not expected to select these names unaided.
Distributors should provide documentation and/or a simple selection
interface that explains each name via a map or via descriptive text like
@@ -142,10 +142,12 @@ among the following goals:
</li>
<li>
Be robust in the presence of political changes.
- For example, names of countries are ordinarily not used, to avoid
+ For example, names are typically not tied to countries, to avoid
incompatibilities when countries change their name (e.g.,
- Zaire&rarr;Congo) or when locations change countries (e.g., Hong
+ Swaziland&rarr;Eswatini) or when locations change countries (e.g., Hong
Kong from UK colony to China).
+ There is no requirement that every country or national
+ capital must have a timezone name.
</li>
<li>
Be portable to a wide variety of implementations.
@@ -215,19 +217,18 @@ in decreasing order of importance:
do not need locations, since local time is not defined there.
</li>
<li>
- There should typically be at least one name for each <a
- href="https://en.wikipedia.org/wiki/ISO_3166-1"><abbr
- title="International Organization for Standardization">ISO</abbr>
- 3166-1</a> officially assigned two-letter code for an inhabited
- country or territory.
- </li>
- <li>
If all the clocks in a timezone have agreed since 1970,
do not bother to include more than one timezone
even if some of the clocks disagreed before 1970.
Otherwise these tables would become annoyingly large.
</li>
<li>
+ If boundaries between regions are fluid, such as during a war or
+ insurrection, do not bother to create a new timezone merely
+ because of yet another boundary change. This helps prevent table
+ bloat and simplifies maintenance.
+ </li>
+ <li>
If a name is ambiguous, use a less ambiguous alternative;
e.g., many cities are named San José and Georgetown, so
prefer <code>America/Costa_Rica</code> to
@@ -299,29 +300,23 @@ in decreasing order of importance:
</ul>
<p>
-The file '<code>zone1970.tab</code>' lists geographical locations used
-to name timezones.
-It is intended to be an exhaustive list of names for geographic
-regions as described above; this is a subset of the timezones in the data.
-Although a '<code>zone1970.tab</code>' location's
-<a href="https://en.wikipedia.org/wiki/Longitude">longitude</a>
-corresponds to
-its <a href="https://en.wikipedia.org/wiki/Local_mean_time">local mean
-time (<abbr>LMT</abbr>)</a> offset with one hour for every 15&deg;
-east longitude, this relationship is not exact.
+Guidelines have evolved with time, and names following old versions of
+this guideline might not follow the current version. When guidelines
+have changed, old names continue to be supported. Guideline changes
+have included the following:
</p>
-<p>
-Older versions of this package used a different naming scheme,
-and these older names are still supported.
+<ul>
+<li>
+Older versions of this package used a different naming scheme.
See the file '<code>backward</code>' for most of these older names
(e.g., '<code>US/Eastern</code>' instead of '<code>America/New_York</code>').
The other old-fashioned names still supported are
'<code>WET</code>', '<code>CET</code>', '<code>MET</code>', and
'<code>EET</code>' (see the file '<code>europe</code>').
-</p>
+</li>
-<p>
+<li>
Older versions of this package defined legacy names that are
incompatible with the first guideline of location names, but which are
still supported.
@@ -332,6 +327,31 @@ Also, the file '<code>backward</code>' defines the legacy names
and the file '<code>northamerica</code>' defines the legacy names
'<code>EST5EDT</code>', '<code>CST6CDT</code>',
'<code>MST7MDT</code>', and '<code>PST8PDT</code>'.
+</li>
+
+<li>
+Older versions of this guideline said that
+there should typically be at least one name for each <a
+href="https://en.wikipedia.org/wiki/ISO_3166-1"><abbr
+title="International Organization for Standardization">ISO</abbr>
+3166-1</a> officially assigned two-letter code for an inhabited
+country or territory.
+This old guideline has been dropped, as it was not needed to handle
+timestamps correctly and it increased maintenance burden.
+</li>
+</ul>
+
+<p>
+The file '<code>zone1970.tab</code>' lists geographical locations used
+to name timezones.
+It is intended to be an exhaustive list of names for geographic
+regions as described above; this is a subset of the timezones in the data.
+Although a '<code>zone1970.tab</code>' location's
+<a href="https://en.wikipedia.org/wiki/Longitude">longitude</a>
+corresponds to
+its <a href="https://en.wikipedia.org/wiki/Local_mean_time">local mean
+time (<abbr>LMT</abbr>)</a> offset with one hour for every 15&deg;
+east longitude, this relationship is not exact.
</p>
<p>
@@ -983,7 +1003,9 @@ an older <code>zic</code>.
constrained to be a string containing abbreviations
and numeric data as described <a href="#POSIX">above</a>.
The file's format is <dfn><abbr>TZif</abbr></dfn>,
- a timezone information format that contains binary data.
+ a timezone information format that contains binary data; see
+ <a href="https://tools.ietf.org/html/8536">Internet
+ <abbr>RFC</abbr> 8536</a>.
The daylight saving time rules to be used for a
particular timezone are encoded in the
<abbr>TZif</abbr> file; the format of the file allows <abbr>US</abbr>,
@@ -1166,7 +1188,7 @@ The <code><abbr>tz</abbr></code> code and data supply the following interfaces:
<ul>
<li>
A set of timezone names as per
- "<a href="#naming">Names of timezones</a>" above.
+ "<a href="#naming">Timezone identifiers</a>" above.
</li>
<li>
Library functions described in "<a href="#functions">Time and date
@@ -1213,6 +1235,17 @@ For example, users should not rely on particular <abbr>UT</abbr>
offsets or abbreviations for timestamps, as data entries are often
based on guesswork and these guesses may be corrected or improved.
</p>
+
+<p>
+Timezone boundaries are not part of the stable interface.
+For example, even though the <samp>Asia/Bangkok</samp> timezone
+currently includes Chang Mai, Hanoi, and Phnom Penh, this is not part
+of the stable interface and the timezone can split at any time.
+If a calendar application records a future event in some location other
+than Bangkok by putting "<samp>Asia/Bangkok</samp>" in the event's record,
+the application should be robust in the presence of timezone splits
+between now and the future time.
+</p>
</section>
<section>
diff --git a/contrib/tzdata/version b/contrib/tzdata/version
index 63f5800..149d790 100644
--- a/contrib/tzdata/version
+++ b/contrib/tzdata/version
@@ -1 +1 @@
-2018i
+2019a
diff --git a/contrib/wpa/CONTRIBUTIONS b/contrib/wpa/CONTRIBUTIONS
index ca09bae..c81ad64 100644
--- a/contrib/wpa/CONTRIBUTIONS
+++ b/contrib/wpa/CONTRIBUTIONS
@@ -29,6 +29,34 @@ using your real name. Pseudonyms or anonymous contributions cannot
unfortunately be accepted.
+The preferred method of submitting the contribution to the project is by
+email to the hostap mailing list:
+hostap@lists.infradead.org
+Note that the list may require subscription before accepting message
+without moderation. You can subscribe to the list at this address:
+http://lists.infradead.org/mailman/listinfo/hostap
+
+The message should contain an inlined patch against the current
+development branch (i.e., the master branch of
+git://w1.fi/hostap.git). Please make sure the software you use for
+sending the patch does not corrupt whitespace. If that cannot be fixed
+for some reason, it is better to include an attached version of the
+patch file than just send a whitespace damaged version in the message
+body.
+
+The patches should be separate logical changes rather than doing
+everything in a single patch. In other words, please keep cleanup, new
+features, and bug fixes all in their own patches. Each patch needs a
+commit log that describes the changes (what the changes fix, what
+functionality is added, why the changes are useful, etc.).
+
+Please try to follow the coding style used in the project.
+
+In general, the best way of generating a suitable formatted patch file
+is by committing the changes to a cloned git repository and using git
+format-patch. The patch can then be sent, e.g., with git send-email.
+
+
History of license and contributions terms
------------------------------------------
@@ -112,7 +140,7 @@ The license terms used for hostap.git files
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/contrib/wpa/COPYING b/contrib/wpa/COPYING
index 5962e2f..5d0115c 100644
--- a/contrib/wpa/COPYING
+++ b/contrib/wpa/COPYING
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
diff --git a/contrib/wpa/README b/contrib/wpa/README
index 07d1d25..a9f8069 100644
--- a/contrib/wpa/README
+++ b/contrib/wpa/README
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
These programs are licensed under the BSD license (the one with
diff --git a/contrib/wpa/hostapd/ChangeLog b/contrib/wpa/hostapd/ChangeLog
index af54e1e..327ee3b 100644
--- a/contrib/wpa/hostapd/ChangeLog
+++ b/contrib/wpa/hostapd/ChangeLog
@@ -1,5 +1,188 @@
ChangeLog for hostapd
+2019-04-21 - v2.8
+ * SAE changes
+ - added support for SAE Password Identifier
+ - changed default configuration to enable only group 19
+ (i.e., disable groups 20, 21, 25, 26 from default configuration) and
+ disable all unsuitable groups completely based on REVmd changes
+ - improved anti-clogging token mechanism and SAE authentication
+ frame processing during heavy CPU load; this mitigates some issues
+ with potential DoS attacks trying to flood an AP with large number
+ of SAE messages
+ - added Finite Cyclic Group field in status code 77 responses
+ - reject use of unsuitable groups based on new implementation guidance
+ in REVmd (allow only FFC groups with prime >= 3072 bits and ECC
+ groups with prime >= 256)
+ - minimize timing and memory use differences in PWE derivation
+ [https://w1.fi/security/2019-1/] (CVE-2019-9494)
+ - fixed confirm message validation in error cases
+ [https://w1.fi/security/2019-3/] (CVE-2019-9496)
+ * EAP-pwd changes
+ - minimize timing and memory use differences in PWE derivation
+ [https://w1.fi/security/2019-2/] (CVE-2019-9495)
+ - verify peer scalar/element
+ [https://w1.fi/security/2019-4/] (CVE-2019-9497 and CVE-2019-9498)
+ - fix message reassembly issue with unexpected fragment
+ [https://w1.fi/security/2019-5/]
+ - enforce rand,mask generation rules more strictly
+ - fix a memory leak in PWE derivation
+ - disallow ECC groups with a prime under 256 bits (groups 25, 26, and
+ 27)
+ * Hotspot 2.0 changes
+ - added support for release number 3
+ - reject release 2 or newer association without PMF
+ * added support for RSN operating channel validation
+ (CONFIG_OCV=y and configuration parameter ocv=1)
+ * added Multi-AP protocol support
+ * added FTM responder configuration
+ * fixed build with LibreSSL
+ * added FT/RRB workaround for short Ethernet frame padding
+ * fixed KEK2 derivation for FILS+FT
+ * added RSSI-based association rejection from OCE
+ * extended beacon reporting functionality
+ * VLAN changes
+ - allow local VLAN management with remote RADIUS authentication
+ - add WPA/WPA2 passphrase/PSK -based VLAN assignment
+ * OpenSSL: allow systemwide policies to be overridden
+ * extended PEAP to derive EMSK to enable use with ERP/FILS
+ * extended WPS to allow SAE configuration to be added automatically
+ for PSK (wps_cred_add_sae=1)
+ * fixed FT and SA Query Action frame with AP-MLME-in-driver cases
+ * OWE: allow Diffie-Hellman Parameter element to be included with DPP
+ in preparation for DPP protocol extension
+ * RADIUS server: started to accept ERP keyName-NAI as user identity
+ automatically without matching EAP database entry
+ * fixed PTK rekeying with FILS and FT
+
+2018-12-02 - v2.7
+ * fixed WPA packet number reuse with replayed messages and key
+ reinstallation
+ [http://w1.fi/security/2017-1/] (CVE-2017-13082)
+ * added support for FILS (IEEE 802.11ai) shared key authentication
+ * added support for OWE (Opportunistic Wireless Encryption, RFC 8110;
+ and transition mode defined by WFA)
+ * added support for DPP (Wi-Fi Device Provisioning Protocol)
+ * FT:
+ - added local generation of PMK-R0/PMK-R1 for FT-PSK
+ (ft_psk_generate_local=1)
+ - replaced inter-AP protocol with a cleaner design that is more
+ easily extensible; this breaks backward compatibility and requires
+ all APs in the ESS to be updated at the same time to maintain FT
+ functionality
+ - added support for wildcard R0KH/R1KH
+ - replaced r0_key_lifetime (minutes) parameter with
+ ft_r0_key_lifetime (seconds)
+ - fixed wpa_psk_file use for FT-PSK
+ - fixed FT-SAE PMKID matching
+ - added expiration to PMK-R0 and PMK-R1 cache
+ - added IEEE VLAN support (including tagged VLANs)
+ - added support for SHA384 based AKM
+ * SAE
+ - fixed some PMKSA caching cases with SAE
+ - added support for configuring SAE password separately of the
+ WPA2 PSK/passphrase
+ - added option to require MFP for SAE associations
+ (sae_require_pmf=1)
+ - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection
+ for SAE;
+ note: this is not backwards compatible, i.e., both the AP and
+ station side implementations will need to be update at the same
+ time to maintain interoperability
+ - added support for Password Identifier
+ * hostapd_cli: added support for command history and completion
+ * added support for requesting beacon report
+ * large number of other fixes, cleanup, and extensions
+ * added option to configure EAPOL-Key retry limits
+ (wpa_group_update_count and wpa_pairwise_update_count)
+ * removed all PeerKey functionality
+ * fixed nl80211 AP mode configuration regression with Linux 4.15 and
+ newer
+ * added support for using wolfSSL cryptographic library
+ * fixed some 20/40 MHz coexistence cases where the BSS could drop to
+ 20 MHz even when 40 MHz would be allowed
+ * Hotspot 2.0
+ - added support for setting Venue URL ANQP-element (venue_url)
+ - added support for advertising Hotspot 2.0 operator icons
+ - added support for Roaming Consortium Selection element
+ - added support for Terms and Conditions
+ - added support for OSEN connection in a shared RSN BSS
+ * added support for using OpenSSL 1.1.1
+ * added EAP-pwd server support for salted passwords
+
+2016-10-02 - v2.6
+ * fixed EAP-pwd last fragment validation
+ [http://w1.fi/security/2015-7/] (CVE-2015-5314)
+ * fixed WPS configuration update vulnerability with malformed passphrase
+ [http://w1.fi/security/2016-1/] (CVE-2016-4476)
+ * extended channel switch support for VHT bandwidth changes
+ * added support for configuring new ANQP-elements with
+ anqp_elem=<InfoID>:<hexdump of payload>
+ * fixed Suite B 192-bit AKM to use proper PMK length
+ (note: this makes old releases incompatible with the fixed behavior)
+ * added no_probe_resp_if_max_sta=1 parameter to disable Probe Response
+ frame sending for not-associated STAs if max_num_sta limit has been
+ reached
+ * added option (-S as command line argument) to request all interfaces
+ to be started at the same time
+ * modified rts_threshold and fragm_threshold configuration parameters
+ to allow -1 to be used to disable RTS/fragmentation
+ * EAP-pwd: added support for Brainpool Elliptic Curves
+ (with OpenSSL 1.0.2 and newer)
+ * fixed EAPOL reauthentication after FT protocol run
+ * fixed FTIE generation for 4-way handshake after FT protocol run
+ * fixed and improved various FST operations
+ * TLS server
+ - support SHA384 and SHA512 hashes
+ - support TLS v1.2 signature algorithm with SHA384 and SHA512
+ - support PKCS #5 v2.0 PBES2
+ - support PKCS #5 with PKCS #12 style key decryption
+ - minimal support for PKCS #12
+ - support OCSP stapling (including ocsp_multi)
+ * added support for OpenSSL 1.1 API changes
+ - drop support for OpenSSL 0.9.8
+ - drop support for OpenSSL 1.0.0
+ * EAP-PEAP: support fast-connect crypto binding
+ * RADIUS
+ - fix Called-Station-Id to not escape SSID
+ - add Event-Timestamp to all Accounting-Request packets
+ - add Acct-Session-Id to Accounting-On/Off
+ - add Acct-Multi-Session-Id ton Access-Request packets
+ - add Service-Type (= Frames)
+ - allow server to provide PSK instead of passphrase for WPA-PSK
+ Tunnel_password case
+ - update full message for interim accounting updates
+ - add Acct-Delay-Time into Accounting messages
+ - add require_message_authenticator configuration option to require
+ CoA/Disconnect-Request packets to be authenticated
+ * started to postpone WNM-Notification frame sending by 100 ms so that
+ the STA has some more time to configure the key before this frame is
+ received after the 4-way handshake
+ * VHT: added interoperability workaround for 80+80 and 160 MHz channels
+ * extended VLAN support (per-STA vif, etc.)
+ * fixed PMKID derivation with SAE
+ * nl80211
+ - added support for full station state operations
+ - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
+ unencrypted EAPOL frames
+ * added initial MBO support; number of extensions to WNM BSS Transition
+ Management
+ * added initial functionality for location related operations
+ * added assocresp_elements parameter to allow vendor specific elements
+ to be added into (Re)Association Response frames
+ * improved Public Action frame addressing
+ - use Address 3 = wildcard BSSID in GAS response if a query from an
+ unassociated STA used that address
+ - fix TX status processing for Address 3 = wildcard BSSID
+ - add gas_address3 configuration parameter to control Address 3
+ behavior
+ * added command line parameter -i to override interface parameter in
+ hostapd.conf
+ * added command completion support to hostapd_cli
+ * added passive client taxonomy determination (CONFIG_TAXONOMY=y
+ compile option and "SIGNATURE <addr>" control interface command)
+ * number of small fixes
+
2015-09-27 - v2.5
* fixed WPS UPnP vulnerability with HTTP chunked transfer encoding
[http://w1.fi/security/2015-2/] (CVE-2015-4141)
diff --git a/contrib/wpa/hostapd/README b/contrib/wpa/hostapd/README
index 366b199..1f30d7e 100644
--- a/contrib/wpa/hostapd/README
+++ b/contrib/wpa/hostapd/README
@@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
@@ -70,7 +70,7 @@ Requirements
Current hardware/software requirements:
- drivers:
Host AP driver for Prism2/2.5/3.
- (http://hostap.epitest.fi/)
+ (http://w1.fi/hostap-driver.html)
Please note that station firmware version needs to be 1.7.0 or newer
to work in WPA mode.
@@ -81,8 +81,7 @@ Current hardware/software requirements:
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)
+ FreeBSD -current
BSD net80211 layer (e.g., Atheros driver)
@@ -186,23 +185,13 @@ 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
-------------------------------------
+Authentication Server
+---------------------
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.
+Authenticator.
Automatic WEP key configuration
-------------------------------
@@ -243,16 +232,15 @@ 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.
+802.11 standard was approved in June 2004 and this amendment was
+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).
+by Wi-Fi Alliance.
IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
for protecting wireless networks. WEP uses RC4 with 40-bit keys,
diff --git a/contrib/wpa/hostapd/README-MULTI-AP b/contrib/wpa/hostapd/README-MULTI-AP
new file mode 100644
index 0000000..ccee69e
--- /dev/null
+++ b/contrib/wpa/hostapd/README-MULTI-AP
@@ -0,0 +1,160 @@
+hostapd, wpa_supplicant and the Multi-AP Specification
+======================================================
+
+This document describes how hostapd and wpa_supplicant can be configured to
+support the Multi-AP Specification.
+
+Introduction to Multi-AP
+------------------------
+
+The Wi-Fi Alliance Multi-AP Specification is the technical specification for
+Wi-Fi CERTIFIED EasyMesh(TM) [1], the Wi-Fi Alliance® certification program for
+Multi-AP. It defines control protocols between Wi-Fi® access points (APs) to
+join them into a network with centralized control and operation. It is targeted
+only at routers (repeaters, gateways, ...), not at clients. Clients are not
+involved at all in the protocols.
+
+Most of the Multi-AP specification falls outside of the scope of
+hostapd/wpa_supplicant. hostapd/wpa_supplicant is only involved for the items
+summarized below. The rest of the protocol must be implemented by a separate
+daemon, e.g., prplMesh [2]. That daemon also needs to communicate with hostapd,
+e.g., to get a list of associated clients, but this can be done using the normal
+hostapd interfaces.
+
+hostapd/wpa_supplicant needs to be configured specifically to support:
+- the WPS onboarding process;
+- configuring backhaul links.
+
+The text below refers to "Multi-AP Specification v1.0" [3].
+
+
+Fronthaul and backhaul links
+----------------------------
+
+In a Multi-AP network, the central controller can configure the BSSs on the
+devices that are joined into the network. These are called fronthaul BSSs.
+From the point of view of hostapd, there is nothing special about these
+fronthaul BSSs.
+
+In addition to fronthaul BSSs, the controller can also configure backhaul
+links. A backhaul link is a link between two access point devices, giving
+internet access to access point devices that don't have a wired link. The
+Multi-AP specification doesn't dictate this, but typically the backhaul link
+will be bridged into a LAN together with (one of) the fronthaul BSS(s) and the
+wired Ethernet ports.
+
+A backhaul link must be treated specially by hostapd and wpa_supplicant. One
+side of the backhaul link is configured through the Multi-AP protocol as the
+"backhaul STA", i.e., the client side of the link. A backhaul STA is like any
+station and is handled appropriately by wpa_supplicant, but two additional
+features are required. It must send an additional information element in each
+(Re)Association Request frame ([3], section 5.2, paragraph 4). In addition, it
+must use 4-address mode for all frames sent over this link ([3], section 14).
+Therefore, wpa_supplicant must be configured explicitly as the backhaul STA
+role, by setting 'multi_ap_backhaul_sta=1' in the network configuration block
+or when configuring the network profile through the control interface. When
+'multi_ap_backhaul_sta=1', wpa_supplicant includes the Multi-AP IE in
+(Re)Association Request frame and verifies that it is included in the
+(Re)Association Response frame. If it is not, association fails. If it is,
+wpa_supplicant sets 4-address mode for this interface through a driver
+callback.
+
+The AP side of the backhaul link is called a "backhaul BSS". Such a BSS must
+be handled specially by hostapd, because it must add an additional information
+element in each (Re)Association Response frame, but only to stations that have
+identified themselves as backhaul stations ([3], section 5.2, paragraph 5-6).
+This is important because it is possible to use the same BSS and SSID for
+fronthaul and backhaul at the same time. The additional information element must
+only be used for frames sent to a backhaul STA, not to a normal STA. Also,
+frames sent to a backhaul STA must use 4-address mode, while frames sent to a
+normal STA (fronthaul, when it's a fronthaul and backhaul BSS) must use
+3-address mode.
+
+A BSS is configured in Multi-AP mode in hostapd by setting the 'multi_ap'
+configuration option to 1 (backhaul BSS), 2 (fronthaul BSS), or 3
+(simultaneous backhaul and fronthaul BSS). If this option is set, hostapd
+parses the Multi-AP information element in the Association Request frame. If the
+station is a backhaul STA and the BSS is configured as a backhaul BSS,
+hostapd sets up 4-address mode. Since there may be multiple stations connected
+simultaneously, and each of them has a different RA (receiver address), a VLAN
+is created for each backhaul STA and it is automatically added to a bridge.
+This is the same behavior as for WDS, and the relevant option ('bridge' or
+'wds_bridge') applies here as well.
+
+If 'multi_ap' is 1 (backhaul BSS only), any station that tries to associate
+without the Multi-AP information element will be denied.
+
+If 'multi_ap' is 2 (fronthaul BSS only), any station that tries to associate
+with the Multi-AP information element will be denied. That is also the only
+difference with 'multi_ap' set to 0: in the latter case, the Multi-AP
+information element is simply ignored.
+
+In summary, this is the end-to-end behavior for a backhaul BSS (i.e.,
+multi_ap_backhaul_sta=1 in wpa_supplicant on STA, and multi_ap=1 or 3 in
+hostapd on AP). Note that point 1 means that hostapd must not be configured
+with WPS support on the backhaul BSS (multi_ap=1). hostapd does not check for
+that.
+
+1. Backhaul BSS beacons do not advertise WPS support (other than that, nothing
+ Multi-AP specific).
+2. STA sends Authentication frame (nothing Multi-AP specific).
+3. AP sends Authentication frame (nothing Multi-AP specific).
+4. STA sends Association Request frame with Multi-AP IE.
+5. AP sends Association Response frame with Multi-AP IE.
+6. STA and AP both use 4-address mode for Data frames.
+
+
+WPS support
+-----------
+
+WPS requires more special handling. WPS must only be advertised on fronthaul
+BSSs, not on backhaul BSSs, so WPS should not be enabled on a backhaul-only
+BSS in hostapd.conf. The WPS configuration purely works on the fronthaul BSS.
+When a WPS M1 message has an additional subelement that indicates a request for
+a Multi-AP backhaul link, hostapd must not respond with the normal fronthaul
+BSS credentials; instead, it should respond with the (potentially different)
+backhaul BSS credentials.
+
+To support this, hostapd has the 'multi_ap_backhaul_ssid',
+'multi_ap_backhaul_wpa_psk' and 'multi_ap_backhaul_wpa_passphrase' options.
+When these are set on an BSS with WPS, they are used instead of the normal
+credentials when hostapd receives a WPS M1 message with the Multi-AP IE. Only
+WPA2-Personal is supported in the Multi-AP specification, so there is no need
+to specify authentication or encryption options. For the backhaul credentials,
+per-device PSK is not supported.
+
+If the BSS is a simultaneous backhaul and fronthaul BSS, there is no need to
+specify the backhaul credentials, since the backhaul and fronthaul credentials
+are identical.
+
+To enable the Multi-AP backhaul STA feature when it performs WPS, a new
+parameter has been introduced to the WPS_PBC control interface call. When this
+"multi_ap=1" option is set, it adds the Multi-AP backhaul subelement to the
+Association Request frame and the M1 message. It then configures the new network
+profile with 'multi_ap_backhaul_sta=1'. Note that this means that if the AP does
+not follow the Multi-AP specification, wpa_supplicant will fail to associate.
+
+In summary, this is the end-to-end behavior for WPS of a backhaul link (i.e.,
+multi_ap=1 option is given in the wps_pbc call on the STA side, and multi_ap=2
+and multi_ap_backhaul_ssid and either multi_ap_backhaul_wpa_psk or
+multi_ap_backhaul_wpa_passphrase are set to the credentials of a backhaul BSS
+in hostapd on Registrar AP).
+
+1. Fronthaul BSS Beacon frames advertise WPS support (nothing Multi-AP
+ specific).
+2. Enrollee sends Authentication frame (nothing Multi-AP specific).
+3. AP sends Authentication frame (nothing Multi-AP specific).
+4. Enrollee sends Association Request frame with Multi-AP IE.
+5. AP sends Association Response frame with Multi-AP IE.
+6. Enrollee sends M1 with additional Multi-AP subelement.
+7. AP sends M8 with backhaul instead of fronthaul credentials.
+8. Enrollee sends Deauthentication frame.
+
+
+References
+----------
+
+[1] https://www.wi-fi.org/discover-wi-fi/wi-fi-easymesh
+[2] https://github.com/prplfoundation/prplMesh
+[3] https://www.wi-fi.org/file/multi-ap-specification-v10
+ (requires registration)
diff --git a/contrib/wpa/hostapd/config_file.c b/contrib/wpa/hostapd/config_file.c
index 82ac61d..42f3b40 100644
--- a/contrib/wpa/hostapd/config_file.c
+++ b/contrib/wpa/hostapd/config_file.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration file parser
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,8 @@
#include "utils/common.h"
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
+#include "crypto/sha256.h"
+#include "crypto/tls.h"
#include "drivers/driver.h"
#include "eap_server/eap.h"
#include "radius/radius_client.h"
@@ -35,7 +37,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
const char *fname)
{
FILE *f;
- char buf[128], *pos, *pos2;
+ char buf[128], *pos, *pos2, *pos3;
int line = 0, vlan_id;
struct hostapd_vlan *vlan;
@@ -80,7 +82,10 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
pos2 = pos;
while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
pos2++;
- *pos2 = '\0';
+
+ if (*pos2 != '\0')
+ *(pos2++) = '\0';
+
if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
"in '%s'", line, fname);
@@ -88,6 +93,13 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
return -1;
}
+ while (*pos2 == ' ' || *pos2 == '\t')
+ pos2++;
+ pos3 = pos2;
+ while (*pos3 != ' ' && *pos3 != '\t' && *pos3 != '\0')
+ pos3++;
+ *pos3 = '\0';
+
vlan = os_zalloc(sizeof(*vlan));
if (vlan == NULL) {
wpa_printf(MSG_ERROR, "Out of memory while reading "
@@ -97,7 +109,10 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
}
vlan->vlan_id = vlan_id;
+ vlan->vlan_desc.untagged = vlan_id;
+ vlan->vlan_desc.notempty = !!vlan_id;
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
+ os_strlcpy(vlan->bridge, pos2, sizeof(vlan->bridge));
vlan->next = bss->vlan;
bss->vlan = vlan;
}
@@ -109,7 +124,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
#endif /* CONFIG_NO_VLAN */
-static int hostapd_acl_comp(const void *a, const void *b)
+int hostapd_acl_comp(const void *a, const void *b)
{
const struct mac_acl_entry *aa = a;
const struct mac_acl_entry *bb = b;
@@ -117,6 +132,44 @@ static int hostapd_acl_comp(const void *a, const void *b)
}
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+ int vlan_id, const u8 *addr)
+{
+ struct mac_acl_entry *newacl;
+
+ newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
+ if (!newacl) {
+ wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+ return -1;
+ }
+
+ *acl = newacl;
+ os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+ os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
+ (*acl)[*num].vlan_id.untagged = vlan_id;
+ (*acl)[*num].vlan_id.notempty = !!vlan_id;
+ (*num)++;
+
+ return 0;
+}
+
+
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+ const u8 *addr)
+{
+ int i = 0;
+
+ while (i < *num) {
+ if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
+ os_remove_in_array(*acl, *num, sizeof(**acl), i);
+ (*num)--;
+ } else {
+ i++;
+ }
+ }
+}
+
+
static int hostapd_config_read_maclist(const char *fname,
struct mac_acl_entry **acl, int *num)
{
@@ -124,12 +177,8 @@ static int hostapd_config_read_maclist(const char *fname,
char buf[128], *pos;
int line = 0;
u8 addr[ETH_ALEN];
- struct mac_acl_entry *newacl;
int vlan_id;
- if (!fname)
- return 0;
-
f = fopen(fname, "r");
if (!f) {
wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
@@ -137,7 +186,7 @@ static int hostapd_config_read_maclist(const char *fname,
}
while (fgets(buf, sizeof(buf), f)) {
- int i, rem = 0;
+ int rem = 0;
line++;
@@ -167,16 +216,7 @@ static int hostapd_config_read_maclist(const char *fname,
}
if (rem) {
- i = 0;
- while (i < *num) {
- if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) ==
- 0) {
- os_remove_in_array(*acl, *num,
- sizeof(**acl), i);
- (*num)--;
- } else
- i++;
- }
+ hostapd_remove_acl_mac(acl, num, addr);
continue;
}
vlan_id = 0;
@@ -188,28 +228,78 @@ static int hostapd_config_read_maclist(const char *fname,
if (*pos != '\0')
vlan_id = atoi(pos);
- newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
- if (newacl == NULL) {
- wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+ if (hostapd_add_acl_maclist(acl, num, vlan_id, addr) < 0) {
fclose(f);
return -1;
}
-
- *acl = newacl;
- os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
- (*acl)[*num].vlan_id = vlan_id;
- (*num)++;
}
fclose(f);
- qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+ if (*acl)
+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
return 0;
}
#ifdef EAP_SERVER
+
+static int hostapd_config_eap_user_salted(struct hostapd_eap_user *user,
+ const char *hash, size_t len,
+ char **pos, int line,
+ const char *fname)
+{
+ char *pos2 = *pos;
+
+ while (*pos2 != '\0' && *pos2 != ' ' && *pos2 != '\t' && *pos2 != '#')
+ pos2++;
+
+ if (pos2 - *pos < (int) (2 * (len + 1))) { /* at least 1 byte of salt */
+ wpa_printf(MSG_ERROR,
+ "Invalid salted %s hash on line %d in '%s'",
+ hash, line, fname);
+ return -1;
+ }
+
+ user->password = os_malloc(len);
+ if (!user->password) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate memory for salted %s hash",
+ hash);
+ return -1;
+ }
+
+ if (hexstr2bin(*pos, user->password, len) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid salted password on line %d in '%s'",
+ line, fname);
+ return -1;
+ }
+ user->password_len = len;
+ *pos += 2 * len;
+
+ user->salt_len = (pos2 - *pos) / 2;
+ user->salt = os_malloc(user->salt_len);
+ if (!user->salt) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate memory for salted %s hash",
+ hash);
+ return -1;
+ }
+
+ if (hexstr2bin(*pos, user->salt, user->salt_len) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid salt for password on line %d in '%s'",
+ line, fname);
+ return -1;
+ }
+
+ *pos = pos2;
+ return 0;
+}
+
+
static int hostapd_config_read_eap_user(const char *fname,
struct hostapd_bss_config *conf)
{
@@ -218,9 +308,6 @@ static int hostapd_config_read_eap_user(const char *fname,
int line = 0, ret = 0, num_methods;
struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
- if (!fname)
- return 0;
-
if (os_strncmp(fname, "sqlite:", 7) == 0) {
#ifdef CONFIG_SQLITE
os_free(conf->eap_user_sqlite);
@@ -307,13 +394,12 @@ static int hostapd_config_read_eap_user(const char *fname,
goto failed;
}
- user->identity = os_malloc(pos - start);
+ user->identity = os_memdup(start, pos - start);
if (user->identity == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate "
"memory for EAP identity");
goto failed;
}
- os_memcpy(user->identity, start, pos - start);
user->identity_len = pos - start;
if (pos[0] == '"' && pos[1] == '*') {
@@ -431,13 +517,12 @@ static int hostapd_config_read_eap_user(const char *fname,
goto failed;
}
- user->password = os_malloc(pos - start);
+ user->password = os_memdup(start, pos - start);
if (user->password == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate "
"memory for EAP password");
goto failed;
}
- os_memcpy(user->password, start, pos - start);
user->password_len = pos - start;
pos++;
@@ -466,6 +551,24 @@ static int hostapd_config_read_eap_user(const char *fname,
user->password_len = 16;
user->password_hash = 1;
pos = pos2;
+ } else if (os_strncmp(pos, "ssha1:", 6) == 0) {
+ pos += 6;
+ if (hostapd_config_eap_user_salted(user, "sha1", 20,
+ &pos,
+ line, fname) < 0)
+ goto failed;
+ } else if (os_strncmp(pos, "ssha256:", 8) == 0) {
+ pos += 8;
+ if (hostapd_config_eap_user_salted(user, "sha256", 32,
+ &pos,
+ line, fname) < 0)
+ goto failed;
+ } else if (os_strncmp(pos, "ssha512:", 8) == 0) {
+ pos += 8;
+ if (hostapd_config_eap_user_salted(user, "sha512", 64,
+ &pos,
+ line, fname) < 0)
+ goto failed;
} else {
pos2 = pos;
while (*pos2 != '\0' && *pos2 != ' ' &&
@@ -517,19 +620,15 @@ static int hostapd_config_read_eap_user(const char *fname,
fclose(f);
if (ret == 0) {
- user = conf->eap_user;
- while (user) {
- struct hostapd_eap_user *prev;
-
- prev = user;
- user = user->next;
- hostapd_config_free_eap_user(prev);
- }
+ hostapd_config_free_eap_users(conf->eap_user);
conf->eap_user = new_user;
+ } else {
+ hostapd_config_free_eap_users(new_user);
}
return ret;
}
+
#endif /* EAP_SERVER */
@@ -631,8 +730,7 @@ hostapd_parse_radius_attr(const char *value)
}
-static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
- const char *val)
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
{
char *secret;
@@ -640,7 +738,7 @@ static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
if (secret == NULL)
return -1;
- secret++;
+ *secret++ = '\0';
if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
return -1;
@@ -680,12 +778,16 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
val |= WPA_KEY_MGMT_PSK;
else if (os_strcmp(start, "WPA-EAP") == 0)
val |= WPA_KEY_MGMT_IEEE8021X;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
else if (os_strcmp(start, "FT-PSK") == 0)
val |= WPA_KEY_MGMT_FT_PSK;
else if (os_strcmp(start, "FT-EAP") == 0)
val |= WPA_KEY_MGMT_FT_IEEE8021X;
-#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SHA384
+ else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
@@ -706,6 +808,30 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ else if (os_strcmp(start, "FILS-SHA256") == 0)
+ val |= WPA_KEY_MGMT_FILS_SHA256;
+ else if (os_strcmp(start, "FILS-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FILS_SHA384;
+#ifdef CONFIG_IEEE80211R_AP
+ else if (os_strcmp(start, "FT-FILS-SHA256") == 0)
+ val |= WPA_KEY_MGMT_FT_FILS_SHA256;
+ else if (os_strcmp(start, "FT-FILS-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FT_FILS_SHA384;
+#endif /* CONFIG_IEEE80211R_AP */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ else if (os_strcmp(start, "OWE") == 0)
+ val |= WPA_KEY_MGMT_OWE;
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ else if (os_strcmp(start, "DPP") == 0)
+ val |= WPA_KEY_MGMT_DPP;
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ else if (os_strcmp(start, "OSEN") == 0)
+ val |= WPA_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -751,17 +877,34 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
{
size_t len = os_strlen(val);
- if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+ if (keyidx < 0 || keyidx > 3)
+ return -1;
+
+ if (len == 0) {
+ int i, set = 0;
+
+ bin_clear_free(wep->key[keyidx], wep->len[keyidx]);
+ wep->key[keyidx] = NULL;
+ wep->len[keyidx] = 0;
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (wep->key[i])
+ set++;
+ }
+ if (!set)
+ wep->keys_set = 0;
+ return 0;
+ }
+
+ if (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);
+ wep->key[keyidx] = os_memdup(val + 1, len);
if (wep->key[keyidx] == NULL)
return -1;
- os_memcpy(wep->key[keyidx], val + 1, len);
wep->len[keyidx] = len;
} else {
if (len & 1)
@@ -974,7 +1117,27 @@ static int hostapd_config_tx_queue(struct hostapd_config *conf,
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
+
+static int rkh_derive_key(const char *pos, u8 *key, size_t key_len)
+{
+ u8 oldkey[16];
+ int ret;
+
+ if (!hexstr2bin(pos, key, key_len))
+ return 0;
+
+ /* Try to use old short key for backwards compatibility */
+ if (hexstr2bin(pos, oldkey, sizeof(oldkey)))
+ return -1;
+
+ ret = hmac_sha256_kdf(oldkey, sizeof(oldkey), "FT OLDKEY", NULL, 0,
+ key, key_len);
+ os_memset(oldkey, 0, sizeof(oldkey));
+ return ret;
+}
+
+
static int add_r0kh(struct hostapd_bss_config *bss, char *value)
{
struct ft_remote_r0kh *r0kh;
@@ -1008,7 +1171,7 @@ static int add_r0kh(struct hostapd_bss_config *bss, char *value)
os_memcpy(r0kh->id, pos, r0kh->id_len);
pos = next;
- if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
+ if (rkh_derive_key(pos, r0kh->key, sizeof(r0kh->key)) < 0) {
wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
os_free(r0kh);
return -1;
@@ -1053,7 +1216,7 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
}
pos = next;
- if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
+ if (rkh_derive_key(pos, r1kh->key, sizeof(r1kh->key)) < 0) {
wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
os_free(r1kh);
return -1;
@@ -1064,7 +1227,7 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211N
@@ -1081,6 +1244,12 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
conf->secondary_channel = 1;
}
+ if (os_strstr(capab, "[HT40+]") && os_strstr(capab, "[HT40-]")) {
+ conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ conf->ht40_plus_minus_allowed = 1;
+ }
+ if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
+ conf->secondary_channel = 0;
if (os_strstr(capab, "[SMPS-STATIC]")) {
conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
@@ -1210,6 +1379,30 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+
+static u8 find_bit_offset(u8 val)
+{
+ u8 res = 0;
+
+ for (; val; val >>= 1) {
+ if (val & 1)
+ break;
+ res++;
+ }
+
+ return res;
+}
+
+
+static u8 set_he_cap(int val, u8 mask)
+{
+ return (u8) (mask & (val << find_bit_offset(mask)));
+}
+
+#endif /* CONFIG_IEEE80211AX */
+
+
#ifdef CONFIG_INTERWORKING
static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
int line)
@@ -1303,6 +1496,44 @@ static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
}
+static int parse_venue_url(struct hostapd_bss_config *bss, char *pos,
+ int line)
+{
+ char *sep;
+ size_t nlen;
+ struct hostapd_venue_url *url;
+ int ret = -1;
+
+ sep = os_strchr(pos, ':');
+ if (!sep)
+ goto fail;
+ *sep++ = '\0';
+
+ nlen = os_strlen(sep);
+ if (nlen > 254)
+ goto fail;
+
+ url = os_realloc_array(bss->venue_url, bss->venue_url_count + 1,
+ sizeof(struct hostapd_venue_url));
+ if (!url)
+ goto fail;
+
+ bss->venue_url = url;
+ url = &bss->venue_url[bss->venue_url_count++];
+
+ url->venue_number = atoi(pos);
+ url->url_len = nlen;
+ os_memcpy(url->url, sep, nlen);
+
+ ret = 0;
+fail:
+ if (ret)
+ wpa_printf(MSG_ERROR, "Line %d: Invalid venue_url '%s'",
+ line, pos);
+ return ret;
+}
+
+
static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
int line)
{
@@ -1519,6 +1750,54 @@ fail:
}
+static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line)
+{
+ char *delim;
+ u16 infoid;
+ size_t len;
+ struct wpabuf *payload;
+ struct anqp_element *elem;
+
+ delim = os_strchr(buf, ':');
+ if (!delim)
+ return -1;
+ delim++;
+ infoid = atoi(buf);
+ len = os_strlen(delim);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ payload = wpabuf_alloc(len);
+ if (!payload)
+ return -1;
+ if (hexstr2bin(delim, wpabuf_put(payload, len), len) < 0) {
+ wpabuf_free(payload);
+ return -1;
+ }
+
+ dl_list_for_each(elem, &bss->anqp_elem, struct anqp_element, list) {
+ if (elem->infoid == infoid) {
+ /* Update existing entry */
+ wpabuf_free(elem->payload);
+ elem->payload = payload;
+ return 0;
+ }
+ }
+
+ /* Add a new entry */
+ elem = os_zalloc(sizeof(*elem));
+ if (!elem) {
+ wpabuf_free(payload);
+ return -1;
+ }
+ elem->infoid = infoid;
+ elem->payload = payload;
+ dl_list_add(&bss->anqp_elem, &elem->list);
+
+ return 0;
+}
+
+
static int parse_qos_map_set(struct hostapd_bss_config *bss,
char *buf, int line)
{
@@ -1805,6 +2084,24 @@ static int hs20_parse_osu_nai(struct hostapd_bss_config *bss,
}
+static int hs20_parse_osu_nai2(struct hostapd_bss_config *bss,
+ char *pos, int line)
+{
+ if (bss->last_osu == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
+ return -1;
+ }
+
+ os_free(bss->last_osu->osu_nai2);
+ bss->last_osu->osu_nai2 = os_strdup(pos);
+ if (bss->last_osu->osu_nai2 == NULL)
+ return -1;
+ bss->hs20_osu_providers_nai_count++;
+
+ return 0;
+}
+
+
static int hs20_parse_osu_method_list(struct hostapd_bss_config *bss, char *pos,
int line)
{
@@ -1864,32 +2161,26 @@ static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss,
return 0;
}
-#endif /* CONFIG_HS20 */
-
-#ifdef CONFIG_WPS_NFC
-static struct wpabuf * hostapd_parse_bin(const char *buf)
+static int hs20_parse_operator_icon(struct hostapd_bss_config *bss, char *pos,
+ int line)
{
- size_t len;
- struct wpabuf *ret;
-
- len = os_strlen(buf);
- if (len & 0x01)
- return NULL;
- len /= 2;
-
- ret = wpabuf_alloc(len);
- if (ret == NULL)
- return NULL;
+ char **n;
- if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
- wpabuf_free(ret);
- return NULL;
- }
+ n = os_realloc_array(bss->hs20_operator_icon,
+ bss->hs20_operator_icon_count + 1, sizeof(char *));
+ if (!n)
+ return -1;
+ bss->hs20_operator_icon = n;
+ bss->hs20_operator_icon[bss->hs20_operator_icon_count] = os_strdup(pos);
+ if (!bss->hs20_operator_icon[bss->hs20_operator_icon_count])
+ return -1;
+ bss->hs20_operator_icon_count++;
- return ret;
+ return 0;
}
-#endif /* CONFIG_WPS_NFC */
+
+#endif /* CONFIG_HS20 */
#ifdef CONFIG_ACS
@@ -1934,6 +2225,157 @@ fail:
#endif /* CONFIG_ACS */
+static int parse_wpabuf_hex(int line, const char *name, struct wpabuf **buf,
+ const char *val)
+{
+ struct wpabuf *elems;
+
+ if (val[0] == '\0') {
+ wpabuf_free(*buf);
+ *buf = NULL;
+ return 0;
+ }
+
+ elems = wpabuf_parse_bin(val);
+ if (!elems) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
+ line, name, val);
+ return -1;
+ }
+
+ wpabuf_free(*buf);
+ *buf = elems;
+
+ return 0;
+}
+
+
+#ifdef CONFIG_FILS
+static int parse_fils_realm(struct hostapd_bss_config *bss, const char *val)
+{
+ struct fils_realm *realm;
+ size_t len;
+
+ len = os_strlen(val);
+ realm = os_zalloc(sizeof(*realm) + len + 1);
+ if (!realm)
+ return -1;
+
+ os_memcpy(realm->realm, val, len);
+ if (fils_domain_name_hash(val, realm->hash) < 0) {
+ os_free(realm);
+ return -1;
+ }
+ dl_list_add_tail(&bss->fils_realms, &realm->list);
+
+ return 0;
+}
+#endif /* CONFIG_FILS */
+
+
+#ifdef EAP_SERVER
+static unsigned int parse_tls_flags(const char *val)
+{
+ unsigned int flags = 0;
+
+ /* Disable TLS v1.3 by default for now to avoid interoperability issue.
+ * This can be enabled by default once the implementation has been fully
+ * completed and tested with other implementations. */
+ flags |= TLS_CONN_DISABLE_TLSv1_3;
+
+ if (os_strstr(val, "[ALLOW-SIGN-RSA-MD5]"))
+ flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
+ if (os_strstr(val, "[DISABLE-TIME-CHECKS]"))
+ flags |= TLS_CONN_DISABLE_TIME_CHECKS;
+ if (os_strstr(val, "[DISABLE-TLSv1.0]"))
+ flags |= TLS_CONN_DISABLE_TLSv1_0;
+ if (os_strstr(val, "[ENABLE-TLSv1.0]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_0;
+ if (os_strstr(val, "[DISABLE-TLSv1.1]"))
+ flags |= TLS_CONN_DISABLE_TLSv1_1;
+ if (os_strstr(val, "[ENABLE-TLSv1.1]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_1;
+ if (os_strstr(val, "[DISABLE-TLSv1.2]"))
+ flags |= TLS_CONN_DISABLE_TLSv1_2;
+ if (os_strstr(val, "[ENABLE-TLSv1.2]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_2;
+ if (os_strstr(val, "[DISABLE-TLSv1.3]"))
+ flags |= TLS_CONN_DISABLE_TLSv1_3;
+ if (os_strstr(val, "[ENABLE-TLSv1.3]"))
+ flags &= ~TLS_CONN_DISABLE_TLSv1_3;
+ if (os_strstr(val, "[SUITEB]"))
+ flags |= TLS_CONN_SUITEB;
+ if (os_strstr(val, "[SUITEB-NO-ECDH]"))
+ flags |= TLS_CONN_SUITEB_NO_ECDH | TLS_CONN_SUITEB;
+
+ return flags;
+}
+#endif /* EAP_SERVER */
+
+
+#ifdef CONFIG_SAE
+static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
+{
+ struct sae_password_entry *pw;
+ const char *pos = val, *pos2, *end = NULL;
+
+ pw = os_zalloc(sizeof(*pw));
+ if (!pw)
+ return -1;
+ os_memset(pw->peer_addr, 0xff, ETH_ALEN); /* default to wildcard */
+
+ pos2 = os_strstr(pos, "|mac=");
+ if (pos2) {
+ end = pos2;
+ pos2 += 5;
+ if (hwaddr_aton(pos2, pw->peer_addr) < 0)
+ goto fail;
+ pos = pos2 + ETH_ALEN * 3 - 1;
+ }
+
+ pos2 = os_strstr(pos, "|vlanid=");
+ if (pos2) {
+ if (!end)
+ end = pos2;
+ pos2 += 8;
+ pw->vlan_id = atoi(pos2);
+ }
+
+ pos2 = os_strstr(pos, "|id=");
+ if (pos2) {
+ if (!end)
+ end = pos2;
+ pos2 += 4;
+ pw->identifier = os_strdup(pos2);
+ if (!pw->identifier)
+ goto fail;
+ }
+
+ if (!end) {
+ pw->password = os_strdup(val);
+ if (!pw->password)
+ goto fail;
+ } else {
+ pw->password = os_malloc(end - val + 1);
+ if (!pw->password)
+ goto fail;
+ os_memcpy(pw->password, val, end - val);
+ pw->password[end - val] = '\0';
+ }
+
+ pw->next = bss->sae_passwords;
+ bss->sae_passwords = pw;
+
+ return 0;
+fail:
+ str_clear_free(pw->password);
+ os_free(pw->identifier);
+ os_free(pw);
+ return -1;
+}
+#endif /* CONFIG_SAE */
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@@ -1949,20 +2391,21 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
} else if (os_strcmp(buf, "driver") == 0) {
int j;
- /* clear to get error below if setting is invalid */
- conf->driver = NULL;
+ const struct wpa_driver_ops *driver = NULL;
+
for (j = 0; wpa_drivers[j]; j++) {
if (os_strcmp(pos, wpa_drivers[j]->name) == 0) {
- conf->driver = wpa_drivers[j];
+ driver = wpa_drivers[j];
break;
}
}
- if (conf->driver == NULL) {
+ if (!driver) {
wpa_printf(MSG_ERROR,
"Line %d: invalid/unknown driver '%s'",
line, pos);
return 1;
}
+ conf->driver = driver;
} else if (os_strcmp(buf, "driver_params") == 0) {
os_free(conf->driver_params);
conf->driver_params = os_strdup(pos);
@@ -2006,13 +2449,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "utf8_ssid") == 0) {
bss->ssid.utf8_ssid = atoi(pos) > 0;
} else if (os_strcmp(buf, "macaddr_acl") == 0) {
- bss->macaddr_acl = atoi(pos);
- if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
- bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
- bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ enum macaddr_acl acl = atoi(pos);
+
+ if (acl != ACCEPT_UNLESS_DENIED &&
+ acl != DENY_UNLESS_ACCEPTED &&
+ acl != USE_EXTERNAL_RADIUS_AUTH) {
wpa_printf(MSG_ERROR, "Line %d: unknown macaddr_acl %d",
- line, bss->macaddr_acl);
+ line, acl);
+ return 1;
}
+ bss->macaddr_acl = acl;
} else if (os_strcmp(buf, "accept_mac_file") == 0) {
if (hostapd_config_read_maclist(pos, &bss->accept_mac,
&bss->num_accept_mac)) {
@@ -2039,8 +2485,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->skip_inactivity_poll = atoi(pos);
} else if (os_strcmp(buf, "country_code") == 0) {
os_memcpy(conf->country, pos, 2);
- /* FIX: make this configurable */
- conf->country[2] = ' ';
+ } else if (os_strcmp(buf, "country3") == 0) {
+ conf->country[2] = strtol(pos, NULL, 16);
} else if (os_strcmp(buf, "ieee80211d") == 0) {
conf->ieee80211d = atoi(pos);
} else if (os_strcmp(buf, "ieee80211h") == 0) {
@@ -2048,13 +2494,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} 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) {
+ int eapol_version = atoi(pos);
+
+ if (eapol_version < 1 || eapol_version > 2) {
wpa_printf(MSG_ERROR,
"Line %d: invalid EAPOL version (%d): '%s'.",
- line, bss->eapol_version, pos);
+ line, eapol_version, pos);
return 1;
}
+ bss->eapol_version = eapol_version;
wpa_printf(MSG_DEBUG, "eapol_version=%d", bss->eapol_version);
#ifdef EAP_SERVER
} else if (os_strcmp(buf, "eap_authenticator") == 0) {
@@ -2077,19 +2525,41 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} 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_cert_subject") == 0) {
+ if (!pos[0]) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown check_cert_subject '%s'",
+ line, pos);
+ return 1;
+ }
+ os_free(bss->check_cert_subject);
+ bss->check_cert_subject = os_strdup(pos);
+ if (!bss->check_cert_subject)
+ return 1;
} else if (os_strcmp(buf, "check_crl") == 0) {
bss->check_crl = atoi(pos);
+ } else if (os_strcmp(buf, "check_crl_strict") == 0) {
+ bss->check_crl_strict = atoi(pos);
+ } else if (os_strcmp(buf, "crl_reload_interval") == 0) {
+ bss->crl_reload_interval = atoi(pos);
} else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
bss->tls_session_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "tls_flags") == 0) {
+ bss->tls_flags = parse_tls_flags(pos);
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
+ } else if (os_strcmp(buf, "ocsp_stapling_response_multi") == 0) {
+ os_free(bss->ocsp_stapling_response_multi);
+ bss->ocsp_stapling_response_multi = os_strdup(pos);
} else if (os_strcmp(buf, "dh_file") == 0) {
os_free(bss->dh_file);
bss->dh_file = os_strdup(pos);
} else if (os_strcmp(buf, "openssl_ciphers") == 0) {
os_free(bss->openssl_ciphers);
bss->openssl_ciphers = os_strdup(pos);
+ } else if (os_strcmp(buf, "openssl_ecdh_curves") == 0) {
+ os_free(bss->openssl_ecdh_curves);
+ bss->openssl_ecdh_curves = os_strdup(pos);
} else if (os_strcmp(buf, "fragment_size") == 0) {
bss->fragment_size = atoi(pos);
#ifdef EAP_SERVER_FAST
@@ -2139,6 +2609,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
os_free(bss->eap_sim_db);
bss->eap_sim_db = os_strdup(pos);
+ } else if (os_strcmp(buf, "eap_sim_db_timeout") == 0) {
+ bss->eap_sim_db_timeout = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
bss->eap_sim_aka_result_ind = atoi(pos);
#endif /* EAP_SERVER_SIM */
@@ -2150,8 +2622,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "pwd_group") == 0) {
bss->pwd_group = atoi(pos);
#endif /* EAP_SERVER_PWD */
+#ifdef CONFIG_ERP
} else if (os_strcmp(buf, "eap_server_erp") == 0) {
bss->eap_server_erp = atoi(pos);
+#endif /* CONFIG_ERP */
#endif /* EAP_SERVER */
} else if (os_strcmp(buf, "eap_message") == 0) {
char *term;
@@ -2177,24 +2651,25 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->erp_domain);
bss->erp_domain = os_strdup(pos);
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
- bss->default_wep_key_len = atoi(pos);
- if (bss->default_wep_key_len > 13) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WEP key len %lu (= %lu bits)",
- line,
- (unsigned long) bss->default_wep_key_len,
- (unsigned long)
- bss->default_wep_key_len * 8);
+ int val = atoi(pos);
+
+ if (val < 0 || val > 13) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid WEP key len %d (= %d bits)",
+ line, val, val * 8);
return 1;
}
+ bss->default_wep_key_len = val;
} else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
- bss->individual_wep_key_len = atoi(pos);
- if (bss->individual_wep_key_len < 0 ||
- bss->individual_wep_key_len > 13) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WEP key len %d (= %d bits)",
- line, bss->individual_wep_key_len,
- bss->individual_wep_key_len * 8);
+ int val = atoi(pos);
+
+ if (val < 0 || val > 13) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid WEP key len %d (= %d bits)",
+ line, val, val * 8);
return 1;
}
+ bss->individual_wep_key_len = val;
} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
bss->wep_rekeying_period = atoi(pos);
if (bss->wep_rekeying_period < 0) {
@@ -2353,6 +2828,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->radius_das_time_window = atoi(pos);
} else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) {
bss->radius_das_require_event_timestamp = atoi(pos);
+ } else if (os_strcmp(buf, "radius_das_require_message_authenticator") ==
+ 0) {
+ bss->radius_das_require_message_authenticator = atoi(pos);
#endif /* CONFIG_NO_RADIUS */
} else if (os_strcmp(buf, "auth_algs") == 0) {
bss->auth_algs = atoi(pos);
@@ -2373,12 +2851,37 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->wpa = atoi(pos);
} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
bss->wpa_group_rekey = atoi(pos);
+ bss->wpa_group_rekey_set = 1;
} else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
bss->wpa_strict_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
bss->wpa_gmk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
bss->wpa_ptk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
+ char *endp;
+ unsigned long val = strtoul(pos, &endp, 0);
+
+ if (*endp || val < 1 || val > (u32) -1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wpa_group_update_count=%lu; allowed range 1..4294967295",
+ line, val);
+ return 1;
+ }
+ bss->wpa_group_update_count = (u32) val;
+ } else if (os_strcmp(buf, "wpa_pairwise_update_count") == 0) {
+ char *endp;
+ unsigned long val = strtoul(pos, &endp, 0);
+
+ if (*endp || val < 1 || val > (u32) -1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wpa_pairwise_update_count=%lu; allowed range 1..4294967295",
+ line, val);
+ return 1;
+ }
+ bss->wpa_pairwise_update_count = (u32) val;
+ } else if (os_strcmp(buf, "wpa_disable_eapol_key_retries") == 0) {
+ bss->wpa_disable_eapol_key_retries = atoi(pos);
} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
int len = os_strlen(pos);
if (len < 8 || len > 63) {
@@ -2437,7 +2940,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
if (bss->wpa_pairwise &
(WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) {
wpa_printf(MSG_ERROR, "Line %d: unsupported pairwise cipher suite '%s'",
- bss->wpa_pairwise, pos);
+ line, pos);
return 1;
}
} else if (os_strcmp(buf, "rsn_pairwise") == 0) {
@@ -2447,7 +2950,21 @@ static int hostapd_config_fill(struct hostapd_config *conf,
if (bss->rsn_pairwise &
(WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) {
wpa_printf(MSG_ERROR, "Line %d: unsupported pairwise cipher suite '%s'",
- bss->rsn_pairwise, pos);
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "group_cipher") == 0) {
+ bss->group_cipher = hostapd_config_parse_cipher(line, pos);
+ if (bss->group_cipher == -1 || bss->group_cipher == 0)
+ return 1;
+ if (bss->group_cipher != WPA_CIPHER_TKIP &&
+ bss->group_cipher != WPA_CIPHER_CCMP &&
+ bss->group_cipher != WPA_CIPHER_GCMP &&
+ bss->group_cipher != WPA_CIPHER_GCMP_256 &&
+ bss->group_cipher != WPA_CIPHER_CCMP_256) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: unsupported group cipher suite '%s'",
+ line, pos);
return 1;
}
#ifdef CONFIG_RSN_PREAUTH
@@ -2457,11 +2974,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->rsn_preauth_interfaces);
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
+ wpa_printf(MSG_INFO,
+ "Line %d: Obsolete peerkey parameter ignored", line);
+#ifdef CONFIG_IEEE80211R_AP
} else if (os_strcmp(buf, "mobility_domain") == 0) {
if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
hexstr2bin(pos, bss->mobility_domain,
@@ -2480,9 +2996,22 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return 1;
}
} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+ /* DEPRECATED: Use ft_r0_key_lifetime instead. */
+ bss->r0_key_lifetime = atoi(pos) * 60;
+ } else if (os_strcmp(buf, "ft_r0_key_lifetime") == 0) {
bss->r0_key_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "r1_max_key_lifetime") == 0) {
+ bss->r1_max_key_lifetime = atoi(pos);
} else if (os_strcmp(buf, "reassociation_deadline") == 0) {
bss->reassociation_deadline = atoi(pos);
+ } else if (os_strcmp(buf, "rkh_pos_timeout") == 0) {
+ bss->rkh_pos_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "rkh_neg_timeout") == 0) {
+ bss->rkh_neg_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "rkh_pull_timeout") == 0) {
+ bss->rkh_pull_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "rkh_pull_retries") == 0) {
+ bss->rkh_pull_retries = atoi(pos);
} else if (os_strcmp(buf, "r0kh") == 0) {
if (add_r0kh(bss, pos) < 0) {
wpa_printf(MSG_DEBUG, "Line %d: Invalid r0kh '%s'",
@@ -2499,7 +3028,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->pmk_r1_push = atoi(pos);
} else if (os_strcmp(buf, "ft_over_ds") == 0) {
bss->ft_over_ds = atoi(pos);
-#endif /* CONFIG_IEEE80211R */
+ } else if (os_strcmp(buf, "ft_psk_generate_local") == 0) {
+ bss->ft_psk_generate_local = atoi(pos);
+#endif /* CONFIG_IEEE80211R_AP */
#ifndef CONFIG_NO_CTRL_IFACE
} else if (os_strcmp(buf, "ctrl_interface") == 0) {
os_free(bss->ctrl_interface);
@@ -2577,6 +3108,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "acs_exclude_dfs") == 0) {
+ conf->acs_exclude_dfs = atoi(pos);
} else if (os_strcmp(buf, "channel") == 0) {
if (os_strcmp(pos, "acs_survey") == 0) {
#ifndef CONFIG_ACS
@@ -2603,9 +3136,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
* cause problems with the current implementation.
* Since it is unlikely that this small numbers are
* useful in real life scenarios, do not allow beacon
- * period to be set below 15 TU. */
- if (val < 15 || val > 65535) {
- wpa_printf(MSG_ERROR, "Line %d: invalid beacon_int %d (expected 15..65535)",
+ * period to be set below 10 TU. */
+ if (val < 10 || val > 65535) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_int %d (expected 10..65535)",
line, val);
return 1;
}
@@ -2627,24 +3161,37 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
#endif /* CONFIG_ACS */
} else if (os_strcmp(buf, "dtim_period") == 0) {
- bss->dtim_period = atoi(pos);
- if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+ int val = atoi(pos);
+
+ if (val < 1 || val > 255) {
wpa_printf(MSG_ERROR, "Line %d: invalid dtim_period %d",
- line, bss->dtim_period);
+ line, val);
return 1;
}
+ bss->dtim_period = val;
} else if (os_strcmp(buf, "bss_load_update_period") == 0) {
- bss->bss_load_update_period = atoi(pos);
- if (bss->bss_load_update_period < 0 ||
- bss->bss_load_update_period > 100) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 100) {
wpa_printf(MSG_ERROR,
"Line %d: invalid bss_load_update_period %d",
- line, bss->bss_load_update_period);
+ line, val);
+ return 1;
+ }
+ bss->bss_load_update_period = val;
+ } else if (os_strcmp(buf, "chan_util_avg_period") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid chan_util_avg_period",
+ line);
return 1;
}
+ bss->chan_util_avg_period = val;
} else if (os_strcmp(buf, "rts_threshold") == 0) {
conf->rts_threshold = atoi(pos);
- if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) {
+ if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) {
wpa_printf(MSG_ERROR,
"Line %d: invalid rts_threshold %d",
line, conf->rts_threshold);
@@ -2652,8 +3199,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "fragm_threshold") == 0) {
conf->fragm_threshold = atoi(pos);
- if (conf->fragm_threshold < 256 ||
- conf->fragm_threshold > 2346) {
+ if (conf->fragm_threshold == -1) {
+ /* allow a value of -1 */
+ } else if (conf->fragm_threshold < 256 ||
+ conf->fragm_threshold > 2346) {
wpa_printf(MSG_ERROR,
"Line %d: invalid fragm_threshold %d",
line, conf->fragm_threshold);
@@ -2666,7 +3215,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, val);
return 1;
}
- conf->send_probe_response = val;
+ bss->send_probe_response = val;
} else if (os_strcmp(buf, "supported_rates") == 0) {
if (hostapd_parse_intlist(&conf->supported_rates, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
@@ -2679,6 +3228,40 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
return 1;
}
+ } else if (os_strcmp(buf, "beacon_rate") == 0) {
+ int val;
+
+ if (os_strncmp(pos, "ht:", 3) == 0) {
+ val = atoi(pos + 3);
+ if (val < 0 || val > 31) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate HT-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_HT;
+ conf->beacon_rate = val;
+ } else if (os_strncmp(pos, "vht:", 4) == 0) {
+ val = atoi(pos + 4);
+ if (val < 0 || val > 9) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate VHT-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_VHT;
+ conf->beacon_rate = val;
+ } else {
+ val = atoi(pos);
+ if (val < 10 || val > 10000) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid legacy beacon_rate %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_LEGACY;
+ conf->beacon_rate = val;
+ }
} else if (os_strcmp(buf, "preamble") == 0) {
if (atoi(pos))
conf->preamble = SHORT_PREAMBLE;
@@ -2686,6 +3269,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->preamble = LONG_PREAMBLE;
} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
bss->ignore_broadcast_ssid = atoi(pos);
+ } else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
+ bss->no_probe_resp_if_max_sta = atoi(pos);
} else if (os_strcmp(buf, "wep_default_key") == 0) {
bss->ssid.wep.idx = atoi(pos);
if (bss->ssid.wep.idx > 3) {
@@ -2707,6 +3292,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
#ifndef CONFIG_NO_VLAN
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
bss->ssid.dynamic_vlan = atoi(pos);
+ } else if (os_strcmp(buf, "per_sta_vif") == 0) {
+ bss->ssid.per_sta_vif = atoi(pos);
} else if (os_strcmp(buf, "vlan_file") == 0) {
if (hostapd_config_read_vlan_file(bss, pos)) {
wpa_printf(MSG_ERROR, "Line %d: failed to read VLAN file '%s'",
@@ -2762,6 +3349,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
return 1;
}
+ } else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
+ conf->use_driver_iface_addr = atoi(pos);
#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
@@ -2794,6 +3383,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return 1;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ } else if (os_strcmp(buf, "ocv") == 0) {
+ bss->ocv = atoi(pos);
+ if (bss->ocv && !bss->ieee80211w)
+ bss->ieee80211w = 1;
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211N
} else if (os_strcmp(buf, "ieee80211n") == 0) {
conf->ieee80211n = atoi(pos);
@@ -2827,7 +3422,111 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
} else if (os_strcmp(buf, "vendor_vht") == 0) {
bss->vendor_vht = atoi(pos);
+ } else if (os_strcmp(buf, "use_sta_nsts") == 0) {
+ bss->use_sta_nsts = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ } else if (os_strcmp(buf, "ieee80211ax") == 0) {
+ conf->ieee80211ax = atoi(pos);
+ } else if (os_strcmp(buf, "he_su_beamformer") == 0) {
+ conf->he_phy_capab.he_su_beamformer = atoi(pos);
+ } else if (os_strcmp(buf, "he_su_beamformee") == 0) {
+ conf->he_phy_capab.he_su_beamformee = atoi(pos);
+ } else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
+ conf->he_phy_capab.he_mu_beamformer = atoi(pos);
+ } else if (os_strcmp(buf, "he_bss_color") == 0) {
+ conf->he_op.he_bss_color = atoi(pos);
+ } else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
+ conf->he_op.he_default_pe_duration = atoi(pos);
+ } else if (os_strcmp(buf, "he_twt_required") == 0) {
+ conf->he_op.he_twt_required = atoi(pos);
+ } else if (os_strcmp(buf, "he_rts_threshold") == 0) {
+ conf->he_op.he_rts_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_param_count") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_EDCA_PARAM_SET_COUNT);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_q_ack") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_Q_ACK);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_queue_request") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_QUEUE_REQUEST);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_txop_request") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_TXOP_REQUEST);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
@@ -2908,7 +3607,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "ap_pin") == 0) {
os_free(bss->ap_pin);
- bss->ap_pin = os_strdup(pos);
+ if (*pos == '\0')
+ bss->ap_pin = NULL;
+ else
+ bss->ap_pin = os_strdup(pos);
} else if (os_strcmp(buf, "skip_cred_build") == 0) {
bss->skip_cred_build = atoi(pos);
} else if (os_strcmp(buf, "extra_cred") == 0) {
@@ -2921,6 +3623,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "wps_cred_processing") == 0) {
bss->wps_cred_processing = atoi(pos);
+ } else if (os_strcmp(buf, "wps_cred_add_sae") == 0) {
+ bss->wps_cred_add_sae = atoi(pos);
} else if (os_strcmp(buf, "ap_settings") == 0) {
os_free(bss->ap_settings);
bss->ap_settings =
@@ -2930,6 +3634,56 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "multi_ap_backhaul_ssid") == 0) {
+ size_t slen;
+ char *str = wpa_config_parse_string(pos, &slen);
+
+ if (!str || slen < 1 || slen > SSID_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
+ line, pos);
+ os_free(str);
+ return 1;
+ }
+ os_memcpy(bss->multi_ap_backhaul_ssid.ssid, str, slen);
+ bss->multi_ap_backhaul_ssid.ssid_len = slen;
+ bss->multi_ap_backhaul_ssid.ssid_set = 1;
+ os_free(str);
+ } else if (os_strcmp(buf, "multi_ap_backhaul_wpa_passphrase") == 0) {
+ int len = os_strlen(pos);
+
+ if (len < 8 || len > 63) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid WPA passphrase length %d (expected 8..63)",
+ line, len);
+ return 1;
+ }
+ os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase);
+ bss->multi_ap_backhaul_ssid.wpa_passphrase = os_strdup(pos);
+ if (bss->multi_ap_backhaul_ssid.wpa_passphrase) {
+ hostapd_config_clear_wpa_psk(
+ &bss->multi_ap_backhaul_ssid.wpa_psk);
+ bss->multi_ap_backhaul_ssid.wpa_passphrase_set = 1;
+ }
+ } else if (os_strcmp(buf, "multi_ap_backhaul_wpa_psk") == 0) {
+ hostapd_config_clear_wpa_psk(
+ &bss->multi_ap_backhaul_ssid.wpa_psk);
+ bss->multi_ap_backhaul_ssid.wpa_psk =
+ os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (!bss->multi_ap_backhaul_ssid.wpa_psk)
+ return 1;
+ if (hexstr2bin(pos, bss->multi_ap_backhaul_ssid.wpa_psk->psk,
+ PMK_LEN) ||
+ pos[PMK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
+ line, pos);
+ hostapd_config_clear_wpa_psk(
+ &bss->multi_ap_backhaul_ssid.wpa_psk);
+ return 1;
+ }
+ bss->multi_ap_backhaul_ssid.wpa_psk->group = 1;
+ os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase);
+ bss->multi_ap_backhaul_ssid.wpa_passphrase = NULL;
+ bss->multi_ap_backhaul_ssid.wpa_psk_set = 1;
} else if (os_strcmp(buf, "upnp_iface") == 0) {
os_free(bss->upnp_iface);
bss->upnp_iface = os_strdup(pos);
@@ -2965,15 +3719,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
wpabuf_free(bss->wps_nfc_dh_pubkey);
- bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_dh_pubkey = wpabuf_parse_bin(pos);
bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
wpabuf_free(bss->wps_nfc_dh_privkey);
- bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_dh_privkey = wpabuf_parse_bin(pos);
bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
wpabuf_free(bss->wps_nfc_dev_pw);
- bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+ bss->wps_nfc_dev_pw = wpabuf_parse_bin(pos);
bss->wps_nfc_pw_from_config = 1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
@@ -3019,12 +3773,14 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->time_zone = os_strdup(pos);
if (bss->time_zone == NULL)
return 1;
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
bss->wnm_sleep_mode = atoi(pos);
+ } else if (os_strcmp(buf, "wnm_sleep_mode_no_keys") == 0) {
+ bss->wnm_sleep_mode_no_keys = atoi(pos);
} else if (os_strcmp(buf, "bss_transition") == 0) {
bss->bss_transition = atoi(pos);
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
#ifdef CONFIG_INTERWORKING
} else if (os_strcmp(buf, "interworking") == 0) {
bss->interworking = atoi(pos);
@@ -3062,6 +3818,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "venue_name") == 0) {
if (parse_venue_name(bss, pos, line) < 0)
return 1;
+ } else if (os_strcmp(buf, "venue_url") == 0) {
+ if (parse_venue_url(bss, pos, line) < 0)
+ return 1;
} else if (os_strcmp(buf, "network_auth_type") == 0) {
u8 auth_type;
u16 redirect_url_len;
@@ -3136,8 +3895,19 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "nai_realm") == 0) {
if (parse_nai_realm(bss, pos, line) < 0)
return 1;
+ } else if (os_strcmp(buf, "anqp_elem") == 0) {
+ if (parse_anqp_elem(bss, pos, line) < 0)
+ return 1;
} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
- bss->gas_frag_limit = atoi(pos);
+ int val = atoi(pos);
+
+ if (val <= 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid gas_frag_limit '%s'",
+ line, pos);
+ return 1;
+ }
+ bss->gas_frag_limit = val;
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
bss->gas_comeback_delay = atoi(pos);
} else if (os_strcmp(buf, "qos_map_set") == 0) {
@@ -3149,13 +3919,25 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->dump_msk_file);
bss->dump_msk_file = os_strdup(pos);
#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_PROXYARP
+ } else if (os_strcmp(buf, "proxy_arp") == 0) {
+ bss->proxy_arp = atoi(pos);
+#endif /* CONFIG_PROXYARP */
#ifdef CONFIG_HS20
} else if (os_strcmp(buf, "hs20") == 0) {
bss->hs20 = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_release") == 0) {
+ int val = atoi(pos);
+
+ if (val < 1 || val > (HS20_VERSION >> 4) + 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Unsupported hs20_release: %s",
+ line, pos);
+ return 1;
+ }
+ bss->hs20_release = val;
} else if (os_strcmp(buf, "disable_dgaf") == 0) {
bss->disable_dgaf = atoi(pos);
- } else if (os_strcmp(buf, "proxy_arp") == 0) {
- bss->proxy_arp = atoi(pos);
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
bss->na_mcast_to_ucast = atoi(pos);
} else if (os_strcmp(buf, "osen") == 0) {
@@ -3216,6 +3998,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "osu_nai") == 0) {
if (hs20_parse_osu_nai(bss, pos, line) < 0)
return 1;
+ } else if (os_strcmp(buf, "osu_nai2") == 0) {
+ if (hs20_parse_osu_nai2(bss, pos, line) < 0)
+ return 1;
} else if (os_strcmp(buf, "osu_method_list") == 0) {
if (hs20_parse_osu_method_list(bss, pos, line) < 0)
return 1;
@@ -3225,12 +4010,34 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "osu_service_desc") == 0) {
if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
return 1;
+ } else if (os_strcmp(buf, "operator_icon") == 0) {
+ if (hs20_parse_operator_icon(bss, pos, line) < 0)
+ return 1;
} else if (os_strcmp(buf, "subscr_remediation_url") == 0) {
os_free(bss->subscr_remediation_url);
bss->subscr_remediation_url = os_strdup(pos);
} else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
bss->subscr_remediation_method = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_t_c_filename") == 0) {
+ os_free(bss->t_c_filename);
+ bss->t_c_filename = os_strdup(pos);
+ } else if (os_strcmp(buf, "hs20_t_c_timestamp") == 0) {
+ bss->t_c_timestamp = strtol(pos, NULL, 0);
+ } else if (os_strcmp(buf, "hs20_t_c_server_url") == 0) {
+ os_free(bss->t_c_server_url);
+ bss->t_c_server_url = os_strdup(pos);
+ } else if (os_strcmp(buf, "hs20_sim_provisioning_url") == 0) {
+ os_free(bss->hs20_sim_provisioning_url);
+ bss->hs20_sim_provisioning_url = os_strdup(pos);
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ } else if (os_strcmp(buf, "mbo") == 0) {
+ bss->mbo_enabled = atoi(pos);
+ } else if (os_strcmp(buf, "mbo_cell_data_conn_pref") == 0) {
+ bss->mbo_cell_data_conn_pref = atoi(pos);
+ } else if (os_strcmp(buf, "oce") == 0) {
+ bss->oce = atoi(pos);
+#endif /* CONFIG_MBO */
#ifdef CONFIG_TESTING_OPTIONS
#define PARSE_TEST_PROBABILITY(_val) \
} else if (os_strcmp(buf, #_val) == 0) { \
@@ -3249,6 +4056,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
PARSE_TEST_PROBABILITY(ignore_assoc_probability)
PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+ } else if (os_strcmp(buf, "ecsa_ie_only") == 0) {
+ conf->ecsa_ie_only = atoi(pos);
} else if (os_strcmp(buf, "bss_load_test") == 0) {
WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
pos = os_strchr(pos, ':');
@@ -3269,7 +4078,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
bss->bss_load_test_set = 1;
} else if (os_strcmp(buf, "radio_measurements") == 0) {
- bss->radio_measurements = atoi(pos);
+ /*
+ * DEPRECATED: This parameter will be removed in the future.
+ * Use rrm_neighbor_report instead.
+ */
+ int val = atoi(pos);
+
+ if (val & BIT(0))
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT;
} else if (os_strcmp(buf, "own_ie_override") == 0) {
struct wpabuf *tmp;
size_t len = os_strlen(pos) / 2;
@@ -3288,39 +4105,30 @@ static int hostapd_config_fill(struct hostapd_config *conf,
wpabuf_free(bss->own_ie_override);
bss->own_ie_override = tmp;
+ } else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
+ bss->sae_reflection_attack = atoi(pos);
+ } else if (os_strcmp(buf, "sae_commit_override") == 0) {
+ wpabuf_free(bss->sae_commit_override);
+ bss->sae_commit_override = wpabuf_parse_bin(pos);
#endif /* CONFIG_TESTING_OPTIONS */
- } else if (os_strcmp(buf, "vendor_elements") == 0) {
- struct wpabuf *elems;
- size_t len = os_strlen(pos);
- if (len & 0x01) {
- wpa_printf(MSG_ERROR,
- "Line %d: Invalid vendor_elements '%s'",
- line, pos);
+#ifdef CONFIG_SAE
+ } else if (os_strcmp(buf, "sae_password") == 0) {
+ if (parse_sae_password(bss, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid sae_password",
+ line);
return 1;
}
- len /= 2;
- if (len == 0) {
- wpabuf_free(bss->vendor_elements);
- bss->vendor_elements = NULL;
- return 0;
- }
-
- elems = wpabuf_alloc(len);
- if (elems == NULL)
+#endif /* CONFIG_SAE */
+ } else if (os_strcmp(buf, "vendor_elements") == 0) {
+ if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
return 1;
-
- if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
- wpabuf_free(elems);
- wpa_printf(MSG_ERROR,
- "Line %d: Invalid vendor_elements '%s'",
- line, pos);
+ } else if (os_strcmp(buf, "assocresp_elements") == 0) {
+ if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
return 1;
- }
-
- wpabuf_free(bss->vendor_elements);
- bss->vendor_elements = elems;
} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
bss->sae_anti_clogging_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "sae_sync") == 0) {
+ bss->sae_sync = atoi(pos);
} else if (os_strcmp(buf, "sae_groups") == 0) {
if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
wpa_printf(MSG_ERROR,
@@ -3328,6 +4136,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "sae_require_mfp") == 0) {
+ bss->sae_require_mfp = atoi(pos);
} else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
int val = atoi(pos);
if (val < 0 || val > 255) {
@@ -3391,7 +4201,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return -1;
}
val = strtol(pos, &endp, 0);
- if (*endp || val < 1 || val > FST_MAX_LLT_MS) {
+ if (*endp || val < 1 ||
+ (unsigned long int) val > FST_MAX_LLT_MS) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
line, val, pos, FST_MAX_LLT_MS);
@@ -3409,6 +4220,135 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
os_free(bss->no_auth_if_seen_on);
bss->no_auth_if_seen_on = os_strdup(pos);
+ } else if (os_strcmp(buf, "lci") == 0) {
+ wpabuf_free(conf->lci);
+ conf->lci = wpabuf_parse_bin(pos);
+ if (conf->lci && wpabuf_len(conf->lci) == 0) {
+ wpabuf_free(conf->lci);
+ conf->lci = NULL;
+ }
+ } else if (os_strcmp(buf, "civic") == 0) {
+ wpabuf_free(conf->civic);
+ conf->civic = wpabuf_parse_bin(pos);
+ if (conf->civic && wpabuf_len(conf->civic) == 0) {
+ wpabuf_free(conf->civic);
+ conf->civic = NULL;
+ }
+ } else if (os_strcmp(buf, "rrm_neighbor_report") == 0) {
+ if (atoi(pos))
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+ } else if (os_strcmp(buf, "rrm_beacon_report") == 0) {
+ if (atoi(pos))
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
+ } else if (os_strcmp(buf, "gas_address3") == 0) {
+ bss->gas_address3 = atoi(pos);
+ } else if (os_strcmp(buf, "stationary_ap") == 0) {
+ conf->stationary_ap = atoi(pos);
+ } else if (os_strcmp(buf, "ftm_responder") == 0) {
+ bss->ftm_responder = atoi(pos);
+ } else if (os_strcmp(buf, "ftm_initiator") == 0) {
+ bss->ftm_initiator = atoi(pos);
+#ifdef CONFIG_FILS
+ } else if (os_strcmp(buf, "fils_cache_id") == 0) {
+ if (hexstr2bin(pos, bss->fils_cache_id, FILS_CACHE_ID_LEN)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid fils_cache_id '%s'",
+ line, pos);
+ return 1;
+ }
+ bss->fils_cache_id_set = 1;
+ } else if (os_strcmp(buf, "fils_realm") == 0) {
+ if (parse_fils_realm(bss, pos) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "fils_dh_group") == 0) {
+ bss->fils_dh_group = atoi(pos);
+ } else if (os_strcmp(buf, "dhcp_server") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->dhcp_server)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "dhcp_rapid_commit_proxy") == 0) {
+ bss->dhcp_rapid_commit_proxy = atoi(pos);
+ } else if (os_strcmp(buf, "fils_hlp_wait_time") == 0) {
+ bss->fils_hlp_wait_time = atoi(pos);
+ } else if (os_strcmp(buf, "dhcp_server_port") == 0) {
+ bss->dhcp_server_port = atoi(pos);
+ } else if (os_strcmp(buf, "dhcp_relay_port") == 0) {
+ bss->dhcp_relay_port = atoi(pos);
+#endif /* CONFIG_FILS */
+ } else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
+ bss->multicast_to_unicast = atoi(pos);
+ } else if (os_strcmp(buf, "broadcast_deauth") == 0) {
+ bss->broadcast_deauth = atoi(pos);
+#ifdef CONFIG_DPP
+ } else if (os_strcmp(buf, "dpp_connector") == 0) {
+ os_free(bss->dpp_connector);
+ bss->dpp_connector = os_strdup(pos);
+ } else if (os_strcmp(buf, "dpp_netaccesskey") == 0) {
+ if (parse_wpabuf_hex(line, buf, &bss->dpp_netaccesskey, pos))
+ return 1;
+ } else if (os_strcmp(buf, "dpp_netaccesskey_expiry") == 0) {
+ bss->dpp_netaccesskey_expiry = strtol(pos, NULL, 0);
+ } else if (os_strcmp(buf, "dpp_csign") == 0) {
+ if (parse_wpabuf_hex(line, buf, &bss->dpp_csign, pos))
+ return 1;
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_OWE
+ } else if (os_strcmp(buf, "owe_transition_bssid") == 0) {
+ if (hwaddr_aton(pos, bss->owe_transition_bssid)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid owe_transition_bssid",
+ line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "owe_transition_ssid") == 0) {
+ size_t slen;
+ char *str = wpa_config_parse_string(pos, &slen);
+
+ if (!str || slen < 1 || slen > SSID_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
+ line, pos);
+ os_free(str);
+ return 1;
+ }
+ os_memcpy(bss->owe_transition_ssid, str, slen);
+ bss->owe_transition_ssid_len = slen;
+ os_free(str);
+ } else if (os_strcmp(buf, "owe_transition_ifname") == 0) {
+ os_strlcpy(bss->owe_transition_ifname, pos,
+ sizeof(bss->owe_transition_ifname));
+ } else if (os_strcmp(buf, "owe_groups") == 0) {
+ if (hostapd_parse_intlist(&bss->owe_groups, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid owe_groups value '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
+ bss->coloc_intf_reporting = atoi(pos);
+#endif /* CONFIG_OWE */
+ } else if (os_strcmp(buf, "multi_ap") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 3) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid multi_ap '%s'",
+ line, buf);
+ return -1;
+ }
+
+ bss->multi_ap = val;
+ } else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) {
+ conf->rssi_reject_assoc_rssi = atoi(pos);
+ } else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
+ conf->rssi_reject_assoc_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "pbss") == 0) {
+ bss->pbss = atoi(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
@@ -3429,7 +4369,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
{
struct hostapd_config *conf;
FILE *f;
- char buf[512], *pos;
+ char buf[4096], *pos;
int line = 0;
int errors = 0;
size_t i;
diff --git a/contrib/wpa/hostapd/config_file.h b/contrib/wpa/hostapd/config_file.h
index c98bdb6..9830f5a 100644
--- a/contrib/wpa/hostapd/config_file.h
+++ b/contrib/wpa/hostapd/config_file.h
@@ -13,5 +13,10 @@ struct hostapd_config * hostapd_config_read(const char *fname);
int hostapd_set_iface(struct hostapd_config *conf,
struct hostapd_bss_config *bss, const char *field,
char *value);
+int hostapd_acl_comp(const void *a, const void *b);
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+ int vlan_id, const u8 *addr);
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+ const u8 *addr);
#endif /* CONFIG_FILE_H */
diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c
index cb6fb17..e4b16e6 100644
--- a/contrib/wpa/hostapd/ctrl_iface.c
+++ b/contrib/wpa/hostapd/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,10 +19,20 @@
#include <sys/stat.h>
#include <stddef.h>
+#ifdef CONFIG_CTRL_IFACE_UDP
+#include <netdb.h>
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/module_tests.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "common/ctrl_iface_common.h"
+#ifdef CONFIG_DPP
+#include "common/dpp.h"
+#endif /* CONFIG_DPP */
+#include "common/wpa_ctrl.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
#include "eapol_auth/eapol_auth_sm.h"
@@ -42,6 +52,9 @@
#include "ap/wnm_ap.h"
#include "ap/wpa_auth.h"
#include "ap/beacon.h"
+#include "ap/neighbor_db.h"
+#include "ap/rrm.h"
+#include "ap/dpp_hostapd.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "fst/fst_ctrl_iface.h"
@@ -51,14 +64,15 @@
#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
-struct wpa_ctrl_dst {
- struct wpa_ctrl_dst *next;
- struct sockaddr_un addr;
- socklen_t addrlen;
- int debug_level;
- int errors;
-};
-
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define COOKIE_LEN 8
+static unsigned char cookie[COOKIE_LEN];
+static unsigned char gcookie[COOKIE_LEN];
+#define HOSTAPD_CTRL_IFACE_PORT 8877
+#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
+#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
+#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT 50
+#endif /* CONFIG_CTRL_IFACE_UDP */
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
enum wpa_msg_type type,
@@ -66,81 +80,27 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
- struct sockaddr_un *from,
- socklen_t fromlen)
+ struct sockaddr_storage *from,
+ socklen_t fromlen, const char *input)
{
- struct wpa_ctrl_dst *dst;
-
- dst = os_zalloc(sizeof(*dst));
- if (dst == NULL)
- return -1;
- os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
- dst->addrlen = fromlen;
- dst->debug_level = MSG_INFO;
- dst->next = hapd->ctrl_dst;
- hapd->ctrl_dst = dst;
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
- (u8 *) from->sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path));
- return 0;
+ return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen, input);
}
static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
- struct wpa_ctrl_dst *dst, *prev = NULL;
-
- dst = hapd->ctrl_dst;
- while (dst) {
- if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path))
- == 0) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
- (u8 *) from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
- if (prev == NULL)
- hapd->ctrl_dst = dst->next;
- else
- prev->next = dst->next;
- os_free(dst);
- return 0;
- }
- prev = dst;
- dst = dst->next;
- }
- return -1;
+ return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen);
}
static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen,
char *level)
{
- struct wpa_ctrl_dst *dst;
-
- wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
-
- dst = hapd->ctrl_dst;
- while (dst) {
- if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path))
- == 0) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
- "level", (u8 *) from->sun_path, fromlen -
- offsetof(struct sockaddr_un, sun_path));
- dst->debug_level = atoi(level);
- return 0;
- }
- dst = dst->next;
- }
-
- return -1;
+ return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level);
}
@@ -808,7 +768,7 @@ static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
const char *cmd)
@@ -883,7 +843,9 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
char *url = NULL;
int ret;
u8 nei_rep[1000];
- u8 *nei_pos = nei_rep;
+ int nei_len;
+ u8 mbo[10];
+ size_t mbo_len = 0;
if (hwaddr_aton(cmd, addr)) {
wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
@@ -921,7 +883,7 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
/* TODO: TSF configurable/learnable */
bss_term_dur[0] = 4; /* Subelement ID */
bss_term_dur[1] = 10; /* Length */
- os_memset(bss_term_dur, 2, 8);
+ os_memset(&bss_term_dur[2], 0, 8);
end = os_strchr(pos, ',');
if (end == NULL) {
wpa_printf(MSG_DEBUG, "Invalid bss_term data");
@@ -931,99 +893,10 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
}
-
- /*
- * BSS Transition Candidate List Entries - Neighbor Report elements
- * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
- * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
- */
- pos = cmd;
- while (pos) {
- u8 *nei_start;
- long int val;
- char *endptr, *tmp;
-
- pos = os_strstr(pos, " neighbor=");
- if (!pos)
- break;
- if (nei_pos + 15 > nei_rep + sizeof(nei_rep)) {
- wpa_printf(MSG_DEBUG,
- "Not enough room for additional neighbor");
- return -1;
- }
- pos += 10;
-
- nei_start = nei_pos;
- *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
- nei_pos++; /* length to be filled in */
-
- if (hwaddr_aton(pos, nei_pos)) {
- wpa_printf(MSG_DEBUG, "Invalid BSSID");
- return -1;
- }
- nei_pos += ETH_ALEN;
- pos += 17;
- if (*pos != ',') {
- wpa_printf(MSG_DEBUG, "Missing BSSID Information");
- return -1;
- }
- pos++;
-
- val = strtol(pos, &endptr, 0);
- WPA_PUT_LE32(nei_pos, val);
- nei_pos += 4;
- if (*endptr != ',') {
- wpa_printf(MSG_DEBUG, "Missing Operating Class");
- return -1;
- }
- pos = endptr + 1;
-
- *nei_pos++ = atoi(pos); /* Operating Class */
- pos = os_strchr(pos, ',');
- if (pos == NULL) {
- wpa_printf(MSG_DEBUG, "Missing Channel Number");
- return -1;
- }
- pos++;
-
- *nei_pos++ = atoi(pos); /* Channel Number */
- pos = os_strchr(pos, ',');
- if (pos == NULL) {
- wpa_printf(MSG_DEBUG, "Missing PHY Type");
- return -1;
- }
- pos++;
-
- *nei_pos++ = atoi(pos); /* PHY Type */
- end = os_strchr(pos, ' ');
- tmp = os_strchr(pos, ',');
- if (tmp && (!end || tmp < end)) {
- /* Optional Subelements (hexdump) */
- size_t len;
-
- pos = tmp + 1;
- end = os_strchr(pos, ' ');
- if (end)
- len = end - pos;
- else
- len = os_strlen(pos);
- if (nei_pos + len / 2 > nei_rep + sizeof(nei_rep)) {
- wpa_printf(MSG_DEBUG,
- "Not enough room for neighbor subelements");
- return -1;
- }
- if (len & 0x01 ||
- hexstr2bin(pos, nei_pos, len / 2) < 0) {
- wpa_printf(MSG_DEBUG,
- "Invalid neighbor subelement info");
- return -1;
- }
- nei_pos += len / 2;
- pos = end;
- }
-
- nei_start[1] = nei_pos - nei_start - 2;
- }
+ nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
+ sizeof(nei_rep));
+ if (nei_len < 0)
+ return -1;
pos = os_strstr(cmd, " url=");
if (pos) {
@@ -1049,15 +922,113 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
if (os_strstr(cmd, " disassoc_imminent=1"))
req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+#ifdef CONFIG_MBO
+ pos = os_strstr(cmd, "mbo=");
+ if (pos) {
+ unsigned int mbo_reason, cell_pref, reassoc_delay;
+ u8 *mbo_pos = mbo;
+
+ ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
+ &reassoc_delay, &cell_pref);
+ if (ret != 3) {
+ wpa_printf(MSG_DEBUG,
+ "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
+ ret = -1;
+ goto fail;
+ }
+
+ if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO transition reason code %u",
+ mbo_reason);
+ ret = -1;
+ goto fail;
+ }
+
+ /* Valid values for Cellular preference are: 0, 1, 255 */
+ if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO cellular capability %u",
+ cell_pref);
+ ret = -1;
+ goto fail;
+ }
+
+ if (reassoc_delay > 65535 ||
+ (reassoc_delay &&
+ !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Assoc retry delay is only valid in disassoc imminent mode");
+ ret = -1;
+ goto fail;
+ }
+
+ *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = mbo_reason;
+ *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = cell_pref;
+
+ if (reassoc_delay) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+ *mbo_pos++ = 2;
+ WPA_PUT_LE16(mbo_pos, reassoc_delay);
+ mbo_pos += 2;
+ }
+
+ mbo_len = mbo_pos - mbo;
+ }
+#endif /* CONFIG_MBO */
+
ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
valid_int, bss_term_dur, url,
- nei_pos > nei_rep ? nei_rep : NULL,
- nei_pos - nei_rep);
+ nei_len ? nei_rep : NULL, nei_len,
+ mbo_len ? mbo : NULL, mbo_len);
+#ifdef CONFIG_MBO
+fail:
+#endif /* CONFIG_MBO */
os_free(url);
return ret;
}
-#endif /* CONFIG_WNM */
+
+static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ const char *pos;
+ unsigned int auto_report, timeout;
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for Collocated Interference Request",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+ auto_report = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ timeout = atoi(pos);
+
+ return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout);
+}
+
+#endif /* CONFIG_WNM_AP */
static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
@@ -1083,7 +1054,7 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "FT-PSK ");
if (os_snprintf_error(end - pos, ret))
@@ -1096,6 +1067,14 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_SHA384
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ ret = os_snprintf(pos, end - pos, "FT-EAP-SHA384 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA384 */
#ifdef CONFIG_SAE
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
ret = os_snprintf(pos, end - pos, "FT-SAE ");
@@ -1104,7 +1083,21 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
pos += ret;
}
#endif /* CONFIG_SAE */
-#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_FILS
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "FT-FILS-SHA256 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "FT-FILS-SHA384 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
@@ -1141,6 +1134,38 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_FILS
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "FILS-SHA256 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "FILS-SHA384 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
+ ret = os_snprintf(pos, end - pos, "OWE ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
+ ret = os_snprintf(pos, end - pos, "DPP ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_DPP */
if (pos > buf && *(pos - 1) == ' ') {
*(pos - 1) = '\0';
@@ -1269,6 +1294,42 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
}
+static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct vlan_description vlan_id;
+
+ if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
+ return;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!hostapd_maclist_found(hapd->conf->accept_mac,
+ hapd->conf->num_accept_mac,
+ sta->addr, &vlan_id) ||
+ (vlan_id.notempty &&
+ vlan_compare(&vlan_id, sta->vlan_desc)))
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ }
+}
+
+
+static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct vlan_description vlan_id;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (hostapd_maclist_found(hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac, sta->addr,
+ &vlan_id) &&
+ (!vlan_id.notempty ||
+ !vlan_compare(&vlan_id, sta->vlan_desc)))
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ }
+}
+
static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
{
char *value;
@@ -1306,51 +1367,67 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
wps_corrupt_pkhash);
#endif /* CONFIG_WPS_TESTING */
-#ifdef CONFIG_INTERWORKING
- } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
- int val = atoi(value);
- if (val <= 0)
- ret = -1;
- else
- hapd->gas_frag_limit = val;
-#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
hapd->ext_mgmt_frame_handling = atoi(value);
} else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
hapd->ext_eapol_frame_io = atoi(value);
+#ifdef CONFIG_DPP
+ } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
+ os_free(hapd->dpp_config_obj_override);
+ hapd->dpp_config_obj_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
+ os_free(hapd->dpp_discovery_override);
+ hapd->dpp_discovery_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
+ os_free(hapd->dpp_groups_override);
+ hapd->dpp_groups_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd,
+ "dpp_ignore_netaccesskey_mismatch") == 0) {
+ hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
+ dpp_test = atoi(value);
+#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
- } else {
- struct sta_info *sta;
- int vlan_id;
+#ifdef CONFIG_MBO
+ } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
+ int val;
+
+ if (!hapd->conf->mbo_enabled)
+ return -1;
+ val = atoi(value);
+ if (val < 0 || val > 1)
+ return -1;
+
+ hapd->mbo_assoc_disallow = val;
+ ieee802_11_update_beacons(hapd->iface);
+
+ /*
+ * TODO: Need to configure drivers that do AP MLME offload with
+ * disallowing station logic.
+ */
+#endif /* CONFIG_MBO */
+#ifdef CONFIG_DPP
+ } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
+ os_free(hapd->dpp_configurator_params);
+ hapd->dpp_configurator_params = os_strdup(value);
+#endif /* CONFIG_DPP */
+ } else {
ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
if (ret)
return ret;
if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (hostapd_maclist_found(
- hapd->conf->deny_mac,
- hapd->conf->num_deny_mac, sta->addr,
- &vlan_id) &&
- (!vlan_id || vlan_id == sta->vlan_id))
- ap_sta_disconnect(
- hapd, sta, sta->addr,
- WLAN_REASON_UNSPECIFIED);
- }
- } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED &&
- os_strcasecmp(cmd, "accept_mac_file") == 0) {
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!hostapd_maclist_found(
- hapd->conf->accept_mac,
- hapd->conf->num_accept_mac,
- sta->addr, &vlan_id) ||
- (vlan_id && vlan_id != sta->vlan_id))
- ap_sta_disconnect(
- hapd, sta, sta->addr,
- WLAN_REASON_UNSPECIFIED);
- }
+ hostapd_disassoc_deny_mac(hapd);
+ } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) {
+ hostapd_disassoc_accept_mac(hapd);
+ } else if (os_strncmp(cmd, "wme_ac_", 7) == 0 ||
+ os_strncmp(cmd, "wmm_ac_", 7) == 0) {
+ hapd->parameter_set_count++;
+ if (ieee802_11_update_beacons(hapd->iface))
+ wpa_printf(MSG_DEBUG,
+ "Failed to update beacons with WMM parameters");
}
}
@@ -1411,6 +1488,63 @@ static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
}
+static int
+hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ struct hostapd_wpa_psk *psk;
+ const u8 *pmk;
+ int pmk_len;
+ int pmk_match;
+ int sta_match;
+ int bss_match;
+ int reason;
+
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+
+ for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) {
+ pmk_match = PMK_LEN == pmk_len &&
+ os_memcmp(psk->psk, pmk, pmk_len) == 0;
+ sta_match = psk->group == 0 &&
+ os_memcmp(sta->addr, psk->addr, ETH_ALEN) == 0;
+ bss_match = psk->group == 1;
+
+ if (pmk_match && (sta_match || bss_match))
+ return 0;
+ }
+
+ wpa_printf(MSG_INFO, "STA " MACSTR
+ " PSK/passphrase no longer valid - disconnect",
+ MAC2STR(sta->addr));
+ reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
+ hostapd_drv_sta_deauth(hapd, sta->addr, reason);
+ ap_sta_deauthenticate(hapd, sta, reason);
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ int err;
+
+ hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
+
+ err = hostapd_setup_wpa_psk(conf);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d",
+ err);
+ return -1;
+ }
+
+ ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter,
+ NULL);
+
+ return 0;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
@@ -1500,6 +1634,137 @@ static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
}
+static int hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data *hapd,
+ char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf;
+ int stype = 0, ok = 0;
+ union wpa_event_data event;
+
+ if (!hapd->ext_mgmt_frame_handling)
+ return -1;
+
+ /* stype=<val> ok=<0/1> buf=<frame hexdump> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT TX status process: %s", cmd);
+
+ pos = cmd;
+ param = os_strstr(pos, "stype=");
+ if (param) {
+ param += 6;
+ stype = atoi(param);
+ }
+
+ param = os_strstr(pos, " ok=");
+ if (param) {
+ param += 4;
+ ok = atoi(param);
+ }
+
+ param = os_strstr(pos, " buf=");
+ if (!param)
+ return -1;
+ param += 5;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (!buf || hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_TYPE_MGMT;
+ event.tx_status.data = buf;
+ event.tx_status.data_len = len;
+ event.tx_status.stype = stype;
+ event.tx_status.ack = ok;
+ hapd->ext_mgmt_frame_handling = 0;
+ wpa_supplicant_event(hapd, EVENT_TX_STATUS, &event);
+ hapd->ext_mgmt_frame_handling = 1;
+
+ os_free(buf);
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data *hapd,
+ char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf;
+ int freq = 0, datarate = 0, ssi_signal = 0;
+ union wpa_event_data event;
+
+ if (!hapd->ext_mgmt_frame_handling)
+ return -1;
+
+ /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
+
+ pos = cmd;
+ param = os_strstr(pos, "freq=");
+ if (param) {
+ param += 5;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " datarate=");
+ if (param) {
+ param += 10;
+ datarate = atoi(param);
+ }
+
+ param = os_strstr(pos, " ssi_signal=");
+ if (param) {
+ param += 12;
+ ssi_signal = atoi(param);
+ }
+
+ param = os_strstr(pos, " frame=");
+ if (param == NULL)
+ return -1;
+ param += 7;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.freq = freq;
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.datarate = datarate;
+ hapd->ext_mgmt_frame_handling = 0;
+ wpa_supplicant_event(hapd, EVENT_RX_MGMT, &event);
+ hapd->ext_mgmt_frame_handling = 1;
+
+ os_free(buf);
+
+ return 0;
+}
+
+
static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
{
char *pos;
@@ -1557,8 +1822,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len)
#define HWSIM_PACKETLEN 1500
#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
-void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
+static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct hostapd_data *hapd = ctx;
const struct ether_header *eth;
@@ -1745,8 +2010,6 @@ done:
static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
char *pos;
wpa_trace_fail_after = atoi(cmd);
@@ -1770,9 +2033,6 @@ static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
wpa_trace_fail_func);
#else /* WPA_TRACE_BFD */
@@ -1784,8 +2044,6 @@ static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
char *pos;
wpa_trace_test_fail_after = atoi(cmd);
@@ -1809,9 +2067,6 @@ static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
wpa_trace_test_fail_func);
#else /* WPA_TRACE_BFD */
@@ -1819,6 +2074,245 @@ static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
#endif /* WPA_TRACE_BFD */
}
+
+static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
+{
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+ u8 zero[WPA_TK_MAX_LEN];
+
+ os_memset(zero, 0, sizeof(zero));
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+#ifdef CONFIG_IEEE80211W
+ if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
+ if (hapd->last_igtk_alg == WPA_ALG_NONE)
+ return -1;
+
+ wpa_printf(MSG_INFO, "TESTING: Reset IPN for IGTK");
+
+ /* First, use a zero key to avoid any possible duplicate key
+ * avoidance in the driver. */
+ if (hostapd_drv_set_key(hapd->conf->iface, hapd,
+ hapd->last_igtk_alg,
+ broadcast_ether_addr,
+ hapd->last_igtk_key_idx, 1, NULL, 0,
+ zero, hapd->last_igtk_len) < 0)
+ return -1;
+
+ /* Set the previously configured key to reset its TSC */
+ return hostapd_drv_set_key(hapd->conf->iface, hapd,
+ hapd->last_igtk_alg,
+ broadcast_ether_addr,
+ hapd->last_igtk_key_idx, 1, NULL, 0,
+ hapd->last_igtk,
+ hapd->last_igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ if (is_broadcast_ether_addr(addr)) {
+ if (hapd->last_gtk_alg == WPA_ALG_NONE)
+ return -1;
+
+ wpa_printf(MSG_INFO, "TESTING: Reset PN for GTK");
+
+ /* First, use a zero key to avoid any possible duplicate key
+ * avoidance in the driver. */
+ if (hostapd_drv_set_key(hapd->conf->iface, hapd,
+ hapd->last_gtk_alg,
+ broadcast_ether_addr,
+ hapd->last_gtk_key_idx, 1, NULL, 0,
+ zero, hapd->last_gtk_len) < 0)
+ return -1;
+
+ /* Set the previously configured key to reset its TSC */
+ return hostapd_drv_set_key(hapd->conf->iface, hapd,
+ hapd->last_gtk_alg,
+ broadcast_ether_addr,
+ hapd->last_gtk_key_idx, 1, NULL, 0,
+ hapd->last_gtk, hapd->last_gtk_len);
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ if (sta->last_tk_alg == WPA_ALG_NONE)
+ return -1;
+
+ wpa_printf(MSG_INFO, "TESTING: Reset PN for " MACSTR,
+ MAC2STR(sta->addr));
+
+ /* First, use a zero key to avoid any possible duplicate key avoidance
+ * in the driver. */
+ if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
+ sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
+ zero, sta->last_tk_len) < 0)
+ return -1;
+
+ /* Set the previously configured key to reset its TSC/RSC */
+ return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
+ sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
+ sta->last_tk, sta->last_tk_len);
+}
+
+
+static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ const char *pos = cmd;
+ enum wpa_alg alg;
+ int idx, set_tx;
+ u8 seq[6], key[WPA_TK_MAX_LEN];
+ size_t key_len;
+
+ /* parameters: alg addr idx set_tx seq key */
+
+ alg = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ if (hwaddr_aton(pos, addr))
+ return -1;
+ pos += 17;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+ idx = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ set_tx = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ if (hexstr2bin(pos, seq, sizeof(seq)) < 0)
+ return -1;
+ pos += 2 * 6;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+ key_len = os_strlen(pos) / 2;
+ if (hexstr2bin(pos, key, key_len) < 0)
+ return -1;
+
+ wpa_printf(MSG_INFO, "TESTING: Set key");
+ return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx,
+ set_tx, seq, 6, key, key_len);
+}
+
+
+static void restore_tk(void *ctx1, void *ctx2)
+{
+ struct hostapd_data *hapd = ctx1;
+ struct sta_info *sta = ctx2;
+
+ wpa_printf(MSG_INFO, "TESTING: Restore TK for " MACSTR,
+ MAC2STR(sta->addr));
+ /* This does not really restore the TSC properly, so this will result
+ * in replay protection issues for now since there is no clean way of
+ * preventing encryption of a single EAPOL frame. */
+ hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
+ sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
+ sta->last_tk, sta->last_tk_len);
+}
+
+
+static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
+{
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+ int plain = os_strstr(cmd, "plaintext") != NULL;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->wpa_sm)
+ return -1;
+
+ if (plain && sta->last_tk_alg == WPA_ALG_NONE)
+ plain = 0; /* no need for special processing */
+ if (plain) {
+ wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
+ MAC2STR(sta->addr));
+ hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
+ sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
+ NULL, 0);
+ }
+
+ wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
+ return wpa_auth_resend_m1(sta->wpa_sm,
+ os_strstr(cmd, "change-anonce") != NULL,
+ plain ? restore_tk : NULL, hapd, sta);
+}
+
+
+static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
+{
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+ int plain = os_strstr(cmd, "plaintext") != NULL;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->wpa_sm)
+ return -1;
+
+ if (plain && sta->last_tk_alg == WPA_ALG_NONE)
+ plain = 0; /* no need for special processing */
+ if (plain) {
+ wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
+ MAC2STR(sta->addr));
+ hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
+ sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
+ NULL, 0);
+ }
+
+ wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
+ return wpa_auth_resend_m3(sta->wpa_sm,
+ plain ? restore_tk : NULL, hapd, sta);
+}
+
+
+static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+ int plain = os_strstr(cmd, "plaintext") != NULL;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->wpa_sm)
+ return -1;
+
+ if (plain && sta->last_tk_alg == WPA_ALG_NONE)
+ plain = 0; /* no need for special processing */
+ if (plain) {
+ wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
+ MAC2STR(sta->addr));
+ hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
+ sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
+ NULL, 0);
+ }
+
+ wpa_printf(MSG_INFO,
+ "TESTING: Send group M1 for the same GTK and zero RSC to "
+ MACSTR, MAC2STR(sta->addr));
+ return wpa_auth_resend_group_m1(sta->wpa_sm,
+ plain ? restore_tk : NULL, hapd, sta);
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
@@ -1835,6 +2329,11 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
return ret;
for (i = 0; i < iface->num_bss; i++) {
+
+ /* Save CHAN_SWITCH VHT config */
+ hostapd_chan_switch_vht_config(
+ iface->bss[i], settings.freq_params.vht_enabled);
+
ret = hostapd_switch_channel(iface->bss[i], &settings);
if (ret) {
/* FIX: What do we do if CSA fails in the middle of
@@ -1875,13 +2374,13 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
/* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
vendor_id = strtoul(cmd, &pos, 16);
- if (!isblank(*pos))
+ if (!isblank((unsigned char) *pos))
return -EINVAL;
subcmd = strtoul(pos, &pos, 10);
if (*pos != '\0') {
- if (!isblank(*pos++))
+ if (!isblank((unsigned char) *pos++))
return -EINVAL;
data_len = os_strlen(pos);
}
@@ -2016,6 +2515,9 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
struct hostapd_sta_info *info;
struct os_reltime now;
+ if (!iface->num_sta_seen)
+ return 0;
+
sta_track_expire(iface, 0);
pos = buf;
@@ -2028,8 +2530,9 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
int ret;
os_reltime_sub(&now, &info->last_seen, &age);
- ret = os_snprintf(pos, end - pos, MACSTR " %u\n",
- MAC2STR(info->addr), (unsigned int) age.sec);
+ ret = os_snprintf(pos, end - pos, MACSTR " %u %d\n",
+ MAC2STR(info->addr), (unsigned int) age.sec,
+ info->ssi_signal);
if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
@@ -2040,10 +2543,378 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
+ return -1;
+ }
+
+ return hostapd_send_lci_req(hapd, addr);
+}
+
+
+static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ char *token, *context = NULL;
+ int random_interval, min_ap;
+ u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
+ unsigned int n_responders;
+
+ token = str_token(cmd, " ", &context);
+ if (!token || hwaddr_aton(token, addr)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE - Bad destination address");
+ return -1;
+ }
+
+ token = str_token(cmd, " ", &context);
+ if (!token)
+ return -1;
+
+ random_interval = atoi(token);
+ if (random_interval < 0 || random_interval > 0xffff)
+ return -1;
+
+ token = str_token(cmd, " ", &context);
+ if (!token)
+ return -1;
+
+ min_ap = atoi(token);
+ if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
+ return -1;
+
+ n_responders = 0;
+ while ((token = str_token(cmd, " ", &context))) {
+ if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE: Too many responders");
+ return -1;
+ }
+
+ if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE: Bad responder address");
+ return -1;
+ }
+
+ n_responders++;
+ }
+
+ if (!n_responders) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE - No FTM responder address");
+ return -1;
+ }
+
+ return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
+ responders, n_responders);
+}
+
+
+static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd,
+ const char *cmd, char *reply,
+ size_t reply_size)
+{
+ u8 addr[ETH_ALEN];
+ const char *pos;
+ struct wpabuf *req;
+ int ret;
+ u8 req_mode = 0;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ if (os_strncmp(pos, "req_mode=", 9) == 0) {
+ int val = hex2byte(pos + 9);
+
+ if (val < 0)
+ return -1;
+ req_mode = val;
+ pos += 11;
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ }
+ req = wpabuf_parse_bin(pos);
+ if (!req)
+ return -1;
+
+ ret = hostapd_send_beacon_req(hapd, addr, req_mode, req);
+ wpabuf_free(req);
+ if (ret >= 0)
+ ret = os_snprintf(reply, reply_size, "%d", ret);
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ struct wpabuf *nr, *lci = NULL, *civic = NULL;
+ int stationary = 0;
+ char *tmp;
+ int ret;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
+ return -1;
+ }
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad or missing SSID");
+ return -1;
+ }
+ buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
+ if (!buf)
+ return -1;
+
+ tmp = os_strstr(buf, "nr=");
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
+ return -1;
+ }
+
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+
+ nr = wpabuf_parse_bin(tmp + 3);
+ if (!nr) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
+ return -1;
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "lci=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ lci = wpabuf_parse_bin(tmp + 4);
+ if (!lci) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad LCI subelement");
+ wpabuf_free(nr);
+ return -1;
+ }
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "civic=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ civic = wpabuf_parse_bin(tmp + 6);
+ if (!civic) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad civic subelement");
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ return -1;
+ }
+ }
+
+ if (!buf)
+ goto set;
+
+ if (os_strstr(buf, "stat"))
+ stationary = 1;
+
+set:
+ ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic,
+ stationary);
+
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ wpabuf_free(civic);
+
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
+ char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ char *tmp;
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
+ return -1;
+ }
+
+ return hostapd_neighbor_remove(hapd, bssid, &ssid);
+}
+
+
+static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
+ size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) iface->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (iface->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
+static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct vlan_description vlan_id;
+
+ if (!(*num))
+ return 0;
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
+ hostapd_remove_acl_mac(acl, num, addr);
+
+ return 0;
+}
+
+
+static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
+ int *num)
+{
+ while (*num)
+ hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
+}
+
+
+static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
+ char *buf, size_t buflen)
+{
+ int i = 0, len = 0, ret = 0;
+
+ if (!acl)
+ return 0;
+
+ while (i < num) {
+ ret = os_snprintf(buf + len, buflen - len,
+ MACSTR " VLAN_ID=%d\n",
+ MAC2STR(acl[i].addr),
+ acl[i].vlan_id.untagged);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ i++;
+ len += ret;
+ }
+ return len;
+}
+
+
+static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct vlan_description vlan_id;
+ int ret = 0, vlanid = 0;
+ const char *pos;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = os_strstr(cmd, "VLAN_ID=");
+ if (pos)
+ vlanid = atoi(pos + 8);
+
+ if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
+ ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
+ if (ret != -1 && *acl)
+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
+ const char *field, char *buf,
+ size_t buflen)
+{
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
+
+#ifdef CONFIG_DPP
+ if (os_strcmp(field, "dpp") == 0) {
+ int res;
+
+#ifdef CONFIG_DPP2
+ res = os_snprintf(buf, buflen, "DPP=2");
+#else /* CONFIG_DPP2 */
+ res = os_snprintf(buf, buflen, "DPP=1");
+#endif /* CONFIG_DPP2 */
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_DPP */
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
+ field);
+
+ return -1;
+}
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
int reply_len, res;
@@ -2057,6 +2928,8 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "RELOG", 5) == 0) {
if (wpa_debug_reopen_file() < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+ wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
} else if (os_strcmp(buf, "STATUS") == 0) {
reply_len = hostapd_ctrl_iface_status(hapd, reply,
reply_size);
@@ -2104,7 +2977,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
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))
+ if (hostapd_ctrl_iface_attach(hapd, from, fromlen, NULL))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
+ if (hostapd_ctrl_iface_attach(hapd, from, fromlen, buf + 7))
reply_len = -1;
} else if (os_strcmp(buf, "DETACH") == 0) {
if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
@@ -2122,6 +2998,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
reply_len = -1;
+#ifdef CONFIG_TAXONOMY
+ } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
+ reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
+ reply, reply_size);
+#endif /* CONFIG_TAXONOMY */
+ } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
+ if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
+ reply_len = -1;
} else if (os_strcmp(buf, "STOP_AP") == 0) {
if (hostapd_ctrl_iface_stop_ap(hapd))
reply_len = -1;
@@ -2188,7 +3072,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
reply_len = -1;
#endif /* CONFIG_HS20 */
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
reply_len = -1;
@@ -2198,7 +3082,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
reply_len = -1;
-#endif /* CONFIG_WNM */
+ } else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) {
+ if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
+ reply_len = -1;
+#endif /* CONFIG_WNM_AP */
} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
reply_size);
@@ -2211,6 +3098,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
if (hostapd_ctrl_iface_enable(hapd->iface))
reply_len = -1;
+ } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
+ if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
+ reply_len = -1;
} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
if (hostapd_ctrl_iface_reload(hapd->iface))
reply_len = -1;
@@ -2227,6 +3117,13 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
reply_len = -1;
+ } else if (os_strncmp(buf, "MGMT_TX_STATUS_PROCESS ", 23) == 0) {
+ if (hostapd_ctrl_iface_mgmt_tx_status_process(hapd,
+ buf + 23) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
+ if (hostapd_ctrl_iface_mgmt_rx_process(hapd, buf + 16) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
reply_len = -1;
@@ -2250,6 +3147,24 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = -1;
} else if (os_strcmp(buf, "GET_FAIL") == 0) {
reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
+ } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) {
+ if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "SET_KEY ", 8) == 0) {
+ if (hostapd_ctrl_set_key(hapd, buf + 8) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "RESEND_M1 ", 10) == 0) {
+ if (hostapd_ctrl_resend_m1(hapd, buf + 10) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "RESEND_M3 ", 10) == 0) {
+ if (hostapd_ctrl_resend_m3(hapd, buf + 10) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
+ if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "REKEY_GTK") == 0) {
+ if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
+ reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -2276,6 +3191,165 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = hostapd_ctrl_iface_track_sta_list(
hapd, reply, reply_size);
#endif /* NEED_AP_MLME */
+ } else if (os_strcmp(buf, "PMKSA") == 0) {
+ reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
+ hostapd_ctrl_iface_pmksa_flush(hapd);
+ } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
+ if (hostapd_ctrl_iface_pmksa_add(hapd, buf + 10) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
+ if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
+ if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
+ if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
+ if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) {
+ reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11,
+ reply, reply_size);
+ } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+ reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "TERMINATE") == 0) {
+ eloop_terminate();
+ } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
+ if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
+ if (!hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf + 19))
+ hostapd_disassoc_accept_mac(hapd);
+ else
+ reply_len = -1;
+ } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
+ hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf + 19);
+ } else if (os_strcmp(buf + 11, "SHOW") == 0) {
+ reply_len = hostapd_ctrl_iface_acl_show_mac(
+ hapd->conf->accept_mac,
+ hapd->conf->num_accept_mac, reply, reply_size);
+ } else if (os_strcmp(buf + 11, "CLEAR") == 0) {
+ hostapd_ctrl_iface_acl_clear_list(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac);
+ }
+ } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
+ if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
+ if (!hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac, buf + 17))
+ hostapd_disassoc_deny_mac(hapd);
+ } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
+ hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac, buf + 17);
+ } else if (os_strcmp(buf + 9, "SHOW") == 0) {
+ reply_len = hostapd_ctrl_iface_acl_show_mac(
+ hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac, reply, reply_size);
+ } else if (os_strcmp(buf + 9, "CLEAR") == 0) {
+ hostapd_ctrl_iface_acl_clear_list(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac);
+ }
+#ifdef CONFIG_DPP
+ } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
+ res = hostapd_dpp_qr_code(hapd, buf + 12);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
+ res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
+ if (dpp_bootstrap_remove(hapd->iface->interfaces->dpp,
+ buf + 21) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
+ const char *uri;
+
+ uri = dpp_bootstrap_get_uri(hapd->iface->interfaces->dpp,
+ atoi(buf + 22));
+ if (!uri) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%s", uri);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
+ reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
+ atoi(buf + 19),
+ reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
+ if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
+ if (hostapd_dpp_listen(hapd, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
+ hostapd_dpp_stop(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
+ res = dpp_configurator_add(hapd->iface->interfaces->dpp,
+ buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
+ if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
+ buf + 24) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
+ if (hostapd_dpp_configurator_sign(hapd, buf + 21) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
+ reply_len = dpp_configurator_get_key_id(
+ hapd->iface->interfaces->dpp,
+ atoi(buf + 25),
+ reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
+ res = hostapd_dpp_pkex_add(hapd, buf + 12);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
+ if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
+ reply_len = -1;
+#endif /* CONFIG_DPP */
+#ifdef RADIUS_SERVER
+ } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
+ if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
+ reply_len = -1;
+#endif /* RADIUS_SERVER */
+ } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
+ reply_len = hostapd_ctrl_iface_get_capability(
+ hapd, buf + 15, reply, reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -2296,12 +3370,15 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
struct hostapd_data *hapd = eloop_ctx;
char buf[4096];
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
- char *reply;
+ char *reply, *pos = buf;
const int reply_size = 4096;
int reply_len;
int level = MSG_DEBUG;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char lcookie[COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
@@ -2311,9 +3388,6 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
return;
}
buf[res] = '\0';
- if (os_strcmp(buf, "PING") == 0)
- level = MSG_EXCESSIVE;
- wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
reply = os_malloc(reply_size);
if (reply == NULL) {
@@ -2325,10 +3399,46 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
return;
}
- reply_len = hostapd_ctrl_iface_receive_process(hapd, buf,
+#ifdef CONFIG_CTRL_IFACE_UDP
+ if (os_strcmp(buf, "GET_COOKIE") == 0) {
+ os_memcpy(reply, "COOKIE=", 7);
+ wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+ cookie, COOKIE_LEN);
+ reply_len = 7 + 2 * COOKIE_LEN;
+ goto done;
+ }
+
+ if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
+ hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: No cookie in the request - drop request");
+ os_free(reply);
+ return;
+ }
+
+ if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid cookie in the request - drop request");
+ os_free(reply);
+ return;
+ }
+
+ pos = buf + 7 + 2 * COOKIE_LEN;
+ while (*pos == ' ')
+ pos++;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+ if (os_strcmp(pos, "PING") == 0)
+ level = MSG_EXCESSIVE;
+ wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
+
+ reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
reply, reply_size,
&from, fromlen);
+#ifdef CONFIG_CTRL_IFACE_UDP
+done:
+#endif /* CONFIG_CTRL_IFACE_UDP */
if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
fromlen) < 0) {
wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
@@ -2338,6 +3448,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
}
+#ifndef CONFIG_CTRL_IFACE_UDP
static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
{
char *buf;
@@ -2357,6 +3468,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
buf[len - 1] = '\0';
return buf;
}
+#endif /* CONFIG_CTRL_IFACE_UDP */
static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
@@ -2372,6 +3484,99 @@ static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
+#ifdef CONFIG_CTRL_IFACE_UDP
+ int port = HOSTAPD_CTRL_IFACE_PORT;
+ char p[32] = { 0 };
+ char port_str[40], *tmp;
+ char *pos;
+ struct addrinfo hints = { 0 }, *res, *saveres;
+ int n;
+
+ if (hapd->ctrl_sock > -1) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+ return 0;
+ }
+
+ if (hapd->conf->ctrl_interface == NULL)
+ return 0;
+
+ pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
+ if (pos) {
+ pos += 4;
+ port = atoi(pos);
+ if (port <= 0) {
+ wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
+ goto fail;
+ }
+ }
+
+ dl_list_init(&hapd->ctrl_dst);
+ hapd->ctrl_sock = -1;
+ os_get_random(cookie, COOKIE_LEN);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ hints.ai_flags = AI_PASSIVE;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ hints.ai_family = AF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ hints.ai_family = AF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ hints.ai_socktype = SOCK_DGRAM;
+
+try_again:
+ os_snprintf(p, sizeof(p), "%d", port);
+ n = getaddrinfo(NULL, p, &hints, &res);
+ if (n) {
+ wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
+ goto fail;
+ }
+
+ saveres = res;
+ hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (hapd->ctrl_sock < 0) {
+ wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
+ goto fail;
+ }
+
+ if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
+ port--;
+ if ((HOSTAPD_CTRL_IFACE_PORT - port) <
+ HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
+ goto try_again;
+ wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
+ goto fail;
+ }
+
+ freeaddrinfo(saveres);
+
+ os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
+ tmp = os_strdup(port_str);
+ if (tmp) {
+ os_free(hapd->conf->ctrl_interface);
+ hapd->conf->ctrl_interface = tmp;
+ }
+ wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
+
+ if (eloop_register_read_sock(hapd->ctrl_sock,
+ hostapd_ctrl_iface_receive, hapd, NULL) <
+ 0) {
+ hostapd_ctrl_iface_deinit(hapd);
+ return -1;
+ }
+
+ hapd->msg_ctx = hapd;
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+ return 0;
+
+fail:
+ if (hapd->ctrl_sock >= 0)
+ close(hapd->ctrl_sock);
+ return -1;
+#else /* CONFIG_CTRL_IFACE_UDP */
struct sockaddr_un addr;
int s = -1;
char *fname = NULL;
@@ -2381,6 +3586,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
return 0;
}
+ dl_list_init(&hapd->ctrl_dst);
+
if (hapd->conf->ctrl_interface == NULL)
return 0;
@@ -2396,18 +3603,18 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(hapd->conf->ctrl_interface, -1,
- hapd->conf->ctrl_interface_gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(hapd->conf->ctrl_interface, -1,
+ hapd->conf->ctrl_interface_gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
return -1;
}
if (!hapd->conf->ctrl_interface_gid_set &&
hapd->iface->interfaces->ctrl_iface_group &&
- chown(hapd->conf->ctrl_interface, -1,
- hapd->iface->interfaces->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(hapd->conf->ctrl_interface, -1,
+ hapd->iface->interfaces->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
return -1;
}
@@ -2480,16 +3687,16 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+ lchown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
strerror(errno));
goto fail;
}
if (!hapd->conf->ctrl_interface_gid_set &&
hapd->iface->interfaces->ctrl_iface_group &&
- chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+ lchown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
strerror(errno));
goto fail;
}
@@ -2520,6 +3727,7 @@ fail:
os_free(fname);
}
return -1;
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
@@ -2528,10 +3736,14 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
struct wpa_ctrl_dst *dst, *prev;
if (hapd->ctrl_sock > -1) {
+#ifndef CONFIG_CTRL_IFACE_UDP
char *fname;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
eloop_unregister_read_sock(hapd->ctrl_sock);
close(hapd->ctrl_sock);
hapd->ctrl_sock = -1;
+#ifndef CONFIG_CTRL_IFACE_UDP
fname = hostapd_ctrl_iface_path(hapd);
if (fname)
unlink(fname);
@@ -2550,15 +3762,12 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
strerror(errno));
}
}
+#endif /* !CONFIG_CTRL_IFACE_UDP */
}
- dst = hapd->ctrl_dst;
- hapd->ctrl_dst = NULL;
- while (dst) {
- prev = dst;
- dst = dst->next;
- os_free(prev);
- }
+ dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
+ list)
+ os_free(dst);
#ifdef CONFIG_TESTING_OPTIONS
l2_packet_deinit(hapd->l2_test);
@@ -2590,54 +3799,19 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
- struct sockaddr_un *from,
- socklen_t fromlen)
+ struct sockaddr_storage *from,
+ socklen_t fromlen, char *input)
{
- struct wpa_ctrl_dst *dst;
-
- dst = os_zalloc(sizeof(*dst));
- if (dst == NULL)
- return -1;
- os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
- dst->addrlen = fromlen;
- dst->debug_level = MSG_INFO;
- dst->next = interfaces->global_ctrl_dst;
- interfaces->global_ctrl_dst = dst;
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached (global)",
- from->sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path));
- return 0;
+ return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen,
+ input);
}
static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
- struct wpa_ctrl_dst *dst, *prev = NULL;
-
- dst = interfaces->global_ctrl_dst;
- while (dst) {
- if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path))
- == 0) {
- wpa_hexdump(MSG_DEBUG,
- "CTRL_IFACE monitor detached (global)",
- from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
- if (prev == NULL)
- interfaces->global_ctrl_dst = dst->next;
- else
- prev->next = dst->next;
- os_free(dst);
- return 0;
- }
- prev = dst;
- dst = dst->next;
- }
- return -1;
+ return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
}
@@ -2648,6 +3822,16 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
wps_testing_dummy_cred = 0;
wps_corrupt_pkhash = 0;
#endif /* CONFIG_WPS_TESTING */
+
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_DPP
+ dpp_test = DPP_TEST_DISABLED;
+#endif /* CONFIG_DPP */
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_DPP
+ dpp_global_clear(interfaces->dpp);
+#endif /* CONFIG_DPP */
}
@@ -2791,6 +3975,51 @@ error_return:
static int
+hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
+ const char *input,
+ char *reply, int reply_size)
+{
+ size_t i, j;
+ int res;
+ char *pos, *end;
+ struct hostapd_iface *iface;
+ int show_ctrl = 0;
+
+ if (input)
+ show_ctrl = !!os_strstr(input, "ctrl");
+
+ pos = reply;
+ end = reply + reply_size;
+
+ for (i = 0; i < interfaces->count; i++) {
+ iface = interfaces->iface[i];
+
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_bss_config *conf;
+
+ conf = iface->conf->bss[j];
+ if (show_ctrl)
+ res = os_snprintf(pos, end - pos,
+ "%s ctrl_iface=%s\n",
+ conf->iface,
+ conf->ctrl_interface ?
+ conf->ctrl_interface : "N/A");
+ else
+ res = os_snprintf(pos, end - pos, "%s\n",
+ conf->iface);
+ if (os_snprintf_error(end - pos, res)) {
+ *pos = '\0';
+ return pos - reply;
+ }
+ pos += res;
+ }
+ }
+
+ return pos - reply;
+}
+
+
+static int
hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
char *cmd)
{
@@ -2839,7 +4068,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
const char *ifname,
char *buf, char *reply,
int reply_size,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
struct hostapd_data *hapd;
@@ -2863,15 +4092,18 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
void *interfaces = eloop_ctx;
- char buf[256];
+ char buffer[256], *buf = buffer;
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply;
int reply_len;
const int reply_size = 4096;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char lcookie[COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
@@ -2894,6 +4126,35 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
os_memcpy(reply, "OK\n", 3);
reply_len = 3;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ if (os_strcmp(buf, "GET_COOKIE") == 0) {
+ os_memcpy(reply, "COOKIE=", 7);
+ wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+ gcookie, COOKIE_LEN);
+ reply_len = 7 + 2 * COOKIE_LEN;
+ goto send_reply;
+ }
+
+ if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
+ hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: No cookie in the request - drop request");
+ os_free(reply);
+ return;
+ }
+
+ if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid cookie in the request - drop request");
+ os_free(reply);
+ return;
+ }
+
+ buf += 7 + 2 * COOKIE_LEN;
+ while (*buf == ' ')
+ buf++;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
if (os_strncmp(buf, "IFNAME=", 7) == 0) {
char *pos = os_strchr(buf + 7, ' ');
@@ -2922,7 +4183,11 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = -1;
} else if (os_strcmp(buf, "ATTACH") == 0) {
if (hostapd_global_ctrl_iface_attach(interfaces, &from,
- fromlen))
+ fromlen, NULL))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
+ if (hostapd_global_ctrl_iface_attach(interfaces, &from,
+ fromlen, buf + 7))
reply_len = -1;
} else if (os_strcmp(buf, "DETACH") == 0) {
if (hostapd_global_ctrl_iface_detach(interfaces, &from,
@@ -2930,7 +4195,6 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = -1;
#ifdef CONFIG_MODULE_TESTS
} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
- int hapd_module_tests(void);
if (hapd_module_tests() < 0)
reply_len = -1;
#endif /* CONFIG_MODULE_TESTS */
@@ -2954,6 +4218,11 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = os_snprintf(reply, reply_size, "OK\n");
else
reply_len = -1;
+ } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
+ reply_len = hostapd_global_ctrl_iface_interfaces(
+ interfaces, buf + 10, reply, sizeof(buffer));
+ } else if (os_strcmp(buf, "TERMINATE") == 0) {
+ eloop_terminate();
} else {
wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
"ignored");
@@ -2975,6 +4244,7 @@ send_reply:
}
+#ifndef CONFIG_CTRL_IFACE_UDP
static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
{
char *buf;
@@ -2994,10 +4264,93 @@ static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
buf[len - 1] = '\0';
return buf;
}
+#endif /* CONFIG_CTRL_IFACE_UDP */
int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
{
+#ifdef CONFIG_CTRL_IFACE_UDP
+ int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
+ char p[32] = { 0 };
+ char *pos;
+ struct addrinfo hints = { 0 }, *res, *saveres;
+ int n;
+
+ if (interface->global_ctrl_sock > -1) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+ return 0;
+ }
+
+ if (interface->global_iface_path == NULL)
+ return 0;
+
+ pos = os_strstr(interface->global_iface_path, "udp:");
+ if (pos) {
+ pos += 4;
+ port = atoi(pos);
+ if (port <= 0) {
+ wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
+ goto fail;
+ }
+ }
+
+ os_get_random(gcookie, COOKIE_LEN);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ hints.ai_flags = AI_PASSIVE;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ hints.ai_family = AF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ hints.ai_family = AF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+ hints.ai_socktype = SOCK_DGRAM;
+
+try_again:
+ os_snprintf(p, sizeof(p), "%d", port);
+ n = getaddrinfo(NULL, p, &hints, &res);
+ if (n) {
+ wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
+ goto fail;
+ }
+
+ saveres = res;
+ interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (interface->global_ctrl_sock < 0) {
+ wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
+ goto fail;
+ }
+
+ if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
+ 0) {
+ port++;
+ if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
+ HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
+ goto try_again;
+ wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
+ goto fail;
+ }
+
+ freeaddrinfo(saveres);
+
+ wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
+
+ if (eloop_register_read_sock(interface->global_ctrl_sock,
+ hostapd_global_ctrl_iface_receive,
+ interface, NULL) < 0) {
+ hostapd_global_ctrl_iface_deinit(interface);
+ return -1;
+ }
+
+ return 0;
+
+fail:
+ if (interface->global_ctrl_sock >= 0)
+ close(interface->global_ctrl_sock);
+ return -1;
+#else /* CONFIG_CTRL_IFACE_UDP */
struct sockaddr_un addr;
int s = -1;
char *fname = NULL;
@@ -3017,9 +4370,9 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
goto fail;
}
} else if (interface->ctrl_iface_group &&
- chown(interface->global_iface_path, -1,
- interface->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(interface->global_iface_path, -1,
+ interface->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
goto fail;
}
@@ -3076,8 +4429,8 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
}
if (interface->ctrl_iface_group &&
- chown(fname, -1, interface->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(fname, -1, interface->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
goto fail;
}
@@ -3103,18 +4456,22 @@ fail:
os_free(fname);
}
return -1;
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
{
+#ifndef CONFIG_CTRL_IFACE_UDP
char *fname = NULL;
+#endif /* CONFIG_CTRL_IFACE_UDP */
struct wpa_ctrl_dst *dst, *prev;
if (interfaces->global_ctrl_sock > -1) {
eloop_unregister_read_sock(interfaces->global_ctrl_sock);
close(interfaces->global_ctrl_sock);
interfaces->global_ctrl_sock = -1;
+#ifndef CONFIG_CTRL_IFACE_UDP
fname = hostapd_global_ctrl_iface_path(interfaces);
if (fname) {
unlink(fname);
@@ -3134,18 +4491,27 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
strerror(errno));
}
}
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = NULL;
- dst = interfaces->global_ctrl_dst;
- interfaces->global_ctrl_dst = NULL;
- while (dst) {
- prev = dst;
- dst = dst->next;
- os_free(prev);
- }
+ dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
+ struct wpa_ctrl_dst, list)
+ os_free(dst);
+}
+
+
+static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst,
+ const char *buf)
+{
+ /* Enable Probe Request events based on explicit request.
+ * Other events are enabled by default.
+ */
+ if (str_starts(buf, RX_PROBE_REQUEST))
+ return !!(dst->events & WPA_EVENT_RX_PROBE_REQUEST);
+ return 1;
}
@@ -3154,6 +4520,7 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
const char *buf, size_t len)
{
struct wpa_ctrl_dst *dst, *next;
+ struct dl_list *ctrl_dst;
struct msghdr msg;
int idx;
struct iovec io[2];
@@ -3162,13 +4529,13 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
if (type != WPA_MSG_ONLY_GLOBAL) {
s = hapd->ctrl_sock;
- dst = hapd->ctrl_dst;
+ ctrl_dst = &hapd->ctrl_dst;
} else {
s = hapd->iface->interfaces->global_ctrl_sock;
- dst = hapd->iface->interfaces->global_ctrl_dst;
+ ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst;
}
- if (s < 0 || dst == NULL)
+ if (s < 0 || dl_list_empty(ctrl_dst))
return;
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
@@ -3181,12 +4548,11 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
msg.msg_iovlen = 2;
idx = 0;
- while (dst) {
- next = dst->next;
- if (level >= dst->debug_level) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
- (u8 *) dst->addr.sun_path, dst->addrlen -
- offsetof(struct sockaddr_un, sun_path));
+ dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
+ if ((level >= dst->debug_level) &&
+ hostapd_ctrl_check_event_enabled(dst, buf)) {
+ sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
+ &dst->addr, dst->addrlen);
msg.msg_name = &dst->addr;
msg.msg_namelen = dst->addrlen;
if (sendmsg(s, &msg, 0) < 0) {
@@ -3210,7 +4576,6 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
dst->errors = 0;
}
idx++;
- dst = next;
}
}
diff --git a/contrib/wpa/hostapd/defconfig b/contrib/wpa/hostapd/defconfig
index 430f758..ea5e2c9 100644
--- a/contrib/wpa/hostapd/defconfig
+++ b/contrib/wpa/hostapd/defconfig
@@ -18,6 +18,9 @@ CONFIG_DRIVER_HOSTAP=y
# Driver interface for drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
+# QCA vendor extensions to nl80211
+#CONFIG_DRIVER_NL80211_QCA=y
+
# driver_nl80211.c requires libnl. If you are compiling it yourself
# you may need to point hostapd to your version of libnl.
#
@@ -28,7 +31,7 @@ CONFIG_DRIVER_NL80211=y
#CONFIG_LIBNL20=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
-#CONFIG_LIBNL32=y
+CONFIG_LIBNL32=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
@@ -47,12 +50,12 @@ 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)
CONFIG_IEEE80211W=y
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
# Integrated EAP server
CONFIG_EAP=y
@@ -154,6 +157,12 @@ CONFIG_IPV6=y
# IEEE 802.11ac (Very High Throughput) support
#CONFIG_IEEE80211AC=y
+# IEEE 802.11ax HE support
+# Note: This is experimental and work in progress. The definitions are still
+# subject to change and this should not be expected to interoperate with the
+# final IEEE 802.11ax version.
+#CONFIG_IEEE80211AX=y
+
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
@@ -163,6 +172,9 @@ CONFIG_IPV6=y
# Disabled by default.
#CONFIG_DEBUG_FILE=y
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+
# Add support for sending all debug messages (regardless of debug verbosity)
# to the Linux kernel tracing facility. This helps debug the entire stack by
# making it easy to record everything happening from the driver up into the
@@ -240,16 +252,25 @@ CONFIG_IPV6=y
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
# Should we use poll instead of select? Select is used by default.
#CONFIG_ELOOP_POLL=y
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
+# Should we use kqueue instead of select? Select is used by default.
+#CONFIG_ELOOP_KQUEUE=y
+
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
# internal = Internal TLSv1 implementation (experimental)
+# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental)
# none = Empty template
#CONFIG_TLS=openssl
@@ -262,6 +283,10 @@ CONFIG_IPV6=y
# can be enabled to enable use of stronger crypto algorithms.
#CONFIG_TLSV12=y
+# Select which ciphers to use by default with OpenSSL if the user does not
+# specify them.
+#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW"
+
# If CONFIG_TLS=internal is used, additional library and include paths are
# needed for LibTomMath. Alternatively, an integrated, minimal version of
# LibTomMath can be used. See beginning of libtommath.c for details on benefits
@@ -326,3 +351,31 @@ CONFIG_IPV6=y
# http://wireless.kernel.org/en/users/Documentation/acs
#
#CONFIG_ACS=y
+
+# Multiband Operation support
+# These extentions facilitate efficient use of multiple frequency bands
+# available to the AP and the devices that may associate with it.
+#CONFIG_MBO=y
+
+# Client Taxonomy
+# Has the AP retain the Probe Request and (Re)Association Request frames from
+# a client, from which a signature can be produced which can identify the model
+# of client device like "Nexus 6P" or "iPhone 5s".
+#CONFIG_TAXONOMY=y
+
+# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
+#CONFIG_FILS=y
+# FILS shared key authentication with PFS
+#CONFIG_FILS_SK_PFS=y
+
+# Include internal line edit mode in hostapd_cli. This can be used to provide
+# limited command line editing and history support.
+#CONFIG_WPA_CLI_EDIT=y
+
+# Opportunistic Wireless Encryption (OWE)
+# Experimental implementation of draft-harkins-owe-07.txt
+#CONFIG_OWE=y
+
+# Override default value for the wpa_disable_eapol_key_retries configuration
+# parameter. See that parameter in hostapd.conf for more details.
+#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
diff --git a/contrib/wpa/hostapd/hapd_module_tests.c b/contrib/wpa/hostapd/hapd_module_tests.c
index f7887eb..a5016f2 100644
--- a/contrib/wpa/hostapd/hapd_module_tests.c
+++ b/contrib/wpa/hostapd/hapd_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
int hapd_module_tests(void)
{
diff --git a/contrib/wpa/hostapd/hlr_auc_gw.c b/contrib/wpa/hostapd/hlr_auc_gw.c
index 84d0308..5caa779 100644
--- a/contrib/wpa/hostapd/hlr_auc_gw.c
+++ b/contrib/wpa/hostapd/hlr_auc_gw.c
@@ -1,6 +1,6 @@
/*
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -284,7 +284,7 @@ static int read_gsm_triplets(const char *fname)
f = fopen(fname, "r");
if (f == NULL) {
- printf("Could not open GSM tripler data file '%s'\n", fname);
+ printf("Could not open GSM triplet data file '%s'\n", fname);
return -1;
}
@@ -312,66 +312,40 @@ static int read_gsm_triplets(const char *fname)
}
/* IMSI */
- pos2 = strchr(pos, ':');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid IMSI (%s)\n",
- fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) >= sizeof(g->imsi)) {
- printf("%s:%d - Too long IMSI (%s)\n",
- fname, line, pos);
+ pos2 = NULL;
+ pos = str_token(buf, ":", &pos2);
+ if (!pos || os_strlen(pos) >= sizeof(g->imsi)) {
+ printf("%s:%d - Invalid IMSI\n", fname, line);
ret = -1;
break;
}
os_strlcpy(g->imsi, pos, sizeof(g->imsi));
- pos = pos2 + 1;
/* Kc */
- pos2 = strchr(pos, ':');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
- printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
+ pos = str_token(buf, ":", &pos2);
+ if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
+ printf("%s:%d - Invalid Kc\n", fname, line);
ret = -1;
break;
}
- pos = pos2 + 1;
/* SRES */
- pos2 = strchr(pos, ':');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid SRES (%s)\n", fname, line,
- pos);
+ pos = str_token(buf, ":", &pos2);
+ if (!pos || os_strlen(pos) != 8 ||
+ hexstr2bin(pos, g->sres, 4)) {
+ printf("%s:%d - Invalid SRES\n", fname, line);
ret = -1;
break;
}
- *pos2 = '\0';
- if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
- printf("%s:%d - Invalid SRES (%s)\n", fname, line,
- pos);
- ret = -1;
- break;
- }
- pos = pos2 + 1;
/* RAND */
- pos2 = strchr(pos, ':');
- if (pos2)
- *pos2 = '\0';
- if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
- printf("%s:%d - Invalid RAND (%s)\n", fname, line,
- pos);
+ pos = str_token(buf, ":", &pos2);
+ if (!pos || os_strlen(pos) != 32 ||
+ hexstr2bin(pos, g->_rand, 16)) {
+ printf("%s:%d - Invalid RAND\n", fname, line);
ret = -1;
break;
}
- pos = pos2 + 1;
g->next = gsm_db;
gsm_db = g;
@@ -450,86 +424,58 @@ static int read_milenage(const char *fname)
}
/* IMSI */
- pos2 = strchr(pos, ' ');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid IMSI (%s)\n",
- fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) >= sizeof(m->imsi)) {
- printf("%s:%d - Too long IMSI (%s)\n",
- fname, line, pos);
+ pos2 = NULL;
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) >= sizeof(m->imsi)) {
+ printf("%s:%d - Invalid IMSI\n", fname, line);
ret = -1;
break;
}
os_strlcpy(m->imsi, pos, sizeof(m->imsi));
- pos = pos2 + 1;
/* Ki */
- pos2 = strchr(pos, ' ');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) != 32 ||
+ hexstr2bin(pos, m->ki, 16)) {
+ printf("%s:%d - Invalid Ki\n", fname, line);
ret = -1;
break;
}
- *pos2 = '\0';
- if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
- printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
- ret = -1;
- break;
- }
- pos = pos2 + 1;
/* OPc */
- pos2 = strchr(pos, ' ');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
- printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) != 32 ||
+ hexstr2bin(pos, m->opc, 16)) {
+ printf("%s:%d - Invalid OPc\n", fname, line);
ret = -1;
break;
}
- pos = pos2 + 1;
/* AMF */
- pos2 = strchr(pos, ' ');
- if (pos2 == NULL) {
- printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
- ret = -1;
- break;
- }
- *pos2 = '\0';
- if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
- printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
+ printf("%s:%d - Invalid AMF\n", fname, line);
ret = -1;
break;
}
- pos = pos2 + 1;
/* SQN */
- pos2 = strchr(pos, ' ');
- if (pos2)
- *pos2 = '\0';
- if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
- printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
+ pos = str_token(buf, " ", &pos2);
+ if (!pos || os_strlen(pos) != 12 ||
+ hexstr2bin(pos, m->sqn, 6)) {
+ printf("%s:%d - Invalid SEQ\n", fname, line);
ret = -1;
break;
}
- if (pos2) {
- pos = pos2 + 1;
+ pos = str_token(buf, " ", &pos2);
+ if (pos) {
m->res_len = atoi(pos);
if (m->res_len &&
(m->res_len < EAP_AKA_RES_MIN_LEN ||
m->res_len > EAP_AKA_RES_MAX_LEN)) {
- printf("%s:%d - Invalid RES_len (%s)\n",
- fname, line, pos);
+ printf("%s:%d - Invalid RES_len\n",
+ fname, line);
ret = -1;
break;
}
@@ -1027,7 +973,7 @@ static void usage(void)
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
- "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
+ "Copyright (c) 2005-2017, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf
index a0071f7..f8caa56 100644
--- a/contrib/wpa/hostapd/hostapd.conf
+++ b/contrib/wpa/hostapd/hostapd.conf
@@ -3,6 +3,8 @@
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
# management frames with the Host AP driver); wlan0 with many nl80211 drivers
+# Note: This attribute can be overridden by the values supplied with the '-i'
+# command line parameter.
interface=wlan0
# In case of atheros and nl80211 driver interfaces, an additional
@@ -96,8 +98,25 @@ ssid=test
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
# Set as needed to indicate country in which device is operating.
# This can limit available channels and transmit power.
+# These two octets are used as the first two octets of the Country String
+# (dot11CountryString)
#country_code=US
+# The third octet of the Country String (dot11CountryString)
+# This parameter is used to set the third octet of the country string.
+#
+# All environments of the current frequency band and country (default)
+#country3=0x20
+# Outdoor environment only
+#country3=0x4f
+# Indoor environment only
+#country3=0x49
+# Noncountry entity (country_code=XX)
+#country3=0x58
+# IEEE 802.11 standard Annex E table indication: 0x01 .. 0x1f
+# Annex E, Table E-4 (Global operating classes)
+#country3=0x04
+
# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
# channels and transmit power levels based on the regulatory limits. The
# country_code setting must be configured with the correct country for
@@ -125,11 +144,13 @@ ssid=test
# ieee80211d=1 and local_pwr_constraint configured.
#spectrum_mgmt_required=1
-# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
-# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
-# specify band). When using ACS (see channel parameter), a special value "any"
-# can be used to indicate that any support band can be used. This special case
-# is currently supported only with drivers with which offloaded ACS is used.
+# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
+# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
+# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
+# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
+# special value "any" can be used to indicate that any support band can be used.
+# This special case is currently supported only with drivers with which
+# offloaded ACS is used.
# Default: IEEE 802.11b
hw_mode=g
@@ -173,11 +194,16 @@ channel=1
# Channel list restriction. This option allows hostapd to select one of the
# provided channels when a channel should be automatically selected.
# Channel list can be provided as range using hyphen ('-') or individual
-# channels can be specified by space (' ') seperated values
+# channels can be specified by space (' ') separated values
# Default: all channels allowed in selected hw_mode
#chanlist=100 104 108 112 116
#chanlist=1 6 11-13
+# Exclude DFS channels from ACS
+# This option can be used to exclude all DFS channels from the ACS channel list
+# in cases where the driver supports DFS channels.
+#acs_exclude_dfs=1
+
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@@ -192,16 +218,16 @@ dtim_period=2
# (default: 2007)
max_num_sta=255
-# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
+# RTS/CTS threshold; -1 = disabled (default); range -1..65535
# If this field is not included in hostapd.conf, hostapd will not control
# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
-rts_threshold=2347
+rts_threshold=-1
-# Fragmentation threshold; 2346 = disabled (default); range 256..2346
+# Fragmentation threshold; -1 = disabled (default); range -1, 256..2346
# If this field is not included in hostapd.conf, hostapd will not control
# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
# it.
-fragm_threshold=2346
+fragm_threshold=-1
# Rate configuration
# Default is to enable all rates supported by the hardware. This configuration
@@ -223,6 +249,19 @@ fragm_threshold=2346
#basic_rates=10 20 55 110
#basic_rates=60 120 240
+# Beacon frame TX rate configuration
+# This sets the TX rate that is used to transmit Beacon frames. If this item is
+# not included, the driver default rate (likely lowest rate) is used.
+# Legacy (CCK/OFDM rates):
+# beacon_rate=<legacy rate in 100 kbps>
+# HT:
+# beacon_rate=ht:<HT MCS>
+# VHT:
+# beacon_rate=vht:<VHT MCS>
+#
+# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
+#beacon_rate=10
+
# Short Preamble
# This parameter can be used to enable optional use of short preamble for
# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
@@ -267,16 +306,30 @@ auth_algs=3
# requests for broadcast SSID
ignore_broadcast_ssid=0
-# Additional vendor specfic elements for Beacon and Probe Response frames
+# Do not reply to broadcast Probe Request frames from unassociated STA if there
+# is no room for additional stations (max_num_sta). This can be used to
+# discourage a STA from trying to associate with this AP if the association
+# would be rejected due to maximum STA limit.
+# Default: 0 (disabled)
+#no_probe_resp_if_max_sta=0
+
+# Additional vendor specific elements for Beacon and Probe Response frames
# This parameter can be used to add additional vendor specific element(s) into
# the end of the Beacon and Probe Response frames. The format for these
# element(s) is a hexdump of the raw information elements (id+len+payload for
# one or more elements)
#vendor_elements=dd0411223301
+# Additional vendor specific elements for (Re)Association Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the (Re)Association Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#assocresp_elements=dd0411223301
+
# TX queue parameters (EDCF / bursting)
# tx_queue_<queue name>_<param>
-# queues: data0, data1, data2, data3, after_beacon, beacon
+# queues: data0, data1, data2, data3
# (data0 is the highest priority queue)
# parameters:
# aifs: AIFS (default 2)
@@ -385,6 +438,13 @@ wmm_ac_vo_txop_limit=47
wmm_ac_vo_acm=0
# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+# Enable Multi-AP functionality
+# 0 = disabled (default)
+# 1 = AP support backhaul BSS
+# 2 = AP support fronthaul BSS
+# 3 = AP supports both backhaul BSS and fronthaul BSS
+#multi_ap=0
+
# Static WEP key configuration
#
# The key number to use when transmitting.
@@ -458,18 +518,45 @@ wmm_ac_vo_acm=0
# Beacon and Probe Response frames.
#bss_load_update_period=50
+# Channel utilization averaging period (in BUs)
+# This field is used to enable and configure channel utilization average
+# calculation with bss_load_update_period. This should be in multiples of
+# bss_load_update_period for more accurate calculation.
+#chan_util_avg_period=600
+
# Fixed BSS Load value for testing purposes
# This field can be used to configure hostapd to add a fixed BSS Load element
# into Beacon and Probe Response frames for testing purposes. The format is
# <station count>:<channel utilization>:<available admission capacity>
#bss_load_test=12:80:20000
+# Multicast to unicast conversion
+# Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and
+# IPv6 frames (possibly within 802.1Q). If enabled, such frames are to be sent
+# to each station separately, with the DA replaced by their own MAC address
+# rather than the group address.
+#
+# Note that this may break certain expectations of the receiver, such as the
+# ability to drop unicast IP packets received within multicast L2 frames, or the
+# ability to not send ICMP destination unreachable messages for packets received
+# in L2 multicast (which is required, but the receiver can't tell the difference
+# if this new option is enabled).
+#
+# This also doesn't implement the 802.11 DMS (directed multicast service).
+#
+#multicast_to_unicast=0
+
+# Send broadcast Deauthentication frame on AP start/stop
+# Default: 1 (enabled)
+#broadcast_deauth=1
+
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
# 0 = disabled (default)
# 1 = enabled
# Note: You will also need to enable WMM for full HT functionality.
+# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
#ieee80211n=1
# ht_capab: HT capabilities (list of flags)
@@ -523,6 +610,7 @@ wmm_ac_vo_acm=0
# 0 = disabled (default)
# 1 = enabled
# Note: You will also need to enable WMM for full VHT functionality.
+# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
#ieee80211ac=1
# vht_capab: VHT capabilities (list of flags)
@@ -605,9 +693,9 @@ wmm_ac_vo_acm=0
# VHT TXOP PS: [VHT-TXOP-PS]
# Indicates whether or not the AP supports VHT TXOP Power Save Mode
# or whether or not the STA is in VHT TXOP Power Save mode
-# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
+# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS
# mode
-# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save
# mode
#
# +HTC-VHT Capable: [HTC-VHT]
@@ -665,6 +753,78 @@ wmm_ac_vo_acm=0
#
#vht_oper_centr_freq_seg1_idx=159
+# Workaround to use station's nsts capability in (Re)Association Response frame
+# This may be needed with some deployed devices as an interoperability
+# workaround for beamforming if the AP's capability is greater than the
+# station's capability. This is disabled by default and can be enabled by
+# setting use_sta_nsts=1.
+#use_sta_nsts=0
+
+##### IEEE 802.11ax related configuration #####################################
+
+#ieee80211ax: Whether IEEE 802.11ax (HE) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+#ieee80211ax=1
+
+#he_su_beamformer: HE single user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#he_su_beamformer=1
+
+#he_su_beamformee: HE single user beamformee support
+# 0 = not supported (default)
+# 1 = supported
+#he_su_beamformee=1
+
+#he_mu_beamformer: HE multiple user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#he_mu_beamformer=1
+
+# he_bss_color: BSS color
+# 0 = no BSS color (default)
+# unsigned integer = BSS color
+#he_bss_color=0
+
+#he_default_pe_duration: The duration of PE field in an HE PPDU in us
+# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
+#he_default_pe_duration=0
+
+#he_twt_required: Whether TWT is required
+# 0 = not required (default)
+# 1 = required
+#he_twt_required=0
+
+#he_rts_threshold: Duration of STA transmission
+# 0 = not set (default)
+# unsigned integer = duration in units of 16 us
+#he_rts_threshold=0
+
+#he_mu_edca_qos_info_param_count
+#he_mu_edca_qos_info_q_ack
+#he_mu_edca_qos_info_queue_request=1
+#he_mu_edca_qos_info_txop_request
+#he_mu_edca_ac_be_aifsn=0
+#he_mu_edca_ac_be_ecwmin=15
+#he_mu_edca_ac_be_ecwmax=15
+#he_mu_edca_ac_be_timer=255
+#he_mu_edca_ac_bk_aifsn=0
+#he_mu_edca_ac_bk_aci=1
+#he_mu_edca_ac_bk_ecwmin=15
+#he_mu_edca_ac_bk_ecwmax=15
+#he_mu_edca_ac_bk_timer=255
+#he_mu_edca_ac_vi_ecwmin=15
+#he_mu_edca_ac_vi_ecwmax=15
+#he_mu_edca_ac_vi_aifsn=0
+#he_mu_edca_ac_vi_aci=2
+#he_mu_edca_ac_vi_timer=255
+#he_mu_edca_ac_vo_aifsn=0
+#he_mu_edca_ac_vo_aci=3
+#he_mu_edca_ac_vo_ecwmin=15
+#he_mu_edca_ac_vo_ecwmax=15
+#he_mu_edca_ac_vo_timer=255
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -762,18 +922,83 @@ eap_server=0
# valid CRL signed by the CA is required to be included in the ca_cert file.
# This can be done by using PEM format for CA certificate and CRL and
# concatenating these into one file. Whenever CRL changes, hostapd needs to be
-# restarted to take the new CRL into use.
+# restarted to take the new CRL into use. Alternatively, crl_reload_interval can
+# be used to configure periodic updating of the loaded CRL information.
# 0 = do not verify CRLs (default)
# 1 = check the CRL of the user certificate
# 2 = check all CRLs in the certificate path
#check_crl=1
+# Specify whether to ignore certificate CRL validity time mismatches with
+# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID.
+#
+# 0 = ignore errors
+# 1 = do not ignore errors (default)
+#check_crl_strict=1
+
+# CRL reload interval in seconds
+# This can be used to reload ca_cert file and the included CRL on every new TLS
+# session if difference between last reload and the current reload time in
+# seconds is greater than crl_reload_interval.
+# Note: If interval time is very short, CPU overhead may be negatively affected
+# and it is advised to not go below 300 seconds.
+# This is applicable only with check_crl values 1 and 2.
+# 0 = do not reload CRLs (default)
+# crl_reload_interval = 300
+
+# If check_cert_subject is set, the value of every field will be checked
+# against the DN of the subject in the client certificate. If the values do
+# not match, the certificate verification will fail, rejecting the user.
+# This option allows hostapd to match every individual field in the right order
+# against the DN of the subject in the client certificate.
+#
+# For example, check_cert_subject=C=US/O=XX/OU=ABC/OU=XYZ/CN=1234 will check
+# every individual DN field of the subject in the client certificate. If OU=XYZ
+# comes first in terms of the order in the client certificate (DN field of
+# client certificate C=US/O=XX/OU=XYZ/OU=ABC/CN=1234), hostapd will reject the
+# client because the order of 'OU' is not matching the specified string in
+# check_cert_subject.
+#
+# This option also allows '*' as a wildcard. This option has some limitation.
+# It can only be used as per the following example.
+#
+# For example, check_cert_subject=C=US/O=XX/OU=Production* and we have two
+# clients and DN of the subject in the first client certificate is
+# (C=US/O=XX/OU=Production Unit) and DN of the subject in the second client is
+# (C=US/O=XX/OU=Production Factory). In this case, hostapd will allow both
+# clients because the value of 'OU' field in both client certificates matches
+# 'OU' value in 'check_cert_subject' up to 'wildcard'.
+#
+# * (Allow all clients, e.g., check_cert_subject=*)
+#check_cert_subject=string
+
# TLS Session Lifetime in seconds
# This can be used to allow TLS sessions to be cached and resumed with an
# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
# (default: 0 = session caching and resumption disabled)
#tls_session_lifetime=3600
+# TLS flags
+# [ALLOW-SIGN-RSA-MD5] = allow MD5-based certificate signatures (depending on
+# the TLS library, these may be disabled by default to enforce stronger
+# security)
+# [DISABLE-TIME-CHECKS] = ignore certificate validity time (this requests
+# the TLS library to accept certificates even if they are not currently
+# valid, i.e., have expired or have not yet become valid; this should be
+# used only for testing purposes)
+# [DISABLE-TLSv1.0] = disable use of TLSv1.0
+# [ENABLE-TLSv1.0] = explicitly enable use of TLSv1.0 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.1] = disable use of TLSv1.1
+# [ENABLE-TLSv1.1] = explicitly enable use of TLSv1.1 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.2] = disable use of TLSv1.2
+# [ENABLE-TLSv1.2] = explicitly enable use of TLSv1.2 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.3] = disable use of TLSv1.3
+# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
+#tls_flags=[flag1][flag2]...
+
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
@@ -788,6 +1013,11 @@ eap_server=0
# -respout /tmp/ocsp-cache.der
#ocsp_stapling_response=/tmp/ocsp-cache.der
+# Cached OCSP stapling response list (DER encoded OCSPResponseList)
+# This is similar to ocsp_stapling_response, but the extended version defined in
+# RFC 6961 to allow multiple OCSP responses to be provided.
+#ocsp_stapling_response_multi=/tmp/ocsp-multi-cache.der
+
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
# ephemeral DH key exchange. In most cases, the default RSA authentication does
@@ -803,12 +1033,26 @@ eap_server=0
# OpenSSL cipher string
#
# This is an OpenSSL specific configuration option for configuring the default
-# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default.
+# ciphers. If not set, the value configured at build time ("DEFAULT:!EXP:!LOW"
+# by default) is used.
# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
# on cipher suite configuration. This is applicable only if hostapd is built to
# use OpenSSL.
#openssl_ciphers=DEFAULT:!EXP:!LOW
+# OpenSSL ECDH curves
+#
+# This is an OpenSSL specific configuration option for configuring the ECDH
+# curves for EAP-TLS/TTLS/PEAP/FAST server. If not set, automatic curve
+# selection is enabled. If set to an empty string, ECDH curve configuration is
+# not done (the exact library behavior depends on the library version).
+# Otherwise, this is a colon separated list of the supported curves (e.g.,
+# P-521:P-384:P-256). This is applicable only if hostapd is built to use
+# OpenSSL. This must not be used for Suite B cases since the same OpenSSL
+# parameter is set differently in those cases and this might conflict with that
+# design.
+#openssl_ecdh_curves=P-521:P-384:P-256
+
# Fragment size for EAP methods
#fragment_size=1400
@@ -825,6 +1069,11 @@ eap_server=0
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
+# EAP-SIM DB request timeout
+# This parameter sets the maximum time to wait for a database request response.
+# The parameter value is in seconds.
+#eap_sim_db_timeout=1
+
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
# random value. It is configured as a 16-octet value in hex format. It can be
# generated, e.g., with the following command:
@@ -888,11 +1137,23 @@ eap_server=0
# The own IP address of the access point (used as NAS-IP-Address)
own_ip_addr=127.0.0.1
-# Optional NAS-Identifier string for RADIUS messages. When used, this should be
-# a unique to the NAS within the scope of the RADIUS server. For example, a
-# fully qualified domain name can be used here.
+# NAS-Identifier string for RADIUS messages. When used, this should be unique
+# to the NAS within the scope of the RADIUS server. Please note that hostapd
+# uses a separate RADIUS client for each BSS and as such, a unique
+# nas_identifier value should be configured separately for each BSS. This is
+# particularly important for cases where RADIUS accounting is used
+# (Accounting-On/Off messages are interpreted as clearing all ongoing sessions
+# and that may get interpreted as applying to all BSSes if the same
+# NAS-Identifier value is used.) For example, a fully qualified domain name
+# prefixed with a unique identifier of the BSS (e.g., BSSID) can be used here.
+#
# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
# 48 octets long.
+#
+# It is mandatory to configure either own_ip_addr or nas_identifier to be
+# compliant with the RADIUS protocol. When using RADIUS accounting, it is
+# strongly recommended that nas_identifier is set to a unique value for each
+# BSS.
#nas_identifier=ap.example.com
# RADIUS client forced local IP address for the access point
@@ -952,11 +1213,24 @@ own_ip_addr=127.0.0.1
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
# be used to set static client MAC address to VLAN ID mapping.
-# 0 = disabled (default)
-# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# Dynamic VLAN mode is also used with VLAN ID assignment based on WPA/WPA2
+# passphrase from wpa_psk_file or vlan_id parameter from sae_password.
+# 0 = disabled (default); only VLAN IDs from accept_mac_file will be used
+# 1 = optional; use default interface if RADIUS server does not include VLAN ID
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
#dynamic_vlan=0
+# Per-Station AP_VLAN interface mode
+# If enabled, each station is assigned its own AP_VLAN interface.
+# This implies per-station group keying and ebtables filtering of inter-STA
+# traffic (when passed through the AP).
+# If the sta is not assigned to any VLAN, then its AP_VLAN interface will be
+# added to the bridge given by the "bridge" configuration option (see above).
+# Otherwise, it will be added to the per-VLAN bridge.
+# 0 = disabled (default)
+# 1 = enabled
+#per_sta_vif=0
+
# VLAN interface list for dynamic VLAN mode is read from a separate text file.
# This list is used to map VLAN ID from the RADIUS server to a network
# interface. Each station is bound to one interface in the same way as with
@@ -965,6 +1239,7 @@ own_ip_addr=127.0.0.1
# white space (space or tab).
# If no entries are provided by this file, the station is statically mapped
# to <bss-iface>.<vlan-id> interfaces.
+# Each line can optionally also contain the name of a bridge to add the VLAN to
#vlan_file=/etc/hostapd.vlan
# Interface where 802.1q tagged packets should appear when a RADIUS server is
@@ -1028,6 +1303,8 @@ own_ip_addr=127.0.0.1
#radius_das_port=3799
#
# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+# Format: <IP address> <shared secret>
+# IP address 0.0.0.0 can be used to allow requests from any address.
#radius_das_client=192.168.1.123 shared secret here
#
# DAS Event-Timestamp time window in seconds
@@ -1035,6 +1312,9 @@ own_ip_addr=127.0.0.1
#
# DAS require Event-Timestamp
#radius_das_require_event_timestamp=1
+#
+# DAS require Message-Authenticator
+#radius_das_require_message_authenticator=1
##### RADIUS authentication server configuration ##############################
@@ -1071,7 +1351,10 @@ own_ip_addr=127.0.0.1
# and/or WPA2 (full IEEE 802.11i/RSN):
# bit0 = WPA
# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
-#wpa=1
+# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2.
+# In other words, for WPA3, wpa=2 is used the configuration (and
+# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
+#wpa=2
# 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
@@ -1100,31 +1383,73 @@ own_ip_addr=127.0.0.1
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
# added to enable SHA256-based stronger algorithms.
+# WPA-PSK = WPA-Personal / WPA2-Personal
+# WPA-PSK-SHA256 = WPA2-Personal using SHA256
+# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
+# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
+# SAE = SAE (WPA3-Personal)
+# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
+# FT-PSK = FT with passphrase/PSK
+# FT-EAP = FT with EAP
+# FT-EAP-SHA384 = FT with EAP using SHA384
+# FT-SAE = FT with SAE
+# FILS-SHA256 = Fast Initial Link Setup with SHA256
+# FILS-SHA384 = Fast Initial Link Setup with SHA384
+# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
+# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
+# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
+# DPP = Device Provisioning Protocol
+# OSEN = Hotspot 2.0 online signup with encryption
# (dot11RSNAConfigAuthenticationSuitesTable)
#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/D7.0]
-# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# CCMP = AES in Counter mode with CBC-MAC (CCMP-128)
+# TKIP = Temporal Key Integrity Protocol
+# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key
+# GCMP = Galois/counter mode protocol (GCMP-128)
+# GCMP-256 = Galois/counter mode protocol with 256-bit key
# 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.
+# TKIP will be used as the group cipher. The optional group_cipher parameter can
+# be used to override this automatic selection.
+#
# (dot11RSNAConfigPairwiseCiphersTable)
# Pairwise cipher for WPA (v1) (default: TKIP)
#wpa_pairwise=TKIP CCMP
# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
#rsn_pairwise=CCMP
+# Optional override for automatic group cipher selection
+# This can be used to select a specific group cipher regardless of which
+# pairwise ciphers were enabled for WPA and RSN. It should be noted that
+# overriding the group cipher with an unexpected value can result in
+# interoperability issues and in general, this parameter is mainly used for
+# testing purposes.
+#group_cipher=CCMP
+
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
# seconds. (dot11RSNAConfigGroupRekeyTime)
-#wpa_group_rekey=600
+# This defaults to 86400 seconds (once per day) when using CCMP/GCMP as the
+# group cipher and 600 seconds (once per 10 minutes) when using TKIP as the
+# group cipher.
+#wpa_group_rekey=86400
# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
# (dot11RSNAConfigGroupRekeyStrict)
#wpa_strict_rekey=1
+# The number of times EAPOL-Key Message 1/2 in the RSN Group Key Handshake is
+#retried per GTK Handshake attempt. (dot11RSNAConfigGroupUpdateCount)
+# This value should only be increased when stations are constantly
+# deauthenticated during GTK rekeying with the log message
+# "group key handshake failed...".
+# You should consider to also increase wpa_pairwise_update_count then.
+# Range 1..4294967295; default: 4
+#wpa_group_update_count=4
+
# Time interval for rekeying GMK (master key used internally to generate GTKs
# (in seconds).
#wpa_gmk_rekey=86400
@@ -1133,6 +1458,36 @@ own_ip_addr=127.0.0.1
# PTK to mitigate some attacks against TKIP deficiencies.
#wpa_ptk_rekey=600
+# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
+# Handshake are retried per 4-Way Handshake attempt.
+# (dot11RSNAConfigPairwiseUpdateCount)
+# Range 1..4294967295; default: 4
+#wpa_pairwise_update_count=4
+
+# Workaround for key reinstallation attacks
+#
+# This parameter can be used to disable retransmission of EAPOL-Key frames that
+# are used to install keys (EAPOL-Key message 3/4 and group message 1/2). This
+# is similar to setting wpa_group_update_count=1 and
+# wpa_pairwise_update_count=1, but with no impact to message 1/4 and with
+# extended timeout on the response to avoid causing issues with stations that
+# may use aggressive power saving have very long time in replying to the
+# EAPOL-Key messages.
+#
+# This option can be used to work around key reinstallation attacks on the
+# station (supplicant) side in cases those station devices cannot be updated
+# for some reason. By removing the retransmissions the attacker cannot cause
+# key reinstallation with a delayed frame transmission. This is related to the
+# station side vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079,
+# CVE-2017-13080, and CVE-2017-13081.
+#
+# This workaround might cause interoperability issues and reduced robustness of
+# key negotiation especially in environments with heavy traffic load due to the
+# number of attempts to perform the key exchange is reduced significantly. As
+# such, this workaround is disabled by default (unless overridden in build
+# configuration). To enable this, set the parameter to 1.
+#wpa_disable_eapol_key_retries=1
+
# 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.
@@ -1148,12 +1503,6 @@ own_ip_addr=127.0.0.1
# one.
#rsn_preauth_interfaces=eth0
-# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
-# allowed. This is only used with RSN/WPA2.
-# 0 = disabled (default)
-# 1 = enabled
-#peerkey=1
-
# ieee80211w: Whether management frame protection (MFP) is enabled
# 0 = disabled (default)
# 1 = optional
@@ -1181,6 +1530,13 @@ own_ip_addr=127.0.0.1
# dot11AssociationSAQueryRetryTimeout, 1...4294967295
#assoc_sa_query_retry_timeout=201
+# ocv: Operating Channel Validation
+# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this automatically also enables ieee80211w, if not yet enabled.
+# 0 = disabled (default)
+# 1 = enabled
+#ocv=1
+
# disable_pmksa_caching: Disable PMKSA caching
# This parameter can be used to disable caching of PMKSA created through EAP
# authentication. RSN preauthentication may still end up using PMKSA caching if
@@ -1196,19 +1552,133 @@ own_ip_addr=127.0.0.1
# 1 = enabled
#okc=1
+# SAE password
+# This parameter can be used to set passwords for SAE. By default, the
+# wpa_passphrase value is used if this separate parameter is not used, but
+# wpa_passphrase follows the WPA-PSK constraints (8..63 characters) even though
+# SAE passwords do not have such constraints. If the BSS enabled both SAE and
+# WPA-PSK and both values are set, SAE uses the sae_password values and WPA-PSK
+# uses the wpa_passphrase value.
+#
+# Each sae_password entry is added to a list of available passwords. This
+# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value
+# starts with the password (dot11RSNAConfigPasswordCredential). That value can
+# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
+# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
+# addition, an optional VLAN ID specification can be used to bind the station
+# to the specified VLAN whenver the specific SAE password entry is used.
+#
+# If the peer MAC address is not included or is set to the wildcard address
+# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
+# specific peer MAC address is included, only a station with that MAC address
+# is allowed to use the entry.
+#
+# If the password identifier (with non-zero length) is included, the entry is
+# limited to be used only with that specified identifier.
+
+# The last matching (based on peer MAC address and identifier) entry is used to
+# select which password to use. Setting sae_password to an empty string has a
+# special meaning of removing all previously added entries.
+#
+# sae_password uses the following encoding:
+#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>]
+# Examples:
+#sae_password=secret
+#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
+#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier
+#sae_password=example secret|vlanid=3|id=pw identifier
+
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
# This parameter defines how many open SAE instances can be in progress at the
# same time before the anti-clogging mechanism is taken into use.
#sae_anti_clogging_threshold=5
+# Maximum number of SAE synchronization errors (dot11RSNASAESync)
+# The offending SAe peer will be disconnected if more than this many
+# synchronization errors happen.
+#sae_sync=5
+
# Enabled SAE finite cyclic groups
# SAE implementation are required to support group 19 (ECC group defined over a
-# 256-bit prime order field). All groups that are supported by the
-# implementation are enabled by default. This configuration parameter can be
+# 256-bit prime order field). This configuration parameter can be used to
+# specify a set of allowed groups. If not included, only the mandatory group 19
+# is enabled.
+# The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+# Note that groups 1, 2, 5, 22, 23, and 24 should not be used in production
+# purposes due limited security (see RFC 8247). Groups that are not as strong as
+# group 19 (ECC, NIST P-256) are unlikely to be useful for production use cases
+# since all implementations are required to support group 19.
+#sae_groups=19 20 21
+
+# Require MFP for all associations using SAE
+# This parameter can be used to enforce negotiation of MFP for all associations
+# that negotiate use of SAE. This is used in cases where SAE-capable devices are
+# known to be MFP-capable and the BSS is configured with optional MFP
+# (ieee80211w=1) for legacy support. The non-SAE stations can connect without
+# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
+#sae_require_mfp=0
+
+# FILS Cache Identifier (16-bit value in hexdump format)
+#fils_cache_id=0011
+
+# FILS Realm Information
+# One or more FILS realms need to be configured when FILS is enabled. This list
+# of realms is used to define which realms (used in keyName-NAI by the client)
+# can be used with FILS shared key authentication for ERP.
+#fils_realm=example.com
+#fils_realm=example.org
+
+# FILS DH Group for PFS
+# 0 = PFS disabled with FILS shared key authentication (default)
+# 1-65535 DH Group to use for FILS PFS
+#fils_dh_group=0
+
+# OWE DH groups
+# OWE implementations are required to support group 19 (NIST P-256). All groups
+# that are supported by the implementation (e.g., groups 19, 20, and 21 when
+# using OpenSSL) are enabled by default. This configuration parameter can be
# used to specify a limited set of allowed groups. The group values are listed
# in the IANA registry:
-# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
-#sae_groups=19 20 21 25 26
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
+#owe_groups=19 20 21
+
+# OWE transition mode configuration
+# Pointer to the matching open/OWE BSS
+#owe_transition_bssid=<bssid>
+# SSID in same format as ssid2 described above.
+#owe_transition_ssid=<SSID>
+# Alternatively, OWE transition mode BSSID/SSID can be configured with a
+# reference to a BSS operated by this hostapd process.
+#owe_transition_ifname=<ifname>
+
+# DHCP server for FILS HLP
+# If configured, hostapd will act as a DHCP relay for all FILS HLP requests
+# that include a DHCPDISCOVER message and send them to the specific DHCP
+# server for processing. hostapd will then wait for a response from that server
+# before replying with (Re)Association Response frame that encapsulates this
+# DHCP response. own_ip_addr is used as the local address for the communication
+# with the DHCP server.
+#dhcp_server=127.0.0.1
+
+# DHCP server UDP port
+# Default: 67
+#dhcp_server_port=67
+
+# DHCP relay UDP port on the local device
+# Default: 67; 0 means not to bind any specific port
+#dhcp_relay_port=67
+
+# DHCP rapid commit proxy
+# If set to 1, this enables hostapd to act as a DHCP rapid commit proxy to
+# allow the rapid commit options (two message DHCP exchange) to be used with a
+# server that supports only the four message DHCP exchange. This is disabled by
+# default (= 0) and can be enabled by setting this to 1.
+#dhcp_rapid_commit_proxy=0
+
+# Wait time for FILS HLP (dot11HLPWaitTime) in TUs
+# default: 30 TUs (= 30.72 milliseconds)
+#fils_hlp_wait_time=30
##### IEEE 802.11r configuration ##############################################
@@ -1222,12 +1692,20 @@ own_ip_addr=127.0.0.1
# 1 to 48 octet identifier.
# This is configured with nas_identifier (see RADIUS client section above).
-# Default lifetime of the PMK-RO in minutes; range 1..65535
+# Default lifetime of the PMK-R0 in seconds; range 60..4294967295
+# (default: 14 days / 1209600 seconds; 0 = disable timeout)
# (dot11FTR0KeyLifetime)
-#r0_key_lifetime=10000
+#ft_r0_key_lifetime=1209600
+
+# Maximum lifetime for PMK-R1; applied only if not zero
+# PMK-R1 is removed at latest after this limit.
+# Removing any PMK-R1 for expiry can be disabled by setting this to -1.
+# (default: 0)
+#r1_max_key_lifetime=0
# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
# 6-octet identifier as a hex string.
+# Defaults to BSSID.
#r1_key_holder=000102030405
# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
@@ -1235,22 +1713,52 @@ own_ip_addr=127.0.0.1
#reassociation_deadline=1000
# List of R0KHs in the same Mobility Domain
-# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
+# format: <MAC address> <NAS Identifier> <256-bit key as hex string>
# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
# address when requesting PMK-R1 key from the R0KH that the STA used during the
# Initial Mobility Domain Association.
-#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
-#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
+#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
+#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
# And so on.. One line per R0KH.
+# Wildcard entry:
+# Upon receiving a response from R0KH, it will be added to this list, so
+# subsequent requests won't be broadcast. If R0KH does not reply, it will be
+# blacklisted.
+#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
# List of R1KHs in the same Mobility Domain
-# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
+# format: <MAC address> <R1KH-ID> <256-bit key as hex string>
# This list is used to map R1KH-ID to a destination MAC address when sending
# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
# that can request PMK-R1 keys.
-#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
-#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
+#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
+#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
# And so on.. One line per R1KH.
+# Wildcard entry:
+# Upon receiving a request from an R1KH not yet known, it will be added to this
+# list and thus will receive push notifications.
+#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff
+
+# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above)
+# Special values: 0 -> do not expire
+# Warning: do not cache implies no sequence number validation with wildcards
+#rkh_pos_timeout=86400 (default = 1 day)
+
+# Timeout (milliseconds) for requesting PMK-R1 from R0KH using PULL request
+# and number of retries.
+#rkh_pull_timeout=1000 (default = 1 second)
+#rkh_pull_retries=4 (default)
+
+# Timeout (seconds) for non replying R0KH (see wildcard entries above)
+# Special values: 0 -> do not cache
+# default: 60 seconds
+#rkh_neg_timeout=60
+
+# Note: The R0KH/R1KH keys used to be 128-bit in length before the message
+# format was changed. That shorter key length is still supported for backwards
+# compatibility of the configuration files. If such a shorter key is used, a
+# 256-bit key is derived from it. For new deployments, configuring the 256-bit
+# key is recommended.
# Whether PMK-R1 push is enabled at R0KH
# 0 = do not push PMK-R1 to all configured R1KHs (default)
@@ -1262,6 +1770,14 @@ own_ip_addr=127.0.0.1
# 1 = FT-over-DS enabled (default)
#ft_over_ds=1
+# Whether to generate FT response locally for PSK networks
+# This avoids use of PMK-R1 push/pull from other APs with FT-PSK networks as
+# the required information (PSK and other session data) is already locally
+# available.
+# 0 = disabled (default)
+# 1 = enabled
+#ft_psk_generate_local=0
+
##### Neighbor table ##########################################################
# Maximum number of entries kept in AP table (either for neigbor table or for
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
@@ -1452,6 +1968,14 @@ own_ip_addr=127.0.0.1
# the configuration appropriately in this case.
#wps_cred_processing=0
+# Whether to enable SAE (WPA3-Personal transition mode) automatically for
+# WPA2-PSK credentials received using WPS.
+# 0 = only add the explicitly listed WPA2-PSK configuration (default)
+# 1 = add both the WPA2-PSK and SAE configuration and enable PMF so that the
+# AP gets configured in WPA3-Personal transition mode (supports both
+# WPA2-Personal (PSK) and WPA3-Personal (SAE) clients).
+#wps_cred_add_sae=0
+
# AP Settings Attributes for M7
# By default, hostapd generates the AP Settings Attributes for M7 based on the
# current configuration. It is possible to override this by providing a file
@@ -1460,6 +1984,15 @@ own_ip_addr=127.0.0.1
# attribute.
#ap_settings=hostapd.ap_settings
+# Multi-AP backhaul BSS config
+# Used in WPS when multi_ap=2 or 3. Defines "backhaul BSS" credentials.
+# These are passed in WPS M8 instead of the normal (fronthaul) credentials
+# if the Enrollee has the Multi-AP subelement set. Backhaul SSID is formatted
+# like ssid2. The key is set like wpa_psk or wpa_passphrase.
+#multi_ap_backhaul_ssid="backhaul"
+#multi_ap_backhaul_wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#multi_ap_backhaul_wpa_passphrase=secret passphrase
+
# WPS UPnP interface
# If set, support for external Registrars is enabled.
#upnp_iface=br0
@@ -1532,6 +2065,18 @@ own_ip_addr=127.0.0.1
# 1 = enabled (allow stations to use WNM-Sleep Mode)
#wnm_sleep_mode=1
+# WNM-Sleep Mode GTK/IGTK workaround
+# Normally, WNM-Sleep Mode exit with management frame protection negotiated
+# would result in the current GTK/IGTK getting added into the WNM-Sleep Mode
+# Response frame. Some station implementations may have a vulnerability that
+# results in GTK/IGTK reinstallation based on this frame being replayed. This
+# configuration parameter can be used to disable that behavior and use EAPOL-Key
+# frames for GTK/IGTK update instead. This would likely be only used with
+# wpa_disable_eapol_key_retries=1 that enables a workaround for similar issues
+# with EAPOL-Key. This is related to station side vulnerabilities CVE-2017-13087
+# and CVE-2017-13088. To enable this AP-side workaround, set the parameter to 1.
+#wnm_sleep_mode_no_keys=0
+
# BSS Transition Management
# 0 = disabled (default)
# 1 = enabled
@@ -1619,6 +2164,15 @@ own_ip_addr=127.0.0.1
# (double quoted string, printf-escaped string)
#venue_name=P"eng:Example\nvenue"
+# Venue URL information
+# This parameter can be used to configure one or more Venue URL Duples to
+# provide additional information corresponding to Venue Name information.
+# Each entry has a Venue Number value separated by colon from the Venue URL
+# string. Venue Number indicates the corresponding venue_name entry (1 = 1st
+# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name)
+#venue_url=1:http://www.example.com/info-eng
+#venue_url=2:http://www.example.com/info-fin
+
# Network Authentication Type
# This parameter indicates what type of network authentication is used in the
# network.
@@ -1684,6 +2238,24 @@ own_ip_addr=127.0.0.1
# username/password
#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+# Arbitrary ANQP-element configuration
+# Additional ANQP-elements with arbitrary values can be defined by specifying
+# their contents in raw format as a hexdump of the payload. Note that these
+# values will override ANQP-element contents that may have been specified in the
+# more higher layer configuration parameters listed above.
+# format: anqp_elem=<InfoID>:<hexdump of payload>
+# For example, AP Geospatial Location ANQP-element with unknown location:
+#anqp_elem=265:0000
+# For example, AP Civic Location ANQP-element with unknown location:
+#anqp_elem=266:000000
+
+# GAS Address 3 behavior
+# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default
+# based on GAS request Address3
+# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3
+# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases)
+#gas_address3=0
+
# QoS Map Set configuration
#
# Comma delimited QoS Map Set in decimal values
@@ -1771,7 +2343,27 @@ own_ip_addr=127.0.0.1
# channels 36-48):
#hs20_operating_class=5173
-# OSU icons
+# Terms and Conditions information
+#
+# hs20_t_c_filename contains the Terms and Conditions filename that the AP
+# indicates in RADIUS Access-Request messages.
+#hs20_t_c_filename=terms-and-conditions
+#
+# hs20_t_c_timestamp contains the Terms and Conditions timestamp that the AP
+# indicates in RADIUS Access-Request messages. Usually, this contains the number
+# of seconds since January 1, 1970 00:00 UTC showing the time when the file was
+# last modified.
+#hs20_t_c_timestamp=1234567
+#
+# hs20_t_c_server_url contains a template for the Terms and Conditions server
+# URL. This template is used to generate the URL for a STA that needs to
+# acknowledge Terms and Conditions. Unlike the other hs20_t_c_* parameters, this
+# parameter is used on the authentication server, not the AP.
+# Macros:
+# @1@ = MAC address of the STA (colon separated hex octets)
+#hs20_t_c_server_url=https://example.com/t_and_c?addr=@1@&ap=123
+
+# OSU and Operator icons
# <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path>
#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png
#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png
@@ -1783,12 +2375,15 @@ own_ip_addr=127.0.0.1
# OSU Providers
# One or more sets of following parameter. Each OSU provider is started by the
# mandatory osu_server_uri item. The other parameters add information for the
-# last added OSU provider.
+# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN
+# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI
+# value for OSEN authentication when using a shared BSS (Single SSID) for OSU.
#
#osu_server_uri=https://example.com/osu/
#osu_friendly_name=eng:Example operator
#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
#osu_nai=anonymous@example.com
+#osu_nai2=anonymous@example.com
#osu_method_list=1 0
#osu_icon=icon32
#osu_icon=icon64
@@ -1797,6 +2392,50 @@ own_ip_addr=127.0.0.1
#
#osu_server_uri=...
+# Operator Icons
+# Operator icons are specified using references to the hs20_icon entries
+# (Name subfield). This information, if present, is advertsised in the
+# Operator Icon Metadata ANQO-element.
+#operator_icon=icon32
+#operator_icon=icon64
+
+##### Multiband Operation (MBO) ###############################################
+#
+# MBO enabled
+# 0 = disabled (default)
+# 1 = enabled
+#mbo=1
+#
+# Cellular data connection preference
+# 0 = Excluded - AP does not want STA to use the cellular data connection
+# 1 = AP prefers the STA not to use cellular data connection
+# 255 = AP prefers the STA to use cellular data connection
+#mbo_cell_data_conn_pref=1
+
+##### Optimized Connectivity Experience (OCE) #################################
+#
+# Enable OCE specific features (bitmap)
+# BIT(0) - Reserved
+# Set BIT(1) (= 2) to enable OCE in STA-CFON mode
+# Set BIT(2) (= 4) to enable OCE in AP mode
+# Default is 0 = OCE disabled
+#oce=0
+
+# RSSI-based assocition rejection
+#
+# Reject STA association if RSSI is below given threshold (in dBm)
+# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
+# Note: This rejection happens based on a signal strength detected while
+# receiving a single frame and as such, there is significant risk of the value
+# not being accurate and this resulting in valid stations being rejected. As
+# such, this functionality is not recommended to be used for purposes other than
+# testing.
+#rssi_reject_assoc_rssi=-75
+#
+# Association retry delay in seconds allowed by the STA if RSSI has not met the
+# threshold (range: 0..255, default=30).
+#rssi_reject_assoc_timeout=30
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
@@ -1823,6 +2462,36 @@ own_ip_addr=127.0.0.1
# Transitioning between states).
#fst_llt=100
+##### Radio measurements / location ###########################################
+
+# The content of a LCI measurement subelement
+#lci=<Hexdump of binary data of the LCI report>
+
+# The content of a location civic measurement subelement
+#civic=<Hexdump of binary data of the location civic report>
+
+# Enable neighbor report via radio measurements
+#rrm_neighbor_report=1
+
+# Enable beacon report via radio measurements
+#rrm_beacon_report=1
+
+# Publish fine timing measurement (FTM) responder functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_initiator=0
+#
+# Stationary AP config indicates that the AP doesn't move hence location data
+# can be considered as always up to date. If configured, LCI data will be sent
+# as a radio measurement even if the request doesn't contain a max age element
+# that allows sending of such data. Default: 0.
+#stationary_ap=0
+
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
@@ -1844,6 +2513,10 @@ own_ip_addr=127.0.0.1
#
# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
#corrupt_gtk_rekey_mic_probability=0.0
+#
+# Include only ECSA IE without CSA IE where possible
+# (channel switch operating class is needed)
+#ecsa_ie_only=0
##### Multiple BSSID support ##################################################
#
@@ -1866,6 +2539,10 @@ own_ip_addr=127.0.0.1
# - is not the same as the MAC address of the radio
# - is not the same as any other explicitly specified BSSID
#
+# Alternatively, the 'use_driver_iface_addr' parameter can be used to request
+# hostapd to use the driver auto-generated interface address (e.g., to use the
+# exact MAC addresses allocated to the device).
+#
# Not all drivers support multiple BSSes. The exact mechanism for determining
# the driver capabilities is driver specific. With the current (i.e., a recent
# kernel) drivers using nl80211, this information can be checked with "iw list"
diff --git a/contrib/wpa/hostapd/hostapd.eap_user_sqlite b/contrib/wpa/hostapd/hostapd.eap_user_sqlite
index 826db34..411b9ea 100644
--- a/contrib/wpa/hostapd/hostapd.eap_user_sqlite
+++ b/contrib/wpa/hostapd/hostapd.eap_user_sqlite
@@ -3,7 +3,8 @@ CREATE TABLE users(
methods TEXT,
password TEXT,
remediation TEXT,
- phase2 INTEGER
+ phase2 INTEGER,
+ t_c_timestamp INTEGER
);
CREATE TABLE wildcards(
@@ -24,3 +25,18 @@ CREATE TABLE authlog(
username TEXT,
note TEXT
);
+
+CREATE TABLE pending_tc(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT
+);
+
+CREATE TABLE current_sessions(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT,
+ start_time TEXT,
+ nas TEXT,
+ hs20_t_c_filtering BOOLEAN,
+ waiting_coa_ack BOOLEAN,
+ coa_ack_received BOOLEAN
+);
diff --git a/contrib/wpa/hostapd/hostapd.wpa_psk b/contrib/wpa/hostapd/hostapd.wpa_psk
index 0a9499a..166e59e 100644
--- a/contrib/wpa/hostapd/hostapd.wpa_psk
+++ b/contrib/wpa/hostapd/hostapd.wpa_psk
@@ -3,7 +3,13 @@
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
# characters or as a 256-bit hex PSK (64 hex digits).
+# An optional key identifier can be added by prefixing the line with
+# keyid=<keyid_string>
+# An optional VLAN ID can be specified by prefixing the line with
+# vlanid=<VLAN ID>.
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+keyid=example_id 00:11:22:33:44:77 passphrase with keyid
+vlanid=3 00:00:00:00:00:00 passphrase with vlanid
00:00:00:00:00:00 another passphrase for all STAs
diff --git a/contrib/wpa/hostapd/hostapd_cli.c b/contrib/wpa/hostapd/hostapd_cli.c
index 46c2f37..23c592a 100644
--- a/contrib/wpa/hostapd/hostapd_cli.c
+++ b/contrib/wpa/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
/*
* hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,79 +15,13 @@
#include "utils/eloop.h"
#include "utils/edit.h"
#include "common/version.h"
+#include "common/cli.h"
+#ifndef CONFIG_NO_CTRL_IFACE
static const char *const hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
-
-
-static const char *const hostapd_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const hostapd_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-" notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-" notice, this list of conditions and the following disclaimer in the\n"
-" documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-" names of its contributors may be used to endorse or promote products\n"
-" derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
-
-static const char *const commands_help =
-"Commands:\n"
-" mib get MIB variables (dot1x, dot11, radius)\n"
-" sta <addr> get MIB variables for one station\n"
-" all_sta get MIB variables for all stations\n"
-" new_sta <addr> add a new station\n"
-" deauthenticate <addr> deauthenticate a station\n"
-" disassociate <addr> disassociate a station\n"
-#ifdef CONFIG_IEEE80211W
-" sa_query <addr> send SA Query to a station\n"
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WPS
-" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
-" wps_check_pin <PIN> verify PIN checksum\n"
-" wps_pbc indicate button pushed to initiate PBC\n"
-" wps_cancel cancel the pending WPS operation\n"
-#ifdef CONFIG_WPS_NFC
-" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
-" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
-" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
-#endif /* CONFIG_WPS_NFC */
-" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
-" wps_config <SSID> <auth> <encr> <key> configure AP\n"
-" wps_get_status show current WPS status\n"
-#endif /* CONFIG_WPS */
-" get_config show current configuration\n"
-" help show this usage help\n"
-" interface [ifname] show interfaces/select interface\n"
-" level <debug level> change debug level\n"
-" license show full hostapd_cli license\n"
-" quit exit hostapd_cli\n";
+"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors";
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
@@ -104,6 +38,15 @@ static const char *pid_file = NULL;
static const char *action_file = NULL;
static int ping_interval = 5;
static int interactive = 0;
+static int event_handler_registered = 0;
+
+static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
+
+static void print_help(FILE *stream, const char *cmd);
+static char ** list_cmd_list(void);
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
+static void update_stations(struct wpa_ctrl *ctrl);
+static void cli_event(const char *str);
static void usage(void)
@@ -128,20 +71,49 @@ static void usage(void)
" -B run a daemon in the background\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
- " socket path)\n\n"
- "%s",
- commands_help);
+ " socket path)\n\n");
+ print_help(stderr, NULL);
+}
+
+
+static void register_event_handler(struct wpa_ctrl *ctrl)
+{
+ if (!ctrl_conn)
+ return;
+ if (interactive) {
+ event_handler_registered =
+ !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
+ hostapd_cli_receive,
+ NULL, NULL);
+ }
+}
+
+
+static void unregister_event_handler(struct wpa_ctrl *ctrl)
+{
+ if (!ctrl_conn)
+ return;
+ if (interactive && event_handler_registered) {
+ eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
+ event_handler_registered = 0;
+ }
}
static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
{
+#ifndef CONFIG_CTRL_IFACE_UDP
char *cfile;
int flen;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
if (ifname == NULL)
return NULL;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ ctrl_conn = wpa_ctrl_open(ifname);
+ return ctrl_conn;
+#else /* CONFIG_CTRL_IFACE_UDP */
flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
cfile = malloc(flen);
if (cfile == NULL)
@@ -158,6 +130,7 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
free(cfile);
return ctrl_conn;
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
@@ -166,6 +139,7 @@ static void hostapd_cli_close_connection(void)
if (ctrl_conn == NULL)
return;
+ unregister_event_handler(ctrl_conn);
if (hostapd_cli_attached) {
wpa_ctrl_detach(ctrl_conn);
hostapd_cli_attached = 0;
@@ -175,13 +149,45 @@ static void hostapd_cli_close_connection(void)
}
+static int hostapd_cli_reconnect(const char *ifname)
+{
+ char *next_ctrl_ifname;
+
+ hostapd_cli_close_connection();
+
+ if (!ifname)
+ return -1;
+
+ next_ctrl_ifname = os_strdup(ifname);
+ os_free(ctrl_ifname);
+ ctrl_ifname = next_ctrl_ifname;
+ if (!ctrl_ifname)
+ return -1;
+
+ ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+ if (!ctrl_conn)
+ return -1;
+ if (!interactive && !action_file)
+ return 0;
+ if (wpa_ctrl_attach(ctrl_conn) == 0) {
+ hostapd_cli_attached = 1;
+ register_event_handler(ctrl_conn);
+ update_stations(ctrl_conn);
+ } else {
+ printf("Warning: Failed to attach to hostapd.\n");
+ }
+ return 0;
+}
+
+
static void hostapd_cli_msg_cb(char *msg, size_t len)
{
+ cli_event(msg);
printf("%s\n", msg);
}
-static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
{
char buf[4096];
size_t len;
@@ -209,12 +215,28 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
}
-static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
+static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
{
return _wpa_ctrl_command(ctrl, cmd, 1);
}
+static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
+ int min_args, int argc, char *argv[])
+{
+ char buf[4096];
+
+ if (argc < min_args) {
+ printf("Invalid %s command - at least %d argument%s required.\n",
+ cmd, min_args, min_args > 1 ? "s are" : " is");
+ return -1;
+ }
+ if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "PING");
@@ -298,6 +320,21 @@ static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static char ** hostapd_complete_stations(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -348,6 +385,22 @@ static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
}
+#ifdef CONFIG_TAXONOMY
+static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+
+ if (argc != 1) {
+ printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
+ return -1;
+ }
+ os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_TAXONOMY */
+
+
#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
@@ -667,8 +720,8 @@ static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
}
-static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
- char *addr, size_t addr_len)
+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
+ char *addr, size_t addr_len, int print)
{
char buf[4096], *pos;
size_t len;
@@ -692,7 +745,8 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
buf[len] = '\0';
if (memcmp(buf, "FAIL", 4) == 0)
return -1;
- printf("%s", buf);
+ if (print)
+ printf("%s", buf);
pos = buf;
while (*pos != '\0' && *pos != '\n')
@@ -708,27 +762,59 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
{
char addr[32], cmd[64];
- if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
return 0;
do {
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
- } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
return -1;
}
+static int hostapd_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char addr[32], cmd[64];
+
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
+ return 0;
+ do {
+ if (os_strcmp(addr, "") != 0)
+ printf("%s\n", addr);
+ os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
+
+ return 0;
+}
+
+
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- printf("%s", commands_help);
+ print_help(stdout, argc > 0 ? argv[0] : NULL);
return 0;
}
+static char ** hostapd_cli_complete_help(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = list_cmd_list();
+ break;
+ }
+
+ return res;
+}
+
+
static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
+ printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
return 0;
}
@@ -839,6 +925,47 @@ static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static void update_stations(struct wpa_ctrl *ctrl)
+{
+ char addr[32], cmd[64];
+
+ if (!ctrl || !interactive)
+ return;
+
+ cli_txt_list_flush(&stations);
+
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
+ return;
+ do {
+ if (os_strcmp(addr, "") != 0)
+ cli_txt_list_add(&stations, addr);
+ os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
+}
+
+
+static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
+ struct dl_list *interfaces)
+{
+ struct dirent *dent;
+ DIR *dir;
+
+ if (!ctrl || !interfaces)
+ return;
+ dir = opendir(ctrl_iface_dir);
+ if (dir == NULL)
+ return;
+
+ while ((dent = readdir(dir))) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ cli_txt_list_add(interfaces, dent->d_name);
+ }
+ closedir(dir);
+}
+
+
static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
struct dirent *dent;
@@ -869,22 +996,7 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
hostapd_cli_list_interfaces(ctrl);
return 0;
}
-
- hostapd_cli_close_connection();
- os_free(ctrl_ifname);
- ctrl_ifname = os_strdup(argv[0]);
- if (ctrl_ifname == NULL)
- return -1;
-
- if (hostapd_cli_open_connection(ctrl_ifname)) {
- printf("Connected to interface '%s.\n", ctrl_ifname);
- if (wpa_ctrl_attach(ctrl_conn) == 0) {
- hostapd_cli_attached = 1;
- } else {
- printf("Warning: Failed to attach to "
- "hostapd.\n");
- }
- } else {
+ if (hostapd_cli_reconnect(argv[0]) != 0) {
printf("Could not connect to interface '%s' - re-trying\n",
ctrl_ifname);
}
@@ -892,9 +1004,27 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
}
+static char ** hostapd_complete_interface(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+ DEFINE_DL_LIST(interfaces);
+
+ switch (arg) {
+ case 1:
+ hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
+ res = cli_txt_list_array(&interfaces);
+ cli_txt_list_flush(&interfaces);
+ break;
+ }
+
+ return res;
+}
+
+
static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
+ char cmd[2048];
int res;
if (argc != 2) {
@@ -912,6 +1042,44 @@ static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static char ** hostapd_complete_set(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+#ifdef CONFIG_WPS_TESTING
+ "wps_version_number", "wps_testing_dummy_cred",
+ "wps_corrupt_pkhash",
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_INTERWORKING
+ "gas_frag_limit",
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_TESTING_OPTIONS
+ "ext_mgmt_frame_handling", "ext_eapol_frame_io",
+#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_MBO
+ "mbo_assoc_disallow",
+#endif /* CONFIG_MBO */
+ "deny_mac_file", "accept_mac_file",
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+
+ if (arg == 1) {
+ char **res;
+
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (!res)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(fields[i]);
+ if (!res[i])
+ return res;
+ }
+ return res;
+ }
+ return NULL;
+}
+
+
static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -932,6 +1100,31 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static char ** hostapd_complete_get(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ "version", "tls_library",
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+
+ if (arg == 1) {
+ char **res;
+
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (!res)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(fields[i]);
+ if (!res[i])
+ return res;
+ }
+ return res;
+ }
+ return NULL;
+}
+
+
#ifdef CONFIG_FST
static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
@@ -1068,68 +1261,460 @@ static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc == 0)
+ return -1;
+ return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
+}
+
+
+static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PMKSA");
+}
+
+
+static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
+}
+
+
+static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[2048];
+ int res;
+
+ if (argc < 3 || argc > 6) {
+ printf("Invalid set_neighbor command: needs 3-6 arguments\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s",
+ argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
+ argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : "");
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long SET_NEIGHBOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[400];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid remove_neighbor command: needs 2 arguments\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long REMOVE_NEIGHBOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid req_lci command - requires destination address\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long REQ_LCI command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc < 4) {
+ printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
+ return -1;
+ }
+
+ return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
+#ifdef CONFIG_DPP
+
+static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN");
+}
+
+
+static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
+}
+
+#endif /* CONFIG_DPP */
+
+
+static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "REQ_BEACON", 2, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+ char ** (*completion)(const char *str, int pos);
+ const char *usage;
};
static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
- { "ping", hostapd_cli_cmd_ping },
- { "mib", hostapd_cli_cmd_mib },
- { "relog", hostapd_cli_cmd_relog },
- { "status", hostapd_cli_cmd_status },
- { "sta", hostapd_cli_cmd_sta },
- { "all_sta", hostapd_cli_cmd_all_sta },
- { "new_sta", hostapd_cli_cmd_new_sta },
- { "deauthenticate", hostapd_cli_cmd_deauthenticate },
- { "disassociate", hostapd_cli_cmd_disassociate },
+ { "ping", hostapd_cli_cmd_ping, NULL,
+ "= pings hostapd" },
+ { "mib", hostapd_cli_cmd_mib, NULL,
+ "= get MIB variables (dot1x, dot11, radius)" },
+ { "relog", hostapd_cli_cmd_relog, NULL,
+ "= reload/truncate debug log output file" },
+ { "status", hostapd_cli_cmd_status, NULL,
+ "= show interface status info" },
+ { "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
+ "<addr> = get MIB variables for one station" },
+ { "all_sta", hostapd_cli_cmd_all_sta, NULL,
+ "= get MIB variables for all stations" },
+ { "list_sta", hostapd_cli_cmd_list_sta, NULL,
+ "= list all stations" },
+ { "new_sta", hostapd_cli_cmd_new_sta, NULL,
+ "<addr> = add a new station" },
+ { "deauthenticate", hostapd_cli_cmd_deauthenticate,
+ hostapd_complete_stations,
+ "<addr> = deauthenticate a station" },
+ { "disassociate", hostapd_cli_cmd_disassociate,
+ hostapd_complete_stations,
+ "<addr> = disassociate a station" },
+#ifdef CONFIG_TAXONOMY
+ { "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
+ "<addr> = get taxonomy signature for a station" },
+#endif /* CONFIG_TAXONOMY */
#ifdef CONFIG_IEEE80211W
- { "sa_query", hostapd_cli_cmd_sa_query },
+ { "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
+ "<addr> = send SA Query to a station" },
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
- { "wps_pin", hostapd_cli_cmd_wps_pin },
- { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
- { "wps_pbc", hostapd_cli_cmd_wps_pbc },
- { "wps_cancel", hostapd_cli_cmd_wps_cancel },
+ { "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
+ "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
+ { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
+ "<PIN> = verify PIN checksum" },
+ { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
+ "= indicate button pushed to initiate PBC" },
+ { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
+ "= cancel the pending WPS operation" },
#ifdef CONFIG_WPS_NFC
- { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
- { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
- { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
- { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
+ { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
+ "<hexdump> = report read NFC tag with WPS data" },
+ { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
+ "<WPS/NDEF> = build NFC configuration token" },
+ { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
+ "<WPS/NDEF/enable/disable> = manager NFC password token" },
+ { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
+ NULL },
#endif /* CONFIG_WPS_NFC */
- { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
- { "wps_config", hostapd_cli_cmd_wps_config },
- { "wps_get_status", hostapd_cli_cmd_wps_get_status },
+ { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
+ "<cmd> [params..] = enable/disable AP PIN" },
+ { "wps_config", hostapd_cli_cmd_wps_config, NULL,
+ "<SSID> <auth> <encr> <key> = configure AP" },
+ { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
+ "= show current WPS status" },
#endif /* CONFIG_WPS */
- { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
- { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
- { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
- { "get_config", hostapd_cli_cmd_get_config },
- { "help", hostapd_cli_cmd_help },
- { "interface", hostapd_cli_cmd_interface },
+ { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL,
+ "= send Disassociation Imminent notification" },
+ { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL,
+ "= send ESS Dissassociation Imminent notification" },
+ { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL,
+ "= send BSS Transition Management Request" },
+ { "get_config", hostapd_cli_cmd_get_config, NULL,
+ "= show current configuration" },
+ { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
+ "= show this usage help" },
+ { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
+ "[ifname] = show interfaces/select interface" },
#ifdef CONFIG_FST
- { "fst", hostapd_cli_cmd_fst },
+ { "fst", hostapd_cli_cmd_fst, NULL,
+ "<params...> = send FST-MANAGER control interface command" },
#endif /* CONFIG_FST */
- { "level", hostapd_cli_cmd_level },
- { "license", hostapd_cli_cmd_license },
- { "quit", hostapd_cli_cmd_quit },
- { "set", hostapd_cli_cmd_set },
- { "get", hostapd_cli_cmd_get },
- { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
- { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
- { "chan_switch", hostapd_cli_cmd_chan_switch },
- { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
- { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
- { "vendor", hostapd_cli_cmd_vendor },
- { "enable", hostapd_cli_cmd_enable },
- { "reload", hostapd_cli_cmd_reload },
- { "disable", hostapd_cli_cmd_disable },
- { "erp_flush", hostapd_cli_cmd_erp_flush },
- { "log_level", hostapd_cli_cmd_log_level },
- { NULL, NULL }
+ { "raw", hostapd_cli_cmd_raw, NULL,
+ "<params..> = send unprocessed command" },
+ { "level", hostapd_cli_cmd_level, NULL,
+ "<debug level> = change debug level" },
+ { "license", hostapd_cli_cmd_license, NULL,
+ "= show full hostapd_cli license" },
+ { "quit", hostapd_cli_cmd_quit, NULL,
+ "= exit hostapd_cli" },
+ { "set", hostapd_cli_cmd_set, hostapd_complete_set,
+ "<name> <value> = set runtime variables" },
+ { "get", hostapd_cli_cmd_get, hostapd_complete_get,
+ "<name> = get runtime info" },
+ { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL,
+ "<arg,arg,...> = set QoS Map set element" },
+ { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf,
+ hostapd_complete_stations,
+ "<addr> = send QoS Map Configure frame" },
+ { "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
+ "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
+ " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
+ " = initiate channel switch announcement" },
+ { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
+ "<addr> <url>\n"
+ " = send WNM-Notification Subscription Remediation Request" },
+ { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL,
+ "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n"
+ " = send WNM-Notification imminent deauthentication indication" },
+ { "vendor", hostapd_cli_cmd_vendor, NULL,
+ "<vendor id> <sub command id> [<hex formatted data>]\n"
+ " = send vendor driver command" },
+ { "enable", hostapd_cli_cmd_enable, NULL,
+ "= enable hostapd on current interface" },
+ { "reload", hostapd_cli_cmd_reload, NULL,
+ "= reload configuration for current interface" },
+ { "disable", hostapd_cli_cmd_disable, NULL,
+ "= disable hostapd on current interface" },
+ { "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
+ "= drop all ERP keys"},
+ { "log_level", hostapd_cli_cmd_log_level, NULL,
+ "[level] = show/change log verbosity level" },
+ { "pmksa", hostapd_cli_cmd_pmksa, NULL,
+ " = show PMKSA cache entries" },
+ { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL,
+ " = flush PMKSA cache" },
+ { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
+ "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
+ " = add AP to neighbor database" },
+ { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
+ "<addr> <ssid=> = remove AP from neighbor database" },
+ { "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
+ "<addr> = send LCI request to a station"},
+ { "req_range", hostapd_cli_cmd_req_range, NULL,
+ " = send FTM range request"},
+ { "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
+ " = show supported driver flags"},
+#ifdef CONFIG_DPP
+ { "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
+ "report a scanned DPP URI from a QR Code" },
+ { "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL,
+ "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
+ { "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL,
+ "*|<id> = remove DPP bootstrap information" },
+ { "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL,
+ "<id> = get DPP bootstrap URI" },
+ { "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
+ "<id> = show DPP bootstrap information" },
+ { "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
+ "peer=<id> [own=<id>] = initiate DPP bootstrapping" },
+ { "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
+ "<freq in MHz> = start DPP listen" },
+ { "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL,
+ "= stop DPP listen" },
+ { "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL,
+ "[curve=..] [key=..] = add DPP configurator" },
+ { "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
+ NULL,
+ "*|<id> = remove DPP configurator" },
+ { "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key,
+ NULL,
+ "<id> = Get DPP configurator's private key" },
+ { "dpp_configurator_sign", hostapd_cli_cmd_dpp_configurator_sign, NULL,
+ "conf=<role> configurator=<id> = generate self DPP configuration" },
+ { "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
+ "add PKEX code" },
+ { "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
+ "*|<id> = remove DPP pkex information" },
+#endif /* CONFIG_DPP */
+ { "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
+ "=Add/Delete/Show/Clear accept MAC ACL" },
+ { "deny_acl", hostapd_cli_cmd_deny_macacl, NULL,
+ "=Add/Delete/Show/Clear deny MAC ACL" },
+ { "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
+ "<addr> = poll a STA to check connectivity with a QoS null frame" },
+ { "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
+ "<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
+ { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
+ "= reload wpa_psk_file only" },
+ { NULL, NULL, NULL, NULL }
};
+/*
+ * Prints command usage, lines are padded with the specified string.
+ */
+static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
+ const char *pad)
+{
+ char c;
+ size_t n;
+
+ if (cmd->usage == NULL)
+ return;
+ fprintf(stream, "%s%s ", pad, cmd->cmd);
+ for (n = 0; (c = cmd->usage[n]); n++) {
+ fprintf(stream, "%c", c);
+ if (c == '\n')
+ fprintf(stream, "%s", pad);
+ }
+ fprintf(stream, "\n");
+}
+
+
+static void print_help(FILE *stream, const char *cmd)
+{
+ int n;
+
+ fprintf(stream, "commands:\n");
+ for (n = 0; hostapd_cli_commands[n].cmd; n++) {
+ if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
+ print_cmd_help(stream, &hostapd_cli_commands[n], " ");
+ }
+}
+
+
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
const struct hostapd_cli_cmd *cmd, *match = NULL;
@@ -1169,6 +1754,34 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static void cli_event(const char *str)
+{
+ const char *start, *s;
+
+ start = os_strchr(str, '>');
+ if (start == NULL)
+ return;
+
+ start++;
+
+ if (str_starts(start, AP_STA_CONNECTED)) {
+ s = os_strchr(start, ' ');
+ if (s == NULL)
+ return;
+ cli_txt_list_add(&stations, s + 1);
+ return;
+ }
+
+ if (str_starts(start, AP_STA_DISCONNECTED)) {
+ s = os_strchr(start, ' ');
+ if (s == NULL)
+ return;
+ cli_txt_list_del_addr(&stations, s + 1);
+ return;
+ }
+}
+
+
static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
int action_monitor)
{
@@ -1176,13 +1789,14 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
if (ctrl_conn == NULL)
return;
while (wpa_ctrl_pending(ctrl)) {
- char buf[256];
+ char buf[4096];
size_t len = sizeof(buf) - 1;
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
buf[len] = '\0';
if (action_monitor)
hostapd_cli_action_process(buf, len);
else {
+ cli_event(buf);
if (in_read && first)
printf("\n");
first = 0;
@@ -1196,35 +1810,9 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
}
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
- char *pos;
- int argc = 0;
-
- pos = cmd;
- for (;;) {
- while (*pos == ' ')
- pos++;
- if (*pos == '\0')
- break;
- argv[argc] = pos;
- argc++;
- if (argc == max_args)
- break;
- if (*pos == '"') {
- char *pos2 = os_strrchr(pos, '"');
- if (pos2)
- pos = pos2 + 1;
- }
- while (*pos != '\0' && *pos != ' ')
- pos++;
- if (*pos == ' ')
- *pos++ = '\0';
- }
-
- return argc;
+ hostapd_cli_recv_pending(ctrl_conn, 0, 0);
}
@@ -1234,18 +1822,8 @@ static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
printf("Connection to hostapd lost - trying to reconnect\n");
hostapd_cli_close_connection();
}
- if (!ctrl_conn) {
- ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
- if (ctrl_conn) {
- printf("Connection to hostapd re-established\n");
- if (wpa_ctrl_attach(ctrl_conn) == 0) {
- hostapd_cli_attached = 1;
- } else {
- printf("Warning: Failed to attach to "
- "hostapd.\n");
- }
- }
- }
+ if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0)
+ printf("Connection to hostapd re-established\n");
if (ctrl_conn)
hostapd_cli_recv_pending(ctrl_conn, 1, 0);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
@@ -1274,18 +1852,100 @@ static void hostapd_cli_edit_eof_cb(void *ctx)
}
+static char ** list_cmd_list(void)
+{
+ char **res;
+ int i, count;
+
+ count = ARRAY_SIZE(hostapd_cli_commands);
+ res = os_calloc(count + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+
+ for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+ res[i] = os_strdup(hostapd_cli_commands[i].cmd);
+ if (res[i] == NULL)
+ break;
+ }
+
+ return res;
+}
+
+
+static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
+ int pos)
+{
+ int i;
+
+ for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+ if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
+ continue;
+ if (hostapd_cli_commands[i].completion)
+ return hostapd_cli_commands[i].completion(str, pos);
+ if (!hostapd_cli_commands[i].usage)
+ return NULL;
+ edit_clear_line();
+ printf("\r%s\n", hostapd_cli_commands[i].usage);
+ edit_redraw();
+ break;
+ }
+
+ return NULL;
+}
+
+
+static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
+ int pos)
+{
+ char **res;
+ const char *end;
+ char *cmd;
+
+ end = os_strchr(str, ' ');
+ if (end == NULL || str + pos < end)
+ return list_cmd_list();
+
+ cmd = os_malloc(pos + 1);
+ if (cmd == NULL)
+ return NULL;
+ os_memcpy(cmd, str, pos);
+ cmd[end - str] = '\0';
+ res = hostapd_cli_cmd_completion(cmd, str, pos);
+ os_free(cmd);
+ return res;
+}
+
+
static void hostapd_cli_interactive(void)
{
+ char *hfile = NULL;
+ char *home;
+
printf("\nInteractive mode\n\n");
+#ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR
+ home = CONFIG_HOSTAPD_CLI_HISTORY_DIR;
+#else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
+ home = getenv("HOME");
+#endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
+ if (home) {
+ const char *fname = ".hostapd_cli_history";
+ int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
+ hfile = os_malloc(hfile_len);
+ if (hfile)
+ os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
+ }
+
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
- NULL, NULL, NULL, NULL);
+ hostapd_cli_edit_completion_cb, NULL, hfile, NULL);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
eloop_run();
- edit_deinit(NULL, NULL);
+ cli_txt_list_flush(&stations);
+ edit_deinit(hfile, NULL);
+ os_free(hfile);
eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
}
@@ -1388,8 +2048,7 @@ int main(int argc, char *argv[])
interactive = (argc == optind) && (action_file == NULL);
if (interactive) {
- printf("%s\n\n%s\n\n", hostapd_cli_version,
- hostapd_cli_license);
+ printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
}
if (eloop_init())
@@ -1413,7 +2072,7 @@ int main(int argc, char *argv[])
closedir(dir);
}
}
- ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+ hostapd_cli_reconnect(ctrl_ifname);
if (ctrl_conn) {
if (warning_displayed)
printf("Connection established.\n");
@@ -1434,17 +2093,9 @@ int main(int argc, char *argv[])
continue;
}
- if (interactive || action_file) {
- if (wpa_ctrl_attach(ctrl_conn) == 0) {
- hostapd_cli_attached = 1;
- } else {
- printf("Warning: Failed to attach to hostapd.\n");
- if (action_file)
- return -1;
- }
- }
-
- if (daemonize && os_daemonize(pid_file))
+ if (action_file && !hostapd_cli_attached)
+ return -1;
+ if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
return -1;
if (interactive)
@@ -1454,8 +2105,18 @@ int main(int argc, char *argv[])
else
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+ unregister_event_handler(ctrl_conn);
os_free(ctrl_ifname);
eloop_destroy();
hostapd_cli_cleanup();
return 0;
}
+
+#else /* CONFIG_NO_CTRL_IFACE */
+
+int main(int argc, char *argv[])
+{
+ return -1;
+}
+
+#endif /* CONFIG_NO_CTRL_IFACE */
diff --git a/contrib/wpa/hostapd/main.c b/contrib/wpa/hostapd/main.c
index 6c7406a..93d2dd3 100644
--- a/contrib/wpa/hostapd/main.c
+++ b/contrib/wpa/hostapd/main.c
@@ -1,6 +1,6 @@
/*
* hostapd / main()
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,12 +18,14 @@
#include "crypto/random.h"
#include "crypto/tls.h"
#include "common/version.h"
+#include "common/dpp.h"
#include "drivers/driver.h"
#include "eap_server/eap.h"
#include "eap_server/tncs.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
+#include "ap/dpp_hostapd.h"
#include "fst/fst.h"
#include "config_file.h"
#include "eap_register.h"
@@ -108,6 +110,10 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
module_str ? module_str : "",
module_str ? ": " : "", txt);
+#ifdef CONFIG_DEBUG_SYSLOG
+ if (wpa_debug_syslog)
+ conf_stdout = 0;
+#endif /* CONFIG_DEBUG_SYSLOG */
if ((conf_stdout & module) && level >= conf_stdout_level) {
wpa_debug_print_timestamp();
wpa_printf(MSG_INFO, "%s", format);
@@ -171,7 +177,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
if (global.drv_priv[i] == NULL &&
wpa_drivers[i]->global_init) {
- global.drv_priv[i] = wpa_drivers[i]->global_init();
+ global.drv_priv[i] =
+ wpa_drivers[i]->global_init(iface->interfaces);
if (global.drv_priv[i] == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize "
"driver '%s'",
@@ -216,11 +223,20 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
iface->drv_flags = capa.flags;
iface->smps_modes = capa.smps_modes;
iface->probe_resp_offloads = capa.probe_resp_offloads;
+ /*
+ * Use default extended capa values from per-radio information
+ */
iface->extended_capa = capa.extended_capa;
iface->extended_capa_mask = capa.extended_capa_mask;
iface->extended_capa_len = capa.extended_capa_len;
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
+ /*
+ * Override extended capa with per-interface type (AP), if
+ * available from the driver.
+ */
+ hostapd_get_ext_capa(iface);
+
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
if (triggs && hapd->driver->set_wowlan) {
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
@@ -238,10 +254,10 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
*
* This function is used to parse configuration file for a full interface (one
* or more BSSes sharing the same radio) and allocate memory for the BSS
- * interfaces. No actiual driver operations are started.
+ * interfaces. No actual driver operations are started.
*/
static struct hostapd_iface *
-hostapd_interface_init(struct hapd_interfaces *interfaces,
+hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
const char *config_fname, int debug)
{
struct hostapd_iface *iface;
@@ -251,6 +267,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
+
+ if (if_name) {
+ os_strlcpy(iface->conf->bss[0]->iface, if_name,
+ sizeof(iface->conf->bss[0]->iface));
+ }
+
iface->interfaces = interfaces;
for (k = 0; k < debug; k++) {
@@ -260,7 +282,8 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
if (iface->conf->bss[0]->iface[0] == '\0' &&
!hostapd_drv_none(iface->bss[0])) {
- wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+ wpa_printf(MSG_ERROR,
+ "Interface name not specified in %s, nor by '-i' parameter",
config_fname);
hostapd_interface_deinit_free(iface);
return NULL;
@@ -329,6 +352,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
return -1;
}
+ interfaces->eloop_initialized = 1;
random_init(entropy_file);
@@ -356,7 +380,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
}
-static void hostapd_global_deinit(const char *pid_file)
+static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
{
int i;
@@ -374,7 +398,8 @@ static void hostapd_global_deinit(const char *pid_file)
random_deinit();
- eloop_destroy();
+ if (eloop_initialized)
+ eloop_destroy();
#ifndef CONFIG_NATIVE_WINDOWS
closelog();
@@ -408,9 +433,16 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
}
#endif /* EAP_SERVER_TNC */
- if (daemonize && os_daemonize(pid_file)) {
- wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
- return -1;
+ if (daemonize) {
+ if (os_daemonize(pid_file)) {
+ wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
+ return -1;
+ }
+ if (eloop_sock_requeue()) {
+ wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s",
+ strerror(errno));
+ return -1;
+ }
}
eloop_run();
@@ -425,7 +457,7 @@ static void show_version(void)
"hostapd v" VERSION_STR "\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
- "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -437,7 +469,8 @@ static void usage(void)
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
"\\\n"
- " [-g <global ctrl_iface>] [-G <group>] \\\n"
+ " [-g <global ctrl_iface>] [-G <group>]\\\n"
+ " [-i <comma-separated list of interface names>]\\\n"
" <configuration file(s)>\n"
"\n"
"options:\n"
@@ -453,9 +486,14 @@ static void usage(void)
" -f log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
#ifdef CONFIG_DEBUG_LINUX_TRACING
- " -T = record to Linux tracing in addition to logging\n"
+ " -T record to Linux tracing in addition to logging\n"
" (records all messages regardless of debug verbosity)\n"
#endif /* CONFIG_DEBUG_LINUX_TRACING */
+ " -i list of interface names to use\n"
+#ifdef CONFIG_DEBUG_SYSLOG
+ " -s log output to syslog instead of stdout\n"
+#endif /* CONFIG_DEBUG_SYSLOG */
+ " -S start all the interfaces synchronously\n"
" -t include timestamps in some debug messages\n"
" -v show hostapd version\n");
@@ -466,9 +504,8 @@ static void usage(void)
static const char * hostapd_msg_ifname_cb(void *ctx)
{
struct hostapd_data *hapd = ctx;
- if (hapd && hapd->iconf && hapd->iconf->bss &&
- hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
- return hapd->iconf->bss[0]->iface;
+ if (hapd && hapd->conf)
+ return hapd->conf->iface;
return NULL;
}
@@ -476,11 +513,16 @@ static const char * hostapd_msg_ifname_cb(void *ctx)
static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
const char *path)
{
+#ifndef CONFIG_CTRL_IFACE_UDP
char *pos;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = os_strdup(path);
if (interfaces->global_iface_path == NULL)
return -1;
+
+#ifndef CONFIG_CTRL_IFACE_UDP
pos = os_strrchr(interfaces->global_iface_path, '/');
if (pos == NULL) {
wpa_printf(MSG_ERROR, "No '/' in the global control interface "
@@ -492,6 +534,7 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
*pos = '\0';
interfaces->global_iface_name = pos + 1;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
return 0;
}
@@ -513,6 +556,43 @@ static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
}
+static int hostapd_get_interface_names(char ***if_names,
+ size_t *if_names_size,
+ char *arg)
+{
+ char *if_name, *tmp, **nnames;
+ size_t i;
+
+ if (!arg)
+ return -1;
+ if_name = strtok_r(arg, ",", &tmp);
+
+ while (if_name) {
+ nnames = os_realloc_array(*if_names, 1 + *if_names_size,
+ sizeof(char *));
+ if (!nnames)
+ goto fail;
+ *if_names = nnames;
+
+ (*if_names)[*if_names_size] = os_strdup(if_name);
+ if (!(*if_names)[*if_names_size])
+ goto fail;
+ (*if_names_size)++;
+ if_name = strtok_r(NULL, ",", &tmp);
+ }
+
+ return 0;
+
+fail:
+ for (i = 0; i < *if_names_size; i++)
+ os_free((*if_names)[i]);
+ os_free(*if_names);
+ *if_names = NULL;
+ *if_names_size = 0;
+ return -1;
+}
+
+
#ifdef CONFIG_WPS
static int gen_uuid(const char *txt_addr)
{
@@ -570,6 +650,9 @@ int main(int argc, char *argv[])
#ifdef CONFIG_DEBUG_LINUX_TRACING
int enable_trace_dbg = 0;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
+ int start_ifaces_in_sync = 0;
+ char **if_names = NULL;
+ size_t if_names_size = 0;
if (os_program_init())
return -1;
@@ -584,10 +667,18 @@ int main(int argc, char *argv[])
interfaces.global_iface_path = NULL;
interfaces.global_iface_name = NULL;
interfaces.global_ctrl_sock = -1;
- interfaces.global_ctrl_dst = NULL;
+ dl_list_init(&interfaces.global_ctrl_dst);
+#ifdef CONFIG_ETH_P_OUI
+ dl_list_init(&interfaces.eth_p_oui);
+#endif /* CONFIG_ETH_P_OUI */
+#ifdef CONFIG_DPP
+ interfaces.dpp = dpp_global_init();
+ if (!interfaces.dpp)
+ return -1;
+#endif /* CONFIG_DPP */
for (;;) {
- c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
+ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
if (c < 0)
break;
switch (c) {
@@ -644,10 +735,23 @@ int main(int argc, char *argv[])
bss_config = tmp_bss;
bss_config[num_bss_configs++] = optarg;
break;
+#ifdef CONFIG_DEBUG_SYSLOG
+ case 's':
+ wpa_debug_syslog = 1;
+ break;
+#endif /* CONFIG_DEBUG_SYSLOG */
+ case 'S':
+ start_ifaces_in_sync = 1;
+ break;
#ifdef CONFIG_WPS
case 'u':
return gen_uuid(optarg);
#endif /* CONFIG_WPS */
+ case 'i':
+ if (hostapd_get_interface_names(&if_names,
+ &if_names_size, optarg))
+ goto out;
+ break;
default:
usage();
break;
@@ -664,6 +768,10 @@ int main(int argc, char *argv[])
wpa_debug_open_file(log_file);
else
wpa_debug_setup_stdout();
+#ifdef CONFIG_DEBUG_SYSLOG
+ if (wpa_debug_syslog)
+ wpa_debug_open_syslog();
+#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (enable_trace_dbg) {
int tret = wpa_debug_open_linux_tracing();
@@ -705,13 +813,21 @@ int main(int argc, char *argv[])
/* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
+ char *if_name = NULL;
+
+ if (i < if_names_size)
+ if_name = if_names[i];
+
interfaces.iface[i] = hostapd_interface_init(&interfaces,
+ if_name,
argv[optind + i],
debug);
if (!interfaces.iface[i]) {
wpa_printf(MSG_ERROR, "Failed to initialize interface");
goto out;
}
+ if (start_ifaces_in_sync)
+ interfaces.iface[i]->need_to_start_in_sync = 1;
}
/* Allocate and parse configuration for per-BSS files */
@@ -787,16 +903,26 @@ int main(int argc, char *argv[])
}
os_free(interfaces.iface);
- eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
- hostapd_global_deinit(pid_file);
+#ifdef CONFIG_DPP
+ dpp_global_deinit(interfaces.dpp);
+#endif /* CONFIG_DPP */
+
+ if (interfaces.eloop_initialized)
+ eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
+ hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
os_free(pid_file);
+ wpa_debug_close_syslog();
if (log_file)
wpa_debug_close_file();
wpa_debug_close_linux_tracing();
os_free(bss_config);
+ for (i = 0; i < if_names_size; i++)
+ os_free(if_names[i]);
+ os_free(if_names);
+
fst_global_deinit();
os_program_deinit();
diff --git a/contrib/wpa/hostapd/wps-ap-nfc.py b/contrib/wpa/hostapd/wps-ap-nfc.py
index 2fc3012..258d841 100755
--- a/contrib/wpa/hostapd/wps-ap-nfc.py
+++ b/contrib/wpa/hostapd/wps-ap-nfc.py
@@ -26,7 +26,7 @@ summary_file = None
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -42,19 +42,19 @@ def wpas_connect():
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find hostapd: ", error
+ except OSError as error:
+ print("Could not find hostapd: ", error)
return None
if len(ifaces) < 1:
- print "No hostapd control interface found"
+ print("No hostapd control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -133,23 +133,23 @@ class HandoverServer(nfc.handover.HandoverServer):
def process_request(self, request):
summary("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
- print str(request).encode("hex")
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
+ print(str(request).encode("hex"))
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
summary("WPS carrier type match - add WPS carrier record")
data = wpas_get_handover_sel()
if data is None:
summary("Could not get handover select carrier record from hostapd")
continue
- print "Handover select carrier record from hostapd:"
- print data.encode("hex")
+ print("Handover select carrier record from hostapd:")
+ print(data.encode("hex"))
if "OK" in wpas_report_handover(carrier.record, data):
success_report("Handover reported successfully")
else:
@@ -158,12 +158,12 @@ class HandoverServer(nfc.handover.HandoverServer):
message = nfc.ndef.Message(data);
sel.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -174,7 +174,7 @@ def wps_tag_read(tag):
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to hostapd")
success = wpas_tag_read(tag.ndef.message)
@@ -193,7 +193,7 @@ def rdwr_connected_write(tag):
global write_data
tag.ndef.message = str(write_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -211,7 +211,7 @@ def wps_write_config_tag(clf, wait_remove=True):
summary("Could not get WPS config token from hostapd")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -224,7 +224,7 @@ def wps_write_password_tag(clf, wait_remove=True):
summary("Could not get WPS password token from hostapd")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -233,11 +233,11 @@ def rdwr_connected(tag):
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = wps_tag_read(tag)
if only_one and success:
global continue_loop
@@ -250,13 +250,13 @@ def rdwr_connected(tag):
def llcp_startup(clf, llc):
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global srv
@@ -304,7 +304,7 @@ def main():
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-config":
@@ -317,15 +317,15 @@ def main():
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if not clf.connect(rdwr={'on-connect': rdwr_connected},
llcp={'on-startup': llcp_startup,
'on-connect': llcp_connected}):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/contrib/wpa/hs20/client/Android.mk b/contrib/wpa/hs20/client/Android.mk
index b23ac17..e4db322 100644
--- a/contrib/wpa/hs20/client/Android.mk
+++ b/contrib/wpa/hs20/client/Android.mk
@@ -4,7 +4,6 @@ INCLUDES = $(LOCAL_PATH)
INCLUDES += $(LOCAL_PATH)/../../src/utils
INCLUDES += $(LOCAL_PATH)/../../src/common
INCLUDES += $(LOCAL_PATH)/../../src
-INCLUDES += external/openssl/include
INCLUDES += external/libxml2/include
INCLUDES += external/curl/include
INCLUDES += external/webkit/Source/WebKit/gtk
@@ -55,6 +54,7 @@ OBJS += ../../src/crypto/crypto_internal.c
OBJS += ../../src/crypto/md5-internal.c
OBJS += ../../src/crypto/sha1-internal.c
OBJS += ../../src/crypto/sha256-internal.c
+OBJS += ../../src/crypto/tls_openssl_ocsp.c
L_CFLAGS += -DEAP_TLS_OPENSSL
diff --git a/contrib/wpa/hs20/client/Makefile b/contrib/wpa/hs20/client/Makefile
index 94cd5f1..67f6f55 100644
--- a/contrib/wpa/hs20/client/Makefile
+++ b/contrib/wpa/hs20/client/Makefile
@@ -8,12 +8,17 @@ ifndef LDO
LDO=$(CC)
endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+else
Q=@
E=echo
ifeq ($(V), 1)
Q=
E=true
endif
+endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
@@ -76,6 +81,7 @@ LIBS += -lcurl
endif
CFLAGS += -DEAP_TLS_OPENSSL
+OBJS += ../../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl -lcrypto
hs20-osu-client: $(OBJS)
diff --git a/contrib/wpa/hs20/client/est.c b/contrib/wpa/hs20/client/est.c
index ec05bc4..db65334 100644
--- a/contrib/wpa/hs20/client/est.c
+++ b/contrib/wpa/hs20/client/est.c
@@ -16,6 +16,10 @@
#include <openssl/asn1t.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include <openssl/opensslv.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/buf.h>
+#endif /* OPENSSL_IS_BORINGSSL */
#include "common.h"
#include "utils/base64.h"
@@ -27,12 +31,28 @@
static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
size_t len, char *pem_file, char *der_file)
{
+#ifdef OPENSSL_IS_BORINGSSL
+ CBS pkcs7_cbs;
+#else /* OPENSSL_IS_BORINGSSL */
PKCS7 *p7 = NULL;
const unsigned char *p = pkcs7;
+#endif /* OPENSSL_IS_BORINGSSL */
STACK_OF(X509) *certs;
int i, num, ret = -1;
BIO *out = NULL;
+#ifdef OPENSSL_IS_BORINGSSL
+ certs = sk_X509_new_null();
+ if (!certs)
+ goto fail;
+ CBS_init(&pkcs7_cbs, pkcs7, len);
+ if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
+ wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ write_result(ctx, "Could not parse PKCS#7 object from EST");
+ goto fail;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
p7 = d2i_PKCS7(NULL, &p, len);
if (p7 == NULL) {
wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
@@ -52,6 +72,7 @@ static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
certs = NULL;
break;
}
+#endif /* OPENSSL_IS_BORINGSSL */
if (!certs || ((num = sk_X509_num(certs)) == 0)) {
wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
@@ -84,7 +105,12 @@ static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
ret = 0;
fail:
+#ifdef OPENSSL_IS_BORINGSSL
+ if (certs)
+ sk_X509_pop_free(certs, X509_free);
+#else /* OPENSSL_IS_BORINGSSL */
PKCS7_free(p7);
+#endif /* OPENSSL_IS_BORINGSSL */
if (out)
BIO_free_all(out);
@@ -194,6 +220,10 @@ typedef struct {
} d;
} AttrOrOID;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+DEFINE_STACK_OF(AttrOrOID)
+#endif
+
typedef struct {
int type;
STACK_OF(AttrOrOID) *attrs;
@@ -310,9 +340,34 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
if (!csrattrs || ! csrattrs->attrs)
return;
+#ifdef OPENSSL_IS_BORINGSSL
+ num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *,
+ csrattrs->attrs));
+ for (i = 0; i < num; i++) {
+ AttrOrOID *ao = sk_value(
+ CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *,
+ csrattrs->attrs), i);
+ switch (ao->type) {
+ case 0:
+ add_csrattrs_oid(ctx, ao->d.oid, exts);
+ break;
+ case 1:
+ add_csrattrs_attr(ctx, ao->d.attribute, exts);
+ break;
+ }
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+ num = sk_AttrOrOID_num(csrattrs->attrs);
+#else
num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
+#endif
for (i = 0; i < num; i++) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+ AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i);
+#else
AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
+#endif
switch (ao->type) {
case 0:
add_csrattrs_oid(ctx, ao->d.oid, exts);
@@ -322,6 +377,7 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
break;
}
}
+#endif /* OPENSSL_IS_BORINGSSL */
}
@@ -340,6 +396,7 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
STACK_OF(X509_EXTENSION) *exts = NULL;
X509_EXTENSION *ex;
BIO *out;
+ CONF *ctmp = NULL;
wpa_printf(MSG_INFO, "Generate RSA private key");
write_summary(ctx, "Generate RSA private key");
@@ -421,20 +478,20 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
if (!exts)
goto fail;
- ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
- "CA:FALSE");
+ ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_basic_constraints,
+ "CA:FALSE");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
- ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
- "nonRepudiation,digitalSignature,keyEncipherment");
+ ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_key_usage,
+ "nonRepudiation,digitalSignature,keyEncipherment");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
- ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage,
- "1.3.6.1.4.1.40808.1.1.2");
+ ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_ext_key_usage,
+ "1.3.6.1.4.1.40808.1.1.2");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
@@ -454,7 +511,9 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
char *txt;
size_t rlen;
+#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
X509_REQ_print(out, req);
+#endif
rlen = BIO_ctrl_pending(out);
txt = os_malloc(rlen + 1);
if (txt) {
@@ -473,7 +532,9 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
FILE *f = fopen(csr_pem, "w");
if (f == NULL)
goto fail;
+#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
X509_REQ_print_fp(f, req);
+#endif
if (!PEM_write_X509_REQ(f, req)) {
fclose(f);
goto fail;
@@ -618,7 +679,6 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
char *buf, *resp, *req, *req2;
size_t buflen, resp_len, len, pkcs7_len;
unsigned char *pkcs7;
- FILE *f;
char client_cert_buf[200];
char client_key_buf[200];
const char *client_cert = NULL, *client_key = NULL;
@@ -673,11 +733,6 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
return -1;
}
wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
- f = fopen("Cert/est-resp.raw", "w");
- if (f) {
- fwrite(resp, resp_len, 1, f);
- fclose(f);
- }
pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
if (pkcs7 == NULL) {
diff --git a/contrib/wpa/hs20/client/oma_dm_client.c b/contrib/wpa/hs20/client/oma_dm_client.c
index 5854b72..d75c845 100644
--- a/contrib/wpa/hs20/client/oma_dm_client.c
+++ b/contrib/wpa/hs20/client/oma_dm_client.c
@@ -111,6 +111,12 @@ static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
xml_node_t *syncml, *synchdr;
xml_namespace_t *ns;
+ if (!ctx->devid) {
+ wpa_printf(MSG_ERROR,
+ "DevId from devinfo.xml is not available - cannot use OMA DM");
+ return NULL;
+ }
+
syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
"SyncML");
diff --git a/contrib/wpa/hs20/client/osu_client.c b/contrib/wpa/hs20/client/osu_client.c
index 0315f7b..1f594ce 100644
--- a/contrib/wpa/hs20/client/osu_client.c
+++ b/contrib/wpa/hs20/client/osu_client.c
@@ -105,6 +105,35 @@ static int valid_fqdn(const char *fqdn)
}
+static int android_update_permission(const char *path, mode_t mode)
+{
+#ifdef ANDROID
+ /* we need to change file/folder permission for Android */
+
+ if (!path) {
+ wpa_printf(MSG_ERROR, "file path null");
+ return -1;
+ }
+
+ /* Allow processes running with Group ID as AID_WIFI,
+ * to read files from SP, SP/<fqdn>, Cert and osu-info directories */
+ if (lchown(path, -1, AID_WIFI)) {
+ wpa_printf(MSG_INFO, "CTRL: Could not lchown directory: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (chmod(path, mode) < 0) {
+ wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
+ strerror(errno));
+ return -1;
+ }
+#endif /* ANDROID */
+
+ return 0;
+}
+
+
int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
{
xml_node_t *node;
@@ -169,6 +198,8 @@ int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
}
mkdir("Cert", S_IRWXU);
+ android_update_permission("Cert", S_IRWXU | S_IRWXG);
+
if (est_load_cacerts(ctx, url) < 0 ||
est_build_csr(ctx, url) < 0 ||
est_simple_enroll(ctx, url, user, pw) < 0)
@@ -262,7 +293,6 @@ static int process_est_cert(struct hs20_osu_client *ctx, xml_node_t *cert,
unlink("Cert/est-req.b64");
unlink("Cert/est-req.pem");
- unlink("Cert/est-resp.raw");
rmdir("Cert");
return 0;
@@ -406,7 +436,7 @@ static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname,
if (node == NULL) {
wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
xml_node_free(ctx->xml, pps);
- return -1;
+ return -2;
}
ret = download_cert(ctx, node, ca_fname);
@@ -433,7 +463,7 @@ static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname,
if (node == NULL) {
wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS");
xml_node_free(ctx->xml, pps);
- return -1;
+ return -2;
}
aaa = xml_node_first_child(ctx->xml, node);
@@ -455,7 +485,7 @@ static int download_trust_roots(struct hs20_osu_client *ctx,
{
char *dir, *pos;
char fname[300];
- int ret;
+ int ret, ret1;
dir = os_strdup(pps_fname);
if (dir == NULL)
@@ -470,9 +500,13 @@ static int download_trust_roots(struct hs20_osu_client *ctx,
snprintf(fname, sizeof(fname), "%s/ca.pem", dir);
ret = cmd_dl_osu_ca(ctx, pps_fname, fname);
snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir);
- cmd_dl_polupd_ca(ctx, pps_fname, fname);
+ ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname);
+ if (ret == 0 && ret1 == -1)
+ ret = -1;
snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir);
- cmd_dl_aaa_ca(ctx, pps_fname, fname);
+ ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname);
+ if (ret == 0 && ret1 == -1)
+ ret = -1;
os_free(dir);
@@ -578,20 +612,8 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
}
}
-#ifdef ANDROID
- /* Allow processes running with Group ID as AID_WIFI,
- * to read files from SP/<fqdn> directory */
- if (chown(fname, -1, AID_WIFI)) {
- wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
- strerror(errno));
- /* Try to continue anyway */
- }
- if (chmod(fname, S_IRWXU | S_IRGRP | S_IXGRP) < 0) {
- wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
- strerror(errno));
- /* Try to continue anyway */
- }
-#endif /* ANDROID */
+ android_update_permission("SP", S_IRWXU | S_IRWXG);
+ android_update_permission(fname, S_IRWXU | S_IRWXG);
snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
@@ -1213,8 +1235,7 @@ static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id,
homeoi) < 0)
wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium");
} else {
- if (set_cred_quoted(ctx->ifname, id, "roaming_consortium",
- homeoi) < 0)
+ if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0)
wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium");
}
@@ -1289,7 +1310,9 @@ static void set_pps_cred_home_sp_roaming_consortium_oi(
if (str == NULL)
return;
wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str);
- /* TODO: Set to wpa_supplicant */
+ if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums",
+ str) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred roaming_consortiums");
xml_node_get_text_free(ctx->xml, str);
}
@@ -1442,10 +1465,92 @@ static void set_pps_cred_able_to_share(struct hs20_osu_client *ctx, int id,
}
+static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ int type;
+ const char *eap_method = NULL;
+
+ if (!str)
+ return;
+ wpa_printf(MSG_INFO,
+ "- Credential/UsernamePassword/EAPMethod/EAPType = %s", str);
+ type = atoi(str);
+ switch (type) {
+ case EAP_TYPE_TLS:
+ eap_method = "TLS";
+ break;
+ case EAP_TYPE_TTLS:
+ eap_method = "TTLS";
+ break;
+ case EAP_TYPE_PEAP:
+ eap_method = "PEAP";
+ break;
+ case EAP_TYPE_PWD:
+ eap_method = "PWD";
+ break;
+ }
+ xml_node_get_text_free(ctx->xml, str);
+ if (!eap_method) {
+ wpa_printf(MSG_INFO, "Unknown EAPType value");
+ return;
+ }
+
+ if (set_cred(ctx->ifname, id, "eap", eap_method) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred eap");
+}
+
+
+static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ const char *phase2 = NULL;
+
+ if (!str)
+ return;
+ wpa_printf(MSG_INFO,
+ "- Credential/UsernamePassword/EAPMethod/InnerMethod = %s",
+ str);
+ if (os_strcmp(str, "PAP") == 0)
+ phase2 = "auth=PAP";
+ else if (os_strcmp(str, "CHAP") == 0)
+ phase2 = "auth=CHAP";
+ else if (os_strcmp(str, "MS-CHAP") == 0)
+ phase2 = "auth=MSCHAP";
+ else if (os_strcmp(str, "MS-CHAP-V2") == 0)
+ phase2 = "auth=MSCHAPV2";
+ xml_node_get_text_free(ctx->xml, str);
+ if (!phase2) {
+ wpa_printf(MSG_INFO, "Unknown InnerMethod value");
+ return;
+ }
+
+ if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred phase2");
+}
+
+
static void set_pps_cred_eap_method(struct hs20_osu_client *ctx, int id,
xml_node_t *node)
{
- wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod - TODO");
+ xml_node_t *child;
+ const char *name;
+
+ wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod");
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ if (os_strcasecmp(name, "EAPType") == 0)
+ set_pps_cred_eap_method_eap_type(ctx, id, child);
+ else if (os_strcasecmp(name, "InnerMethod") == 0)
+ set_pps_cred_eap_method_inner_method(ctx, id, child);
+ else
+ wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'",
+ name);
+ }
}
@@ -1884,7 +1989,9 @@ struct osu_data {
char url[256];
unsigned int methods;
char osu_ssid[33];
+ char osu_ssid2[33];
char osu_nai[256];
+ char osu_nai2[256];
struct osu_lang_text friendly_name[MAX_OSU_VALS];
size_t friendly_name_count;
struct osu_lang_text serv_desc[MAX_OSU_VALS];
@@ -1943,12 +2050,24 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
continue;
}
+ if (strncmp(buf, "osu_ssid2=", 10) == 0) {
+ snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
+ "%s", buf + 10);
+ continue;
+ }
+
if (os_strncmp(buf, "osu_nai=", 8) == 0) {
os_snprintf(last->osu_nai, sizeof(last->osu_nai),
"%s", buf + 8);
continue;
}
+ if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
+ os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
+ "%s", buf + 9);
+ continue;
+ }
+
if (strncmp(buf, "friendly_name=", 14) == 0) {
struct osu_lang_text *txt;
if (last->friendly_name_count == MAX_OSU_VALS)
@@ -2024,9 +2143,9 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
- const char *ssid, const char *url,
+ const char *ssid, const char *ssid2, const char *url,
unsigned int methods, int no_prod_assoc,
- const char *osu_nai)
+ const char *osu_nai, const char *osu_nai2)
{
int id;
const char *ifname = ctx->ifname;
@@ -2034,26 +2153,54 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
struct wpa_ctrl *mon;
int res;
+ if (ssid2 && ssid2[0] == '\0')
+ ssid2 = NULL;
+
+ if (ctx->osu_ssid) {
+ if (os_strcmp(ssid, ctx->osu_ssid) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Enforced OSU SSID matches ANQP info");
+ ssid2 = NULL;
+ } else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Enforced OSU SSID matches RSN[OSEN] info");
+ ssid = ssid2;
+ } else {
+ wpa_printf(MSG_INFO, "Enforced OSU SSID did not match");
+ write_summary(ctx, "Enforced OSU SSID did not match");
+ return -1;
+ }
+ }
+
id = add_network(ifname);
if (id < 0)
return -1;
if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
return -1;
+ if (ssid2)
+ osu_nai = osu_nai2;
if (osu_nai && os_strlen(osu_nai) > 0) {
char dir[255], fname[300];
if (getcwd(dir, sizeof(dir)) == NULL)
return -1;
os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir);
+ if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0)
+ return -1;
+
if (set_network(ifname, id, "proto", "OSEN") < 0 ||
set_network(ifname, id, "key_mgmt", "OSEN") < 0 ||
set_network(ifname, id, "pairwise", "CCMP") < 0 ||
- set_network(ifname, id, "group", "GTK_NOT_USED") < 0 ||
+ set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 ||
set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 ||
set_network(ifname, id, "ocsp", "2") < 0 ||
set_network_quoted(ifname, id, "identity", osu_nai) < 0 ||
set_network_quoted(ifname, id, "ca_cert", fname) < 0)
return -1;
+ } else if (ssid2) {
+ wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]");
+ write_summary(ctx, "No OSU_NAI set for RSN[OSEN]");
+ return -1;
} else {
if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
return -1;
@@ -2134,7 +2281,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
char fname[255];
FILE *f;
struct osu_data *osu = NULL, *last = NULL;
- size_t osu_count, i, j;
+ size_t osu_count = 0, i, j;
int ret;
write_summary(ctx, "OSU provider selection");
@@ -2229,8 +2376,12 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
"SSID: %s<br>\n",
last->bssid, last->osu_ssid);
- if (last->osu_nai)
+ if (last->osu_ssid2[0])
+ fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2);
+ if (last->osu_nai[0])
fprintf(f, "NAI: %s<br>\n", last->osu_nai);
+ if (last->osu_nai2[0])
+ fprintf(f, "NAI2: %s<br>\n", last->osu_nai2);
fprintf(f, "URL: %s<br>\n"
"methods:%s%s<br>\n"
"</small></p>\n",
@@ -2257,6 +2408,8 @@ selected:
ret = 0;
wpa_printf(MSG_INFO, "BSSID: %s", last->bssid);
wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid);
+ if (last->osu_ssid2[0])
+ wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2);
wpa_printf(MSG_INFO, "URL: %s", last->url);
write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s",
ret, last->bssid, last->osu_ssid, last->url);
@@ -2311,10 +2464,13 @@ selected:
"No supported OSU provisioning method");
ret = -1;
}
- } else if (connect)
+ } else if (connect) {
ret = osu_connect(ctx, last->bssid, last->osu_ssid,
+ last->osu_ssid2,
last->url, last->methods,
- no_prod_assoc, last->osu_nai);
+ no_prod_assoc, last->osu_nai,
+ last->osu_nai2);
+ }
} else
ret = -1;
@@ -2339,12 +2495,15 @@ static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
return -1;
snprintf(fname, sizeof(fname), "%s/osu-info", dir);
- if (mkdir(fname, S_IRWXU | S_IRWXG) < 0 && errno != EEXIST) {
+ if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 &&
+ errno != EEXIST) {
wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
fname, strerror(errno));
return -1;
}
+ android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+
snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
if (wpa_command(ifname, buf) < 0) {
wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant");
@@ -2559,7 +2718,7 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
if (!pps_fname) {
char buf[256];
wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
- if (os_strncmp(address, "fqdn=", 5) == 0) {
+ if (address && os_strncmp(address, "fqdn=", 5) == 0) {
wpa_printf(MSG_INFO, "Use requested FQDN from command line");
os_snprintf(buf, sizeof(buf), "%s", address + 5);
address = NULL;
@@ -2909,24 +3068,17 @@ static int init_ctx(struct hs20_osu_client *ctx)
return -1;
devinfo = node_from_file(ctx->xml, "devinfo.xml");
- if (!devinfo) {
- wpa_printf(MSG_ERROR, "devinfo.xml not found");
- return -1;
- }
-
- devid = get_node(ctx->xml, devinfo, "DevId");
- if (devid) {
- char *tmp = xml_node_get_text(ctx->xml, devid);
- if (tmp) {
- ctx->devid = os_strdup(tmp);
- xml_node_get_text_free(ctx->xml, tmp);
+ if (devinfo) {
+ devid = get_node(ctx->xml, devinfo, "DevId");
+ if (devid) {
+ char *tmp = xml_node_get_text(ctx->xml, devid);
+
+ if (tmp) {
+ ctx->devid = os_strdup(tmp);
+ xml_node_get_text_free(ctx->xml, tmp);
+ }
}
- }
- xml_node_free(ctx->xml, devinfo);
-
- if (ctx->devid == NULL) {
- wpa_printf(MSG_ERROR, "Could not fetch DevId from devinfo.xml");
- return -1;
+ xml_node_free(ctx->xml, devinfo);
}
ctx->http = http_init_ctx(ctx, ctx->xml);
@@ -3029,7 +3181,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
- c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
+ c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
if (c < 0)
break;
switch (c) {
@@ -3046,6 +3198,9 @@ int main(int argc, char *argv[])
case 'N':
no_prod_assoc = 1;
break;
+ case 'o':
+ ctx.osu_ssid = optarg;
+ break;
case 'O':
friendly_name = optarg;
break;
@@ -3122,20 +3277,12 @@ int main(int argc, char *argv[])
usage();
exit(0);
}
- if (argc - optind < 2)
- wpa_printf(MSG_ERROR, "Server URL missing from command line");
- else
- ret = cmd_sub_rem(&ctx, argv[optind + 1],
- argc > optind + 2 ?
- argv[optind + 2] : NULL,
- argc > optind + 3 ?
- argv[optind + 3] : NULL);
+ ret = cmd_sub_rem(&ctx, argv[optind + 1],
+ argc > optind + 2 ? argv[optind + 2] : NULL,
+ argc > optind + 3 ? argv[optind + 3] : NULL);
} else if (strcmp(argv[optind], "pol_upd") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ret = cmd_pol_upd(&ctx, argc > 2 ? argv[optind + 1] : NULL,
+ ret = cmd_pol_upd(&ctx,
+ argc > optind + 1 ? argv[optind + 1] : NULL,
argc > optind + 2 ? argv[optind + 2] : NULL,
argc > optind + 3 ? argv[optind + 3] : NULL);
} else if (strcmp(argv[optind], "prov") == 0) {
diff --git a/contrib/wpa/hs20/client/osu_client.h b/contrib/wpa/hs20/client/osu_client.h
index 9a7059e..5c8e6d0 100644
--- a/contrib/wpa/hs20/client/osu_client.h
+++ b/contrib/wpa/hs20/client/osu_client.h
@@ -47,6 +47,7 @@ struct hs20_osu_client {
int client_cert_present;
char **server_dnsname;
size_t server_dnsname_count;
+ const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds;
};
diff --git a/contrib/wpa/patches/openssl-0.9.8za-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8za-tls-extensions.patch
deleted file mode 100644
index 82bfe23..0000000
--- a/contrib/wpa/patches/openssl-0.9.8za-tls-extensions.patch
+++ /dev/null
@@ -1,397 +0,0 @@
-This patch adds support for TLS SessionTicket extension (RFC 5077) for
-the parts used by EAP-FAST (RFC 4851).
-
-This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8za does not enable TLS extension support by default, so it
-will need to be enabled by adding enable-tlsext to config script
-command line.
-
-
-diff -upr openssl-0.9.8za.orig/ssl/s3_clnt.c openssl-0.9.8za/ssl/s3_clnt.c
---- openssl-0.9.8za.orig/ssl/s3_clnt.c 2014-06-05 11:09:26.000000000 +0300
-+++ openssl-0.9.8za/ssl/s3_clnt.c 2014-06-05 20:37:09.221387312 +0300
-@@ -767,6 +767,22 @@ int ssl3_get_server_hello(SSL *s)
- goto f_err;
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->session->cipher=pref_cipher ?
-+ pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
-+ }
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- if (j != 0 && j == s->session->session_id_length
- && memcmp(p,s->session->session_id,j) == 0)
- {
-@@ -2745,11 +2760,8 @@ int ssl3_check_finished(SSL *s)
- {
- int ok;
- long n;
-- /* If we have no ticket or session ID is non-zero length (a match of
-- * a non-zero session length would never reach here) it cannot be a
-- * resumed session.
-- */
-- if (!s->session->tlsext_tick || s->session->session_id_length)
-+ /* If we have no ticket it cannot be a resumed session. */
-+ if (!s->session->tlsext_tick)
- return 1;
- /* this function is called when we really expect a Certificate
- * message, so permit appropriate message length */
-diff -upr openssl-0.9.8za.orig/ssl/s3_srvr.c openssl-0.9.8za/ssl/s3_srvr.c
---- openssl-0.9.8za.orig/ssl/s3_srvr.c 2014-06-05 11:09:26.000000000 +0300
-+++ openssl-0.9.8za/ssl/s3_srvr.c 2014-06-05 20:37:09.225387312 +0300
-@@ -1011,6 +1011,59 @@ int ssl3_get_client_hello(SSL *s)
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
-+
-+ /* Check if we want to use external pre-shared secret for this
-+ * handshake for not reused session only. We need to generate
-+ * server_random before calling tls_session_secret_cb in order to allow
-+ * SessionTicket processing to use it in key derivation. */
-+ {
-+ unsigned long Time;
-+ unsigned char *pos;
-+ Time=(unsigned long)time(NULL); /* Time */
-+ pos=s->s3->server_random;
-+ l2n(Time,pos);
-+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
-+ {
-+ al=SSL_AD_INTERNAL_ERROR;
-+ goto f_err;
-+ }
-+ }
-+
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
-+ {
-+ SSL_CIPHER *pref_cipher=NULL;
-+
-+ s->session->master_key_length=sizeof(s->session->master_key);
-+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
-+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
-+ {
-+ s->hit=1;
-+ s->session->ciphers=ciphers;
-+ s->session->verify_result=X509_V_OK;
-+
-+ ciphers=NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-+ if (pref_cipher == NULL)
-+ {
-+ al=SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher=pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
- #endif
- /* Worst case, we will use the NULL compression, but if we have other
- * options, we will now look for them. We have i-1 compression
-@@ -1161,16 +1214,22 @@ int ssl3_send_server_hello(SSL *s)
- unsigned char *buf;
- unsigned char *p,*d;
- int i,sl;
-- unsigned long l,Time;
-+ unsigned long l;
-+#ifdef OPENSSL_NO_TLSEXT
-+ unsigned long Time;
-+#endif
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
- {
- buf=(unsigned char *)s->init_buf->data;
-+#ifdef OPENSSL_NO_TLSEXT
- p=s->s3->server_random;
-+ /* Generate server_random if it was not needed previously */
- Time=(unsigned long)time(NULL); /* Time */
- l2n(Time,p);
- if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
- return -1;
-+#endif
- /* Do the message type and length last */
- d=p= &(buf[4]);
-
-diff -upr openssl-0.9.8za.orig/ssl/ssl_err.c openssl-0.9.8za/ssl/ssl_err.c
---- openssl-0.9.8za.orig/ssl/ssl_err.c 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl_err.c 2014-06-05 20:37:09.225387312 +0300
-@@ -265,6 +265,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
- {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
- {0,NULL}
- };
-
-diff -upr openssl-0.9.8za.orig/ssl/ssl.h openssl-0.9.8za/ssl/ssl.h
---- openssl-0.9.8za.orig/ssl/ssl.h 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl.h 2014-06-05 20:37:09.229387312 +0300
-@@ -344,6 +344,7 @@ extern "C" {
- * 'struct ssl_st *' function parameters used to prototype callbacks
- * in SSL_CTX. */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st
-@@ -362,6 +363,9 @@ typedef struct ssl_cipher_st
-
- DECLARE_STACK_OF(SSL_CIPHER)
-
-+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st
- {
-@@ -1053,6 +1057,18 @@ struct ssl_st
-
- /* RFC4507 session ticket expected to be received or sent */
- int tlsext_ticket_expected;
-+
-+ /* TLS Session Ticket extension override */
-+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
-+
-+ /* TLS Session Ticket extension callback */
-+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
-+ void *tls_session_ticket_ext_cb_arg;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
-+
- SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
- #define session_ctx initial_ctx
- #else
-@@ -1668,6 +1684,15 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id,void *cm);
- #endif
-
-+/* TLS extensions functions */
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+ void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
-+
- /* BEGIN ERROR CODES */
- /* The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
-@@ -1872,6 +1897,7 @@ void ERR_load_SSL_strings(void);
- #define SSL_F_TLS1_ENC 210
- #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- #define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
-
- /* Reason codes. */
- #define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -upr openssl-0.9.8za.orig/ssl/ssl_sess.c openssl-0.9.8za/ssl/ssl_sess.c
---- openssl-0.9.8za.orig/ssl/ssl_sess.c 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/ssl_sess.c 2014-06-05 20:37:09.229387312 +0300
-@@ -712,6 +712,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
- return(s->session_timeout);
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
-+ {
-+ if (s == NULL) return(0);
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return(1);
-+ }
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+ void *arg)
-+ {
-+ if (s == NULL) return(0);
-+ s->tls_session_ticket_ext_cb = cb;
-+ s->tls_session_ticket_ext_cb_arg = arg;
-+ return(1);
-+ }
-+
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
-+ {
-+ if (s->version >= TLS1_VERSION)
-+ {
-+ if (s->tlsext_session_ticket)
-+ {
-+ OPENSSL_free(s->tlsext_session_ticket);
-+ s->tlsext_session_ticket = NULL;
-+ }
-+
-+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
-+ if (!s->tlsext_session_ticket)
-+ {
-+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ if (ext_data)
-+ {
-+ s->tlsext_session_ticket->length = ext_len;
-+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
-+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
-+ }
-+ else
-+ {
-+ s->tlsext_session_ticket->length = 0;
-+ s->tlsext_session_ticket->data = NULL;
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- typedef struct timeout_param_st
- {
- SSL_CTX *ctx;
-diff -upr openssl-0.9.8za.orig/ssl/t1_lib.c openssl-0.9.8za/ssl/t1_lib.c
---- openssl-0.9.8za.orig/ssl/t1_lib.c 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/t1_lib.c 2014-06-05 20:37:09.229387312 +0300
-@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
-
- void tls1_free(SSL *s)
- {
-+#ifndef OPENSSL_NO_TLSEXT
-+ if (s->tlsext_session_ticket)
-+ {
-+ OPENSSL_free(s->tlsext_session_ticket);
-+ }
-+#endif
- ssl3_free(s);
- }
-
-@@ -206,8 +212,23 @@ unsigned char *ssl_add_clienthello_tlsex
- int ticklen;
- if (!s->new_session && s->session && s->session->tlsext_tick)
- ticklen = s->session->tlsext_ticklen;
-+ else if (s->session && s->tlsext_session_ticket &&
-+ s->tlsext_session_ticket->data)
-+ {
-+ ticklen = s->tlsext_session_ticket->length;
-+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-+ if (!s->session->tlsext_tick)
-+ return NULL;
-+ memcpy(s->session->tlsext_tick,
-+ s->tlsext_session_ticket->data,
-+ ticklen);
-+ s->session->tlsext_ticklen = ticklen;
-+ }
- else
- ticklen = 0;
-+ if (ticklen == 0 && s->tlsext_session_ticket &&
-+ s->tlsext_session_ticket->data == NULL)
-+ goto skip_ext;
- /* Check for enough room 2 for extension type, 2 for len
- * rest for ticket
- */
-@@ -221,6 +242,7 @@ unsigned char *ssl_add_clienthello_tlsex
- ret += ticklen;
- }
- }
-+ skip_ext:
-
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
- s->version != DTLS1_VERSION)
-@@ -574,6 +596,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
- return 0;
- renegotiate_seen = 1;
- }
-+ else if (type == TLSEXT_TYPE_session_ticket)
-+ {
-+ if (s->tls_session_ticket_ext_cb &&
-+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
-+ {
-+ *al = TLS1_AD_INTERNAL_ERROR;
-+ return 0;
-+ }
-+ }
- else if (type == TLSEXT_TYPE_status_request &&
- s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
- {
-@@ -751,6 +782,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
- }
- else if (type == TLSEXT_TYPE_session_ticket)
- {
-+ if (s->tls_session_ticket_ext_cb &&
-+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
-+ {
-+ *al = TLS1_AD_INTERNAL_ERROR;
-+ return 0;
-+ }
- if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
- || (size > 0))
- {
-@@ -1043,6 +1080,15 @@ int tls1_process_ticket(SSL *s, unsigned
- s->tlsext_ticket_expected = 1;
- return 0; /* Cache miss */
- }
-+ if (s->tls_session_secret_cb)
-+ {
-+ /* Indicate cache miss here and instead of
-+ * generating the session from ticket now,
-+ * trigger abbreviated handshake based on
-+ * external mechanism to calculate the master
-+ * secret later. */
-+ return 0;
-+ }
- return tls_decrypt_ticket(s, p, size, session_id, len,
- ret);
- }
-diff -upr openssl-0.9.8za.orig/ssl/tls1.h openssl-0.9.8za/ssl/tls1.h
---- openssl-0.9.8za.orig/ssl/tls1.h 2014-06-05 11:09:08.000000000 +0300
-+++ openssl-0.9.8za/ssl/tls1.h 2014-06-05 20:37:09.229387312 +0300
-@@ -415,6 +415,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
- #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
- #endif
-
-+/* TLS extension struct */
-+struct tls_session_ticket_ext_st
-+ {
-+ unsigned short length;
-+ void *data;
-+ };
-+
- #ifdef __cplusplus
- }
- #endif
-diff -upr openssl-0.9.8za.orig/util/ssleay.num openssl-0.9.8za/util/ssleay.num
---- openssl-0.9.8za.orig/util/ssleay.num 2014-06-05 12:38:45.000000000 +0300
-+++ openssl-0.9.8za/util/ssleay.num 2014-06-05 20:37:09.229387312 +0300
-@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
- SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
- SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
- SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
-+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT
diff --git a/contrib/wpa/patches/openssl-0.9.8zf-tls-extensions.patch b/contrib/wpa/patches/openssl-0.9.8zf-tls-extensions.patch
deleted file mode 100644
index 3a8f90e..0000000
--- a/contrib/wpa/patches/openssl-0.9.8zf-tls-extensions.patch
+++ /dev/null
@@ -1,398 +0,0 @@
-This patch adds support for TLS SessionTicket extension (RFC 5077) for
-the parts used by EAP-FAST (RFC 4851).
-
-This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
-(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
-
-OpenSSL 0.9.8zf does not enable TLS extension support by default, so it
-will need to be enabled by adding enable-tlsext to config script
-command line.
-
-
-diff -upr openssl-0.9.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
---- openssl-0.9.8zf.orig/ssl/s3_clnt.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/s3_clnt.c 2015-03-24 16:19:14.043911769 +0200
-@@ -760,6 +760,23 @@ int ssl3_get_server_hello(SSL *s)
- goto f_err;
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+ /* check if we want to resume the session based on external pre-shared secret */
-+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
-+ SSL_CIPHER *pref_cipher = NULL;
-+
-+ s->session->master_key_length = sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key,
-+ &s->session->master_key_length,
-+ NULL, &pref_cipher,
-+ s->tls_session_secret_cb_arg)) {
-+ s->session->cipher = pref_cipher ?
-+ pref_cipher : ssl_get_cipher_by_char(s, p + j);
-+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
-+ }
-+ }
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- if (j != 0 && j == s->session->session_id_length
- && memcmp(p, s->session->session_id, j) == 0) {
- if (s->sid_ctx_length != s->session->sid_ctx_length
-@@ -2684,12 +2701,8 @@ int ssl3_check_finished(SSL *s)
- {
- int ok;
- long n;
-- /*
-- * If we have no ticket or session ID is non-zero length (a match of a
-- * non-zero session length would never reach here) it cannot be a resumed
-- * session.
-- */
-- if (!s->session->tlsext_tick || s->session->session_id_length)
-+ /* If we have no ticket it cannot be a resumed session. */
-+ if (!s->session->tlsext_tick)
- return 1;
- /*
- * this function is called when we really expect a Certificate message,
-diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
---- openssl-0.9.8zf.orig/ssl/s3_srvr.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/s3_srvr.c 2015-03-24 16:23:34.567909681 +0200
-@@ -999,6 +999,59 @@ int ssl3_get_client_hello(SSL *s)
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
- goto err;
- }
-+
-+ /* Check if we want to use external pre-shared secret for this
-+ * handshake for not reused session only. We need to generate
-+ * server_random before calling tls_session_secret_cb in order to allow
-+ * SessionTicket processing to use it in key derivation. */
-+ {
-+ unsigned long Time;
-+ unsigned char *pos;
-+ Time = (unsigned long)time(NULL); /* Time */
-+ pos = s->s3->server_random;
-+ l2n(Time, pos);
-+ if (RAND_pseudo_bytes(pos, SSL3_RANDOM_SIZE - 4) <= 0) {
-+ al = SSL_AD_INTERNAL_ERROR;
-+ goto f_err;
-+ }
-+ }
-+
-+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
-+ SSL_CIPHER *pref_cipher = NULL;
-+
-+ s->session->master_key_length = sizeof(s->session->master_key);
-+ if (s->tls_session_secret_cb(s, s->session->master_key,
-+ &s->session->master_key_length,
-+ ciphers, &pref_cipher,
-+ s->tls_session_secret_cb_arg)) {
-+ s->hit = 1;
-+ s->session->ciphers = ciphers;
-+ s->session->verify_result = X509_V_OK;
-+
-+ ciphers = NULL;
-+
-+ /* check if some cipher was preferred by call back */
-+ pref_cipher = pref_cipher ? pref_cipher :
-+ ssl3_choose_cipher(s, s->session->ciphers,
-+ SSL_get_ciphers(s));
-+ if (pref_cipher == NULL) {
-+ al = SSL_AD_HANDSHAKE_FAILURE;
-+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
-+ goto f_err;
-+ }
-+
-+ s->session->cipher = pref_cipher;
-+
-+ if (s->cipher_list)
-+ sk_SSL_CIPHER_free(s->cipher_list);
-+
-+ if (s->cipher_list_by_id)
-+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
-+
-+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-+ }
-+ }
- #endif
- /*
- * Worst case, we will use the NULL compression, but if we have other
-@@ -1143,15 +1196,21 @@ int ssl3_send_server_hello(SSL *s)
- unsigned char *buf;
- unsigned char *p, *d;
- int i, sl;
-- unsigned long l, Time;
-+ unsigned long l;
-+#ifdef OPENSSL_NO_TLSEXT
-+ unsigned long Time;
-+#endif
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
- buf = (unsigned char *)s->init_buf->data;
-+#ifdef OPENSSL_NO_TLSEXT
- p = s->s3->server_random;
-+ /* Generate server_random if it was not needed previously */
- Time = (unsigned long)time(NULL); /* Time */
- l2n(Time, p);
- if (RAND_pseudo_bytes(p, SSL3_RANDOM_SIZE - 4) <= 0)
- return -1;
-+#endif
- /* Do the message type and length last */
- d = p = &(buf[4]);
-
-diff -upr openssl-0.9.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
---- openssl-0.9.8zf.orig/ssl/ssl_err.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl_err.c 2015-03-24 16:35:58.627903717 +0200
-@@ -316,6 +316,7 @@ static ERR_STRING_DATA SSL_str_functs[]
- {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
- {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
- {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
-+ {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
- {0, NULL}
- };
-
-diff -upr openssl-0.9.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
---- openssl-0.9.8zf.orig/ssl/ssl.h 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl.h 2015-03-24 16:25:44.339908641 +0200
-@@ -349,6 +349,7 @@ extern "C" {
- * function parameters used to prototype callbacks in SSL_CTX.
- */
- typedef struct ssl_st *ssl_crock_st;
-+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
-
- /* used to hold info on the particular ciphers used */
- typedef struct ssl_cipher_st {
-@@ -366,6 +367,12 @@ typedef struct ssl_cipher_st {
-
- DECLARE_STACK_OF(SSL_CIPHER)
-
-+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data,
-+ int len, void *arg);
-+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers,
-+ SSL_CIPHER **cipher, void *arg);
-+
- /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
- typedef struct ssl_method_st {
- int version;
-@@ -1116,6 +1123,18 @@ struct ssl_st {
- int tlsext_ocsp_resplen;
- /* RFC4507 session ticket expected to be received or sent */
- int tlsext_ticket_expected;
-+
-+ /* TLS Session Ticket extension override */
-+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
-+
-+ /* TLS Session Ticket extension callback */
-+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
-+ void *tls_session_ticket_ext_cb_arg;
-+
-+ /* TLS pre-shared secret session resumption */
-+ tls_session_secret_cb_fn tls_session_secret_cb;
-+ void *tls_session_secret_cb_arg;
-+
- SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */
- # define session_ctx initial_ctx
- # else
-@@ -1772,6 +1791,17 @@ void *SSL_COMP_get_compression_methods(v
- int SSL_COMP_add_compression_method(int id, void *cm);
- # endif
-
-+/* TLS extensions functions */
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+ void *arg);
-+
-+/* Pre-shared secret session resumption functions */
-+int SSL_set_session_secret_cb(SSL *s,
-+ tls_session_secret_cb_fn tls_session_secret_cb,
-+ void *arg);
-+
- /* BEGIN ERROR CODES */
- /*
- * The following lines are auto generated by the script mkerr.pl. Any changes
-@@ -1977,6 +2007,7 @@ void ERR_load_SSL_strings(void);
- # define SSL_F_TLS1_ENC 210
- # define SSL_F_TLS1_SETUP_KEY_BLOCK 211
- # define SSL_F_WRITE_PENDING 212
-+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
-
- /* Reason codes. */
- # define SSL_R_APP_DATA_IN_HANDSHAKE 100
-diff -upr openssl-0.9.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
---- openssl-0.9.8zf.orig/ssl/ssl_sess.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/ssl_sess.c 2015-03-24 16:28:04.819907515 +0200
-@@ -716,6 +716,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
- return (s->session_timeout);
- }
-
-+#ifndef OPENSSL_NO_TLSEXT
-+int SSL_set_session_secret_cb(
-+ SSL *s,
-+ int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
-+ STACK_OF(SSL_CIPHER) *peer_ciphers,
-+ SSL_CIPHER **cipher, void *arg), void *arg)
-+{
-+ if (s == NULL)
-+ return 0;
-+ s->tls_session_secret_cb = tls_session_secret_cb;
-+ s->tls_session_secret_cb_arg = arg;
-+ return 1;
-+}
-+
-+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
-+ void *arg)
-+{
-+ if (s == NULL)
-+ return 0;
-+ s->tls_session_ticket_ext_cb = cb;
-+ s->tls_session_ticket_ext_cb_arg = arg;
-+ return 1;
-+}
-+
-+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
-+{
-+ if (s->version >= TLS1_VERSION) {
-+ if (s->tlsext_session_ticket) {
-+ OPENSSL_free(s->tlsext_session_ticket);
-+ s->tlsext_session_ticket = NULL;
-+ }
-+
-+ s->tlsext_session_ticket = OPENSSL_malloc(
-+ sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
-+ if (!s->tlsext_session_ticket) {
-+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
-+ return 0;
-+ }
-+
-+ if (ext_data) {
-+ s->tlsext_session_ticket->length = ext_len;
-+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
-+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
-+ } else {
-+ s->tlsext_session_ticket->length = 0;
-+ s->tlsext_session_ticket->data = NULL;
-+ }
-+
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+#endif /* OPENSSL_NO_TLSEXT */
-+
- typedef struct timeout_param_st {
- SSL_CTX *ctx;
- long time;
-diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
---- openssl-0.9.8zf.orig/ssl/t1_lib.c 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/t1_lib.c 2015-03-24 16:32:46.923905254 +0200
-@@ -108,6 +108,11 @@ int tls1_new(SSL *s)
-
- void tls1_free(SSL *s)
- {
-+#ifndef OPENSSL_NO_TLSEXT
-+ if (s->tlsext_session_ticket) {
-+ OPENSSL_free(s->tlsext_session_ticket);
-+ }
-+#endif
- ssl3_free(s);
- }
-
-@@ -206,8 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
- int ticklen;
- if (!s->new_session && s->session && s->session->tlsext_tick)
- ticklen = s->session->tlsext_ticklen;
-- else
-+ else if (s->session && s->tlsext_session_ticket &&
-+ s->tlsext_session_ticket->data) {
-+ ticklen = s->tlsext_session_ticket->length;
-+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-+ if (!s->session->tlsext_tick)
-+ return NULL;
-+ memcpy(s->session->tlsext_tick, s->tlsext_session_ticket->data,
-+ ticklen);
-+ s->session->tlsext_ticklen = ticklen;
-+ } else
- ticklen = 0;
-+ if (ticklen == 0 && s->tlsext_session_ticket &&
-+ s->tlsext_session_ticket->data == NULL)
-+ goto skip_ext;
- /*
- * Check for enough room 2 for extension type, 2 for len rest for
- * ticket
-@@ -221,6 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
- ret += ticklen;
- }
- }
-+skip_ext:
-
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
- s->version != DTLS1_VERSION) {
-@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
- if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
- return 0;
- renegotiate_seen = 1;
-+ } else if (type == TLSEXT_TYPE_session_ticket) {
-+ if (s->tls_session_ticket_ext_cb &&
-+ !s->tls_session_ticket_ext_cb(s, data, size,
-+ s->tls_session_ticket_ext_cb_arg))
-+ {
-+ *al = TLS1_AD_INTERNAL_ERROR;
-+ return 0;
-+ }
- } else if (type == TLSEXT_TYPE_status_request &&
- s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) {
-
-@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
- }
- tlsext_servername = 1;
- } else if (type == TLSEXT_TYPE_session_ticket) {
-+ if (s->tls_session_ticket_ext_cb &&
-+ !s->tls_session_ticket_ext_cb(
-+ s, data, size,
-+ s->tls_session_ticket_ext_cb_arg)) {
-+ *al = TLS1_AD_INTERNAL_ERROR;
-+ return 0;
-+ }
- if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
- || (size > 0)) {
- *al = TLS1_AD_UNSUPPORTED_EXTENSION;
-@@ -993,6 +1026,14 @@ int tls1_process_ticket(SSL *s, unsigned
- s->tlsext_ticket_expected = 1;
- return 0; /* Cache miss */
- }
-+ if (s->tls_session_secret_cb) {
-+ /* Indicate cache miss here and instead of
-+ * generating the session from ticket now,
-+ * trigger abbreviated handshake based on
-+ * external mechanism to calculate the master
-+ * secret later. */
-+ return 0;
-+ }
- return tls_decrypt_ticket(s, p, size, session_id, len, ret);
- }
- p += size;
-diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
---- openssl-0.9.8zf.orig/ssl/tls1.h 2015-03-19 15:46:46.000000000 +0200
-+++ openssl-0.9.8zf/ssl/tls1.h 2015-03-24 16:33:31.855904894 +0200
-@@ -460,6 +460,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
- # define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
- # endif
-
-+/* TLS extension struct */
-+struct tls_session_ticket_ext_st {
-+ unsigned short length;
-+ void *data;
-+};
-+
- #ifdef __cplusplus
- }
- #endif
-diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
---- openssl-0.9.8zf.orig/util/ssleay.num 2015-03-19 15:47:15.000000000 +0200
-+++ openssl-0.9.8zf/util/ssleay.num 2015-03-24 16:33:51.127904739 +0200
-@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
- SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
- SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
- SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
-+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT
diff --git a/contrib/wpa/src/ap/accounting.c b/contrib/wpa/src/ap/accounting.c
index a096de4..0aacc3c 100644
--- a/contrib/wpa/src/ap/accounting.c
+++ b/contrib/wpa/src/ap/accounting.c
@@ -1,6 +1,6 @@
/*
* hostapd / RADIUS Accounting
- * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -41,6 +41,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
size_t len;
int i;
struct wpabuf *b;
+ struct os_time now;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
@@ -49,44 +50,24 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
return NULL;
}
- if (sta) {
- radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
-
- if ((hapd->conf->wpa & 2) &&
- !hapd->conf->disable_pmksa_caching &&
- sta->eapol_sm && sta->eapol_sm->acct_multi_session_id_hi) {
- os_snprintf(buf, sizeof(buf), "%08X+%08X",
- sta->eapol_sm->acct_multi_session_id_hi,
- sta->eapol_sm->acct_multi_session_id_lo);
- if (!radius_msg_add_attr(
- msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
- (u8 *) buf, os_strlen(buf))) {
- wpa_printf(MSG_INFO,
- "Could not add Acct-Multi-Session-Id");
- goto fail;
- }
- }
- } else {
- radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
- }
-
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
status_type)) {
wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
goto fail;
}
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_ACCT_AUTHENTIC) &&
- !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
- hapd->conf->ieee802_1x ?
- RADIUS_ACCT_AUTHENTIC_RADIUS :
- RADIUS_ACCT_AUTHENTIC_LOCAL)) {
- wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
- goto fail;
- }
-
if (sta) {
+ if (!hostapd_config_get_radius_attr(
+ hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_ACCT_AUTHENTIC) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+ hapd->conf->ieee802_1x ?
+ RADIUS_ACCT_AUTHENTIC_RADIUS :
+ RADIUS_ACCT_AUTHENTIC_LOCAL)) {
+ wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
+ goto fail;
+ }
+
/* Use 802.1X identity if available */
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
@@ -147,6 +128,32 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
goto fail;
}
+
+ if (sta->ipaddr &&
+ !radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_FRAMED_IP_ADDRESS,
+ be_to_host32(sta->ipaddr))) {
+ wpa_printf(MSG_ERROR,
+ "Could not add Framed-IP-Address");
+ goto fail;
+ }
+ }
+
+ os_get_time(&now);
+ if (now.sec > 1000000000 &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+ now.sec)) {
+ wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
+ goto fail;
+ }
+
+ /*
+ * Add Acct-Delay-Time with zero value for the first transmission. This
+ * will be updated within radius_client.c when retransmitting the frame.
+ */
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_DELAY_TIME, 0)) {
+ wpa_printf(MSG_INFO, "Could not add Acct-Delay-Time");
+ goto fail;
}
return msg;
@@ -164,19 +171,25 @@ static int accounting_sta_update_stats(struct hostapd_data *hapd,
if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
return -1;
- if (sta->last_rx_bytes > data->rx_bytes)
- sta->acct_input_gigawords++;
- if (sta->last_tx_bytes > data->tx_bytes)
- sta->acct_output_gigawords++;
- sta->last_rx_bytes = data->rx_bytes;
- sta->last_tx_bytes = data->tx_bytes;
+ if (!data->bytes_64bit) {
+ /* Extend 32-bit counters from the driver to 64-bit counters */
+ if (sta->last_rx_bytes_lo > data->rx_bytes)
+ sta->last_rx_bytes_hi++;
+ sta->last_rx_bytes_lo = data->rx_bytes;
+
+ if (sta->last_tx_bytes_lo > data->tx_bytes)
+ sta->last_tx_bytes_hi++;
+ sta->last_tx_bytes_lo = data->tx_bytes;
+ }
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
- "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
- "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
- sta->last_rx_bytes, sta->acct_input_gigawords,
- sta->last_tx_bytes, sta->acct_output_gigawords);
+ HOSTAPD_LEVEL_DEBUG,
+ "updated TX/RX stats: rx_bytes=%llu [%u:%u] tx_bytes=%llu [%u:%u] bytes_64bit=%d",
+ data->rx_bytes, sta->last_rx_bytes_hi,
+ sta->last_rx_bytes_lo,
+ data->tx_bytes, sta->last_tx_bytes_hi,
+ sta->last_tx_bytes_lo,
+ data->bytes_64bit);
return 0;
}
@@ -217,12 +230,14 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "starting accounting session %08X-%08X",
- sta->acct_session_id_hi, sta->acct_session_id_lo);
+ "starting accounting session %016llX",
+ (unsigned long long) sta->acct_session_id);
os_get_reltime(&sta->acct_session_start);
- sta->last_rx_bytes = sta->last_tx_bytes = 0;
- sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
+ sta->last_rx_bytes_hi = 0;
+ sta->last_rx_bytes_lo = 0;
+ sta->last_tx_bytes_hi = 0;
+ sta->last_tx_bytes_lo = 0;
hostapd_drv_sta_clear_stats(hapd, sta->addr);
if (!hapd->conf->radius->acct_server)
@@ -251,8 +266,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
int cause = sta->acct_terminate_cause;
struct hostap_sta_driver_data data;
struct os_reltime now_r, diff;
- struct os_time now;
- u32 gigawords;
+ u64 bytes;
if (!hapd->conf->radius->acct_server)
return;
@@ -266,7 +280,6 @@ static void accounting_sta_report(struct hostapd_data *hapd,
}
os_get_reltime(&now_r);
- os_get_time(&now);
os_reltime_sub(&now_r, &sta->acct_session_start, &diff);
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
diff.sec)) {
@@ -287,48 +300,42 @@ static void accounting_sta_report(struct hostapd_data *hapd,
wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
goto fail;
}
+ if (data.bytes_64bit)
+ bytes = data.rx_bytes;
+ else
+ bytes = ((u64) sta->last_rx_bytes_hi << 32) |
+ sta->last_rx_bytes_lo;
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_OCTETS,
- data.rx_bytes)) {
+ (u32) bytes)) {
wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
goto fail;
}
- gigawords = sta->acct_input_gigawords;
-#if __WORDSIZE == 64
- gigawords += data.rx_bytes >> 32;
-#endif
- if (gigawords &&
- !radius_msg_add_attr_int32(
- msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
- gigawords)) {
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
+ (u32) (bytes >> 32))) {
wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
goto fail;
}
+ if (data.bytes_64bit)
+ bytes = data.tx_bytes;
+ else
+ bytes = ((u64) sta->last_tx_bytes_hi << 32) |
+ sta->last_tx_bytes_lo;
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
- data.tx_bytes)) {
+ (u32) bytes)) {
wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
goto fail;
}
- gigawords = sta->acct_output_gigawords;
-#if __WORDSIZE == 64
- gigawords += data.tx_bytes >> 32;
-#endif
- if (gigawords &&
- !radius_msg_add_attr_int32(
- msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
- gigawords)) {
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
+ (u32) (bytes >> 32))) {
wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
goto fail;
}
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
- now.sec)) {
- wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
- goto fail;
- }
-
if (eloop_terminated())
cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
@@ -375,22 +382,17 @@ void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(accounting_interim_update, hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "stopped accounting session %08X-%08X",
- sta->acct_session_id_hi,
- sta->acct_session_id_lo);
+ "stopped accounting session %016llX",
+ (unsigned long long) sta->acct_session_id);
sta->acct_session_started = 0;
}
}
-void accounting_sta_get_id(struct hostapd_data *hapd,
- struct sta_info *sta)
+int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta)
{
- sta->acct_session_id_lo = hapd->acct_session_id_lo++;
- if (hapd->acct_session_id_lo == 0) {
- hapd->acct_session_id_hi++;
- }
- sta->acct_session_id_hi = hapd->acct_session_id_hi;
+ return radius_gen_session_id((u8 *) &sta->acct_session_id,
+ sizeof(sta->acct_session_id));
}
@@ -437,12 +439,14 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
if (!msg)
return;
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
- RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
- {
- wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
- radius_msg_free(msg);
- return;
+ if (hapd->acct_session_id) {
+ char buf[20];
+
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) hapd->acct_session_id);
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ (u8 *) buf, os_strlen(buf)))
+ wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
}
if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
@@ -450,6 +454,63 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
}
+static void accounting_interim_error_cb(const u8 *addr, void *ctx)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ unsigned int i, wait_time;
+ int res;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return;
+ sta->acct_interim_errors++;
+ if (sta->acct_interim_errors > 10 /* RADIUS_CLIENT_MAX_RETRIES */) {
+ wpa_printf(MSG_DEBUG,
+ "Interim RADIUS accounting update failed for " MACSTR
+ " - too many errors, abandon this interim accounting update",
+ MAC2STR(addr));
+ sta->acct_interim_errors = 0;
+ /* Next update will be tried after normal update interval */
+ return;
+ }
+
+ /*
+ * Use a shorter update interval as an improved retransmission mechanism
+ * for failed interim accounting updates. This allows the statistics to
+ * be updated for each retransmission.
+ *
+ * RADIUS client code has already waited RADIUS_CLIENT_FIRST_WAIT.
+ * Schedule the first retry attempt immediately and every following one
+ * with exponential backoff.
+ */
+ if (sta->acct_interim_errors == 1) {
+ wait_time = 0;
+ } else {
+ wait_time = 3; /* RADIUS_CLIENT_FIRST_WAIT */
+ for (i = 1; i < sta->acct_interim_errors; i++)
+ wait_time *= 2;
+ }
+ res = eloop_deplete_timeout(wait_time, 0, accounting_interim_update,
+ hapd, sta);
+ if (res == 1)
+ wpa_printf(MSG_DEBUG,
+ "Interim RADIUS accounting update failed for " MACSTR
+ " (error count: %u) - schedule next update in %u seconds",
+ MAC2STR(addr), sta->acct_interim_errors, wait_time);
+ else if (res == 0)
+ wpa_printf(MSG_DEBUG,
+ "Interim RADIUS accounting update failed for " MACSTR
+ " (error count: %u)", MAC2STR(addr),
+ sta->acct_interim_errors);
+ else
+ wpa_printf(MSG_DEBUG,
+ "Interim RADIUS accounting update failed for " MACSTR
+ " (error count: %u) - no timer found", MAC2STR(addr),
+ sta->acct_interim_errors);
+}
+
+
/**
* accounting_init: Initialize accounting
* @hapd: hostapd BSS data
@@ -457,20 +518,15 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
*/
int accounting_init(struct hostapd_data *hapd)
{
- struct os_time now;
-
- /* Acct-Session-Id should be unique over reboots. Using a random number
- * is preferred. If that is not available, take the current time. Mix
- * in microseconds to make this more likely to be unique. */
- os_get_time(&now);
- if (os_get_random((u8 *) &hapd->acct_session_id_hi,
- sizeof(hapd->acct_session_id_hi)) < 0)
- hapd->acct_session_id_hi = now.sec;
- hapd->acct_session_id_hi ^= now.usec;
+ if (radius_gen_session_id((u8 *) &hapd->acct_session_id,
+ sizeof(hapd->acct_session_id)) < 0)
+ return -1;
if (radius_client_register(hapd->radius, RADIUS_ACCT,
accounting_receive, hapd))
return -1;
+ radius_client_set_interim_error_cb(hapd->radius,
+ accounting_interim_error_cb, hapd);
accounting_report_state(hapd, 1);
diff --git a/contrib/wpa/src/ap/accounting.h b/contrib/wpa/src/ap/accounting.h
index dcc54ee..de5a33f 100644
--- a/contrib/wpa/src/ap/accounting.h
+++ b/contrib/wpa/src/ap/accounting.h
@@ -10,9 +10,10 @@
#define ACCOUNTING_H
#ifdef CONFIG_NO_ACCOUNTING
-static inline void accounting_sta_get_id(struct hostapd_data *hapd,
- struct sta_info *sta)
+static inline int accounting_sta_get_id(struct hostapd_data *hapd,
+ struct sta_info *sta)
{
+ return 0;
}
static inline void accounting_sta_start(struct hostapd_data *hapd,
@@ -34,7 +35,7 @@ static inline void accounting_deinit(struct hostapd_data *hapd)
{
}
#else /* CONFIG_NO_ACCOUNTING */
-void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
+int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
int accounting_init(struct hostapd_data *hapd);
diff --git a/contrib/wpa/src/ap/acs.c b/contrib/wpa/src/ap/acs.c
index 03d797f..3b45075 100644
--- a/contrib/wpa/src/ap/acs.c
+++ b/contrib/wpa/src/ap/acs.c
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "hostapd.h"
@@ -260,7 +261,7 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
}
-static void acs_cleanup(struct hostapd_iface *iface)
+void acs_cleanup(struct hostapd_iface *iface)
{
int i;
struct hostapd_channel_data *chan;
@@ -314,7 +315,7 @@ acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
/* TODO: figure out the best multiplier for noise floor base */
factor = pow(10, survey->nf / 5.0L) +
- (busy / total) *
+ (total ? (busy / total) : 0) *
pow(2, pow(10, (long double) survey->nf / 10.0L) -
pow(10, (long double) min_nf / 10.0L));
@@ -331,10 +332,8 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
long double int_factor = 0;
unsigned count = 0;
- if (dl_list_empty(&chan->survey_list))
- return;
-
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ if (dl_list_empty(&chan->survey_list) ||
+ (chan->flag & HOSTAPD_CHAN_DISABLED))
return;
chan->interference_factor = 0;
@@ -359,13 +358,12 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
(unsigned long) survey->channel_time_rx);
}
- if (!count)
- return;
- chan->interference_factor /= count;
+ if (count)
+ chan->interference_factor /= count;
}
-static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
+static int acs_usable_ht40_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
157, 184, 192 };
@@ -379,7 +377,7 @@ static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
}
-static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
+static int acs_usable_vht80_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 52, 100, 116, 132, 149 };
unsigned int i;
@@ -392,6 +390,19 @@ static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
}
+static int acs_usable_vht160_chan(const struct hostapd_channel_data *chan)
+{
+ const int allowed[] = { 36, 100 };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(allowed); i++)
+ if (chan->chan == allowed[i])
+ return 1;
+
+ return 0;
+}
+
+
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
@@ -450,13 +461,9 @@ static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
- continue;
-
- if (!acs_survey_list_is_sufficient(chan))
- continue;
-
- valid++;
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ acs_survey_list_is_sufficient(chan))
+ valid++;
}
/* We need at least survey data for one channel */
@@ -466,13 +473,9 @@ static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
static int acs_usable_chan(struct hostapd_channel_data *chan)
{
- if (dl_list_empty(&chan->survey_list))
- return 0;
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
- return 0;
- if (!acs_survey_list_is_sufficient(chan))
- return 0;
- return 1;
+ return !dl_list_empty(&chan->survey_list) &&
+ !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ acs_survey_list_is_sufficient(chan);
}
@@ -576,6 +579,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
long double factor, ideal_factor = 0;
int i, j;
int n_chans = 1;
+ u32 bw;
unsigned int k;
/* TODO: HT40- support */
@@ -590,17 +594,23 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
iface->conf->secondary_channel)
n_chans = 2;
- if (iface->conf->ieee80211ac &&
- iface->conf->vht_oper_chwidth == 1)
- n_chans = 4;
+ if (iface->conf->ieee80211ac) {
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ n_chans = 4;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ n_chans = 8;
+ break;
+ }
+ }
+
+ bw = num_chan_to_bw(n_chans);
- /* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */
+ /* TODO: VHT80+80. Update acs_adjust_vht_center_freq() too. */
- wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz",
- n_chans == 1 ? 20 :
- n_chans == 2 ? 40 :
- n_chans == 4 ? 80 :
- -1);
+ wpa_printf(MSG_DEBUG,
+ "ACS: Survey analysis for selected bandwidth %d MHz", bw);
for (i = 0; i < iface->current_mode->num_channels; i++) {
double total_weight;
@@ -608,12 +618,23 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
chan = &iface->current_mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ /* Since in the current ACS implementation the first channel is
+ * always a primary channel, skip channels not available as
+ * primary until more sophisticated channel selection is
+ * implemented. */
+ if (!chan_pri_allowed(chan))
continue;
if (!is_in_chanlist(iface, chan))
continue;
+ if (!chan_bw_allowed(chan, bw, 1, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: BW %u is not supported",
+ chan->chan, bw);
+ continue;
+ }
+
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
@@ -626,12 +647,24 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
}
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
- iface->conf->ieee80211ac &&
- iface->conf->vht_oper_chwidth == 1 &&
- !acs_usable_vht80_chan(chan)) {
- wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80",
- chan->chan);
- continue;
+ iface->conf->ieee80211ac) {
+ if (iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_80MHZ &&
+ !acs_usable_vht80_chan(chan)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: not allowed as primary channel for VHT80",
+ chan->chan);
+ continue;
+ }
+
+ if (iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_160MHZ &&
+ !acs_usable_vht160_chan(chan)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: not allowed as primary channel for VHT160",
+ chan->chan);
+ continue;
+ }
}
factor = 0;
@@ -644,6 +677,13 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
if (!adj_chan)
break;
+ if (!chan_bw_allowed(adj_chan, bw, 1, 0)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: PRI Channel %d: secondary channel %d BW %u is not supported",
+ chan->chan, adj_chan->chan, bw);
+ break;
+ }
+
if (acs_usable_chan(adj_chan)) {
factor += adj_chan->interference_factor;
total_weight += 1;
@@ -756,10 +796,14 @@ static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
case VHT_CHANWIDTH_80MHZ:
offset = 6;
break;
+ case VHT_CHANWIDTH_160MHZ:
+ offset = 14;
+ break;
default:
/* TODO: How can this be calculated? Adjust
* acs_find_ideal_chan() */
- wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now");
+ wpa_printf(MSG_INFO,
+ "ACS: Only VHT20/40/80/160 is supported now");
return;
}
@@ -789,10 +833,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
static int acs_study_options(struct hostapd_iface *iface)
{
- int err;
-
- err = acs_study_survey_based(iface);
- if (err == 0)
+ if (acs_study_survey_based(iface) == 0)
return 0;
/* TODO: If no surveys are available/sufficient this is a good
@@ -921,22 +962,21 @@ static int acs_request_scan(struct hostapd_iface *iface)
enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
{
- int err;
-
wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");
if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) {
wpa_printf(MSG_INFO, "ACS: Offloading to driver");
- err = hostapd_drv_do_acs(iface->bss[0]);
- if (err)
+ if (hostapd_drv_do_acs(iface->bss[0]))
return HOSTAPD_CHAN_INVALID;
return HOSTAPD_CHAN_ACS;
}
+ if (!iface->current_mode)
+ return HOSTAPD_CHAN_INVALID;
+
acs_cleanup(iface);
- err = acs_request_scan(iface);
- if (err < 0)
+ if (acs_request_scan(iface) < 0)
return HOSTAPD_CHAN_INVALID;
hostapd_set_state(iface, HAPD_IFACE_ACS);
diff --git a/contrib/wpa/src/ap/acs.h b/contrib/wpa/src/ap/acs.h
index fc85259..ec84f0e 100644
--- a/contrib/wpa/src/ap/acs.h
+++ b/contrib/wpa/src/ap/acs.h
@@ -13,6 +13,7 @@
#ifdef CONFIG_ACS
enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
+void acs_cleanup(struct hostapd_iface *iface);
#else /* CONFIG_ACS */
@@ -22,6 +23,10 @@ static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
return HOSTAPD_CHAN_INVALID;
}
+static inline void acs_cleanup(struct hostapd_iface *iface)
+{
+}
+
#endif /* CONFIG_ACS */
#endif /* ACS_H */
diff --git a/contrib/wpa/src/ap/ap_config.c b/contrib/wpa/src/ap/ap_config.c
index 9a96e50..e640e99 100644
--- a/contrib/wpa/src/ap/ap_config.c
+++ b/contrib/wpa/src/ap/ap_config.c
@@ -10,9 +10,11 @@
#include "utils/common.h"
#include "crypto/sha1.h"
+#include "crypto/tls.h"
#include "radius/radius_client.h"
#include "common/ieee802_11_defs.h"
#include "common/eapol_common.h"
+#include "common/dhcp.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
@@ -36,8 +38,14 @@ static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
}
+#ifndef DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES
+#define DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES 0
+#endif /* DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES */
+
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
{
+ dl_list_init(&bss->anqp_elem);
+
bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
bss->logger_syslog = (unsigned int) -1;
@@ -53,6 +61,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
+ bss->wpa_group_update_count = 4;
+ bss->wpa_pairwise_update_count = 4;
+ bss->wpa_disable_eapol_key_retries =
+ DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
bss->wpa_pairwise = WPA_CIPHER_TKIP;
bss->wpa_group = WPA_CIPHER_TKIP;
@@ -63,6 +75,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->dtim_period = 2;
bss->radius_server_auth_port = 1812;
+ bss->eap_sim_db_timeout = 1;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
bss->eapol_version = EAPOL_VERSION;
@@ -85,13 +98,48 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
/* Set to -1 as defaults depends on HT in setup */
bss->wmm_enabled = -1;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
bss->ft_over_ds = 1;
-#endif /* CONFIG_IEEE80211R */
+ bss->rkh_pos_timeout = 86400;
+ bss->rkh_neg_timeout = 60;
+ bss->rkh_pull_timeout = 1000;
+ bss->rkh_pull_retries = 4;
+ bss->r0_key_lifetime = 1209600;
+#endif /* CONFIG_IEEE80211R_AP */
bss->radius_das_time_window = 300;
bss->sae_anti_clogging_threshold = 5;
+ bss->sae_sync = 5;
+
+ bss->gas_frag_limit = 1400;
+
+#ifdef CONFIG_FILS
+ dl_list_init(&bss->fils_realms);
+ bss->fils_hlp_wait_time = 30;
+ bss->dhcp_server_port = DHCP_SERVER_PORT;
+ bss->dhcp_relay_port = DHCP_SERVER_PORT;
+#endif /* CONFIG_FILS */
+
+ bss->broadcast_deauth = 1;
+
+#ifdef CONFIG_MBO
+ bss->mbo_cell_data_conn_pref = -1;
+#endif /* CONFIG_MBO */
+
+ /* Disable TLS v1.3 by default for now to avoid interoperability issue.
+ * This can be enabled by default once the implementation has been fully
+ * completed and tested with other implementations. */
+ bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
+
+ bss->send_probe_response = 1;
+
+#ifdef CONFIG_HS20
+ bss->hs20_release = (HS20_VERSION >> 4) + 1;
+#endif /* CONFIG_HS20 */
+
+ /* Default to strict CRL checking. */
+ bss->check_crl_strict = 1;
}
@@ -152,9 +200,8 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->num_bss = 1;
conf->beacon_int = 100;
- conf->rts_threshold = -1; /* use driver default: 2347 */
- conf->fragm_threshold = -1; /* user driver default: 2346 */
- conf->send_probe_response = 1;
+ conf->rts_threshold = -2; /* use driver default: 2347 */
+ conf->fragm_threshold = -2; /* user driver default: 2346 */
/* Set to invalid value means do not add Power Constraint IE */
conf->local_pwr_constraint = -1;
@@ -180,6 +227,7 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ignore_assoc_probability = 0.0;
conf->ignore_reassoc_probability = 0.0;
conf->corrupt_gtk_rekey_mic_probability = 0.0;
+ conf->ecsa_ie_only = 0;
#endif /* CONFIG_TESTING_OPTIONS */
conf->acs = 0;
@@ -188,6 +236,14 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
+ /* The third octet of the country string uses an ASCII space character
+ * by default to indicate that the regulations encompass all
+ * environments for the current frequency band in the country. */
+ conf->country[2] = ' ';
+
+ conf->rssi_reject_assoc_rssi = 0;
+ conf->rssi_reject_assoc_timeout = 30;
+
return conf;
}
@@ -198,18 +254,17 @@ int hostapd_mac_comp(const void *a, const void *b)
}
-int hostapd_mac_comp_empty(const void *a)
-{
- macaddr empty = { 0 };
- return os_memcmp(a, empty, sizeof(macaddr));
-}
-
-
static int hostapd_config_read_wpa_psk(const char *fname,
struct hostapd_ssid *ssid)
{
FILE *f;
char buf[128], *pos;
+ const char *keyid;
+ char *context;
+ char *context2;
+ char *token;
+ char *name;
+ char *value;
int line = 0, ret = 0, len, ok;
u8 addr[ETH_ALEN];
struct hostapd_wpa_psk *psk;
@@ -224,6 +279,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
}
while (fgets(buf, sizeof(buf), f)) {
+ int vlan_id = 0;
+
line++;
if (buf[0] == '#')
@@ -239,9 +296,39 @@ static int hostapd_config_read_wpa_psk(const char *fname,
if (buf[0] == '\0')
continue;
- if (hwaddr_aton(buf, addr)) {
+ context = NULL;
+ keyid = NULL;
+ while ((token = str_token(buf, " ", &context))) {
+ if (!os_strchr(token, '='))
+ break;
+ context2 = NULL;
+ name = str_token(token, "=", &context2);
+ if (!name)
+ break;
+ value = str_token(token, "", &context2);
+ if (!value)
+ value = "";
+ if (!os_strcmp(name, "keyid")) {
+ keyid = value;
+ } else if (!os_strcmp(name, "vlanid")) {
+ vlan_id = atoi(value);
+ } else {
+ wpa_printf(MSG_ERROR,
+ "Unrecognized '%s=%s' on line %d in '%s'",
+ name, value, line, fname);
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret == -1)
+ break;
+
+ if (!token)
+ token = "";
+ if (hwaddr_aton(token, addr)) {
wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
- "line %d in '%s'", buf, line, fname);
+ "line %d in '%s'", token, line, fname);
ret = -1;
break;
}
@@ -252,20 +339,20 @@ static int hostapd_config_read_wpa_psk(const char *fname,
ret = -1;
break;
}
+ psk->vlan_id = vlan_id;
if (is_zero_ether_addr(addr))
psk->group = 1;
else
os_memcpy(psk->addr, addr, ETH_ALEN);
- pos = buf + 17;
- if (*pos == '\0') {
+ pos = str_token(buf, "", &context);
+ if (!pos) {
wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
line, fname);
os_free(psk);
ret = -1;
break;
}
- pos++;
ok = 0;
len = os_strlen(pos);
@@ -284,6 +371,18 @@ static int hostapd_config_read_wpa_psk(const char *fname,
break;
}
+ if (keyid) {
+ len = os_strlcpy(psk->keyid, keyid, sizeof(psk->keyid));
+ if ((size_t) len >= sizeof(psk->keyid)) {
+ wpa_printf(MSG_ERROR,
+ "PSK keyid too long on line %d in '%s'",
+ line, fname);
+ os_free(psk);
+ ret = -1;
+ break;
+ }
+ }
+
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@@ -332,13 +431,7 @@ int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
ssid->wpa_psk->group = 1;
}
- if (ssid->wpa_psk_file) {
- if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
- &conf->ssid))
- return -1;
- }
-
- return 0;
+ return hostapd_config_read_wpa_psk(ssid->wpa_psk_file, &conf->ssid);
}
@@ -383,10 +476,23 @@ void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
hostapd_config_free_radius_attr(user->accept_attr);
os_free(user->identity);
bin_clear_free(user->password, user->password_len);
+ bin_clear_free(user->salt, user->salt_len);
os_free(user);
}
+void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
+{
+ struct hostapd_eap_user *prev_user;
+
+ while (user) {
+ prev_user = user;
+ user = user->next;
+ hostapd_config_free_eap_user(prev_user);
+ }
+}
+
+
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
@@ -410,10 +516,51 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
}
-void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
+{
+ struct anqp_element *elem;
+
+ while ((elem = dl_list_first(&conf->anqp_elem, struct anqp_element,
+ list))) {
+ dl_list_del(&elem->list);
+ wpabuf_free(elem->payload);
+ os_free(elem);
+ }
+}
+
+
+static void hostapd_config_free_fils_realms(struct hostapd_bss_config *conf)
{
- struct hostapd_eap_user *user, *prev_user;
+#ifdef CONFIG_FILS
+ struct fils_realm *realm;
+
+ while ((realm = dl_list_first(&conf->fils_realms, struct fils_realm,
+ list))) {
+ dl_list_del(&realm->list);
+ os_free(realm);
+ }
+#endif /* CONFIG_FILS */
+}
+
+static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
+{
+ struct sae_password_entry *pw, *tmp;
+
+ pw = conf->sae_passwords;
+ conf->sae_passwords = NULL;
+ while (pw) {
+ tmp = pw;
+ pw = pw->next;
+ str_clear_free(tmp->password);
+ os_free(tmp->identifier);
+ os_free(tmp);
+ }
+}
+
+
+void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+{
if (conf == NULL)
return;
@@ -426,12 +573,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
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);
- }
+ hostapd_config_free_eap_users(conf->eap_user);
os_free(conf->eap_user_sqlite);
os_free(conf->eap_req_id_text);
@@ -453,9 +595,12 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->server_cert);
os_free(conf->private_key);
os_free(conf->private_key_passwd);
+ os_free(conf->check_cert_subject);
os_free(conf->ocsp_stapling_response);
+ os_free(conf->ocsp_stapling_response_multi);
os_free(conf->dh_file);
os_free(conf->openssl_ciphers);
+ os_free(conf->openssl_ecdh_curves);
os_free(conf->pac_opaque_encr_key);
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
@@ -466,7 +611,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
hostapd_config_free_vlan(conf);
os_free(conf->time_zone);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
{
struct ft_remote_r0kh *r0kh, *r0kh_prev;
struct ft_remote_r1kh *r1kh, *r1kh_prev;
@@ -487,7 +632,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(r1kh_prev);
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_WPS
os_free(conf->wps_pin_requests);
@@ -500,6 +645,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->ap_pin);
os_free(conf->extra_cred);
os_free(conf->ap_settings);
+ hostapd_config_clear_wpa_psk(&conf->multi_ap_backhaul_ssid.wpa_psk);
+ str_clear_free(conf->multi_ap_backhaul_ssid.wpa_passphrase);
os_free(conf->upnp_iface);
os_free(conf->friendly_name);
os_free(conf->manufacturer_url);
@@ -519,10 +666,12 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->roaming_consortium);
os_free(conf->venue_name);
+ os_free(conf->venue_url);
os_free(conf->nai_realm_data);
os_free(conf->network_auth_type);
os_free(conf->anqp_3gpp_cell_net);
os_free(conf->domain_name);
+ hostapd_config_free_anqp_elem(conf);
#ifdef CONFIG_RADIUS_TEST
os_free(conf->dump_msk_file);
@@ -547,16 +696,31 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(p->icons[j]);
os_free(p->icons);
os_free(p->osu_nai);
+ os_free(p->osu_nai2);
os_free(p->service_desc);
}
os_free(conf->hs20_osu_providers);
}
+ if (conf->hs20_operator_icon) {
+ size_t i;
+
+ for (i = 0; i < conf->hs20_operator_icon_count; i++)
+ os_free(conf->hs20_operator_icon[i]);
+ os_free(conf->hs20_operator_icon);
+ }
os_free(conf->subscr_remediation_url);
+ os_free(conf->hs20_sim_provisioning_url);
+ os_free(conf->t_c_filename);
+ os_free(conf->t_c_server_url);
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
+ wpabuf_free(conf->assocresp_elements);
os_free(conf->sae_groups);
+#ifdef CONFIG_OWE
+ os_free(conf->owe_groups);
+#endif /* CONFIG_OWE */
os_free(conf->wowlan_triggers);
@@ -564,11 +728,22 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
+ wpabuf_free(conf->sae_commit_override);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
os_free(conf->no_auth_if_seen_on);
+ hostapd_config_free_fils_realms(conf);
+
+#ifdef CONFIG_DPP
+ os_free(conf->dpp_connector);
+ wpabuf_free(conf->dpp_netaccesskey);
+ wpabuf_free(conf->dpp_csign);
+#endif /* CONFIG_DPP */
+
+ hostapd_config_free_sae_passwords(conf);
+
os_free(conf);
}
@@ -594,6 +769,8 @@ void hostapd_config_free(struct hostapd_config *conf)
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
#endif /* CONFIG_ACS */
+ wpabuf_free(conf->lci);
+ wpabuf_free(conf->civic);
os_free(conf);
}
@@ -610,7 +787,7 @@ void hostapd_config_free(struct hostapd_config *conf)
* Perform a binary search for given MAC address from a pre-sorted list.
*/
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
- const u8 *addr, int *vlan_id)
+ const u8 *addr, struct vlan_description *vlan_id)
{
int start, end, middle, res;
@@ -650,11 +827,26 @@ int hostapd_rate_found(int *list, int rate)
}
-int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_valid(struct hostapd_vlan *vlan,
+ struct vlan_description *vlan_desc)
{
struct hostapd_vlan *v = vlan;
+ int i;
+
+ if (!vlan_desc->notempty || vlan_desc->untagged < 0 ||
+ vlan_desc->untagged > MAX_VLAN_ID)
+ return 0;
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN; i++) {
+ if (vlan_desc->tagged[i] < 0 ||
+ vlan_desc->tagged[i] > MAX_VLAN_ID)
+ return 0;
+ }
+ if (!vlan_desc->untagged && !vlan_desc->tagged[0])
+ return 0;
+
while (v) {
- if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+ if (!vlan_compare(&v->vlan_desc, vlan_desc) ||
+ v->vlan_id == VLAN_ID_WILDCARD)
return 1;
v = v->next;
}
@@ -676,11 +868,14 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *p2p_dev_addr,
- const u8 *prev_psk)
+ const u8 *prev_psk, int *vlan_id)
{
struct hostapd_wpa_psk *psk;
int next_ok = prev_psk == NULL;
+ if (vlan_id)
+ *vlan_id = 0;
+
if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) {
wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
" p2p_dev_addr=" MACSTR " prev_psk=%p",
@@ -698,8 +893,11 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
(addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
(!addr && p2p_dev_addr &&
os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
- 0)))
+ 0))) {
+ if (vlan_id)
+ *vlan_id = psk->vlan_id;
return psk->psk;
+ }
if (psk->psk == prev_psk)
next_ok = 1;
@@ -756,7 +954,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
- if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
+ if (full_config && !is_zero_ether_addr(bss->bssid)) {
size_t i;
for (i = 0; i < conf->num_bss; i++) {
@@ -772,7 +970,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
(bss->nas_identifier == NULL ||
os_strlen(bss->nas_identifier) < 1 ||
@@ -782,7 +980,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
"string");
return -1;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211N
if (full_config && conf->ieee80211n &&
@@ -811,6 +1009,25 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (full_config && conf->ieee80211ac &&
+ bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+ bss->disable_11ac = 1;
+ wpa_printf(MSG_ERROR,
+ "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
+ }
+
+ if (full_config && conf->ieee80211ac && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
+ {
+ bss->disable_11ac = 1;
+ wpa_printf(MSG_ERROR,
+ "VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
+ }
+#endif /* CONFIG_IEEE80211AC */
+
#ifdef CONFIG_WPS
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
@@ -827,7 +1044,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
- !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP_256)))) {
wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
"WPA2/CCMP/GCMP forced WPS to be disabled");
bss->wps_state = 0;
@@ -847,6 +1066,24 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (full_config && bss->mbo_enabled && (bss->wpa & 2) &&
+ bss->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_ERROR,
+ "MBO: PMF needs to be enabled whenever using WPA2 with MBO");
+ return -1;
+ }
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_OCV
+ if (full_config && bss->ieee80211w == NO_MGMT_FRAME_PROTECTION &&
+ bss->ocv) {
+ wpa_printf(MSG_ERROR,
+ "OCV: PMF needs to be enabled whenever using OCV");
+ return -1;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
@@ -928,8 +1165,15 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
bss->rsn_pairwise = bss->wpa_pairwise;
- bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
- bss->rsn_pairwise);
+ if (bss->group_cipher)
+ bss->wpa_group = bss->group_cipher;
+ else
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+ bss->wpa_pairwise,
+ bss->rsn_pairwise);
+ if (!bss->wpa_group_rekey_set)
+ bss->wpa_group_rekey = bss->wpa_group == WPA_CIPHER_TKIP ?
+ 600 : 86400;
if (full_config) {
bss->radius->auth_server = bss->radius->auth_servers;
@@ -983,3 +1227,26 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
}
}
}
+
+
+int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
+{
+ int with_id = 0, without_id = 0;
+ struct sae_password_entry *pw;
+
+ if (conf->ssid.wpa_passphrase)
+ without_id = 1;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->identifier)
+ with_id = 1;
+ else
+ without_id = 1;
+ if (with_id && without_id)
+ break;
+ }
+
+ if (with_id && !without_id)
+ return 2;
+ return with_id;
+}
diff --git a/contrib/wpa/src/ap/ap_config.h b/contrib/wpa/src/ap/ap_config.h
index de470a9..509677a 100644
--- a/contrib/wpa/src/ap/ap_config.h
+++ b/contrib/wpa/src/ap/ap_config.h
@@ -10,12 +10,14 @@
#define HOSTAPD_CONFIG_H
#include "common/defs.h"
+#include "utils/list.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
#include "fst/fst.h"
+#include "vlan.h"
/**
* mesh_conf - local MBSS state and settings
@@ -39,6 +41,11 @@ struct mesh_conf {
#define MESH_CONF_SEC_AUTH BIT(1)
#define MESH_CONF_SEC_AMPE BIT(2)
unsigned int security;
+ enum mfp_options ieee80211w;
+ int ocv;
+ unsigned int pairwise_cipher;
+ unsigned int group_cipher;
+ unsigned int mgmt_group_cipher;
int dot11MeshMaxRetries;
int dot11MeshRetryTimeout; /* msec */
int dot11MeshConfirmTimeout; /* msec */
@@ -52,7 +59,7 @@ typedef u8 macaddr[ETH_ALEN];
struct mac_acl_entry {
macaddr addr;
- int vlan_id;
+ struct vlan_description vlan_id;
};
struct hostapd_radius_servers;
@@ -102,6 +109,7 @@ struct hostapd_ssid {
#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
#define DYNAMIC_VLAN_NAMING_END 2
int vlan_naming;
+ int per_sta_vif;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -113,7 +121,9 @@ struct hostapd_ssid {
struct hostapd_vlan {
struct hostapd_vlan *next;
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+ struct vlan_description vlan_desc;
char ifname[IFNAMSIZ + 1];
+ char bridge[IFNAMSIZ + 1];
int configured;
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -124,17 +134,25 @@ struct hostapd_vlan {
};
#define PMK_LEN 32
+#define KEYID_LEN 32
+#define MIN_PASSPHRASE_LEN 8
+#define MAX_PASSPHRASE_LEN 63
struct hostapd_sta_wpa_psk_short {
struct hostapd_sta_wpa_psk_short *next;
+ unsigned int is_passphrase:1;
u8 psk[PMK_LEN];
+ char passphrase[MAX_PASSPHRASE_LEN + 1];
+ int ref; /* (number of references held) - 1 */
};
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
+ char keyid[KEYID_LEN];
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
+ int vlan_id;
};
struct hostapd_eap_user {
@@ -147,6 +165,8 @@ struct hostapd_eap_user {
} methods[EAP_MAX_METHODS];
u8 *password;
size_t password_len;
+ u8 *salt;
+ size_t salt_len; /* non-zero when password is salted */
int phase2;
int force_version;
unsigned int wildcard_prefix:1;
@@ -156,6 +176,7 @@ struct hostapd_eap_user {
unsigned int macacl:1;
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
struct hostapd_radius_attr *accept_attr;
+ u32 t_c_timestamp;
};
struct hostapd_radius_attr {
@@ -188,6 +209,12 @@ struct hostapd_lang_string {
u8 name[252];
};
+struct hostapd_venue_url {
+ u8 venue_number;
+ u8 url_len;
+ u8 url[254];
+};
+
#define MAX_NAI_REALMS 10
#define MAX_NAI_REALMLEN 255
#define MAX_NAI_EAP_METHODS 5
@@ -205,6 +232,26 @@ struct hostapd_nai_realm_data {
} eap_method[MAX_NAI_EAP_METHODS];
};
+struct anqp_element {
+ struct dl_list list;
+ u16 infoid;
+ struct wpabuf *payload;
+};
+
+struct fils_realm {
+ struct dl_list list;
+ u8 hash[2];
+ char realm[];
+};
+
+struct sae_password_entry {
+ struct sae_password_entry *next;
+ char *password;
+ char *identifier;
+ u8 peer_addr[ETH_ALEN];
+ int vlan_id;
+};
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -222,7 +269,8 @@ struct hostapd_bss_config {
int max_num_sta; /* maximum number of STAs in station table */
int dtim_period;
- int bss_load_update_period;
+ unsigned int bss_load_update_period;
+ unsigned int chan_util_avg_period;
int ieee802_1x; /* use IEEE 802.1X */
int eapol_version;
@@ -231,6 +279,7 @@ struct hostapd_bss_config {
struct hostapd_eap_user *eap_user;
char *eap_user_sqlite;
char *eap_sim_db;
+ unsigned int eap_sim_db_timeout;
int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
@@ -242,6 +291,7 @@ struct hostapd_bss_config {
int radius_das_port;
unsigned int radius_das_time_window;
int radius_das_require_event_timestamp;
+ int radius_das_require_message_authenticator;
struct hostapd_ip_addr radius_das_client_addr;
u8 *radius_das_shared_secret;
size_t radius_das_shared_secret_len;
@@ -265,7 +315,7 @@ struct hostapd_bss_config {
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
* frames */
- enum {
+ enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
USE_EXTERNAL_RADIUS_AUTH = 2
@@ -291,33 +341,46 @@ struct hostapd_bss_config {
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ int ocv; /* Operating Channel Validation */
+#endif /* CONFIG_OCV */
enum {
PSK_RADIUS_IGNORED = 0,
PSK_RADIUS_ACCEPTED = 1,
PSK_RADIUS_REQUIRED = 2
} wpa_psk_radius;
int wpa_pairwise;
+ int group_cipher; /* wpa_group value override from configuation */
int wpa_group;
int wpa_group_rekey;
+ int wpa_group_rekey_set;
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ u32 wpa_group_update_count;
+ u32 wpa_pairwise_update_count;
+ int wpa_disable_eapol_key_retries;
int rsn_pairwise;
int rsn_preauth;
char *rsn_preauth_interfaces;
- int peerkey;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
/* 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 r0_key_lifetime; /* PMK-R0 lifetime seconds */
+ int rkh_pos_timeout;
+ int rkh_neg_timeout;
+ int rkh_pull_timeout; /* ms */
+ int rkh_pull_retries;
u32 reassociation_deadline;
struct ft_remote_r0kh *r0kh_list;
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
int ft_over_ds;
-#endif /* CONFIG_IEEE80211R */
+ int ft_psk_generate_local;
+ int r1_max_key_lifetime;
+#endif /* CONFIG_IEEE80211R_AP */
char *ctrl_interface; /* directory for UNIX domain sockets */
#ifndef CONFIG_NATIVE_WINDOWS
@@ -329,11 +392,17 @@ struct hostapd_bss_config {
char *server_cert;
char *private_key;
char *private_key_passwd;
+ char *check_cert_subject;
int check_crl;
+ int check_crl_strict;
+ unsigned int crl_reload_interval;
unsigned int tls_session_lifetime;
+ unsigned int tls_flags;
char *ocsp_stapling_response;
+ char *ocsp_stapling_response_multi;
char *dh_file;
char *openssl_ciphers;
+ char *openssl_ecdh_curves;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
@@ -358,6 +427,7 @@ struct hostapd_bss_config {
int ap_max_inactivity;
int ignore_broadcast_ssid;
+ int no_probe_resp_if_max_sta;
int wmm_enabled;
int wmm_uapsd;
@@ -395,9 +465,11 @@ struct hostapd_bss_config {
u8 *extra_cred;
size_t extra_cred_len;
int wps_cred_processing;
+ int wps_cred_add_sae;
int force_per_enrollee_psk;
u8 *ap_settings;
size_t ap_settings_len;
+ struct hostapd_ssid multi_ap_backhaul_ssid;
char *upnp_iface;
char *friendly_name;
char *manufacturer_url;
@@ -440,6 +512,7 @@ struct hostapd_bss_config {
int time_advertisement;
char *time_zone;
int wnm_sleep_mode;
+ int wnm_sleep_mode_no_keys;
int bss_transition;
/* IEEE 802.11u - Interworking */
@@ -462,6 +535,10 @@ struct hostapd_bss_config {
unsigned int venue_name_count;
struct hostapd_lang_string *venue_name;
+ /* Venue URL duples */
+ unsigned int venue_url_count;
+ struct hostapd_venue_url *venue_url;
+
/* IEEE 802.11u - Network Authentication Type */
u8 *network_auth_type;
size_t network_auth_type_len;
@@ -481,8 +558,11 @@ struct hostapd_bss_config {
unsigned int nai_realm_count;
struct hostapd_nai_realm_data *nai_realm_data;
+ struct dl_list anqp_elem; /* list of struct anqp_element */
+
u16 gas_comeback_delay;
- int gas_frag_limit;
+ size_t gas_frag_limit;
+ int gas_address3;
u8 qos_map_set[16 + 2 * 21];
unsigned int qos_map_set_len;
@@ -492,6 +572,7 @@ struct hostapd_bss_config {
int na_mcast_to_ucast;
#ifdef CONFIG_HS20
int hs20;
+ int hs20_release;
int disable_dgaf;
u16 anqp_domain_id;
unsigned int hs20_oper_friendly_name_count;
@@ -520,13 +601,21 @@ struct hostapd_bss_config {
char **icons;
size_t icons_count;
char *osu_nai;
+ char *osu_nai2;
unsigned int service_desc_count;
struct hostapd_lang_string *service_desc;
} *hs20_osu_providers, *last_osu;
size_t hs20_osu_providers_count;
+ size_t hs20_osu_providers_nai_count;
+ char **hs20_operator_icon;
+ size_t hs20_operator_icon_count;
unsigned int hs20_deauth_req_timeout;
char *subscr_remediation_url;
u8 subscr_remediation_method;
+ char *hs20_sim_provisioning_url;
+ char *t_c_filename;
+ u32 t_c_timestamp;
+ char *t_c_server_url;
#endif /* CONFIG_HS20 */
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
@@ -536,9 +625,13 @@ struct hostapd_bss_config {
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
+ struct wpabuf *assocresp_elements;
unsigned int sae_anti_clogging_threshold;
+ unsigned int sae_sync;
+ int sae_require_mfp;
int *sae_groups;
+ struct sae_password_entry *sae_passwords;
char *wowlan_triggers; /* Wake-on-WLAN triggers */
@@ -546,19 +639,96 @@ struct hostapd_bss_config {
u8 bss_load_test[5];
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
+ int sae_reflection_attack;
+ struct wpabuf *sae_commit_override;
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
int mesh;
- int radio_measurements;
+ u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
int vendor_vht;
+ int use_sta_nsts;
char *no_probe_resp_if_seen_on;
char *no_auth_if_seen_on;
+
+ int pbss;
+
+#ifdef CONFIG_MBO
+ int mbo_enabled;
+ /**
+ * oce - Enable OCE in AP and/or STA-CFON mode
+ * - BIT(0) is Reserved
+ * - Set BIT(1) to enable OCE in STA-CFON mode
+ * - Set BIT(2) to enable OCE in AP mode
+ */
+ unsigned int oce;
+ int mbo_cell_data_conn_pref;
+#endif /* CONFIG_MBO */
+
+ int ftm_responder;
+ int ftm_initiator;
+
+#ifdef CONFIG_FILS
+ u8 fils_cache_id[FILS_CACHE_ID_LEN];
+ int fils_cache_id_set;
+ struct dl_list fils_realms; /* list of struct fils_realm */
+ int fils_dh_group;
+ struct hostapd_ip_addr dhcp_server;
+ int dhcp_rapid_commit_proxy;
+ unsigned int fils_hlp_wait_time;
+ u16 dhcp_server_port;
+ u16 dhcp_relay_port;
+#endif /* CONFIG_FILS */
+
+ int multicast_to_unicast;
+
+ int broadcast_deauth;
+
+#ifdef CONFIG_DPP
+ char *dpp_connector;
+ struct wpabuf *dpp_netaccesskey;
+ unsigned int dpp_netaccesskey_expiry;
+ struct wpabuf *dpp_csign;
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_OWE
+ macaddr owe_transition_bssid;
+ u8 owe_transition_ssid[SSID_MAX_LEN];
+ size_t owe_transition_ssid_len;
+ char owe_transition_ifname[IFNAMSIZ + 1];
+ int *owe_groups;
+#endif /* CONFIG_OWE */
+
+ int coloc_intf_reporting;
+
+ u8 send_probe_response;
+
+#define BACKHAUL_BSS 1
+#define FRONTHAUL_BSS 2
+ int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
};
+/**
+ * struct he_phy_capabilities_info - HE PHY capabilities
+ */
+struct he_phy_capabilities_info {
+ Boolean he_su_beamformer;
+ Boolean he_su_beamformee;
+ Boolean he_mu_beamformer;
+};
+
+/**
+ * struct he_operation - HE operation
+ */
+struct he_operation {
+ u8 he_bss_color;
+ u8 he_default_pe_duration;
+ u8 he_twt_required;
+ u8 he_rts_threshold;
+};
/**
* struct hostapd_config - Per-radio interface configuration
@@ -570,10 +740,10 @@ struct hostapd_config {
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
- u8 send_probe_response;
u8 channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
+ int acs_exclude_dfs;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
@@ -582,6 +752,8 @@ struct hostapd_config {
int *supported_rates;
int *basic_rates;
+ unsigned int beacon_rate;
+ enum beacon_rate_type rate_type;
const struct wpa_driver_ops *driver;
char *driver_params;
@@ -597,6 +769,9 @@ struct hostapd_config {
* ' ' (ascii 32): all environments
* 'O': Outdoor environemnt only
* 'I': Indoor environment only
+ * 'X': Used with noncountry entity ("XXX")
+ * 0x00..0x31: identifying IEEE 802.11 standard
+ * Annex E table (0x04 = global table)
*/
int ieee80211d;
@@ -637,6 +812,10 @@ struct hostapd_config {
u8 vht_oper_chwidth;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
+ u8 ht40_plus_minus_allowed;
+
+ /* Use driver-generated interface addresses when adding multiple BSSs */
+ u8 use_driver_iface_addr;
#ifdef CONFIG_FST
struct fst_iface_cfg fst_cfg;
@@ -652,6 +831,7 @@ struct hostapd_config {
double ignore_assoc_probability;
double ignore_reassoc_probability;
double corrupt_gtk_rekey_mic_probability;
+ int ecsa_ie_only;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_ACS
@@ -662,25 +842,45 @@ struct hostapd_config {
} *acs_chan_bias;
unsigned int num_acs_chan_bias;
#endif /* CONFIG_ACS */
+
+ struct wpabuf *lci;
+ struct wpabuf *civic;
+ int stationary_ap;
+
+ int ieee80211ax;
+#ifdef CONFIG_IEEE80211AX
+ struct he_phy_capabilities_info he_phy_capab;
+ struct he_operation he_op;
+ struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
+#endif /* CONFIG_IEEE80211AX */
+
+ /* VHT enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_VHT_ENABLED BIT(0)
+#define CH_SWITCH_VHT_DISABLED BIT(1)
+ unsigned int ch_switch_vht_config;
+
+ int rssi_reject_assoc_rssi;
+ int rssi_reject_assoc_timeout;
};
int hostapd_mac_comp(const void *a, const void *b);
-int hostapd_mac_comp_empty(const void *a);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
+void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
- const u8 *addr, int *vlan_id);
+ const u8 *addr, struct vlan_description *vlan_id);
int hostapd_rate_found(int *list, int rate);
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *p2p_dev_addr,
- const u8 *prev_psk);
+ const u8 *prev_psk, int *vlan_id);
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
-int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
+int hostapd_vlan_valid(struct hostapd_vlan *vlan,
+ struct vlan_description *vlan_desc);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
struct hostapd_radius_attr *
@@ -688,5 +888,6 @@ hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
+int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/contrib/wpa/src/ap/ap_drv_ops.c b/contrib/wpa/src/ap/ap_drv_ops.c
index 6cafcb7..067cf86 100644
--- a/contrib/wpa/src/ap/ap_drv_ops.c
+++ b/contrib/wpa/src/ap/ap_drv_ops.c
@@ -19,6 +19,7 @@
#include "ap_config.h"
#include "p2p_hostapd.h"
#include "hs20.h"
+#include "wpa_auth.h"
#include "ap_drv_ops.h"
@@ -33,10 +34,36 @@ u32 hostapd_sta_flags_to_drv(u32 flags)
res |= WPA_STA_SHORT_PREAMBLE;
if (flags & WLAN_STA_MFP)
res |= WPA_STA_MFP;
+ if (flags & WLAN_STA_AUTH)
+ res |= WPA_STA_AUTHENTICATED;
+ if (flags & WLAN_STA_ASSOC)
+ res |= WPA_STA_ASSOCIATED;
return res;
}
+static int add_buf(struct wpabuf **dst, const struct wpabuf *src)
+{
+ if (!src)
+ return 0;
+ if (wpabuf_resize(dst, wpabuf_len(src)) != 0)
+ return -1;
+ wpabuf_put_buf(*dst, src);
+ return 0;
+}
+
+
+static int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len)
+{
+ if (!data || !len)
+ return 0;
+ if (wpabuf_resize(dst, len) != 0)
+ return -1;
+ wpabuf_put_data(*dst, data, len);
+ return 0;
+}
+
+
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
struct wpabuf **beacon_ret,
struct wpabuf **proberesp_ret,
@@ -49,82 +76,45 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
pos = buf;
pos = hostapd_eid_time_adv(hapd, pos);
- if (pos != buf) {
- if (wpabuf_resize(&beacon, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(beacon, buf, pos - buf);
- }
+ if (add_buf_data(&beacon, buf, pos - buf) < 0)
+ goto fail;
pos = hostapd_eid_time_zone(hapd, pos);
- if (pos != buf) {
- if (wpabuf_resize(&proberesp, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(proberesp, buf, pos - buf);
- }
+ if (add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
pos = buf;
pos = hostapd_eid_ext_capab(hapd, pos);
- if (pos != buf) {
- if (wpabuf_resize(&assocresp, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(assocresp, buf, pos - buf);
- }
+ if (add_buf_data(&assocresp, buf, pos - buf) < 0)
+ goto fail;
pos = hostapd_eid_interworking(hapd, pos);
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
- if (pos != buf) {
- if (wpabuf_resize(&beacon, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(beacon, buf, pos - buf);
-
- if (wpabuf_resize(&proberesp, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(proberesp, buf, pos - buf);
- }
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
#ifdef CONFIG_FST
- if (hapd->iface->fst_ies) {
- size_t add = wpabuf_len(hapd->iface->fst_ies);
-
- if (wpabuf_resize(&beacon, add) < 0)
- goto fail;
- wpabuf_put_buf(beacon, hapd->iface->fst_ies);
- if (wpabuf_resize(&proberesp, add) < 0)
- goto fail;
- wpabuf_put_buf(proberesp, hapd->iface->fst_ies);
- if (wpabuf_resize(&assocresp, add) < 0)
- goto fail;
- wpabuf_put_buf(assocresp, hapd->iface->fst_ies);
- }
+ if (add_buf(&beacon, hapd->iface->fst_ies) < 0 ||
+ add_buf(&proberesp, hapd->iface->fst_ies) < 0 ||
+ add_buf(&assocresp, hapd->iface->fst_ies) < 0)
+ goto fail;
#endif /* CONFIG_FST */
- if (hapd->wps_beacon_ie) {
- if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
- 0)
- goto fail;
- wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
- }
+#ifdef CONFIG_FILS
+ pos = hostapd_eid_fils_indic(hapd, buf, 0);
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
+#endif /* CONFIG_FILS */
- if (hapd->wps_probe_resp_ie) {
- if (wpabuf_resize(&proberesp,
- wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
- goto fail;
- wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
- }
+ if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
+ add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
+ goto fail;
#ifdef CONFIG_P2P
- if (hapd->p2p_beacon_ie) {
- if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
- 0)
- goto fail;
- wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
- }
-
- if (hapd->p2p_probe_resp_ie) {
- if (wpabuf_resize(&proberesp,
- wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
- goto fail;
- wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
- }
+ if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 ||
+ add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0)
+ goto fail;
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
@@ -148,8 +138,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
#ifdef CONFIG_WPS
if (hapd->conf->wps_state) {
struct wpabuf *a = wps_build_assoc_resp_ie();
- if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
- wpabuf_put_buf(assocresp, a);
+ add_buf(&assocresp, a);
wpabuf_free(a);
}
#endif /* CONFIG_WPS */
@@ -169,44 +158,44 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
if (hapd->p2p_group) {
struct wpabuf *a;
a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
- if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
- wpabuf_put_buf(assocresp, a);
+ add_buf(&assocresp, a);
wpabuf_free(a);
}
#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_HS20
- pos = buf;
- pos = hostapd_eid_hs20_indication(hapd, pos);
- if (pos != buf) {
- if (wpabuf_resize(&beacon, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(beacon, buf, pos - buf);
-
- if (wpabuf_resize(&proberesp, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(proberesp, buf, pos - buf);
- }
+ pos = hostapd_eid_hs20_indication(hapd, buf);
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
pos = hostapd_eid_osen(hapd, buf);
- if (pos != buf) {
- if (wpabuf_resize(&beacon, pos - buf) != 0)
- goto fail;
- wpabuf_put_data(beacon, buf, pos - buf);
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
+#endif /* CONFIG_HS20 */
- if (wpabuf_resize(&proberesp, pos - buf) != 0)
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled ||
+ OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
+ pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0 ||
+ add_buf_data(&assocresp, buf, pos - buf) < 0)
goto fail;
- wpabuf_put_data(proberesp, buf, pos - buf);
}
-#endif /* CONFIG_HS20 */
+#endif /* CONFIG_MBO */
- if (hapd->conf->vendor_elements) {
- size_t add = wpabuf_len(hapd->conf->vendor_elements);
- if (wpabuf_resize(&beacon, add) == 0)
- wpabuf_put_buf(beacon, hapd->conf->vendor_elements);
- if (wpabuf_resize(&proberesp, add) == 0)
- wpabuf_put_buf(proberesp, hapd->conf->vendor_elements);
- }
+#ifdef CONFIG_OWE
+ pos = hostapd_eid_owe_trans(hapd, buf, sizeof(buf));
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
+#endif /* CONFIG_OWE */
+
+ add_buf(&beacon, hapd->conf->vendor_elements);
+ add_buf(&proberesp, hapd->conf->vendor_elements);
+ add_buf(&assocresp, hapd->conf->assocresp_elements);
*beacon_ret = beacon;
*proberesp_ret = proberesp;
@@ -367,10 +356,44 @@ int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
u16 seq, u16 status, const u8 *ie, size_t len)
{
+ struct wpa_driver_sta_auth_params params;
+#ifdef CONFIG_FILS
+ struct sta_info *sta;
+#endif /* CONFIG_FILS */
+
if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
return 0;
- return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
- seq, status, ie, len);
+
+ os_memset(&params, 0, sizeof(params));
+
+#ifdef CONFIG_FILS
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for sta_auth processing",
+ MAC2STR(addr));
+ return 0;
+ }
+
+ if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ params.fils_auth = 1;
+ wpa_auth_get_fils_aead_params(sta->wpa_sm, params.fils_anonce,
+ params.fils_snonce,
+ params.fils_kek,
+ &params.fils_kek_len);
+ }
+#endif /* CONFIG_FILS */
+
+ params.own_addr = hapd->own_addr;
+ params.addr = addr;
+ params.seq = seq;
+ params.status = status;
+ params.ie = ie;
+ params.len = len;
+
+ return hapd->driver->sta_auth(hapd->drv_priv, &params);
}
@@ -390,7 +413,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo, u8 vht_opmode)
+ u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+ int set)
{
struct hostapd_sta_add_params params;
@@ -412,6 +436,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
+ params.support_p2p_ps = supp_p2p_ps;
+ params.set = set;
return hapd->driver->sta_add(hapd->drv_priv, &params);
}
@@ -468,7 +494,7 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
return -1;
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
bss_ctx, drv_priv, force_ifname, if_addr,
- bridge, use_existing);
+ bridge, use_existing, 1);
}
@@ -578,13 +604,13 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
- u16 *flags)
+ u16 *flags, u8 *dfs_domain)
{
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);
+ flags, dfs_domain);
}
@@ -647,16 +673,28 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack)
{
+ if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
+ NULL, 0);
+}
+
+
+int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len)
+{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
+ csa_offs, csa_offs_len);
}
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
- if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+ if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
return 0;
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
reason);
@@ -666,7 +704,7 @@ int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
- if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+ if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
return 0;
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
@@ -687,6 +725,45 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
{
+ const u8 *bssid;
+ const u8 wildcard_bssid[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
+ return 0;
+ bssid = hapd->own_addr;
+ if (!is_multicast_ether_addr(dst) &&
+ len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+ struct sta_info *sta;
+
+ /*
+ * Public Action frames to a STA that is not a member of the BSS
+ * shall use wildcard BSSID value.
+ */
+ sta = ap_get_sta(hapd, dst);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC))
+ bssid = wildcard_bssid;
+ } else if (is_broadcast_ether_addr(dst) &&
+ len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+ /*
+ * The only current use case of Public Action frames with
+ * broadcast destination address is DPP PKEX. That case is
+ * directing all devices and not just the STAs within the BSS,
+ * so have to use the wildcard BSSID value.
+ */
+ bssid = wildcard_bssid;
+ }
+ return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+ hapd->own_addr, bssid, data, len, 0);
+}
+
+
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+ unsigned int freq,
+ unsigned int wait, const u8 *dst,
+ const u8 *data, size_t len)
+{
if (hapd->driver == NULL || hapd->driver->send_action == NULL)
return 0;
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
@@ -736,7 +813,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
const u8 *qos_map_set, u8 qos_map_set_len)
{
- if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
+ if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
return 0;
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
qos_map_set_len);
@@ -756,12 +833,28 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
if ((acs_ch_list_all ||
freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
chan->chan)) &&
- !(chan->flag & HOSTAPD_CHAN_DISABLED))
+ !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ !(hapd->iface->conf->acs_exclude_dfs &&
+ (chan->flag & HOSTAPD_CHAN_RADAR)))
int_array_add_unique(freq_list, chan->freq);
}
}
+void hostapd_get_ext_capa(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+
+ if (!hapd->driver || !hapd->driver->get_ext_capab)
+ return;
+
+ hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
+ &iface->extended_capa,
+ &iface->extended_capa_mask,
+ &iface->extended_capa_len);
+}
+
+
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
@@ -797,6 +890,9 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
&hapd->iface->conf->acs_ch_list,
chan->chan))
continue;
+ if (hapd->iface->conf->acs_exclude_dfs &&
+ (chan->flag & HOSTAPD_CHAN_RADAR))
+ continue;
if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
channels[num_channels++] = chan->chan;
int_array_add_unique(&freq_list, chan->freq);
diff --git a/contrib/wpa/src/ap/ap_drv_ops.h b/contrib/wpa/src/ap/ap_drv_ops.h
index 82eaf3f..de40171 100644
--- a/contrib/wpa/src/ap/ap_drv_ops.h
+++ b/contrib/wpa/src/ap/ap_drv_ops.h
@@ -41,7 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo, u8 vht_opmode);
+ u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+ int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
@@ -71,7 +72,7 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time);
struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
- u16 *flags);
+ u16 *flags, u8 *dfs_domain);
int hostapd_driver_commit(struct hostapd_data *hapd);
int hostapd_drv_none(struct hostapd_data *hapd);
int hostapd_driver_scan(struct hostapd_data *hapd,
@@ -88,6 +89,9 @@ int hostapd_drv_set_key(const char *ifname,
const u8 *key, size_t key_len);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack);
+int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
@@ -95,6 +99,18 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len);
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+ unsigned int freq,
+ unsigned int wait, const u8 *dst,
+ const u8 *data, size_t len);
+static inline void
+hostapd_drv_send_action_cancel_wait(struct hostapd_data *hapd)
+{
+ if (!hapd->driver || !hapd->driver->send_action_cancel_wait ||
+ !hapd->drv_priv)
+ return;
+ hapd->driver->send_action_cancel_wait(hapd->drv_priv);
+}
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg);
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
@@ -120,6 +136,8 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
u8 qos_map_set_len);
+void hostapd_get_ext_capa(struct hostapd_iface *iface);
+
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
@@ -150,7 +168,7 @@ static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
const u8 *addr)
{
- if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+ if (!hapd->driver || !hapd->driver->sta_remove || !hapd->drv_priv)
return 0;
return hapd->driver->sta_remove(hapd->drv_priv, addr);
}
@@ -264,8 +282,9 @@ static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings)
{
- if (hapd->driver == NULL || hapd->driver->switch_channel == NULL)
- return -ENOTSUP;
+ if (hapd->driver == NULL || hapd->driver->switch_channel == NULL ||
+ hapd->drv_priv == NULL)
+ return -1;
return hapd->driver->switch_channel(hapd->drv_priv, settings);
}
@@ -273,7 +292,7 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
- if (hapd->driver == NULL || hapd->driver->status == NULL)
+ if (!hapd->driver || !hapd->driver->status || !hapd->drv_priv)
return -1;
return hapd->driver->status(hapd->drv_priv, buf, buflen);
}
@@ -332,9 +351,27 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
{
- if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+ if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
return 0;
return hapd->driver->stop_ap(hapd->drv_priv);
}
+static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
+ struct wpa_channel_info *ci)
+{
+ if (!hapd->driver || !hapd->driver->channel_info)
+ return -1;
+ return hapd->driver->channel_info(hapd->drv_priv, ci);
+}
+
+static inline int
+hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
+ struct external_auth *params)
+{
+ if (!hapd->driver || !hapd->drv_priv ||
+ !hapd->driver->send_external_auth_status)
+ return -1;
+ return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/contrib/wpa/src/ap/ap_mlme.c b/contrib/wpa/src/ap/ap_mlme.c
index 13604ed..db8a267 100644
--- a/contrib/wpa/src/ap/ap_mlme.c
+++ b/contrib/wpa/src/ap/ap_mlme.c
@@ -57,8 +57,13 @@ void mlme_authenticate_indication(struct hostapd_data *hapd,
HOSTAPD_LEVEL_DEBUG,
"MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
- if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
+ if (sta->auth_alg != WLAN_AUTH_FT &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
+ sta->auth_alg != WLAN_AUTH_FILS_PK &&
+ !(sta->flags & WLAN_STA_MFP))
mlme_deletekeys_request(hapd, sta);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
}
@@ -104,8 +109,12 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
HOSTAPD_LEVEL_DEBUG,
"MLME-ASSOCIATE.indication(" MACSTR ")",
MAC2STR(sta->addr));
- if (sta->auth_alg != WLAN_AUTH_FT)
+ if (sta->auth_alg != WLAN_AUTH_FT &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
+ sta->auth_alg != WLAN_AUTH_FILS_PK)
mlme_deletekeys_request(hapd, sta);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
}
@@ -128,8 +137,12 @@ void mlme_reassociate_indication(struct hostapd_data *hapd,
HOSTAPD_LEVEL_DEBUG,
"MLME-REASSOCIATE.indication(" MACSTR ")",
MAC2STR(sta->addr));
- if (sta->auth_alg != WLAN_AUTH_FT)
+ if (sta->auth_alg != WLAN_AUTH_FT &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
+ sta->auth_alg != WLAN_AUTH_FILS_PK)
mlme_deletekeys_request(hapd, sta);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
}
diff --git a/contrib/wpa/src/ap/authsrv.c b/contrib/wpa/src/ap/authsrv.c
index 934dcfc..eced6c7 100644
--- a/contrib/wpa/src/ap/authsrv.c
+++ b/contrib/wpa/src/ap/authsrv.c
@@ -71,19 +71,26 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
}
if (eap_user->password) {
- user->password = os_malloc(eap_user->password_len);
+ user->password = os_memdup(eap_user->password,
+ eap_user->password_len);
if (user->password == NULL)
goto out;
- os_memcpy(user->password, eap_user->password,
- eap_user->password_len);
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
+ if (eap_user->salt && eap_user->salt_len) {
+ user->salt = os_memdup(eap_user->salt,
+ eap_user->salt_len);
+ if (!user->salt)
+ goto out;
+ user->salt_len = eap_user->salt_len;
+ }
}
user->force_version = eap_user->force_version;
user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
user->accept_attr = eap_user->accept_attr;
+ user->t_c_timestamp = eap_user->t_c_timestamp;
rv = 0;
out:
@@ -129,10 +136,13 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
#ifdef CONFIG_HS20
srv.subscr_remediation_url = conf->subscr_remediation_url;
srv.subscr_remediation_method = conf->subscr_remediation_method;
+ srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url;
+ srv.t_c_server_url = conf->t_c_server_url;
#endif /* CONFIG_HS20 */
srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
srv.tls_session_lifetime = conf->tls_session_lifetime;
+ srv.tls_flags = conf->tls_flags;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@@ -146,6 +156,40 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
#endif /* RADIUS_SERVER */
+#ifdef EAP_TLS_FUNCS
+static void authsrv_tls_event(void *ctx, enum tls_event ev,
+ union tls_event_data *data)
+{
+ switch (ev) {
+ case TLS_CERT_CHAIN_SUCCESS:
+ wpa_printf(MSG_DEBUG, "authsrv: remote certificate verification success");
+ break;
+ case TLS_CERT_CHAIN_FAILURE:
+ wpa_printf(MSG_INFO, "authsrv: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
+ data->cert_fail.reason,
+ data->cert_fail.depth,
+ data->cert_fail.subject,
+ data->cert_fail.reason_txt);
+ break;
+ case TLS_PEER_CERTIFICATE:
+ wpa_printf(MSG_DEBUG, "authsrv: peer certificate: depth=%d serial_num=%s subject=%s",
+ data->peer_cert.depth,
+ data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
+ data->peer_cert.subject);
+ break;
+ case TLS_ALERT:
+ if (data->alert.is_local)
+ wpa_printf(MSG_DEBUG, "authsrv: local TLS alert: %s",
+ data->alert.description);
+ else
+ wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
+ data->alert.description);
+ break;
+ }
+}
+#endif /* EAP_TLS_FUNCS */
+
+
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef EAP_TLS_FUNCS
@@ -157,6 +201,19 @@ int authsrv_init(struct hostapd_data *hapd)
os_memset(&conf, 0, sizeof(conf));
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ if (hapd->conf->crl_reload_interval > 0 &&
+ hapd->conf->check_crl <= 0) {
+ wpa_printf(MSG_INFO,
+ "Cannot enable CRL reload functionality - it depends on check_crl being set");
+ } else if (hapd->conf->crl_reload_interval > 0) {
+ conf.crl_reload_interval =
+ hapd->conf->crl_reload_interval;
+ wpa_printf(MSG_INFO,
+ "Enabled CRL reload functionality");
+ }
+ conf.tls_flags = hapd->conf->tls_flags;
+ conf.event_cb = authsrv_tls_event;
+ conf.cb_ctx = hapd;
hapd->ssl_ctx = tls_init(&conf);
if (hapd->ssl_ctx == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize TLS");
@@ -171,8 +228,12 @@ int authsrv_init(struct hostapd_data *hapd)
params.private_key_passwd = hapd->conf->private_key_passwd;
params.dh_file = hapd->conf->dh_file;
params.openssl_ciphers = hapd->conf->openssl_ciphers;
+ params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves;
params.ocsp_stapling_response =
hapd->conf->ocsp_stapling_response;
+ params.ocsp_stapling_response_multi =
+ hapd->conf->ocsp_stapling_response_multi;
+ params.check_cert_subject = hapd->conf->check_cert_subject;
if (tls_global_set_params(hapd->ssl_ctx, &params)) {
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
@@ -181,7 +242,8 @@ int authsrv_init(struct hostapd_data *hapd)
}
if (tls_global_set_verify(hapd->ssl_ctx,
- hapd->conf->check_crl)) {
+ hapd->conf->check_crl,
+ hapd->conf->check_crl_strict)) {
wpa_printf(MSG_ERROR, "Failed to enable check_crl");
authsrv_deinit(hapd);
return -1;
@@ -193,6 +255,7 @@ int authsrv_init(struct hostapd_data *hapd)
if (hapd->conf->eap_sim_db) {
hapd->eap_sim_db_priv =
eap_sim_db_init(hapd->conf->eap_sim_db,
+ hapd->conf->eap_sim_db_timeout,
hostapd_sim_db_cb, hapd);
if (hapd->eap_sim_db_priv == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
diff --git a/contrib/wpa/src/ap/beacon.c b/contrib/wpa/src/ap/beacon.c
index 5fe8fd5..3e62991 100644
--- a/contrib/wpa/src/ap/beacon.c
+++ b/contrib/wpa/src/ap/beacon.c
@@ -16,6 +16,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/hw_features_common.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
@@ -29,6 +30,8 @@
#include "beacon.h"
#include "hs20.h"
#include "dfs.h"
+#include "taxonomy.h"
+#include "ieee802_11_auth.h"
#ifdef NEED_AP_MLME
@@ -36,18 +39,21 @@
static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
size_t len)
{
- if (!hapd->conf->radio_measurements || len < 2 + 4)
+ size_t i;
+
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i])
+ break;
+ }
+
+ if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
return eid;
*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
- *eid++ = 5;
- *eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
- WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- return eid;
+ *eid++ = RRM_CAPABILITIES_IE_LEN;
+ os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+ return eid + RRM_CAPABILITIES_IE_LEN;
}
@@ -297,65 +303,65 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
{
- u8 chan;
-
- if (!hapd->cs_freq_params.freq)
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->iface->cs_oper_class && hapd->iconf->ecsa_ie_only)
return eid;
+#endif /* CONFIG_TESTING_OPTIONS */
- if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
- NUM_HOSTAPD_MODES)
+ if (!hapd->cs_freq_params.channel)
return eid;
*eid++ = WLAN_EID_CHANNEL_SWITCH;
*eid++ = 3;
*eid++ = hapd->cs_block_tx;
- *eid++ = chan;
+ *eid++ = hapd->cs_freq_params.channel;
*eid++ = hapd->cs_count;
return eid;
}
-static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
+static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid)
{
- u8 sec_ch;
-
- if (!hapd->cs_freq_params.sec_channel_offset)
+ if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class)
return eid;
- if (hapd->cs_freq_params.sec_channel_offset == -1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
- else if (hapd->cs_freq_params.sec_channel_offset == 1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
- else
- return eid;
-
- *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
- *eid++ = 1;
- *eid++ = sec_ch;
+ *eid++ = WLAN_EID_EXT_CHANSWITCH_ANN;
+ *eid++ = 4;
+ *eid++ = hapd->cs_block_tx;
+ *eid++ = hapd->iface->cs_oper_class;
+ *eid++ = hapd->cs_freq_params.channel;
+ *eid++ = hapd->cs_count;
return eid;
}
-static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
- u8 *start, unsigned int *csa_counter_off)
+static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
{
- u8 *old_pos = pos;
+ u8 op_class, channel;
- if (!csa_counter_off)
- return pos;
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) ||
+ !hapd->iface->freq)
+ return eid;
- *csa_counter_off = 0;
- pos = hostapd_eid_csa(hapd, pos);
+ if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ &op_class, &channel) ==
+ NUM_HOSTAPD_MODES)
+ return eid;
- if (pos != old_pos) {
- /* save an offset to the counter - should be last byte */
- *csa_counter_off = pos - start - 1;
- pos = hostapd_eid_secondary_channel(hapd, pos);
- }
+ *eid++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
+ *eid++ = 2;
- return pos;
+ /* Current Operating Class */
+ *eid++ = op_class;
+
+ /* TODO: Advertise all the supported operating classes */
+ *eid++ = 0;
+
+ return eid;
}
@@ -364,7 +370,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
int is_p2p, size_t *resp_len)
{
struct ieee80211_mgmt *resp;
- u8 *pos, *epos;
+ u8 *pos, *epos, *csa_pos;
size_t buflen;
#define MAX_PROBERESP_LEN 768
@@ -387,6 +393,18 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
2 + sizeof(struct ieee80211_vht_operation);
}
+
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
+ 3 + sizeof(struct ieee80211_he_operation) +
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+ buflen += hostapd_mbo_ie_len(hapd);
+ buflen += hostapd_eid_owe_trans_len(hapd);
+
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -424,20 +442,39 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* Power Constraint element */
pos = hostapd_eid_pwr_constraint(hapd, pos);
+ /* CSA IE */
+ csa_pos = hostapd_eid_csa(hapd, pos);
+ if (csa_pos != pos)
+ hapd->cs_c_off_proberesp = csa_pos - (u8 *) resp - 1;
+ pos = csa_pos;
+
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
/* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos);
- /* RSN, MDIE, WPA */
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+ /* RSN, MDIE */
+ if (hapd->conf->wpa != WPA_PROTO_WPA)
+ pos = hostapd_eid_wpa(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+ /* eCSA IE */
+ csa_pos = hostapd_eid_ecsa(hapd, pos);
+ if (csa_pos != pos)
+ hapd->cs_c_off_ecsa_proberesp = csa_pos - (u8 *) resp - 1;
+ pos = csa_pos;
+
+ pos = hostapd_eid_supported_op_classes(hapd, pos);
+
#ifdef CONFIG_IEEE80211N
+ /* Secondary Channel Offset element */
+ /* TODO: The standard doesn't specify a position for this element. */
+ pos = hostapd_eid_secondary_channel(hapd, pos);
+
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
#endif /* CONFIG_IEEE80211N */
@@ -451,9 +488,6 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
- pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
- &hapd->cs_c_off_proberesp);
-
#ifdef CONFIG_FST
if (hapd->iface->fst_ies) {
os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
@@ -464,13 +498,32 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
+ pos = hostapd_eid_txpower_envelope(hapd, pos);
+ pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
}
+#endif /* CONFIG_IEEE80211AC */
+
+ pos = hostapd_eid_fils_indic(hapd, pos, 0);
+
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ pos = hostapd_eid_he_capab(hapd, pos);
+ pos = hostapd_eid_he_operation(hapd, pos);
+ pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
+ /* WPA */
+ if (hapd->conf->wpa == WPA_PROTO_WPA)
+ pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -501,6 +554,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
+ pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
+ pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
+
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@@ -537,8 +593,8 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
pos = ssid_list;
end = ssid_list + ssid_list_len;
- while (pos + 1 <= end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos >= 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[1] == 0)
wildcard = 1;
@@ -574,7 +630,7 @@ void sta_track_expire(struct hostapd_iface *iface, int force)
MAC2STR(info->addr));
dl_list_del(&info->list);
iface->num_sta_seen--;
- os_free(info);
+ sta_track_del(info);
}
}
@@ -592,7 +648,7 @@ static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
}
-void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
+void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal)
{
struct hostapd_sta_info *info;
@@ -602,13 +658,17 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
dl_list_del(&info->list);
dl_list_add_tail(&iface->sta_seen, &info->list);
os_get_reltime(&info->last_seen);
+ info->ssi_signal = ssi_signal;
return;
}
/* Add a new entry */
info = os_zalloc(sizeof(*info));
+ if (info == NULL)
+ return;
os_memcpy(info->addr, addr, ETH_ALEN);
os_get_reltime(&info->last_seen);
+ info->ssi_signal = ssi_signal;
if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
/* Expire oldest entry to make room for a new one */
@@ -648,6 +708,23 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
}
+#ifdef CONFIG_TAXONOMY
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+ struct wpabuf **probe_ie_taxonomy)
+{
+ struct hostapd_sta_info *info;
+
+ info = sta_track_get(iface, addr);
+ if (!info)
+ return;
+
+ wpabuf_free(*probe_ie_taxonomy);
+ *probe_ie_taxonomy = info->probe_ie_taxonomy;
+ info->probe_ie_taxonomy = NULL;
+}
+#endif /* CONFIG_TAXONOMY */
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
@@ -659,13 +736,32 @@ void handle_probe_req(struct hostapd_data *hapd,
size_t i, resp_len;
int noack;
enum ssid_match_result res;
-
- ie = mgmt->u.probe_req.variable;
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ int ret;
+ u16 csa_offs[2];
+ size_t csa_offs_len;
+ u32 session_timeout, acct_interim_interval;
+ struct vlan_description vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
+ char *identity = NULL;
+ char *radius_cui = NULL;
+
+ if (len < IEEE80211_HDRLEN)
return;
+ ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
if (hapd->iconf->track_sta_max_num)
- sta_track_add(hapd->iface, mgmt->sa);
- ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
+ ie_len = len - IEEE80211_HDRLEN;
+
+ ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &session_timeout,
+ &acct_interim_interval, &vlan_id,
+ &psk, &identity, &radius_cui, 1);
+ if (ret == HOSTAPD_ACL_REJECT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Ignore Probe Request frame from " MACSTR
+ " due to ACL reject ", MAC2STR(mgmt->sa));
+ return;
+ }
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
@@ -673,7 +769,7 @@ void handle_probe_req(struct hostapd_data *hapd,
ie, ie_len, ssi_signal) > 0)
return;
- if (!hapd->iconf->send_probe_response)
+ if (!hapd->conf->send_probe_response)
return;
if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
@@ -711,7 +807,7 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#ifdef CONFIG_P2P
- if (hapd->p2p && elems.wps_ie) {
+ if (hapd->p2p && hapd->p2p_group && elems.wps_ie) {
struct wpabuf *wps;
wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
@@ -724,7 +820,7 @@ void handle_probe_req(struct hostapd_data *hapd,
wpabuf_free(wps);
}
- if (hapd->p2p && elems.p2p) {
+ if (hapd->p2p && hapd->p2p_group && elems.p2p) {
struct wpabuf *p2p;
p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE);
if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) {
@@ -754,6 +850,21 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_TAXONOMY
+ {
+ struct sta_info *sta;
+ struct hostapd_sta_info *info;
+
+ if ((sta = ap_get_sta(hapd, mgmt->sa)) != NULL) {
+ taxonomy_sta_info_probe_req(hapd, sta, ie, ie_len);
+ } else if ((info = sta_track_get(hapd->iface,
+ mgmt->sa)) != NULL) {
+ taxonomy_hostapd_sta_info_probe_req(hapd, info,
+ ie, ie_len);
+ }
+ }
+#endif /* CONFIG_TAXONOMY */
+
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
elems.ssid_list, elems.ssid_list_len);
if (res == NO_SSID_MATCH) {
@@ -825,6 +936,17 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
+ if (hapd->conf->no_probe_resp_if_max_sta &&
+ is_multicast_ether_addr(mgmt->da) &&
+ is_multicast_ether_addr(mgmt->bssid) &&
+ hapd->num_sta >= hapd->conf->max_num_sta &&
+ !ap_get_sta(hapd, mgmt->sa)) {
+ wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
+ " since no room for additional STA",
+ hapd->conf->iface, MAC2STR(mgmt->sa));
+ return;
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->iconf->ignore_probe_probability > 0.0 &&
drand48() < hapd->iconf->ignore_probe_probability) {
@@ -835,6 +957,9 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
+ " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
+
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
&resp_len);
if (resp == NULL)
@@ -847,7 +972,22 @@ void handle_probe_req(struct hostapd_data *hapd,
noack = !!(res == WILDCARD_SSID_MATCH &&
is_broadcast_ether_addr(mgmt->da));
- if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
+ csa_offs_len = 0;
+ if (hapd->csa_in_progress) {
+ if (hapd->cs_c_off_proberesp)
+ csa_offs[csa_offs_len++] =
+ hapd->cs_c_off_proberesp;
+
+ if (hapd->cs_c_off_ecsa_proberesp)
+ csa_offs[csa_offs_len++] =
+ hapd->cs_c_off_ecsa_proberesp;
+ }
+
+ ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
+ csa_offs_len ? csa_offs : NULL,
+ csa_offs_len);
+
+ if (ret < 0)
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
os_free(resp);
@@ -896,6 +1036,16 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+void sta_track_del(struct hostapd_sta_info *info)
+{
+#ifdef CONFIG_TAXONOMY
+ wpabuf_free(info->probe_ie_taxonomy);
+ info->probe_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+ os_free(info);
+}
+
+
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@@ -906,7 +1056,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
size_t resp_len = 0;
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos;
+ u8 *pos, *tailpos, *csa_pos;
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@@ -934,6 +1084,17 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
+ 3 + sizeof(struct ieee80211_he_operation) +
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+ tail_len += hostapd_mbo_ie_len(hapd);
+ tail_len += hostapd_eid_owe_trans_len(hapd);
+
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -987,15 +1148,23 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
/* Power Constraint element */
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
+ /* CSA IE */
+ csa_pos = hostapd_eid_csa(hapd, tailpos);
+ if (csa_pos != tailpos)
+ hapd->cs_c_off_beacon = csa_pos - tail - 1;
+ tailpos = csa_pos;
+
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);
/* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
- /* RSN, MDIE, WPA */
- tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
+ /* RSN, MDIE */
+ if (hapd->conf->wpa != WPA_PROTO_WPA)
+ tailpos = hostapd_eid_wpa(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE -
+ tailpos);
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
@@ -1004,7 +1173,19 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_bss_load(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ /* eCSA IE */
+ csa_pos = hostapd_eid_ecsa(hapd, tailpos);
+ if (csa_pos != tailpos)
+ hapd->cs_c_off_ecsa_beacon = csa_pos - tail - 1;
+ tailpos = csa_pos;
+
+ tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
+
#ifdef CONFIG_IEEE80211N
+ /* Secondary Channel Offset element */
+ /* TODO: The standard doesn't specify a position for this element. */
+ tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
+
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
#endif /* CONFIG_IEEE80211N */
@@ -1020,8 +1201,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_interworking(hapd, tailpos);
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
- tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
- &hapd->cs_c_off_beacon);
#ifdef CONFIG_FST
if (hapd->iface->fst_ies) {
@@ -1033,13 +1212,34 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
+ tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
}
+#endif /* CONFIG_IEEE80211AC */
+
+ tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ tailpos = hostapd_eid_he_capab(hapd, tailpos);
+ tailpos = hostapd_eid_he_operation(hapd, tailpos);
+ tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
+ /* WPA */
+ if (hapd->conf->wpa == WPA_PROTO_WPA)
+ tailpos = hostapd_eid_wpa(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE -
+ tailpos);
+
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -1069,6 +1269,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
+ tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
+ tailpos = hostapd_eid_owe_trans(hapd, tailpos,
+ tail + tail_len - tailpos);
+
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@@ -1090,6 +1294,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->dtim_period = hapd->conf->dtim_period;
params->beacon_int = hapd->iconf->beacon_int;
params->basic_rates = hapd->iface->basic_rates;
+ params->beacon_rate = hapd->iconf->beacon_rate;
+ params->rate_type = hapd->iconf->rate_type;
params->ssid = hapd->conf->ssid.ssid;
params->ssid_len = hapd->conf->ssid.ssid_len;
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
@@ -1153,6 +1359,20 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->osen = 1;
}
#endif /* CONFIG_HS20 */
+ params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
+ params->pbss = hapd->conf->pbss;
+
+ if (hapd->conf->ftm_responder) {
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_FTM_RESPONDER) {
+ params->ftm_responder = 1;
+ params->lci = hapd->iface->conf->lci;
+ params->civic = hapd->iface->conf->civic;
+ } else {
+ wpa_printf(MSG_WARNING,
+ "Not configuring FTM responder as the driver doesn't advertise support for it");
+ }
+ }
+
return 0;
}
diff --git a/contrib/wpa/src/ap/beacon.h b/contrib/wpa/src/ap/beacon.h
index d98f42e..a26e308 100644
--- a/contrib/wpa/src/ap/beacon.h
+++ b/contrib/wpa/src/ap/beacon.h
@@ -21,10 +21,13 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface);
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params);
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
-void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
+void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal);
+void sta_track_del(struct hostapd_sta_info *info);
void sta_track_expire(struct hostapd_iface *iface, int force);
struct hostapd_data *
sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
const char *ifname);
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+ struct wpabuf **probe_ie_taxonomy);
#endif /* BEACON_H */
diff --git a/contrib/wpa/src/ap/bss_load.c b/contrib/wpa/src/ap/bss_load.c
index fb63942..725d3cd 100644
--- a/contrib/wpa/src/ap/bss_load.c
+++ b/contrib/wpa/src/ap/bss_load.c
@@ -16,11 +16,35 @@
#include "beacon.h"
+static int get_bss_load_update_timeout(struct hostapd_data *hapd,
+ unsigned int *sec, unsigned int *usec)
+{
+ unsigned int update_period = hapd->conf->bss_load_update_period;
+ unsigned int beacon_int = hapd->iconf->beacon_int;
+ unsigned int update_timeout;
+
+ if (!update_period || !beacon_int) {
+ wpa_printf(MSG_ERROR,
+ "BSS Load: Invalid BSS load update configuration (period=%u beacon_int=%u)",
+ update_period, beacon_int);
+ return -1;
+ }
+
+ update_timeout = update_period * beacon_int;
+
+ *sec = ((update_timeout / 1000) * 1024) / 1000;
+ *usec = (update_timeout % 1000) * 1024;
+
+ return 0;
+}
+
+
static void update_channel_utilization(void *eloop_data, void *user_data)
{
struct hostapd_data *hapd = eloop_data;
unsigned int sec, usec;
int err;
+ struct hostapd_iface *iface = hapd->iface;
if (!(hapd->beacon_set_done && hapd->started))
return;
@@ -33,8 +57,24 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
ieee802_11_set_beacon(hapd);
- sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
- usec = (hapd->bss_load_update_timeout % 1000) * 1024;
+ if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
+ return;
+
+ if (hapd->conf->chan_util_avg_period) {
+ iface->chan_util_samples_sum += iface->channel_utilization;
+ iface->chan_util_num_sample_periods +=
+ hapd->conf->bss_load_update_period;
+ if (iface->chan_util_num_sample_periods >=
+ hapd->conf->chan_util_avg_period) {
+ iface->chan_util_average =
+ iface->chan_util_samples_sum /
+ (iface->chan_util_num_sample_periods /
+ hapd->conf->bss_load_update_period);
+ iface->chan_util_samples_sum = 0;
+ iface->chan_util_num_sample_periods = 0;
+ }
+ }
+
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
NULL);
}
@@ -42,17 +82,11 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
int bss_load_update_init(struct hostapd_data *hapd)
{
- struct hostapd_bss_config *conf = hapd->conf;
- struct hostapd_config *iconf = hapd->iconf;
unsigned int sec, usec;
- if (!conf->bss_load_update_period || !iconf->beacon_int)
+ if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
return -1;
- hapd->bss_load_update_timeout = conf->bss_load_update_period *
- iconf->beacon_int;
- sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
- usec = (hapd->bss_load_update_timeout % 1000) * 1024;
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
NULL);
return 0;
diff --git a/contrib/wpa/src/ap/ctrl_iface_ap.c b/contrib/wpa/src/ap/ctrl_iface_ap.c
index c98978f..c693715 100644
--- a/contrib/wpa/src/ap/ctrl_iface_ap.c
+++ b/contrib/wpa/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
/*
* Control interface for shared AP commands
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,6 +22,32 @@
#include "p2p_hostapd.h"
#include "ctrl_iface_ap.h"
#include "ap_drv_ops.h"
+#include "mbo_ap.h"
+#include "taxonomy.h"
+
+
+static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
+ size_t curr_len, const u8 *mcs_set)
+{
+ int ret;
+ size_t len = curr_len;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "ht_mcs_bitmask=");
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ /* 77 first bits (+ 3 reserved bits) */
+ len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
+
+ ret = os_snprintf(buf + len, buflen - len, "\n");
+ if (os_snprintf_error(buflen - len, ret))
+ return curr_len;
+ len += ret;
+
+ return len;
+}
static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
@@ -30,17 +56,111 @@ static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
{
struct hostap_sta_driver_data data;
int ret;
+ int len = 0;
if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
return 0;
ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
- "rx_bytes=%lu\ntx_bytes=%lu\n",
+ "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
+ "signal=%d\n",
data.rx_packets, data.tx_packets,
- data.rx_bytes, data.tx_bytes);
+ data.rx_bytes, data.tx_bytes, data.inactive_msec,
+ data.signal);
if (os_snprintf_error(buflen, ret))
return 0;
- return ret;
+ len += ret;
+
+ ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
+ data.current_rx_rate);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ if (data.flags & STA_DRV_DATA_RX_MCS) {
+ ret = os_snprintf(buf + len, buflen - len, " mcs %u",
+ data.rx_mcs);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
+ ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
+ data.rx_vhtmcs);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
+ ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
+ data.rx_vht_nss);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
+ ret = os_snprintf(buf + len, buflen - len, " shortGI");
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ ret = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+
+ ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
+ data.current_tx_rate);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ if (data.flags & STA_DRV_DATA_TX_MCS) {
+ ret = os_snprintf(buf + len, buflen - len, " mcs %u",
+ data.tx_mcs);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
+ ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
+ data.tx_vhtmcs);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
+ ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
+ data.tx_vht_nss);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
+ ret = os_snprintf(buf + len, buflen - len, " shortGI");
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ ret = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+
+ if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "rx_vht_mcs_map=%04x\n"
+ "tx_vht_mcs_map=%04x\n",
+ le_to_host16(sta->vht_capabilities->
+ vht_supported_mcs_set.rx_map),
+ le_to_host16(sta->vht_capabilities->
+ vht_supported_mcs_set.tx_map));
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
+ if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
+ len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
+ sta->ht_capabilities->
+ supported_mcs_set);
+ }
+
+ if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "last_ack_signal=%d\n", data.last_ack_rssi);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
+ return len;
}
@@ -87,6 +207,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
int len, res, ret, i;
+ const char *keyid;
if (!sta)
return 0;
@@ -161,6 +282,73 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
len += res;
}
+ res = mbo_ap_get_info(sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+
+ if (sta->supp_op_classes &&
+ buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
+ len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
+ len += wpa_snprintf_hex(buf + len, buflen - len,
+ sta->supp_op_classes + 1,
+ sta->supp_op_classes[0]);
+ len += os_snprintf(buf + len, buflen - len, "\n");
+ }
+
+ if (sta->power_capab) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "min_txpower=%d\n"
+ "max_txpower=%d\n",
+ sta->min_tx_power, sta->max_tx_power);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
+#ifdef CONFIG_IEEE80211AC
+ if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
+ res = os_snprintf(buf + len, buflen - len,
+ "vht_caps_info=0x%08x\n",
+ le_to_host32(sta->vht_capabilities->
+ vht_capabilities_info));
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_IEEE80211AC */
+
+#ifdef CONFIG_IEEE80211N
+ if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
+ res = os_snprintf(buf + len, buflen - len,
+ "ht_caps_info=0x%04x\n",
+ le_to_host16(sta->ht_capabilities->
+ ht_capabilities_info));
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_IEEE80211N */
+
+ if (sta->ext_capability &&
+ buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
+ len += os_snprintf(buf + len, buflen - len, "ext_capab=");
+ len += wpa_snprintf_hex(buf + len, buflen - len,
+ sta->ext_capability + 1,
+ sta->ext_capability[0]);
+ len += os_snprintf(buf + len, buflen - len, "\n");
+ }
+
+ if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "wds_sta_ifname=%s\n", sta->ifname_wds);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
+ keyid = ap_sta_wpa_get_keyid(hapd, sta);
+ if (keyid) {
+ ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
return len;
}
@@ -244,7 +432,7 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
int ret;
u8 *pos;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
mgmt = os_zalloc(sizeof(*mgmt) + 100);
@@ -255,7 +443,7 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
" with minor reason code %u (stype=%u (%s))",
MAC2STR(addr), minor_reason_code, stype,
- fc2str(mgmt->frame_control));
+ fc2str(le_to_host16(mgmt->frame_control)));
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
@@ -263,11 +451,11 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
if (stype == WLAN_FC_STYPE_DEAUTH) {
mgmt->u.deauth.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+ pos = mgmt->u.deauth.variable;
} else {
mgmt->u.disassoc.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
+ pos = mgmt->u.disassoc.variable;
}
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
@@ -311,7 +499,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
pos += 6;
encrypt = atoi(pos);
@@ -338,7 +526,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_deauth(hapd, addr, reason);
+ if (os_strstr(txtaddr, " tx=0"))
+ hostapd_drv_sta_remove(hapd, addr);
+ else
+ hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_deauthenticate(hapd, sta, reason);
@@ -371,7 +562,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
pos += 6;
encrypt = atoi(pos);
@@ -398,7 +589,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_disassoc(hapd, addr, reason);
+ if (os_strstr(txtaddr, " tx=0"))
+ hostapd_drv_sta_remove(hapd, addr);
+ else
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_disassociate(hapd, sta, reason);
@@ -409,11 +603,55 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
}
+#ifdef CONFIG_TAXONOMY
+int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
+}
+#endif /* CONFIG_TAXONOMY */
+
+
+int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
+ sta->flags & WLAN_STA_WMM);
+ return 0;
+}
+
+
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
struct hostapd_iface *iface = hapd->iface;
- int len = 0, ret;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ int len = 0, ret, j;
size_t i;
ret = os_snprintf(buf + len, buflen - len,
@@ -474,19 +712,92 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
- "vht_oper_chwidth=%d\n"
- "vht_oper_centr_freq_seg0_idx=%d\n"
- "vht_oper_centr_freq_seg1_idx=%d\n",
+ "beacon_int=%u\n"
+ "dtim_period=%d\n",
iface->conf->channel,
- iface->conf->secondary_channel,
- iface->conf->ieee80211n,
- iface->conf->ieee80211ac,
- iface->conf->vht_oper_chwidth,
- iface->conf->vht_oper_centr_freq_seg0_idx,
- iface->conf->vht_oper_centr_freq_seg1_idx);
+ iface->conf->ieee80211n && !hapd->conf->disable_11n ?
+ iface->conf->secondary_channel : 0,
+ iface->conf->ieee80211n && !hapd->conf->disable_11n,
+ iface->conf->ieee80211ac &&
+ !hapd->conf->disable_11ac,
+ iface->conf->beacon_int,
+ hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+ if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "vht_oper_chwidth=%d\n"
+ "vht_oper_centr_freq_seg0_idx=%d\n"
+ "vht_oper_centr_freq_seg1_idx=%d\n"
+ "vht_caps_info=%08x\n",
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx,
+ iface->conf->vht_capab);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
+ u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
+ u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "rx_vht_mcs_map=%04x\n"
+ "tx_vht_mcs_map=%04x\n",
+ rxmap, txmap);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "ht_caps_info=%04x\n",
+ hapd->iconf->ht_capab);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
+ len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
+ mode->mcs_set);
+ }
+
+ if (iface->current_rates && iface->num_rates) {
+ ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ for (j = 0; j < iface->num_rates; j++) {
+ ret = os_snprintf(buf + len, buflen - len, "%s%02x",
+ j > 0 ? " " : "",
+ iface->current_rates[j].rate / 5);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+ ret = os_snprintf(buf + len, buflen - len, "\n");
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ for (j = 0; mode && j < mode->num_channels; j++) {
+ if (mode->channels[j].freq == iface->freq) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "max_txpower=%u\n",
+ mode->channels[j].max_tx_power);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ break;
+ }
+ }
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *bss = iface->bss[i];
@@ -506,6 +817,15 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
len += ret;
}
+ if (hapd->conf->chan_util_avg_period) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "chan_util_avg=%u\n",
+ iface->chan_util_average);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
return len;
}
@@ -554,3 +874,121 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
{
return hostapd_drv_stop_ap(hapd);
}
+
+
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+ size_t len)
+{
+ return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
+}
+
+
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
+{
+ wpa_auth_pmksa_flush(hapd->wpa_auth);
+}
+
+
+int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
+{
+ u8 spa[ETH_ALEN];
+ u8 pmkid[PMKID_LEN];
+ u8 pmk[PMK_LEN_MAX];
+ size_t pmk_len;
+ char *pos, *pos2;
+ int akmp = 0, expiration = 0;
+
+ /*
+ * Entry format:
+ * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
+ */
+
+ if (hwaddr_aton(cmd, spa))
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+
+ if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
+ return -1;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+
+ pos2 = os_strchr(pos, ' ');
+ if (!pos2)
+ return -1;
+ pmk_len = (pos2 - pos) / 2;
+ if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
+ hexstr2bin(pos, pmk, pmk_len) < 0)
+ return -1;
+
+ pos = pos2 + 1;
+
+ if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
+ return -1;
+
+ return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
+ pmkid, expiration, akmp);
+}
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
+ const u8 *addr, char *buf, size_t len)
+{
+ return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
+}
+
+
+void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
+{
+ u8 spa[ETH_ALEN];
+ u8 pmkid[PMKID_LEN];
+ u8 pmk[PMK_LEN_MAX];
+ char *pos;
+ int expiration;
+
+ /*
+ * Entry format:
+ * <BSSID> <PMKID> <PMK> <expiration in seconds>
+ */
+
+ if (hwaddr_aton(cmd, spa))
+ return NULL;
+
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ return NULL;
+ pos++;
+
+ if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
+ return NULL;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return NULL;
+ pos++;
+
+ if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
+ return NULL;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return NULL;
+ pos++;
+
+ if (sscanf(pos, "%d", &expiration) != 1)
+ return NULL;
+
+ return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
diff --git a/contrib/wpa/src/ap/ctrl_iface_ap.h b/contrib/wpa/src/ap/ctrl_iface_ap.h
index e5297d0..d1dcebf 100644
--- a/contrib/wpa/src/ap/ctrl_iface_ap.h
+++ b/contrib/wpa/src/ap/ctrl_iface_ap.h
@@ -19,10 +19,22 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
const char *txtaddr);
int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
const char *txtaddr);
+int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen);
+int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
+ const char *txtaddr);
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
size_t buflen);
int hostapd_parse_csa_settings(const char *pos,
struct csa_settings *settings);
int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+ size_t len);
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
+int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd);
+int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
+ const u8 *addr, char *buf, size_t len);
+void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd);
#endif /* CTRL_IFACE_AP_H */
diff --git a/contrib/wpa/src/ap/dfs.c b/contrib/wpa/src/ap/dfs.c
index 715f19b..79cd00f 100644
--- a/contrib/wpa/src/ap/dfs.c
+++ b/contrib/wpa/src/ap/dfs.c
@@ -1,7 +1,7 @@
/*
* DFS - Dynamic Frequency Selection
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2013-2015, Qualcomm Atheros, Inc.
+ * Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -142,18 +142,30 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
{
struct hostapd_channel_data *first_chan, *chan;
int i;
+ u32 bw = num_chan_to_bw(num_chans);
if (first_chan_idx + num_chans > mode->num_channels)
return 0;
first_chan = &mode->channels[first_chan_idx];
+ /* hostapd DFS implementation assumes the first channel as primary.
+ * If it's not allowed to use the first channel as primary, decline the
+ * whole channel range. */
+ if (!chan_pri_allowed(first_chan))
+ return 0;
+
for (i = 0; i < num_chans; i++) {
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx);
if (!chan)
return 0;
+ /* HT 40 MHz secondary channel availability checked only for
+ * primary channel */
+ if (!chan_bw_allowed(chan, bw, 1, !i))
+ return 0;
+
if (!dfs_channel_available(chan, skip_radar))
return 0;
}
@@ -197,7 +209,8 @@ static int dfs_find_channel(struct hostapd_iface *iface,
/* Skip HT40/VHT incompatible channels */
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
- !dfs_is_chan_allowed(chan, n_chans))
+ (!dfs_is_chan_allowed(chan, n_chans) ||
+ !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
continue;
/* Skip incompatible chandefs */
@@ -450,7 +463,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL;
if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
- _rand = os_random();
+ return NULL;
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
@@ -704,7 +717,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
skip_radar);
if (!channel) {
wpa_printf(MSG_ERROR, "could not get valid channel");
- return -1;
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ return 0;
}
iface->freq = channel->freq;
@@ -746,6 +760,23 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
}
+static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
+{
+ int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
+
+ /* Get the start (first) channel for current configuration */
+ start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
+ if (start_chan_idx < 0)
+ return 0;
+
+ /* Get the number of used channels, depending on width */
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
+
+ /* Check if all channels are DFS available */
+ return dfs_check_chans_available(iface, start_chan_idx, n_chans);
+}
+
+
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
@@ -766,8 +797,21 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
set_dfs_state(iface, freq, ht_enabled, chan_offset,
chan_width, cf1, cf2,
HOSTAPD_CHAN_DFS_AVAILABLE);
- iface->cac_started = 0;
- hostapd_setup_interface_complete(iface, 0);
+ /*
+ * Just mark the channel available when CAC completion
+ * event is received in enabled state. CAC result could
+ * have been propagated from another radio having the
+ * same regulatory configuration. When CAC completion is
+ * received during non-HAPD_IFACE_ENABLED state, make
+ * sure the configured channel is available because this
+ * CAC completion event could have been propagated from
+ * another radio.
+ */
+ if (iface->state != HAPD_IFACE_ENABLED &&
+ hostapd_config_dfs_chan_available(iface)) {
+ hostapd_setup_interface_complete(iface, 0);
+ iface->cac_started = 0;
+ }
}
}
@@ -775,6 +819,25 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
}
+int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2)
+{
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED
+ "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
+ freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+ /* Proceed only if DFS is not offloaded to the driver */
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return 0;
+
+ set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+
+ return 0;
+}
+
+
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@@ -793,7 +856,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available");
- hostapd_setup_interface_complete(iface, err);
return err;
}
@@ -817,16 +879,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
}
-static int hostapd_csa_in_progress(struct hostapd_iface *iface)
-{
- unsigned int i;
- for (i = 0; i < iface->num_bss; i++)
- if (iface->bss[i]->csa_in_progress)
- return 1;
- return 0;
-}
-
-
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@@ -850,6 +902,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
if (iface->cac_started)
return hostapd_dfs_start_channel_switch_cac(iface);
+ /*
+ * Allow selection of DFS channel in ETSI to comply with
+ * uniform spreading.
+ */
+ if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
+ skip_radar = 0;
+
/* Perform channel switch/CSA */
channel = dfs_get_valid_channel(iface, &secondary_channel,
&vht_oper_centr_freq_seg0_idx,
@@ -868,8 +927,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
&vht_oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
- /* FIXME: Wait for channel(s) to become available */
- hostapd_disable_iface(iface);
+ wpa_printf(MSG_INFO,
+ "%s: no DFS channels left, waiting for NOP to finish",
+ __func__);
return err;
}
@@ -992,6 +1052,11 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
/* TODO add correct implementation here */
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+
+ /* Handle cases where all channels were initially unavailable */
+ if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
+ hostapd_handle_dfs(iface);
+
return 0;
}
@@ -1059,7 +1124,8 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
return 1;
}
- if (ieee80211_is_dfs(iface->freq)) {
+ if (ieee80211_is_dfs(iface->freq, iface->hw_features,
+ iface->num_hw_features)) {
wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
__func__, iface->freq);
return 0;
diff --git a/contrib/wpa/src/ap/dfs.h b/contrib/wpa/src/ap/dfs.h
index be8c0e6..f0fa6f6 100644
--- a/contrib/wpa/src/ap/dfs.h
+++ b/contrib/wpa/src/ap/dfs.h
@@ -1,7 +1,7 @@
/*
* DFS - Dynamic Frequency Selection
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface);
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
+int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2);
int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width,
diff --git a/contrib/wpa/src/ap/dhcp_snoop.c b/contrib/wpa/src/ap/dhcp_snoop.c
index 3a77225..ed37fc8 100644
--- a/contrib/wpa/src/ap/dhcp_snoop.c
+++ b/contrib/wpa/src/ap/dhcp_snoop.c
@@ -7,10 +7,9 @@
*/
#include "utils/includes.h"
-#include <netinet/ip.h>
-#include <netinet/udp.h>
#include "utils/common.h"
+#include "common/dhcp.h"
#include "l2_packet/l2_packet.h"
#include "hostapd.h"
#include "sta_info.h"
@@ -18,29 +17,6 @@
#include "x_snoop.h"
#include "dhcp_snoop.h"
-struct bootp_pkt {
- struct iphdr iph;
- struct udphdr udph;
- u8 op;
- u8 htype;
- u8 hlen;
- u8 hops;
- be32 xid;
- be16 secs;
- be16 flags;
- be32 client_ip;
- be32 your_ip;
- be32 server_ip;
- be32 relay_ip;
- u8 hw_addr[16];
- u8 serv_name[64];
- u8 boot_file[128];
- u8 exten[312];
-} STRUCT_PACKED;
-
-#define DHCPACK 5
-static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
-
static const char * ipaddr_str(u32 addr)
{
@@ -74,24 +50,26 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
if (tot_len > (unsigned int) (len - ETH_HLEN))
return;
- if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
+ if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
return;
/* Parse DHCP options */
end = (const u8 *) b + tot_len;
pos = &b->exten[4];
- while (pos < end && *pos != 0xff) {
+ while (pos < end && *pos != DHCP_OPT_END) {
const u8 *opt = pos++;
- if (*opt == 0) /* padding */
+ if (*opt == DHCP_OPT_PAD)
continue;
+ if (pos >= end || 1 + *pos > end - pos)
+ break;
pos += *pos + 1;
if (pos >= end)
break;
switch (*opt) {
- case 1: /* subnet mask */
+ case DHCP_OPT_SUBNET_MASK:
if (opt[1] == 4)
subnet_mask = WPA_GET_BE32(&opt[2]);
if (subnet_mask == 0)
@@ -101,7 +79,7 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
prefixlen--;
}
break;
- case 53: /* message type */
+ case DHCP_OPT_MSG_TYPE:
if (opt[1])
msgtype = opt[2];
break;
@@ -110,6 +88,15 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
}
}
+ if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!(sta->flags & WLAN_STA_AUTHORIZED))
+ continue;
+ x_snoop_mcast_to_ucast_convert_send(hapd, sta,
+ (u8 *) buf, len);
+ }
+ }
+
if (msgtype == DHCPACK) {
if (b->your_ip == 0)
return;
@@ -121,7 +108,8 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
" @ IPv4 address %s/%d",
- MAC2STR(sta->addr), ipaddr_str(ntohl(b->your_ip)),
+ MAC2STR(sta->addr),
+ ipaddr_str(be_to_host32(b->your_ip)),
prefixlen);
if (sta->ipaddr == b->your_ip)
@@ -145,15 +133,6 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
}
sta->ipaddr = b->your_ip;
}
-
- if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!(sta->flags & WLAN_STA_AUTHORIZED))
- continue;
- x_snoop_mcast_to_ucast_convert_send(hapd, sta,
- (u8 *) buf, len);
- }
- }
}
@@ -175,4 +154,5 @@ int dhcp_snoop_init(struct hostapd_data *hapd)
void dhcp_snoop_deinit(struct hostapd_data *hapd)
{
l2_packet_deinit(hapd->sock_dhcp);
+ hapd->sock_dhcp = NULL;
}
diff --git a/contrib/wpa/src/ap/dpp_hostapd.c b/contrib/wpa/src/ap/dpp_hostapd.c
new file mode 100644
index 0000000..75edbc9
--- /dev/null
+++ b/contrib/wpa/src/ap/dpp_hostapd.c
@@ -0,0 +1,1646 @@
+/*
+ * hostapd / DPP integration
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/dpp.h"
+#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "gas_query_ap.h"
+#include "wpa_auth.h"
+#include "dpp_hostapd.h"
+
+
+static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
+static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
+static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
+
+static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+/**
+ * hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
+ * @hapd: Pointer to hostapd_data
+ * @cmd: DPP URI read from a QR Code
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_bootstrap_info *bi;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ bi = dpp_add_qr_code(hapd->iface->interfaces->dpp, cmd);
+ if (!bi)
+ return -1;
+
+ if (auth && auth->response_pending &&
+ dpp_notify_new_qr_code(auth, bi) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Sending out pending authentication response");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ hostapd_drv_send_action(hapd, auth->curr_freq, 0,
+ auth->peer_mac_addr,
+ wpabuf_head(hapd->dpp_auth->resp_msg),
+ wpabuf_len(hapd->dpp_auth->resp_msg));
+ }
+
+ return bi->id;
+}
+
+
+static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->resp_msg)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Retry Authentication Response after timeout");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ hostapd_drv_send_action(hapd, auth->curr_freq, 500, auth->peer_mac_addr,
+ wpabuf_head(auth->resp_msg),
+ wpabuf_len(auth->resp_msg));
+}
+
+
+static void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ unsigned int wait_time, max_tries;
+
+ if (!auth || !auth->resp_msg)
+ return;
+
+ if (hapd->dpp_resp_max_tries)
+ max_tries = hapd->dpp_resp_max_tries;
+ else
+ max_tries = 5;
+ auth->auth_resp_tries++;
+ if (auth->auth_resp_tries >= max_tries) {
+ wpa_printf(MSG_INFO,
+ "DPP: No confirm received from initiator - stopping exchange");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+
+ if (hapd->dpp_resp_retry_time)
+ wait_time = hapd->dpp_resp_retry_time;
+ else
+ wait_time = 1000;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Schedule retransmission of Authentication Response frame in %u ms",
+ wait_time);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+ eloop_register_timeout(wait_time / 1000,
+ (wait_time % 1000) * 1000,
+ hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+}
+
+
+void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
+ const u8 *data, size_t data_len, int ok)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: TX status: dst=" MACSTR " ok=%d",
+ MAC2STR(dst), ok);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED");
+
+ if (!hapd->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore TX status since there is no ongoing authentication exchange");
+ return;
+ }
+
+#ifdef CONFIG_DPP2
+ if (auth->connect_on_tx_status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Complete exchange on configuration result");
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
+ if (hapd->dpp_auth->remove_on_tx_status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate authentication exchange due to an earlier error");
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+ hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
+ NULL);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+
+ if (hapd->dpp_auth_ok_on_ack)
+ hostapd_dpp_auth_success(hapd, 1);
+
+ if (!is_broadcast_ether_addr(dst) && !ok) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unicast DPP Action frame was not ACKed");
+ if (auth->waiting_auth_resp) {
+ /* In case of DPP Authentication Request frame, move to
+ * the next channel immediately. */
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_auth_init_next(hapd);
+ return;
+ }
+ if (auth->waiting_auth_conf) {
+ hostapd_dpp_auth_resp_retry(hapd);
+ return;
+ }
+ }
+
+ if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
+ /* Allow timeout handling to stop iteration if no response is
+ * received from a peer that has ACKed a request. */
+ auth->auth_req_ack = 1;
+ }
+
+ if (!hapd->dpp_auth_ok_on_ack && hapd->dpp_auth->neg_freq > 0 &&
+ hapd->dpp_auth->curr_freq != hapd->dpp_auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
+ hapd->dpp_auth->curr_freq,
+ hapd->dpp_auth->neg_freq);
+ hostapd_drv_send_action_cancel_wait(hapd);
+
+ if (hapd->dpp_auth->neg_freq !=
+ (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
+ /* TODO: Listen operation on non-operating channel */
+ wpa_printf(MSG_INFO,
+ "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+ hapd->dpp_auth->neg_freq, hapd->iface->freq);
+ }
+ }
+
+ if (hapd->dpp_auth_ok_on_ack)
+ hapd->dpp_auth_ok_on_ack = 0;
+}
+
+
+static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ unsigned int freq;
+ struct os_reltime now, diff;
+ unsigned int wait_time, diff_ms;
+
+ if (!auth || !auth->waiting_auth_resp)
+ return;
+
+ wait_time = hapd->dpp_resp_wait_time ?
+ hapd->dpp_resp_wait_time : 2000;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &hapd->dpp_last_init, &diff);
+ diff_ms = diff.sec * 1000 + diff.usec / 1000;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
+ wait_time, diff_ms);
+
+ if (auth->auth_req_ack && diff_ms >= wait_time) {
+ /* Peer ACK'ed Authentication Request frame, but did not reply
+ * with Authentication Response frame within two seconds. */
+ wpa_printf(MSG_INFO,
+ "DPP: No response received from responder - stopping initiation attempt");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+
+ if (diff_ms >= wait_time) {
+ /* Authentication Request frame was not ACK'ed and no reply
+ * was receiving within two seconds. */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue Initiator channel iteration");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ hostapd_dpp_auth_init_next(hapd);
+ return;
+ }
+
+ /* Driver did not support 2000 ms long wait_time with TX command, so
+ * schedule listen operation to continue waiting for the response.
+ *
+ * DPP listen operations continue until stopped, so simply schedule a
+ * new call to this function at the point when the two second reply
+ * wait has expired. */
+ wait_time -= diff_ms;
+
+ freq = auth->curr_freq;
+ if (auth->neg_freq > 0)
+ freq = auth->neg_freq;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue reply wait on channel %u MHz for %u ms",
+ freq, wait_time);
+ hapd->dpp_in_response_listen = 1;
+
+ if (freq != (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
+ /* TODO: Listen operation on non-operating channel */
+ wpa_printf(MSG_INFO,
+ "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+ freq, hapd->iface->freq);
+ }
+
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ hostapd_dpp_reply_wait_timeout, hapd, NULL);
+}
+
+
+static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
+ struct dpp_authentication *auth)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->dpp_config_obj_override)
+ auth->config_obj_override =
+ os_strdup(hapd->dpp_config_obj_override);
+ if (hapd->dpp_discovery_override)
+ auth->discovery_override =
+ os_strdup(hapd->dpp_discovery_override);
+ if (hapd->dpp_groups_override)
+ auth->groups_override = os_strdup(hapd->dpp_groups_override);
+ auth->ignore_netaccesskey_mismatch =
+ hapd->dpp_ignore_netaccesskey_mismatch;
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
+static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+
+ if (!hapd->dpp_auth)
+ return;
+ wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
+ hostapd_dpp_auth_init_next(hapd);
+}
+
+
+static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ const u8 *dst;
+ unsigned int wait_time, max_wait_time, freq, max_tries, used;
+ struct os_reltime now, diff;
+
+ if (!auth)
+ return -1;
+
+ if (auth->freq_idx == 0)
+ os_get_reltime(&hapd->dpp_init_iter_start);
+
+ if (auth->freq_idx >= auth->num_freq) {
+ auth->num_freq_iters++;
+ if (hapd->dpp_init_max_tries)
+ max_tries = hapd->dpp_init_max_tries;
+ else
+ max_tries = 5;
+ if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
+ wpa_printf(MSG_INFO,
+ "DPP: No response received from responder - stopping initiation attempt");
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_AUTH_INIT_FAILED);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+ hapd, NULL);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return -1;
+ }
+ auth->freq_idx = 0;
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ if (hapd->dpp_init_retry_time)
+ wait_time = hapd->dpp_init_retry_time;
+ else
+ wait_time = 10000;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &hapd->dpp_init_iter_start, &diff);
+ used = diff.sec * 1000 + diff.usec / 1000;
+ if (used > wait_time)
+ wait_time = 0;
+ else
+ wait_time -= used;
+ wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
+ wait_time);
+ eloop_register_timeout(wait_time / 1000,
+ (wait_time % 1000) * 1000,
+ hostapd_dpp_init_timeout, hapd,
+ NULL);
+ return 0;
+ }
+ freq = auth->freq[auth->freq_idx++];
+ auth->curr_freq = freq;
+
+ if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ dst = broadcast;
+ else
+ dst = auth->peer_bi->mac_addr;
+ hapd->dpp_auth_ok_on_ack = 0;
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
+ max_wait_time = hapd->dpp_resp_wait_time ?
+ hapd->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wait_time += 10; /* give the driver some extra time to complete */
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ wait_time -= 10;
+ if (auth->neg_freq > 0 && freq != auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
+ freq, auth->neg_freq);
+ }
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
+ auth->auth_req_ack = 0;
+ os_get_reltime(&hapd->dpp_last_init);
+ return hostapd_drv_send_action(hapd, freq, wait_time,
+ dst,
+ wpabuf_head(hapd->dpp_auth->req_msg),
+ wpabuf_len(hapd->dpp_auth->req_msg));
+}
+
+
+int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
+ u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ unsigned int neg_freq = 0;
+
+ pos = os_strstr(cmd, " peer=");
+ if (!pos)
+ return -1;
+ pos += 6;
+ peer_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Could not find bootstrapping info for the identified peer");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " own=");
+ if (pos) {
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp,
+ atoi(pos));
+ if (!own_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Could not find bootstrapping info for the identified local entry");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
+ peer_bi->curve->name, own_bi->curve->name);
+ return -1;
+ }
+ }
+
+ pos = os_strstr(cmd, " role=");
+ if (pos) {
+ pos += 6;
+ if (os_strncmp(pos, "configurator", 12) == 0)
+ allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strncmp(pos, "enrollee", 8) == 0)
+ allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ else
+ goto fail;
+ }
+
+ pos = os_strstr(cmd, " neg_freq=");
+ if (pos)
+ neg_freq = atoi(pos + 10);
+
+ if (hapd->dpp_auth) {
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+ hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
+ NULL);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(hapd->dpp_auth);
+ }
+
+ hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
+ allowed_roles, neg_freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
+ if (!hapd->dpp_auth)
+ goto fail;
+ hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
+ if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ hapd->dpp_auth, cmd) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ goto fail;
+ }
+
+ hapd->dpp_auth->neg_freq = neg_freq;
+
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
+ os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
+ ETH_ALEN);
+
+ return hostapd_dpp_auth_init_next(hapd);
+fail:
+ return -1;
+}
+
+
+int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
+{
+ int freq;
+
+ freq = atoi(cmd);
+ if (freq <= 0)
+ return -1;
+
+ if (os_strstr(cmd, " role=configurator"))
+ hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strstr(cmd, " role=enrollee"))
+ hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ else
+ hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ hapd->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
+
+ if (freq != hapd->iface->freq && hapd->iface->freq > 0) {
+ /* TODO: Listen operation on non-operating channel */
+ wpa_printf(MSG_INFO,
+ "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+ freq, hapd->iface->freq);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
+{
+ /* TODO: Stop listen operation on non-operating channel */
+}
+
+
+static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap, *i_bootstrap;
+ u16 r_bootstrap_len, i_bootstrap_len;
+ struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
+
+ if (!hapd->iface->interfaces->dpp)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+
+ i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
+ i_bootstrap, i_bootstrap_len);
+
+ /* Try to find own and peer bootstrapping key matches based on the
+ * received hash values */
+ dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
+ r_bootstrap, &own_bi, &peer_bi);
+ if (!own_bi) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "No matching own bootstrapping key found - ignore message");
+ return;
+ }
+
+ if (hapd->dpp_auth) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Already in DPP authentication exchange - ignore new one");
+ return;
+ }
+
+ hapd->dpp_auth_ok_on_ack = 0;
+ hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
+ hapd->dpp_qr_mutual,
+ peer_bi, own_bi, freq, hdr, buf, len);
+ if (!hapd->dpp_auth) {
+ wpa_printf(MSG_DEBUG, "DPP: No response generated");
+ return;
+ }
+ hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
+ if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ hapd->dpp_auth,
+ hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+ os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN);
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(src), hapd->dpp_auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0,
+ src, wpabuf_head(hapd->dpp_auth->resp_msg),
+ wpabuf_len(hapd->dpp_auth->resp_msg));
+}
+
+
+static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
+ struct dpp_authentication *auth)
+{
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
+ dpp_akm_str(auth->akm));
+ if (auth->ssid_len)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
+ wpa_ssid_txt(auth->ssid, auth->ssid_len));
+ if (auth->connector) {
+ /* TODO: Save the Connector and consider using a command
+ * to fetch the value instead of sending an event with
+ * it. The Connector could end up being larger than what
+ * most clients are ready to receive as an event
+ * message. */
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
+ auth->connector);
+ } else if (auth->passphrase[0]) {
+ char hex[64 * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex),
+ (const u8 *) auth->passphrase,
+ os_strlen(auth->passphrase));
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
+ hex);
+ } else if (auth->psk_set) {
+ char hex[PMK_LEN * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
+ hex);
+ }
+ if (auth->c_sign_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hex = os_malloc(hexlen);
+ if (hex) {
+ wpa_snprintf_hex(hex, hexlen,
+ wpabuf_head(auth->c_sign_key),
+ wpabuf_len(auth->c_sign_key));
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_C_SIGN_KEY "%s", hex);
+ os_free(hex);
+ }
+ }
+ if (auth->net_access_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
+ hex = os_malloc(hexlen);
+ if (hex) {
+ wpa_snprintf_hex(hex, hexlen,
+ wpabuf_head(auth->net_access_key),
+ wpabuf_len(auth->net_access_key));
+ if (auth->net_access_key_expiry)
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
+ (unsigned long)
+ auth->net_access_key_expiry);
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_NET_ACCESS_KEY "%s", hex);
+ os_free(hex);
+ }
+ }
+}
+
+
+static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
+ enum gas_query_ap_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code)
+{
+ struct hostapd_data *hapd = ctx;
+ const u8 *pos;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+
+ if (!auth || !auth->auth_success) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return;
+ }
+ if (!resp || status_code != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
+ goto fail;
+ }
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
+ adv_proto);
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
+ resp);
+
+ if (wpabuf_len(adv_proto) != 10 ||
+ !(pos = wpabuf_head(adv_proto)) ||
+ pos[0] != WLAN_EID_ADV_PROTO ||
+ pos[1] != 8 ||
+ pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[4] != 5 ||
+ WPA_GET_BE24(&pos[5]) != OUI_WFA ||
+ pos[8] != 0x1a ||
+ pos[9] != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not a DPP Advertisement Protocol ID");
+ goto fail;
+ }
+
+ if (dpp_conf_resp_rx(auth, resp) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
+ goto fail;
+ }
+
+ hostapd_dpp_handle_config_obj(hapd, auth);
+ status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_REJECT_CONFIG) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
+ status = DPP_STATUS_CONFIG_REJECTED;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+fail:
+ if (status != DPP_STATUS_OK)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
+ msg = dpp_build_conf_result(auth, status);
+ if (!msg)
+ goto fail2;
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(addr), auth->curr_freq,
+ DPP_PA_CONFIGURATION_RESULT);
+ hostapd_drv_send_action(hapd, auth->curr_freq, 0,
+ addr, wpabuf_head(msg),
+ wpabuf_len(msg));
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+ auth->connect_on_tx_status = 1;
+ return;
+ }
+fail2:
+#endif /* CONFIG_DPP2 */
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+}
+
+
+static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ struct wpabuf *buf;
+ char json[100];
+ int res;
+ int netrole_ap = 1;
+
+ os_snprintf(json, sizeof(json),
+ "{\"name\":\"Test\","
+ "\"wi-fi_tech\":\"infra\","
+ "\"netRole\":\"%s\"}",
+ netrole_ap ? "ap" : "sta");
+ wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
+
+ buf = dpp_build_conf_req(auth, json);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration request data available");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq);
+
+ res = gas_query_ap_req(hapd->gas, auth->peer_mac_addr, auth->curr_freq,
+ buf, hostapd_dpp_gas_resp_cb, hapd);
+ if (res < 0) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Failed to send Query Request");
+ wpabuf_free(buf);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: GAS query started with dialog token %u", res);
+ }
+}
+
+
+static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator)
+{
+ wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d",
+ initiator);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Confirm");
+ if (hapd->dpp_auth->configurator) {
+ /* Prevent GAS response */
+ hapd->dpp_auth->auth_success = 0;
+ }
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!hapd->dpp_auth->configurator)
+ hostapd_dpp_start_gas_client(hapd);
+}
+
+
+static void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Authentication in progress - drop");
+ return;
+ }
+
+ if (!is_zero_ether_addr(auth->peer_mac_addr) &&
+ os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+
+ if (auth->curr_freq != freq && auth->neg_freq == freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder accepted request for different negotiation channel");
+ auth->curr_freq = freq;
+ }
+
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ msg = dpp_auth_resp_rx(auth, hdr, buf, len);
+ if (!msg) {
+ if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
+ wpa_printf(MSG_DEBUG, "DPP: Wait for full response");
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
+ return;
+ }
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_CONF);
+ hostapd_drv_send_action(hapd, auth->curr_freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+ hapd->dpp_auth_ok_on_ack = 1;
+}
+
+
+static void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Authentication in progress - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+ return;
+ }
+
+ hostapd_dpp_auth_success(hapd, 0);
+}
+
+
+#ifdef CONFIG_DPP2
+
+static void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Configuration Result");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
+static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ enum dpp_status_error status;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth || !auth->waiting_conf_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ status = dpp_conf_result_rx(auth, hdr, buf, len);
+
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ if (status == DPP_STATUS_OK)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
+ NULL);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
+ const u8 *src, unsigned int freq,
+ u8 trans_id,
+ enum dpp_status_error status)
+{
+ struct wpabuf *msg;
+
+ msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
+ 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
+ if (!msg)
+ return;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
+ goto skip_trans_id;
+ }
+ if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
+ trans_id ^= 0x01;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, trans_id);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_trans_id:
+ if (dpp_test == DPP_TEST_NO_STATUS_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ goto skip_status;
+ }
+ if (dpp_test == DPP_TEST_INVALID_STATUS_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 254;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Status */
+ wpabuf_put_le16(msg, DPP_ATTR_STATUS);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+ if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
+ goto skip_connector;
+ }
+ if (status == DPP_STATUS_OK &&
+ dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP) {
+ char *connector;
+
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
+ connector = dpp_corrupt_connector_signature(
+ hapd->conf->dpp_connector);
+ if (!connector) {
+ wpabuf_free(msg);
+ return;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(connector));
+ wpabuf_put_str(msg, connector);
+ os_free(connector);
+ goto skip_connector;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Connector */
+ if (status == DPP_STATUS_OK) {
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
+ wpabuf_put_str(msg, hapd->conf->dpp_connector);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_connector:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
+ " status=%d", MAC2STR(src), status);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d status=%d", MAC2STR(src), freq,
+ DPP_PA_PEER_DISCOVERY_RESP, status);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+}
+
+
+static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
+ const u8 *src,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *connector, *trans_id;
+ u16 connector_len, trans_id_len;
+ struct os_time now;
+ struct dpp_introduction intro;
+ os_time_t expire;
+ int expiration;
+ enum dpp_status_error res;
+
+ wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
+ MAC2STR(src));
+ if (!hapd->wpa_auth ||
+ !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) ||
+ !(hapd->conf->wpa & WPA_PROTO_RSN)) {
+ wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use");
+ return;
+ }
+
+ if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey ||
+ !hapd->conf->dpp_csign) {
+ wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set");
+ return;
+ }
+
+ os_get_time(&now);
+
+ if (hapd->conf->dpp_netaccesskey_expiry &&
+ (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) {
+ wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired");
+ return;
+ }
+
+ trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Transaction ID");
+ return;
+ }
+
+ connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
+ if (!connector) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include its Connector");
+ return;
+ }
+
+ res = dpp_peer_intro(&intro, hapd->conf->dpp_connector,
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey),
+ wpabuf_head(hapd->conf->dpp_csign),
+ wpabuf_len(hapd->conf->dpp_csign),
+ connector, connector_len, &expire);
+ if (res == 255) {
+ wpa_printf(MSG_INFO,
+ "DPP: Network Introduction protocol resulted in internal failure (peer "
+ MACSTR ")", MAC2STR(src));
+ return;
+ }
+ if (res != DPP_STATUS_OK) {
+ wpa_printf(MSG_INFO,
+ "DPP: Network Introduction protocol resulted in failure (peer "
+ MACSTR " status %d)", MAC2STR(src), res);
+ hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
+ res);
+ return;
+ }
+
+ if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
+ expire = hapd->conf->dpp_netaccesskey_expiry;
+ if (expire)
+ expiration = expire - now.sec;
+ else
+ expiration = 0;
+
+ if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
+ intro.pmkid, expiration,
+ WPA_KEY_MGMT_DPP) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
+ return;
+ }
+
+ hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
+ DPP_STATUS_OK);
+}
+
+
+static void
+hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
+ MAC2STR(src));
+
+ /* TODO: Support multiple PKEX codes by iterating over all the enabled
+ * values here */
+
+ if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No PKEX code configured - ignore request");
+ return;
+ }
+
+ if (hapd->dpp_pkex) {
+ /* TODO: Support parallel operations */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Already in PKEX session - ignore new request");
+ return;
+ }
+
+ hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx,
+ hapd->dpp_pkex_bi,
+ hapd->own_addr, src,
+ hapd->dpp_pkex_identifier,
+ hapd->dpp_pkex_code,
+ buf, len);
+ if (!hapd->dpp_pkex) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to process the request - ignore it");
+ return;
+ }
+
+ msg = hapd->dpp_pkex->exchange_resp;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_EXCHANGE_RESP);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ if (hapd->dpp_pkex->failed) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate PKEX exchange due to an earlier error");
+ if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
+ hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t;
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+ }
+}
+
+
+static void
+hostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src,
+ const u8 *buf, size_t len, unsigned int freq)
+{
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
+ MAC2STR(src));
+
+ /* TODO: Support multiple PKEX codes by iterating over all the enabled
+ * values here */
+
+ if (!hapd->dpp_pkex || !hapd->dpp_pkex->initiator ||
+ hapd->dpp_pkex->exchange_done) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+ return;
+ }
+
+ msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len);
+ if (!msg) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
+ MAC2STR(src));
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_COMMIT_REVEAL_REQ);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+}
+
+
+static void
+hostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct wpabuf *msg;
+ struct dpp_pkex *pkex = hapd->dpp_pkex;
+ struct dpp_bootstrap_info *bi;
+
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
+ MAC2STR(src));
+
+ if (!pkex || pkex->initiator || !pkex->exchange_done) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+ return;
+ }
+
+ msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
+ if (!msg) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
+ if (hapd->dpp_pkex->failed) {
+ wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
+ if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
+ hapd->dpp_pkex->own_bi->pkex_t =
+ hapd->dpp_pkex->t;
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+ }
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
+ MACSTR, MAC2STR(src));
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_COMMIT_REVEAL_RESP);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+
+ bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
+ if (!bi)
+ return;
+ hapd->dpp_pkex = NULL;
+}
+
+
+static void
+hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ int res;
+ struct dpp_bootstrap_info *bi;
+ struct dpp_pkex *pkex = hapd->dpp_pkex;
+ char cmd[500];
+
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
+ MAC2STR(src));
+
+ if (!pkex || !pkex->initiator || !pkex->exchange_done) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+ return;
+ }
+
+ res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
+ return;
+ }
+
+ bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
+ if (!bi)
+ return;
+ hapd->dpp_pkex = NULL;
+
+ os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
+ bi->id,
+ hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : "");
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start authentication after PKEX with parameters: %s",
+ cmd);
+ if (hostapd_dpp_auth_init(hapd, cmd) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Authentication initialization failed");
+ return;
+ }
+}
+
+
+void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
+ const u8 *buf, size_t len, unsigned int freq)
+{
+ u8 crypto_suite;
+ enum dpp_public_action_frame_type type;
+ const u8 *hdr;
+ unsigned int pkex_t;
+
+ if (len < DPP_HDR_LEN)
+ return;
+ if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
+ return;
+ hdr = buf;
+ buf += 4;
+ len -= 4;
+ crypto_suite = *buf++;
+ type = *buf++;
+ len -= 2;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Public Action frame crypto suite %u type %d from "
+ MACSTR " freq=%u",
+ crypto_suite, type, MAC2STR(src), freq);
+ if (crypto_suite != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
+ crypto_suite);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d ignore=unsupported-crypto-suite",
+ MAC2STR(src), freq, type);
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
+ if (dpp_check_attrs(buf, len) < 0) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d ignore=invalid-attributes",
+ MAC2STR(src), freq, type);
+ return;
+ }
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq, type);
+
+ switch (type) {
+ case DPP_PA_AUTHENTICATION_REQ:
+ hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
+ break;
+ case DPP_PA_AUTHENTICATION_RESP:
+ hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len, freq);
+ break;
+ case DPP_PA_AUTHENTICATION_CONF:
+ hostapd_dpp_rx_auth_conf(hapd, src, hdr, buf, len);
+ break;
+ case DPP_PA_PEER_DISCOVERY_REQ:
+ hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq);
+ break;
+ case DPP_PA_PKEX_EXCHANGE_REQ:
+ hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq);
+ break;
+ case DPP_PA_PKEX_EXCHANGE_RESP:
+ hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq);
+ break;
+ case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
+ hostapd_dpp_rx_pkex_commit_reveal_req(hapd, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
+ hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len,
+ freq);
+ break;
+#ifdef CONFIG_DPP2
+ case DPP_PA_CONFIGURATION_RESULT:
+ hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
+ break;
+#endif /* CONFIG_DPP2 */
+ default:
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignored unsupported frame subtype %d", type);
+ break;
+ }
+
+ if (hapd->dpp_pkex)
+ pkex_t = hapd->dpp_pkex->t;
+ else if (hapd->dpp_pkex_bi)
+ pkex_t = hapd->dpp_pkex_bi->pkex_t;
+ else
+ pkex_t = 0;
+ if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
+ hostapd_dpp_pkex_remove(hapd, "*");
+ }
+}
+
+
+struct wpabuf *
+hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
+ const u8 *query, size_t query_len)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ struct wpabuf *resp;
+
+ wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
+ if (!auth || !auth->auth_success ||
+ os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Received Configuration Request (GAS Query Request)",
+ query, query_len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
+ MAC2STR(sa));
+ resp = dpp_conf_req_rx(auth, query, query_len);
+ if (!resp)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ return resp;
+}
+
+
+void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
+ ok);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+#ifdef CONFIG_DPP2
+ if (ok && auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
+ auth->waiting_conf_result = 1;
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
+ hapd, NULL);
+ eloop_register_timeout(2, 0,
+ hostapd_dpp_config_result_wait_timeout,
+ hapd, NULL);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+ hostapd_drv_send_action_cancel_wait(hapd);
+
+ if (ok)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+}
+
+
+int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_authentication *auth;
+ int ret = -1;
+ char *curve = NULL;
+
+ auth = os_zalloc(sizeof(*auth));
+ if (!auth)
+ return -1;
+
+ curve = get_param(cmd, " curve=");
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ auth, cmd) == 0 &&
+ dpp_configurator_own_config(auth, curve, 1) == 0) {
+ hostapd_dpp_handle_config_obj(hapd, auth);
+ ret = 0;
+ }
+
+ dpp_auth_deinit(auth);
+ os_free(curve);
+
+ return ret;
+}
+
+
+int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_bootstrap_info *own_bi;
+ const char *pos, *end;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not found");
+ return -1;
+ }
+ if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not for PKEX");
+ return -1;
+ }
+ hapd->dpp_pkex_bi = own_bi;
+ own_bi->pkex_t = 0; /* clear pending errors on new code */
+
+ os_free(hapd->dpp_pkex_identifier);
+ hapd->dpp_pkex_identifier = NULL;
+ pos = os_strstr(cmd, " identifier=");
+ if (pos) {
+ pos += 12;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ return -1;
+ hapd->dpp_pkex_identifier = os_malloc(end - pos + 1);
+ if (!hapd->dpp_pkex_identifier)
+ return -1;
+ os_memcpy(hapd->dpp_pkex_identifier, pos, end - pos);
+ hapd->dpp_pkex_identifier[end - pos] = '\0';
+ }
+
+ pos = os_strstr(cmd, " code=");
+ if (!pos)
+ return -1;
+ os_free(hapd->dpp_pkex_code);
+ hapd->dpp_pkex_code = os_strdup(pos + 6);
+ if (!hapd->dpp_pkex_code)
+ return -1;
+
+ if (os_strstr(cmd, " init=1")) {
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
+ hapd->own_addr,
+ hapd->dpp_pkex_identifier,
+ hapd->dpp_pkex_code);
+ if (!hapd->dpp_pkex)
+ return -1;
+
+ msg = hapd->dpp_pkex->exchange_req;
+ /* TODO: Which channel to use? */
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(broadcast), 2437,
+ DPP_PA_PKEX_EXCHANGE_REQ);
+ hostapd_drv_send_action(hapd, 2437, 0, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg));
+ }
+
+ /* TODO: Support multiple PKEX info entries */
+
+ os_free(hapd->dpp_pkex_auth_cmd);
+ hapd->dpp_pkex_auth_cmd = os_strdup(cmd);
+
+ return 1;
+}
+
+
+int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id)
+{
+ unsigned int id_val;
+
+ if (os_strcmp(id, "*") == 0) {
+ id_val = 0;
+ } else {
+ id_val = atoi(id);
+ if (id_val == 0)
+ return -1;
+ }
+
+ if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code)
+ return -1;
+
+ /* TODO: Support multiple PKEX entries */
+ os_free(hapd->dpp_pkex_code);
+ hapd->dpp_pkex_code = NULL;
+ os_free(hapd->dpp_pkex_identifier);
+ hapd->dpp_pkex_identifier = NULL;
+ os_free(hapd->dpp_pkex_auth_cmd);
+ hapd->dpp_pkex_auth_cmd = NULL;
+ hapd->dpp_pkex_bi = NULL;
+ /* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+ return 0;
+}
+
+
+void hostapd_dpp_stop(struct hostapd_data *hapd)
+{
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+}
+
+
+int hostapd_dpp_init(struct hostapd_data *hapd)
+{
+ hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
+ hapd->dpp_init_done = 1;
+ return 0;
+}
+
+
+void hostapd_dpp_deinit(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(hapd->dpp_config_obj_override);
+ hapd->dpp_config_obj_override = NULL;
+ os_free(hapd->dpp_discovery_override);
+ hapd->dpp_discovery_override = NULL;
+ os_free(hapd->dpp_groups_override);
+ hapd->dpp_groups_override = NULL;
+ hapd->dpp_ignore_netaccesskey_mismatch = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!hapd->dpp_init_done)
+ return;
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
+ NULL);
+#endif /* CONFIG_DPP2 */
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ hostapd_dpp_pkex_remove(hapd, "*");
+ hapd->dpp_pkex = NULL;
+ os_free(hapd->dpp_configurator_params);
+ hapd->dpp_configurator_params = NULL;
+}
diff --git a/contrib/wpa/src/ap/dpp_hostapd.h b/contrib/wpa/src/ap/dpp_hostapd.h
new file mode 100644
index 0000000..449ca16
--- /dev/null
+++ b/contrib/wpa/src/ap/dpp_hostapd.h
@@ -0,0 +1,37 @@
+/*
+ * hostapd / DPP integration
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DPP_HOSTAPD_H
+#define DPP_HOSTAPD_H
+
+int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
+void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
+void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
+ const u8 *buf, size_t len, unsigned int freq);
+void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
+ const u8 *data, size_t data_len, int ok);
+struct wpabuf *
+hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
+ const u8 *query, size_t query_len);
+void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok);
+int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
+int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_configurator_get_key(struct hostapd_data *hapd, unsigned int id,
+ char *buf, size_t buflen);
+int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id);
+void hostapd_dpp_stop(struct hostapd_data *hapd);
+int hostapd_dpp_init(struct hostapd_data *hapd);
+void hostapd_dpp_deinit(struct hostapd_data *hapd);
+void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
+void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
+
+#endif /* DPP_HOSTAPD_H */
diff --git a/contrib/wpa/src/ap/drv_callbacks.c b/contrib/wpa/src/ap/drv_callbacks.c
index ca8b75c..8ddf754 100644
--- a/contrib/wpa/src/ap/drv_callbacks.c
+++ b/contrib/wpa/src/ap/drv_callbacks.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/dpp.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -22,6 +23,7 @@
#include "wnm_ap.h"
#include "hostapd.h"
#include "ieee802_11.h"
+#include "ieee802_11_auth.h"
#include "sta_info.h"
#include "accounting.h"
#include "tkip_countermeasures.h"
@@ -30,9 +32,75 @@
#include "wps_hostapd.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
+#include "ap_mlme.h"
#include "hw_features.h"
#include "dfs.h"
#include "beacon.h"
+#include "mbo_ap.h"
+#include "dpp_hostapd.h"
+#include "fils_hlp.h"
+#include "neighbor_db.h"
+
+
+#ifdef CONFIG_FILS
+void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ u16 reply_res = WLAN_STATUS_SUCCESS;
+ struct ieee802_11_elems elems;
+ u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf;
+ int new_assoc;
+
+ wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR,
+ __func__, MAC2STR(sta->addr));
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ if (!sta->fils_pending_assoc_req)
+ return;
+
+ ieee802_11_parse_elems(sta->fils_pending_assoc_req,
+ sta->fils_pending_assoc_req_len, &elems, 0);
+ if (!elems.fils_session) {
+ wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element",
+ __func__);
+ return;
+ }
+
+ p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
+ elems.fils_session,
+ sta->fils_hlp_resp);
+
+ reply_res = hostapd_sta_assoc(hapd, sta->addr,
+ sta->fils_pending_assoc_is_reassoc,
+ WLAN_STATUS_SUCCESS,
+ buf, p - buf);
+ ap_sta_set_authorized(hapd, sta, 1);
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
+ hostapd_set_sta_flags(hapd, sta);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+ hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+ os_free(sta->fils_pending_assoc_req);
+ sta->fils_pending_assoc_req = NULL;
+ sta->fils_pending_assoc_req_len = 0;
+ wpabuf_free(sta->fils_hlp_resp);
+ sta->fils_hlp_resp = NULL;
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+ fils_hlp_deinit(hapd);
+
+ /*
+ * Remove the station in case transmission of a success response fails
+ * (the STA was added associated to the driver) or if the station was
+ * previously added unassociated.
+ */
+ if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
+}
+#endif /* CONFIG_FILS */
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -43,10 +111,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
@@ -114,6 +182,21 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+ /*
+ * ACL configurations to the drivers (implementing AP SME and ACL
+ * offload) without hostapd's knowledge, can result in a disconnection
+ * though the driver accepts the connection. Skip the hostapd check for
+ * ACL if the driver supports ACL offload to avoid potentially
+ * conflicting ACL rules.
+ */
+ if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
+ hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
+ wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
+ MAC2STR(addr));
+ reason = WLAN_REASON_UNSPECIFIED;
+ goto fail;
+ }
+
#ifdef CONFIG_P2P
if (elems.p2p) {
wpabuf_free(sta->p2p_ie);
@@ -154,6 +237,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
elems.hs20_len - 4);
} else
sta->hs20_ie = NULL;
+
+ wpabuf_free(sta->roaming_consortium);
+ if (elems.roaming_cons_sel)
+ sta->roaming_consortium = wpabuf_alloc_copy(
+ elems.roaming_cons_sel + 4,
+ elems.roaming_cons_sel_len - 4);
+ else
+ sta->roaming_consortium = NULL;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
@@ -164,6 +255,11 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->mb_ies = NULL;
#endif /* CONFIG_FST */
+ mbo_ap_check_sta_assoc(hapd, sta, &elems);
+
+ ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
+ elems.supp_op_classes_len);
+
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
@@ -176,7 +272,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#endif /* CONFIG_WPS */
wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
- return -1;
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ goto fail;
}
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
@@ -208,8 +306,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return -1;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq,
ie, ielen,
- elems.mdie, elems.mdie_len);
+ elems.mdie, elems.mdie_len,
+ elems.owe_dh, elems.owe_dh_len);
if (res != WPA_IE_OK) {
wpa_printf(MSG_DEBUG,
"WPA/RSN information element rejected? (res %u)",
@@ -230,8 +330,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
- reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
- status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+ status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
#endif /* CONFIG_IEEE80211W */
else {
@@ -241,10 +341,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
#ifdef CONFIG_IEEE80211W
- if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+ (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+ !sta->sa_query_timed_out &&
sta->sa_query_count > 0)
ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+ (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+ !sta->sa_query_timed_out &&
(sta->auth_alg != WLAN_AUTH_FT)) {
/*
* STA has already been associated with MFP and SA
@@ -271,7 +375,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->flags &= ~WLAN_STA_MFP;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
req_ies_len);
@@ -285,7 +389,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@@ -338,23 +442,175 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
}
+
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
+ elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
+ hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_INFO,
+ "MBO: Reject WPA2 association without PMF");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+#endif /* CONFIG_MBO */
+
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
sta->auth_alg, req_ies, req_ies_len);
+ if (!p) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_FILS
+ if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ int delay_assoc = 0;
+
+ if (!req_ies)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies,
+ req_ies_len,
+ sta->fils_session)) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Session validation failed");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies,
+ req_ies_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Key Confirm validation failed");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Delaying Assoc Response (HLP)");
+ delay_assoc = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Going ahead with Assoc Response (no HLP)");
+ }
+
+ if (sta) {
+ wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup");
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ os_free(sta->fils_pending_assoc_req);
+ sta->fils_pending_assoc_req = NULL;
+ sta->fils_pending_assoc_req_len = 0;
+ wpabuf_free(sta->fils_hlp_resp);
+ sta->fils_hlp_resp = NULL;
+ sta->fils_drv_assoc_finish = 0;
+ }
+
+ if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) {
+ u8 *req_tmp;
+
+ req_tmp = os_malloc(req_ies_len);
+ if (!req_tmp) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: buffer allocation failed for assoc req");
+ goto fail;
+ }
+ os_memcpy(req_tmp, req_ies, req_ies_len);
+ sta->fils_pending_assoc_req = req_tmp;
+ sta->fils_pending_assoc_req_len = req_ies_len;
+ sta->fils_pending_assoc_is_reassoc = reassoc;
+ sta->fils_drv_assoc_finish = 1;
+ wpa_printf(MSG_DEBUG,
+ "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
+ MACSTR, MAC2STR(sta->addr));
+ eloop_register_timeout(
+ 0, hapd->conf->fils_hlp_wait_time * 1024,
+ fils_hlp_timeout, hapd, sta);
+ return 0;
+ }
+ p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
+ elems.fils_session,
+ sta->fils_hlp_resp);
+ wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)",
+ buf, p - buf);
+ }
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
+ elems.owe_dh) {
+ u8 *npos;
+
+ npos = owe_assoc_req_process(hapd, sta,
+ elems.owe_dh, elems.owe_dh_len,
+ p, sizeof(buf) - (p - buf),
+ &reason);
+ if (npos)
+ p = npos;
+ if (!npos &&
+ reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+ p - buf);
+ return 0;
+ }
+
+ if (!npos || reason != WLAN_STATUS_SUCCESS)
+ goto fail;
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
+ elems.owe_dh) {
+ sta->dpp_pfs = dpp_pfs_init(
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey));
+ if (!sta->dpp_pfs) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not initialize PFS");
+ /* Try to continue without PFS */
+ goto pfs_fail;
+ }
+
+ if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
+ elems.owe_dh_len) < 0) {
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+ reason = WLAN_REASON_UNSPECIFIED;
+ goto fail;
+ }
+ }
+
+ wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
+ sta->dpp_pfs->secret : NULL);
+ pfs_fail:
+#endif /* CONFIG_DPP2 */
+
+#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
- if (sta->auth_alg == WLAN_AUTH_FT)
+ if (sta->auth_alg == WLAN_AUTH_FT ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK)
ap_sta_set_authorized(hapd, sta, 1);
-#else /* CONFIG_IEEE80211R */
+#else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
/* Keep compiler silent about unused variables */
if (status) {
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
@@ -364,6 +620,12 @@ skip_wpa_check:
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+#ifdef CONFIG_FILS
+ else if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK)
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
+#endif /* CONFIG_FILS */
else
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
@@ -381,9 +643,9 @@ skip_wpa_check:
return 0;
fail:
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
return -1;
@@ -431,29 +693,99 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta = ap_get_sta(hapd, addr);
- if (!sta || !hapd->conf->disassoc_low_ack)
+ if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
return;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"disconnected due to excessive missing ACKs");
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
- if (sta)
- ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
+ ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
+}
+
+
+void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
+ enum smps_mode smps_mode,
+ enum chan_width chan_width, u8 rx_nss)
+{
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ const char *txt;
+
+ if (!sta)
+ return;
+
+ switch (smps_mode) {
+ case SMPS_AUTOMATIC:
+ txt = "automatic";
+ break;
+ case SMPS_OFF:
+ txt = "off";
+ break;
+ case SMPS_DYNAMIC:
+ txt = "dynamic";
+ break;
+ case SMPS_STATIC:
+ txt = "static";
+ break;
+ default:
+ txt = NULL;
+ break;
+ }
+ if (txt) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED
+ MACSTR " %s", MAC2STR(addr), txt);
+ }
+
+ switch (chan_width) {
+ case CHAN_WIDTH_20_NOHT:
+ txt = "20(no-HT)";
+ break;
+ case CHAN_WIDTH_20:
+ txt = "20";
+ break;
+ case CHAN_WIDTH_40:
+ txt = "40";
+ break;
+ case CHAN_WIDTH_80:
+ txt = "80";
+ break;
+ case CHAN_WIDTH_80P80:
+ txt = "80+80";
+ break;
+ case CHAN_WIDTH_160:
+ txt = "160";
+ break;
+ default:
+ txt = NULL;
+ break;
+ }
+ if (txt) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED
+ MACSTR " %s", MAC2STR(addr), txt);
+ }
+
+ if (rx_nss != 0xff) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED
+ MACSTR " %d", MAC2STR(addr), rx_nss);
+ }
}
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2)
{
+ /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
+
#ifdef NEED_AP_MLME
- int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
+ int channel, chwidth, is_dfs;
+ u8 seg0_idx = 0, seg1_idx = 0;
+ size_t i;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
- freq, ht, offset, width, channel_width_to_string(width),
- cf1, cf2);
+ "driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ freq, ht, hapd->iconf->ch_switch_vht_config, offset,
+ width, channel_width_to_string(width), cf1, cf2);
hapd->iface->freq = freq;
@@ -491,21 +823,33 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
seg1_idx = (cf2 - 5000) / 5;
break;
default:
- seg0_idx = hostapd_hw_get_channel(hapd, cf1);
- seg1_idx = hostapd_hw_get_channel(hapd, cf2);
+ ieee80211_freq_to_chan(cf1, &seg0_idx);
+ ieee80211_freq_to_chan(cf2, &seg1_idx);
break;
}
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
- if (!ht)
+ if (!ht) {
hapd->iconf->ieee80211ac = 0;
+ } else if (hapd->iconf->ch_switch_vht_config) {
+ /* CHAN_SWITCH VHT config */
+ if (hapd->iconf->ch_switch_vht_config &
+ CH_SWITCH_VHT_ENABLED)
+ hapd->iconf->ieee80211ac = 1;
+ else if (hapd->iconf->ch_switch_vht_config &
+ CH_SWITCH_VHT_DISABLED)
+ hapd->iconf->ieee80211ac = 0;
+ }
+ hapd->iconf->ch_switch_vht_config = 0;
+
hapd->iconf->secondary_channel = offset;
hapd->iconf->vht_oper_chwidth = chwidth;
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
- is_dfs = ieee80211_is_dfs(freq);
+ is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (hapd->csa_in_progress &&
freq == hapd->cs_freq_params.freq) {
@@ -518,6 +862,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
}
+
+ for (i = 0; i < hapd->iface->num_bss; i++)
+ hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
#endif /* NEED_AP_MLME */
}
@@ -539,10 +886,11 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
#ifdef CONFIG_ACS
-static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
- struct acs_selected_channels *acs_res)
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ struct acs_selected_channels *acs_res)
{
int ret, i;
+ int err = 0;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@@ -564,7 +912,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver selected to bad hw_mode");
- return;
+ err = 1;
+ goto out;
}
}
@@ -574,7 +923,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
- return;
+ err = 1;
+ goto out;
}
hapd->iconf->channel = acs_res->pri_channel;
@@ -588,7 +938,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
- return;
+ err = 1;
+ goto out;
}
if (hapd->iface->conf->ieee80211ac) {
@@ -617,7 +968,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
}
}
- ret = hostapd_acs_completed(hapd->iface, 0);
+out:
+ ret = hostapd_acs_completed(hapd->iface, err);
if (ret) {
wpa_printf(MSG_ERROR,
"ACS: Possibly channel configuration is invalid");
@@ -651,7 +1003,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
#ifdef HOSTAPD
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
const u8 *bssid,
u16 auth_transaction, u16 status,
@@ -670,7 +1022,33 @@ static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+
+#ifdef CONFIG_FILS
+static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 resp,
+ struct wpabuf *data, int pub)
+{
+ if (resp == WLAN_STATUS_SUCCESS) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)");
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->auth_alg = WLAN_AUTH_FILS_SK;
+ mlme_authenticate_indication(hapd, sta);
+ } else {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "authentication failed (FILS)");
+ }
+
+ hostapd_sta_auth(hapd, sta->addr, 2, resp,
+ data ? wpabuf_head(data) : NULL,
+ data ? wpabuf_len(data) : 0);
+ wpabuf_free(data);
+}
+#endif /* CONFIG_FILS */
static void hostapd_notif_auth(struct hostapd_data *hapd,
@@ -691,7 +1069,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
}
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
sta->auth_alg = WLAN_AUTH_FT;
if (sta->wpa_sm == NULL)
@@ -709,13 +1087,26 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
hostapd_notify_auth_ft_finish, hapd);
return;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_FILS
+ if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) {
+ sta->auth_alg = WLAN_AUTH_FILS_SK;
+ handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len,
+ rx_auth->auth_type, rx_auth->auth_transaction,
+ rx_auth->status_code,
+ hostapd_notify_auth_fils_finish);
+ return;
+ }
+#endif /* CONFIG_FILS */
+
fail:
hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
status, resp_ies, resp_ies_len);
}
+#ifndef NEED_AP_MLME
static void hostapd_action_rx(struct hostapd_data *hapd,
struct rx_mgmt *drv_mgmt)
{
@@ -723,53 +1114,72 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
struct sta_info *sta;
size_t plen __maybe_unused;
u16 fc;
+ u8 *action __maybe_unused;
- if (drv_mgmt->frame_len < 24 + 1)
+ if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
return;
- plen = drv_mgmt->frame_len - 24 - 1;
+ plen = drv_mgmt->frame_len - IEEE80211_HDRLEN;
mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
fc = le_to_host16(mgmt->frame_control);
if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
return; /* handled by the driver */
- wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
- mgmt->u.action.category, (int) plen);
+ action = (u8 *) &mgmt->u.action.u;
+ wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
+ " da " MACSTR " plen %d",
+ mgmt->u.action.category, *action,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen);
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
return;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (mgmt->u.action.category == WLAN_ACTION_FT) {
- const u8 *payload = drv_mgmt->frame + 24 + 1;
-
- wpa_ft_action_rx(sta->wpa_sm, payload, plen);
+ wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen);
+ return;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
- if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
- ieee802_11_sa_query_action(
- hapd, mgmt->sa,
- mgmt->u.action.u.sa_query_resp.action,
- mgmt->u.action.u.sa_query_resp.trans_id);
+ if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
+ ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
+ return;
}
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
+ return;
}
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
#ifdef CONFIG_FST
if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
return;
}
#endif /* CONFIG_FST */
-
+#ifdef CONFIG_DPP
+ if (plen >= 2 + 4 &&
+ mgmt->u.action.u.vs_public_action.action ==
+ WLAN_PA_VENDOR_SPECIFIC &&
+ WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
+ OUI_WFA &&
+ mgmt->u.action.u.vs_public_action.variable[0] ==
+ DPP_OUI_TYPE) {
+ const u8 *pos, *end;
+
+ pos = mgmt->u.action.u.vs_public_action.oui;
+ end = drv_mgmt->frame + drv_mgmt->frame_len;
+ hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
+ drv_mgmt->freq);
+ return;
+ }
+#endif /* CONFIG_DPP */
}
+#endif /* NEED_AP_MLME */
#ifdef NEED_AP_MLME
@@ -852,6 +1262,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
}
os_memset(&fi, 0, sizeof(fi));
+ fi.freq = rx_mgmt->freq;
fi.datarate = rx_mgmt->datarate;
fi.ssi_signal = rx_mgmt->ssi_signal;
@@ -884,11 +1295,24 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
size_t len, u16 stype, int ok)
{
struct ieee80211_hdr *hdr;
+ struct hostapd_data *orig_hapd = hapd;
hdr = (struct ieee80211_hdr *) buf;
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
- if (hapd == NULL || hapd == HAPD_BROADCAST)
+ if (!hapd)
return;
+ if (hapd == HAPD_BROADCAST) {
+ if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
+ buf[24] != WLAN_ACTION_PUBLIC)
+ return;
+ hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
+ if (!hapd || hapd == HAPD_BROADCAST)
+ return;
+ /*
+ * Allow processing of TX status for a Public Action frame that
+ * used wildcard BBSID.
+ */
+ }
ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
}
@@ -935,6 +1359,8 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
ieee802_1x_receive(hapd, src, data, data_len);
}
+#endif /* HOSTAPD */
+
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
@@ -944,8 +1370,6 @@ static struct hostapd_channel_data * hostapd_get_mode_channel(
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
- if (!chan)
- return NULL;
if ((unsigned int) chan->freq == freq)
return chan;
}
@@ -1009,10 +1433,9 @@ static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
}
-static void hostapd_event_get_survey(struct hostapd_data *hapd,
- struct survey_results *survey_results)
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_results)
{
- struct hostapd_iface *iface = hapd->iface;
struct freq_survey *survey, *tmp;
struct hostapd_channel_data *chan;
@@ -1044,6 +1467,7 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd,
}
+#ifdef HOSTAPD
#ifdef NEED_AP_MLME
static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
@@ -1070,6 +1494,16 @@ static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
}
+static void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd,
+ struct dfs_event *radar)
+{
+ wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq);
+ hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled,
+ radar->chan_offset, radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
+
static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
struct dfs_event *radar)
{
@@ -1112,6 +1546,28 @@ static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
+ int istatus,
+ const char *ifname,
+ const u8 *addr)
+{
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+
+ if (sta) {
+ os_free(sta->ifname_wds);
+ if (istatus == INTERFACE_ADDED)
+ sta->ifname_wds = os_strdup(ifname);
+ else
+ sta->ifname_wds = NULL;
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR,
+ istatus == INTERFACE_ADDED ?
+ WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED,
+ ifname, MAC2STR(addr));
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -1185,10 +1641,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (!data->rx_mgmt.frame)
break;
#ifdef NEED_AP_MLME
- if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
- break;
-#endif /* NEED_AP_MLME */
+ hostapd_mgmt_rx(hapd, &data->rx_mgmt);
+#else /* NEED_AP_MLME */
hostapd_action_rx(hapd, &data->rx_mgmt);
+#endif /* NEED_AP_MLME */
break;
case EVENT_RX_PROBE_REQ:
if (data->rx_probe_req.sa == NULL ||
@@ -1251,7 +1707,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->connect_failed_reason.code);
break;
case EVENT_SURVEY:
- hostapd_event_get_survey(hapd, &data->survey_results);
+ hostapd_event_get_survey(hapd->iface, &data->survey_results);
break;
#ifdef NEED_AP_MLME
case EVENT_INTERFACE_UNAVAILABLE:
@@ -1262,6 +1718,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
break;
+ case EVENT_DFS_PRE_CAC_EXPIRED:
+ if (!data)
+ break;
+ hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event);
+ break;
case EVENT_DFS_CAC_FINISHED:
if (!data)
break;
@@ -1299,9 +1760,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
* Try to re-enable interface if the driver stopped it
* when the interface got disabled.
*/
- wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+ if (hapd->wpa_auth)
+ wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+ else
+ hostapd_reconfig_encryption(hapd);
hapd->reenable_beacon = 1;
ieee802_11_set_beacon(hapd);
+#ifdef NEED_AP_MLME
+ } else if (hapd->disabled && hapd->iface->cac_started) {
+ wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
+ hostapd_handle_dfs(hapd->iface);
+#endif /* NEED_AP_MLME */
}
break;
case EVENT_INTERFACE_DISABLED:
@@ -1315,10 +1784,49 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
&data->acs_selected_channels);
break;
#endif /* CONFIG_ACS */
+ case EVENT_STATION_OPMODE_CHANGED:
+ hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr,
+ data->sta_opmode.smps_mode,
+ data->sta_opmode.chan_width,
+ data->sta_opmode.rx_nss);
+ break;
+ case EVENT_WDS_STA_INTERFACE_STATUS:
+ hostapd_event_wds_sta_interface_status(
+ hapd, data->wds_sta_interface.istatus,
+ data->wds_sta_interface.ifname,
+ data->wds_sta_interface.sta_addr);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
}
}
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct hapd_interfaces *interfaces = ctx;
+ struct hostapd_data *hapd;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
+ if (hapd && hapd->driver && hapd->driver->get_ifindex &&
+ hapd->drv_priv) {
+ unsigned int ifindex;
+
+ ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "interface status ifindex %d mismatch (%d)",
+ ifindex, data->interface_status.ifindex);
+ return;
+ }
+ }
+ if (hapd)
+ wpa_supplicant_event(hapd, event, data);
+}
+
#endif /* HOSTAPD */
diff --git a/contrib/wpa/src/ap/eap_user_db.c b/contrib/wpa/src/ap/eap_user_db.c
index 082d0f5..a510ee3 100644
--- a/contrib/wpa/src/ap/eap_user_db.c
+++ b/contrib/wpa/src/ap/eap_user_db.c
@@ -91,6 +91,8 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
set_user_methods(user, argv[i]);
} else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
user->remediation = strlen(argv[i]) > 0;
+ } else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) {
+ user->t_c_timestamp = strtol(argv[i], NULL, 10);
}
}
@@ -137,6 +139,7 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
struct hostapd_eap_user *user = NULL;
char id_str[256], cmd[300];
size_t i;
+ int res;
if (identity_len >= sizeof(id_str)) {
wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
@@ -172,6 +175,7 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
if (hapd->tmp_eap_user.identity == NULL)
return NULL;
os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+ hapd->tmp_eap_user.identity_len = identity_len;
if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
@@ -180,9 +184,12 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
return NULL;
}
- os_snprintf(cmd, sizeof(cmd),
- "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
- id_str, phase2);
+ res = os_snprintf(cmd, sizeof(cmd),
+ "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
+ id_str, phase2);
+ if (os_snprintf_error(sizeof(cmd), res))
+ goto fail;
+
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {
@@ -212,6 +219,7 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
}
}
+fail:
sqlite3_close(db);
return user;
diff --git a/contrib/wpa/src/ap/eth_p_oui.c b/contrib/wpa/src/ap/eth_p_oui.c
new file mode 100644
index 0000000..aba901e
--- /dev/null
+++ b/contrib/wpa/src/ap/eth_p_oui.c
@@ -0,0 +1,191 @@
+/*
+ * hostapd / IEEE 802 OUI Extended EtherType 88-B7
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "l2_packet/l2_packet.h"
+#include "hostapd.h"
+#include "eth_p_oui.h"
+
+/*
+ * See IEEE Std 802-2014, Clause 9.2.4 for the definition of the OUI Extended
+ * EtherType 88-B7. This file implements this with OUI 00:13:74 and
+ * vendor-specific subtype 0x0001.
+ */
+static const u8 global_oui[] = { 0x00, 0x13, 0x74, 0x00, 0x01 };
+
+struct eth_p_oui_iface {
+ struct dl_list list;
+ char ifname[IFNAMSIZ + 1];
+ struct l2_packet_data *l2;
+ struct dl_list receiver;
+};
+
+struct eth_p_oui_ctx {
+ struct dl_list list;
+ struct eth_p_oui_iface *iface;
+ /* all data needed to deliver and unregister */
+ u8 oui_suffix; /* last byte of OUI */
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *dst_addr, u8 oui_suffix,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+};
+
+
+void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
+ const u8 *dst_addr, const u8 *buf, size_t len)
+{
+ ctx->rx_callback(ctx->rx_callback_ctx, src_addr, dst_addr,
+ ctx->oui_suffix, buf, len);
+}
+
+
+static void eth_p_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct eth_p_oui_iface *iface = ctx;
+ struct eth_p_oui_ctx *receiver;
+ const struct l2_ethhdr *ethhdr;
+
+ if (len < sizeof(*ethhdr) + sizeof(global_oui) + 1) {
+ /* too short packet */
+ return;
+ }
+
+ ethhdr = (struct l2_ethhdr *) buf;
+ /* trim eth_hdr from buf and len */
+ buf += sizeof(*ethhdr);
+ len -= sizeof(*ethhdr);
+
+ /* verify OUI and vendor-specific subtype match */
+ if (os_memcmp(buf, global_oui, sizeof(global_oui)) != 0)
+ return;
+ buf += sizeof(global_oui);
+ len -= sizeof(global_oui);
+
+ dl_list_for_each(receiver, &iface->receiver,
+ struct eth_p_oui_ctx, list) {
+ if (buf[0] != receiver->oui_suffix)
+ continue;
+
+ eth_p_oui_deliver(receiver, ethhdr->h_source, ethhdr->h_dest,
+ buf + 1, len - 1);
+ }
+}
+
+
+struct eth_p_oui_ctx *
+eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *dst_addr, u8 oui_suffix,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx)
+{
+ struct eth_p_oui_iface *iface;
+ struct eth_p_oui_ctx *receiver;
+ int found = 0;
+ struct hapd_interfaces *interfaces;
+
+ receiver = os_zalloc(sizeof(*receiver));
+ if (!receiver)
+ goto err;
+
+ receiver->oui_suffix = oui_suffix;
+ receiver->rx_callback = rx_callback;
+ receiver->rx_callback_ctx = rx_callback_ctx;
+
+ interfaces = hapd->iface->interfaces;
+
+ dl_list_for_each(iface, &interfaces->eth_p_oui, struct eth_p_oui_iface,
+ list) {
+ if (os_strcmp(iface->ifname, ifname) != 0)
+ continue;
+ found = 1;
+ break;
+ }
+
+ if (!found) {
+ iface = os_zalloc(sizeof(*iface));
+ if (!iface)
+ goto err;
+
+ os_strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
+ iface->l2 = l2_packet_init(ifname, NULL, ETH_P_OUI, eth_p_rx,
+ iface, 1);
+ if (!iface->l2) {
+ os_free(iface);
+ goto err;
+ }
+ dl_list_init(&iface->receiver);
+
+ dl_list_add_tail(&interfaces->eth_p_oui, &iface->list);
+ }
+
+ dl_list_add_tail(&iface->receiver, &receiver->list);
+ receiver->iface = iface;
+
+ return receiver;
+err:
+ os_free(receiver);
+ return NULL;
+}
+
+
+void eth_p_oui_unregister(struct eth_p_oui_ctx *ctx)
+{
+ struct eth_p_oui_iface *iface;
+
+ if (!ctx)
+ return;
+
+ iface = ctx->iface;
+
+ dl_list_del(&ctx->list);
+ os_free(ctx);
+
+ if (dl_list_empty(&iface->receiver)) {
+ dl_list_del(&iface->list);
+ l2_packet_deinit(iface->l2);
+ os_free(iface);
+ }
+}
+
+
+int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
+ const u8 *dst_addr, const u8 *buf, size_t len)
+{
+ struct eth_p_oui_iface *iface = ctx->iface;
+ u8 *packet, *p;
+ size_t packet_len;
+ int ret;
+ struct l2_ethhdr *ethhdr;
+
+ packet_len = sizeof(*ethhdr) + sizeof(global_oui) + 1 + len;
+ packet = os_zalloc(packet_len);
+ if (!packet)
+ return -1;
+ p = packet;
+
+ ethhdr = (struct l2_ethhdr *) packet;
+ os_memcpy(ethhdr->h_source, src_addr, ETH_ALEN);
+ os_memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
+ ethhdr->h_proto = host_to_be16(ETH_P_OUI);
+ p += sizeof(*ethhdr);
+
+ os_memcpy(p, global_oui, sizeof(global_oui));
+ p[sizeof(global_oui)] = ctx->oui_suffix;
+ p += sizeof(global_oui) + 1;
+
+ os_memcpy(p, buf, len);
+
+ ret = l2_packet_send(iface->l2, NULL, 0, packet, packet_len);
+ os_free(packet);
+ return ret;
+}
diff --git a/contrib/wpa/src/ap/eth_p_oui.h b/contrib/wpa/src/ap/eth_p_oui.h
new file mode 100644
index 0000000..466fdc3
--- /dev/null
+++ b/contrib/wpa/src/ap/eth_p_oui.h
@@ -0,0 +1,28 @@
+/*
+ * hostapd / IEEE 802 OUI Extended Ethertype
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef ETH_P_OUI_H
+#define ETH_P_OUI_H
+
+struct eth_p_oui_ctx;
+struct hostapd_data;
+
+/* rx_callback only gets payload after OUI passed as buf */
+struct eth_p_oui_ctx *
+eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *dst_addr, u8 oui_suffix,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx);
+void eth_p_oui_unregister(struct eth_p_oui_ctx *eth_p_oui);
+int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
+ const u8 *dst_addr, const u8 *buf, size_t len);
+void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
+ const u8 *dst_addr, const u8 *buf, size_t len);
+
+#endif /* ETH_P_OUI_H */
diff --git a/contrib/wpa/src/ap/fils_hlp.c b/contrib/wpa/src/ap/fils_hlp.c
new file mode 100644
index 0000000..6da514a
--- /dev/null
+++ b/contrib/wpa/src/ap/fils_hlp.c
@@ -0,0 +1,654 @@
+/*
+ * FILS HLP request processing
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/dhcp.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ieee802_11.h"
+#include "fils_hlp.h"
+
+
+static be16 ip_checksum(const void *buf, size_t len)
+{
+ u32 sum = 0;
+ const u16 *pos;
+
+ for (pos = buf; len >= 2; len -= 2)
+ sum += ntohs(*pos++);
+ if (len)
+ sum += ntohs(*pos << 8);
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += sum >> 16;
+ return htons(~sum);
+}
+
+
+static int fils_dhcp_request(struct hostapd_data *hapd, struct sta_info *sta,
+ struct dhcp_data *dhcpoffer, u8 *dhcpofferend)
+{
+ u8 *pos, *end;
+ struct dhcp_data *dhcp;
+ struct sockaddr_in addr;
+ ssize_t res;
+ const u8 *server_id = NULL;
+
+ if (!sta->hlp_dhcp_discover) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No pending HLP DHCPDISCOVER available");
+ return -1;
+ }
+
+ /* Convert to DHCPREQUEST, remove rapid commit option, replace requested
+ * IP address option with yiaddr. */
+ pos = wpabuf_mhead(sta->hlp_dhcp_discover);
+ end = pos + wpabuf_len(sta->hlp_dhcp_discover);
+ dhcp = (struct dhcp_data *) pos;
+ pos = (u8 *) (dhcp + 1);
+ pos += 4; /* skip magic */
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ *pos = DHCPREQUEST;
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ case DHCP_OPT_REQUESTED_IP_ADDRESS:
+ case DHCP_OPT_SERVER_ID:
+ /* Remove option */
+ pos -= 2;
+ os_memmove(pos, pos + 2 + olen, end - pos - 2 - olen);
+ end -= 2 + olen;
+ olen = 0;
+ break;
+ }
+ pos += olen;
+ }
+ if (pos >= end || *pos != DHCP_OPT_END) {
+ wpa_printf(MSG_DEBUG, "FILS: Could not update DHCPDISCOVER");
+ return -1;
+ }
+ sta->hlp_dhcp_discover->used = pos - (u8 *) dhcp;
+
+ /* Copy Server ID option from DHCPOFFER to DHCPREQUEST */
+ pos = (u8 *) (dhcpoffer + 1);
+ end = dhcpofferend;
+ pos += 4; /* skip magic */
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_SERVER_ID:
+ server_id = pos - 2;
+ break;
+ }
+ pos += olen;
+ }
+
+ if (wpabuf_resize(&sta->hlp_dhcp_discover,
+ 6 + 1 + (server_id ? 2 + server_id[1] : 0)))
+ return -1;
+ if (server_id)
+ wpabuf_put_data(sta->hlp_dhcp_discover, server_id,
+ 2 + server_id[1]);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_REQUESTED_IP_ADDRESS);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, 4);
+ wpabuf_put_data(sta->hlp_dhcp_discover, &dhcpoffer->your_ip, 4);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_END);
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_server_port);
+ res = sendto(hapd->dhcp_sock, wpabuf_head(sta->hlp_dhcp_discover),
+ wpabuf_len(sta->hlp_dhcp_discover), 0,
+ (const struct sockaddr *) &addr, sizeof(addr));
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
+ strerror(errno));
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "FILS: Acting as DHCP rapid commit proxy for %s:%d",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+ sta->fils_dhcp_rapid_commit_proxy = 1;
+ return 0;
+}
+
+
+static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = sock_ctx;
+ struct sta_info *sta;
+ u8 buf[1500], *pos, *end, *end_opt = NULL;
+ struct dhcp_data *dhcp;
+ struct sockaddr_in addr;
+ socklen_t addr_len;
+ ssize_t res;
+ u8 msgtype = 0;
+ int rapid_commit = 0;
+ struct iphdr *iph;
+ struct udphdr *udph;
+ struct wpabuf *resp;
+ const u8 *rpos;
+ size_t left, len;
+
+ addr_len = sizeof(addr);
+ res = recvfrom(sd, buf, sizeof(buf), 0,
+ (struct sockaddr *) &addr, &addr_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: DHCP read failed: %s",
+ strerror(errno));
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "FILS: DHCP response from server %s:%d (len=%d)",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), (int) res);
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP - DHCP server response", buf, res);
+ if ((size_t) res < sizeof(*dhcp))
+ return;
+ dhcp = (struct dhcp_data *) buf;
+ if (dhcp->op != 2)
+ return; /* Not a BOOTREPLY */
+ if (dhcp->relay_ip != hapd->conf->own_ip_addr.u.v4.s_addr) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - DHCP response to unknown relay address 0x%x",
+ dhcp->relay_ip);
+ return;
+ }
+ dhcp->relay_ip = 0;
+ pos = (u8 *) (dhcp + 1);
+ end = &buf[res];
+
+ if (end - pos < 4 || WPA_GET_BE32(pos) != DHCP_MAGIC) {
+ wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic in response");
+ return;
+ }
+ pos += 4;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options in response",
+ pos, end - pos);
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ msgtype = pos[0];
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ rapid_commit = 1;
+ break;
+ }
+ pos += olen;
+ }
+ if (pos < end && *pos == DHCP_OPT_END)
+ end_opt = pos;
+
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - DHCP message type %u (rapid_commit=%d hw_addr="
+ MACSTR ")",
+ msgtype, rapid_commit, MAC2STR(dhcp->hw_addr));
+
+ sta = ap_get_sta(hapd, dhcp->hw_addr);
+ if (!sta || !sta->fils_pending_assoc_req) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No pending HLP DHCP exchange with hw_addr "
+ MACSTR, MAC2STR(dhcp->hw_addr));
+ return;
+ }
+
+ if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPOFFER &&
+ !rapid_commit) {
+ /* Use hostapd to take care of 4-message exchange and convert
+ * the final DHCPACK to rapid commit version. */
+ if (fils_dhcp_request(hapd, sta, dhcp, end) == 0)
+ return;
+ /* failed, so send the server response as-is */
+ } else if (msgtype != DHCPACK) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No DHCPACK available from the server and cannot do rapid commit proxying");
+ }
+
+ pos = buf;
+ resp = wpabuf_alloc(2 * ETH_ALEN + 6 + 2 +
+ sizeof(*iph) + sizeof(*udph) + (end - pos) + 2);
+ if (!resp)
+ return;
+ wpabuf_put_data(resp, sta->addr, ETH_ALEN);
+ wpabuf_put_data(resp, hapd->own_addr, ETH_ALEN);
+ wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
+ wpabuf_put_be16(resp, ETH_P_IP);
+ iph = wpabuf_put(resp, sizeof(*iph));
+ iph->version = 4;
+ iph->ihl = sizeof(*iph) / 4;
+ iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+ iph->ttl = 1;
+ iph->protocol = 17; /* UDP */
+ iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
+ iph->daddr = dhcp->client_ip;
+ iph->check = ip_checksum(iph, sizeof(*iph));
+ udph = wpabuf_put(resp, sizeof(*udph));
+ udph->uh_sport = htons(DHCP_SERVER_PORT);
+ udph->uh_dport = htons(DHCP_CLIENT_PORT);
+ udph->uh_ulen = htons(sizeof(*udph) + (end - pos));
+ udph->uh_sum = htons(0x0000); /* TODO: calculate checksum */
+ if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPACK &&
+ !rapid_commit && sta->fils_dhcp_rapid_commit_proxy && end_opt) {
+ /* Add rapid commit option */
+ wpabuf_put_data(resp, pos, end_opt - pos);
+ wpabuf_put_u8(resp, DHCP_OPT_RAPID_COMMIT);
+ wpabuf_put_u8(resp, 0);
+ wpabuf_put_data(resp, end_opt, end - end_opt);
+ } else {
+ wpabuf_put_data(resp, pos, end - pos);
+ }
+ if (wpabuf_resize(&sta->fils_hlp_resp, wpabuf_len(resp) +
+ 2 * wpabuf_len(resp) / 255 + 100)) {
+ wpabuf_free(resp);
+ return;
+ }
+
+ rpos = wpabuf_head(resp);
+ left = wpabuf_len(resp);
+
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXTENSION); /* Element ID */
+ if (left <= 254)
+ len = 1 + left;
+ else
+ len = 255;
+ wpabuf_put_u8(sta->fils_hlp_resp, len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXT_FILS_HLP_CONTAINER);
+ /* Destination MAC Address, Source MAC Address, HLP Packet.
+ * HLP Packet is in MSDU format (i.e., including the LLC/SNAP header
+ * when LPD is used). */
+ wpabuf_put_data(sta->fils_hlp_resp, rpos, len - 1);
+ rpos += len - 1;
+ left -= len - 1;
+ while (left) {
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_FRAGMENT);
+ len = left > 255 ? 255 : left;
+ wpabuf_put_u8(sta->fils_hlp_resp, len);
+ wpabuf_put_data(sta->fils_hlp_resp, rpos, len);
+ rpos += len;
+ left -= len;
+ }
+ wpabuf_free(resp);
+
+ if (sta->fils_drv_assoc_finish)
+ hostapd_notify_assoc_fils_finish(hapd, sta);
+ else
+ fils_hlp_finish_assoc(hapd, sta);
+}
+
+
+static int fils_process_hlp_dhcp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *msg, size_t len)
+{
+ const struct dhcp_data *dhcp;
+ struct wpabuf *dhcp_buf;
+ struct dhcp_data *dhcp_msg;
+ u8 msgtype = 0;
+ int rapid_commit = 0;
+ const u8 *pos = msg, *end;
+ struct sockaddr_in addr;
+ ssize_t res;
+
+ if (len < sizeof(*dhcp))
+ return 0;
+ dhcp = (const struct dhcp_data *) pos;
+ end = pos + len;
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request DHCP: op=%u htype=%u hlen=%u hops=%u xid=0x%x",
+ dhcp->op, dhcp->htype, dhcp->hlen, dhcp->hops,
+ ntohl(dhcp->xid));
+ pos += sizeof(*dhcp);
+ if (dhcp->op != 1)
+ return 0; /* Not a BOOTREQUEST */
+
+ if (end - pos < 4)
+ return 0;
+ if (WPA_GET_BE32(pos) != DHCP_MAGIC) {
+ wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic");
+ return 0;
+ }
+ pos += 4;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options", pos, end - pos);
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ msgtype = pos[0];
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ rapid_commit = 1;
+ break;
+ }
+ pos += olen;
+ }
+
+ wpa_printf(MSG_DEBUG, "FILS: HLP - DHCP message type %u", msgtype);
+ if (msgtype != DHCPDISCOVER)
+ return 0;
+
+ if (hapd->conf->dhcp_server.af != AF_INET ||
+ hapd->conf->dhcp_server.u.v4.s_addr == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - no DHCPv4 server configured - drop request");
+ return 0;
+ }
+
+ if (hapd->conf->own_ip_addr.af != AF_INET ||
+ hapd->conf->own_ip_addr.u.v4.s_addr == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - no IPv4 own_ip_addr configured - drop request");
+ return 0;
+ }
+
+ if (hapd->dhcp_sock < 0) {
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Failed to open DHCP socket: %s",
+ strerror(errno));
+ return 0;
+ }
+
+ if (hapd->conf->dhcp_relay_port) {
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr =
+ hapd->conf->own_ip_addr.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_relay_port);
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr))) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Failed to bind DHCP socket: %s",
+ strerror(errno));
+ close(s);
+ return 0;
+ }
+ }
+ if (eloop_register_sock(s, EVENT_TYPE_READ,
+ fils_dhcp_handler, NULL, hapd)) {
+ close(s);
+ return 0;
+ }
+
+ hapd->dhcp_sock = s;
+ }
+
+ dhcp_buf = wpabuf_alloc(len);
+ if (!dhcp_buf)
+ return 0;
+ dhcp_msg = wpabuf_put(dhcp_buf, len);
+ os_memcpy(dhcp_msg, msg, len);
+ dhcp_msg->relay_ip = hapd->conf->own_ip_addr.u.v4.s_addr;
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_server_port);
+ res = sendto(hapd->dhcp_sock, dhcp_msg, len, 0,
+ (const struct sockaddr *) &addr, sizeof(addr));
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
+ strerror(errno));
+ wpabuf_free(dhcp_buf);
+ /* Close the socket to try to recover from error */
+ eloop_unregister_read_sock(hapd->dhcp_sock);
+ close(hapd->dhcp_sock);
+ hapd->dhcp_sock = -1;
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP relayed DHCP request to server %s:%d (rapid_commit=%d)",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
+ rapid_commit);
+ if (hapd->conf->dhcp_rapid_commit_proxy && rapid_commit) {
+ /* Store a copy of the DHCPDISCOVER for rapid commit proxying
+ * purposes if the server does not support the rapid commit
+ * option. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Store DHCPDISCOVER for rapid commit proxy");
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = dhcp_buf;
+ } else {
+ wpabuf_free(dhcp_buf);
+ }
+
+ return 1;
+}
+
+
+static int fils_process_hlp_udp(struct hostapd_data *hapd,
+ struct sta_info *sta, const u8 *dst,
+ const u8 *pos, size_t len)
+{
+ const struct iphdr *iph;
+ const struct udphdr *udph;
+ u16 sport, dport, ulen;
+
+ if (len < sizeof(*iph) + sizeof(*udph))
+ return 0;
+ iph = (const struct iphdr *) pos;
+ udph = (const struct udphdr *) (iph + 1);
+ sport = ntohs(udph->uh_sport);
+ dport = ntohs(udph->uh_dport);
+ ulen = ntohs(udph->uh_ulen);
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request UDP: sport=%u dport=%u ulen=%u sum=0x%x",
+ sport, dport, ulen, ntohs(udph->uh_sum));
+ /* TODO: Check UDP checksum */
+ if (ulen < sizeof(*udph) || ulen > len - sizeof(*iph))
+ return 0;
+
+ if (dport == DHCP_SERVER_PORT && sport == DHCP_CLIENT_PORT) {
+ return fils_process_hlp_dhcp(hapd, sta, (const u8 *) (udph + 1),
+ ulen - sizeof(*udph));
+ }
+
+ return 0;
+}
+
+
+static int fils_process_hlp_ip(struct hostapd_data *hapd,
+ struct sta_info *sta, const u8 *dst,
+ const u8 *pos, size_t len)
+{
+ const struct iphdr *iph;
+ u16 tot_len;
+
+ if (len < sizeof(*iph))
+ return 0;
+ iph = (const struct iphdr *) pos;
+ if (ip_checksum(iph, sizeof(*iph)) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request IPv4 packet had invalid header checksum - dropped");
+ return 0;
+ }
+ tot_len = ntohs(iph->tot_len);
+ if (tot_len > len)
+ return 0;
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
+ iph->saddr, iph->daddr, iph->protocol);
+ switch (iph->protocol) {
+ case 17:
+ return fils_process_hlp_udp(hapd, sta, dst, pos, len);
+ }
+
+ return 0;
+}
+
+
+static int fils_process_hlp_req(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *pos, size_t len)
+{
+ const u8 *pkt, *end;
+
+ wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
+ " src=" MACSTR " len=%u)",
+ MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
+ (unsigned int) len);
+ if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Ignore HLP request with unexpected source address"
+ MACSTR, MAC2STR(pos + ETH_ALEN));
+ return 0;
+ }
+
+ end = pos + len;
+ pkt = pos + 2 * ETH_ALEN;
+ if (end - pkt >= 6 &&
+ os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
+ pkt += 6; /* Remove SNAP/LLC header */
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
+
+ if (end - pkt < 2)
+ return 0;
+
+ switch (WPA_GET_BE16(pkt)) {
+ case ETH_P_IP:
+ return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
+ end - pkt - 2);
+ }
+
+ return 0;
+}
+
+
+int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, int left)
+{
+ const u8 *end = pos + left;
+ u8 *tmp, *tmp_pos;
+ int ret = 0;
+
+ if (sta->fils_pending_assoc_req &&
+ eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta)) {
+ /* Do not process FILS HLP request again if the station
+ * retransmits (Re)Association Request frame before the previous
+ * HLP response has either been received or timed out. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Do not relay another HLP request from "
+ MACSTR
+ " before processing of the already pending one has been completed",
+ MAC2STR(sta->addr));
+ return 1;
+ }
+
+ /* Old DHCPDISCOVER is not needed anymore, if it was still pending */
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+ sta->fils_dhcp_rapid_commit_proxy = 0;
+
+ /* Check if there are any FILS HLP Container elements */
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ return 0;
+ if (pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 + 2 * ETH_ALEN &&
+ pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ pos += 2 + pos[1];
+ }
+ if (end - pos < 2)
+ return 0; /* No FILS HLP Container elements */
+
+ tmp = os_malloc(end - pos);
+ if (!tmp)
+ return 0;
+
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos ||
+ pos[0] != WLAN_EID_EXTENSION ||
+ pos[1] < 1 + 2 * ETH_ALEN ||
+ pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ tmp_pos = tmp;
+ os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
+ tmp_pos += pos[1] - 1;
+ pos += 2 + pos[1];
+
+ /* Add possible fragments */
+ while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
+ 2 + pos[1] <= end - pos) {
+ os_memcpy(tmp_pos, pos + 2, pos[1]);
+ tmp_pos += pos[1];
+ pos += 2 + pos[1];
+ }
+
+ if (fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp) > 0)
+ ret = 1;
+ }
+
+ os_free(tmp);
+
+ return ret;
+}
+
+
+void fils_hlp_deinit(struct hostapd_data *hapd)
+{
+ if (hapd->dhcp_sock >= 0) {
+ eloop_unregister_read_sock(hapd->dhcp_sock);
+ close(hapd->dhcp_sock);
+ hapd->dhcp_sock = -1;
+ }
+}
diff --git a/contrib/wpa/src/ap/fils_hlp.h b/contrib/wpa/src/ap/fils_hlp.h
new file mode 100644
index 0000000..e14a6bf
--- /dev/null
+++ b/contrib/wpa/src/ap/fils_hlp.h
@@ -0,0 +1,27 @@
+/*
+ * FILS HLP request processing
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef FILS_HLP_H
+#define FILS_HLP_H
+
+int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, int left);
+
+#ifdef CONFIG_FILS
+
+void fils_hlp_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_FILS */
+
+static inline void fils_hlp_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_FILS */
+
+#endif /* FILS_HLP_H */
diff --git a/contrib/wpa/src/ap/gas_query_ap.c b/contrib/wpa/src/ap/gas_query_ap.c
new file mode 100644
index 0000000..fdb3cad
--- /dev/null
+++ b/contrib/wpa/src/ap/gas_query_ap.c
@@ -0,0 +1,714 @@
+/*
+ * Generic advertisement service (GAS) query (hostapd)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011-2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "utils/list.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "gas_query_ap.h"
+
+
+/** GAS query timeout in seconds */
+#define GAS_QUERY_TIMEOUT_PERIOD 2
+
+/* GAS query wait-time / duration in ms */
+#define GAS_QUERY_WAIT_TIME_INITIAL 1000
+#define GAS_QUERY_WAIT_TIME_COMEBACK 150
+
+/**
+ * struct gas_query_pending - Pending GAS query
+ */
+struct gas_query_pending {
+ struct dl_list list;
+ struct gas_query_ap *gas;
+ u8 addr[ETH_ALEN];
+ u8 dialog_token;
+ u8 next_frag_id;
+ unsigned int wait_comeback:1;
+ unsigned int offchannel_tx_started:1;
+ unsigned int retry:1;
+ int freq;
+ u16 status_code;
+ struct wpabuf *req;
+ struct wpabuf *adv_proto;
+ struct wpabuf *resp;
+ struct os_reltime last_oper;
+ void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+ enum gas_query_ap_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code);
+ void *ctx;
+ u8 sa[ETH_ALEN];
+};
+
+/**
+ * struct gas_query_ap - Internal GAS query data
+ */
+struct gas_query_ap {
+ struct hostapd_data *hapd;
+ void *msg_ctx;
+ struct dl_list pending; /* struct gas_query_pending */
+ struct gas_query_pending *current;
+};
+
+
+static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_tx_initial_req(struct gas_query_ap *gas,
+ struct gas_query_pending *query);
+static int gas_query_new_dialog_token(struct gas_query_ap *gas, const u8 *dst);
+
+
+static int ms_from_time(struct os_reltime *last)
+{
+ struct os_reltime now, res;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, last, &res);
+ return res.sec * 1000 + res.usec / 1000;
+}
+
+
+/**
+ * gas_query_ap_init - Initialize GAS query component
+ * @hapd: Pointer to hostapd data
+ * Returns: Pointer to GAS query data or %NULL on failure
+ */
+struct gas_query_ap * gas_query_ap_init(struct hostapd_data *hapd,
+ void *msg_ctx)
+{
+ struct gas_query_ap *gas;
+
+ gas = os_zalloc(sizeof(*gas));
+ if (!gas)
+ return NULL;
+
+ gas->hapd = hapd;
+ gas->msg_ctx = msg_ctx;
+ dl_list_init(&gas->pending);
+
+ return gas;
+}
+
+
+static const char * gas_result_txt(enum gas_query_ap_result result)
+{
+ switch (result) {
+ case GAS_QUERY_AP_SUCCESS:
+ return "SUCCESS";
+ case GAS_QUERY_AP_FAILURE:
+ return "FAILURE";
+ case GAS_QUERY_AP_TIMEOUT:
+ return "TIMEOUT";
+ case GAS_QUERY_AP_PEER_ERROR:
+ return "PEER_ERROR";
+ case GAS_QUERY_AP_INTERNAL_ERROR:
+ return "INTERNAL_ERROR";
+ case GAS_QUERY_AP_DELETED_AT_DEINIT:
+ return "DELETED_AT_DEINIT";
+ }
+
+ return "N/A";
+}
+
+
+static void gas_query_free(struct gas_query_pending *query, int del_list)
+{
+ if (del_list)
+ dl_list_del(&query->list);
+
+ wpabuf_free(query->req);
+ wpabuf_free(query->adv_proto);
+ wpabuf_free(query->resp);
+ os_free(query);
+}
+
+
+static void gas_query_done(struct gas_query_ap *gas,
+ struct gas_query_pending *query,
+ enum gas_query_ap_result result)
+{
+ wpa_msg(gas->msg_ctx, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR
+ " dialog_token=%u freq=%d status_code=%u result=%s",
+ MAC2STR(query->addr), query->dialog_token, query->freq,
+ query->status_code, gas_result_txt(result));
+ if (gas->current == query)
+ gas->current = NULL;
+ eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
+ dl_list_del(&query->list);
+ query->cb(query->ctx, query->addr, query->dialog_token, result,
+ query->adv_proto, query->resp, query->status_code);
+ gas_query_free(query, 0);
+}
+
+
+/**
+ * gas_query_ap_deinit - Deinitialize GAS query component
+ * @gas: GAS query data from gas_query_init()
+ */
+void gas_query_ap_deinit(struct gas_query_ap *gas)
+{
+ struct gas_query_pending *query, *next;
+
+ if (gas == NULL)
+ return;
+
+ dl_list_for_each_safe(query, next, &gas->pending,
+ struct gas_query_pending, list)
+ gas_query_done(gas, query, GAS_QUERY_AP_DELETED_AT_DEINIT);
+
+ os_free(gas);
+}
+
+
+static struct gas_query_pending *
+gas_query_get_pending(struct gas_query_ap *gas, const u8 *addr, u8 dialog_token)
+{
+ struct gas_query_pending *q;
+ dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
+ if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 &&
+ q->dialog_token == dialog_token)
+ return q;
+ }
+ return NULL;
+}
+
+
+static int gas_query_append(struct gas_query_pending *query, const u8 *data,
+ size_t len)
+{
+ if (wpabuf_resize(&query->resp, len) < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
+ return -1;
+ }
+ wpabuf_put_data(query->resp, data, len);
+ return 0;
+}
+
+
+void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst,
+ const u8 *data, size_t data_len, int ok)
+{
+ struct gas_query_pending *query;
+ int dur;
+
+ if (!gas || !gas->current) {
+ wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: dst=" MACSTR
+ " ok=%d - no query in progress", MAC2STR(dst), ok);
+ return;
+ }
+
+ query = gas->current;
+
+ dur = ms_from_time(&query->last_oper);
+ wpa_printf(MSG_DEBUG, "GAS: TX status: dst=" MACSTR
+ " ok=%d query=%p dialog_token=%u dur=%d ms",
+ MAC2STR(dst), ok, query, query->dialog_token, dur);
+ if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
+ return;
+ }
+ os_get_reltime(&query->last_oper);
+
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ if (!ok) {
+ wpa_printf(MSG_DEBUG, "GAS: No ACK to GAS request");
+ eloop_register_timeout(0, 250000, gas_query_timeout,
+ gas, query);
+ } else {
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+ gas_query_timeout, gas, query);
+ }
+ if (query->wait_comeback && !query->retry) {
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout,
+ gas, query);
+ eloop_register_timeout(
+ 0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000,
+ gas_query_rx_comeback_timeout, gas, query);
+ }
+}
+
+
+static int pmf_in_use(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, addr);
+ return sta && (sta->flags & WLAN_STA_MFP);
+}
+
+
+static int gas_query_tx(struct gas_query_ap *gas,
+ struct gas_query_pending *query,
+ struct wpabuf *req, unsigned int wait_time)
+{
+ int res, prot = pmf_in_use(gas->hapd, query->addr);
+
+ wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
+ "freq=%d prot=%d using src addr " MACSTR,
+ MAC2STR(query->addr), (unsigned int) wpabuf_len(req),
+ query->freq, prot, MAC2STR(query->sa));
+ if (prot) {
+ u8 *categ = wpabuf_mhead_u8(req);
+ *categ = WLAN_ACTION_PROTECTED_DUAL;
+ }
+ os_get_reltime(&query->last_oper);
+ res = hostapd_drv_send_action(gas->hapd, query->freq, wait_time,
+ query->addr, wpabuf_head(req),
+ wpabuf_len(req));
+ return res;
+}
+
+
+static void gas_query_tx_comeback_req(struct gas_query_ap *gas,
+ struct gas_query_pending *query)
+{
+ struct wpabuf *req;
+ unsigned int wait_time;
+
+ req = gas_build_comeback_req(query->dialog_token);
+ if (req == NULL) {
+ gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
+ return;
+ }
+
+ wait_time = (query->retry || !query->offchannel_tx_started) ?
+ GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK;
+
+ if (gas_query_tx(gas, query, req, wait_time) < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+ MACSTR, MAC2STR(query->addr));
+ gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
+ }
+
+ wpabuf_free(req);
+}
+
+
+static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx)
+{
+ struct gas_query_ap *gas = eloop_data;
+ struct gas_query_pending *query = user_ctx;
+ int dialog_token;
+
+ wpa_printf(MSG_DEBUG,
+ "GAS: No response to comeback request received (retry=%u)",
+ query->retry);
+ if (gas->current != query || query->retry)
+ return;
+ dialog_token = gas_query_new_dialog_token(gas, query->addr);
+ if (dialog_token < 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "GAS: Retry GAS query due to comeback response timeout");
+ query->retry = 1;
+ query->dialog_token = dialog_token;
+ *(wpabuf_mhead_u8(query->req) + 2) = dialog_token;
+ query->wait_comeback = 0;
+ query->next_frag_id = 0;
+ wpabuf_free(query->adv_proto);
+ query->adv_proto = NULL;
+ eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ gas_query_tx_initial_req(gas, query);
+}
+
+
+static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
+{
+ struct gas_query_ap *gas = eloop_data;
+ struct gas_query_pending *query = user_ctx;
+
+ wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR,
+ MAC2STR(query->addr));
+ gas_query_tx_comeback_req(gas, query);
+}
+
+
+static void gas_query_tx_comeback_req_delay(struct gas_query_ap *gas,
+ struct gas_query_pending *query,
+ u16 comeback_delay)
+{
+ unsigned int secs, usecs;
+
+ secs = (comeback_delay * 1024) / 1000000;
+ usecs = comeback_delay * 1024 - secs * 1000000;
+ wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
+ " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs);
+ eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+ eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout,
+ gas, query);
+}
+
+
+static void gas_query_rx_initial(struct gas_query_ap *gas,
+ struct gas_query_pending *query,
+ const u8 *adv_proto, const u8 *resp,
+ size_t len, u16 comeback_delay)
+{
+ wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
+ MACSTR " (dialog_token=%u comeback_delay=%u)",
+ MAC2STR(query->addr), query->dialog_token, comeback_delay);
+
+ query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
+ if (query->adv_proto == NULL) {
+ gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
+ return;
+ }
+
+ if (comeback_delay) {
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ query->wait_comeback = 1;
+ gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
+ return;
+ }
+
+ /* Query was completed without comeback mechanism */
+ if (gas_query_append(query, resp, len) < 0) {
+ gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
+ return;
+ }
+
+ gas_query_done(gas, query, GAS_QUERY_AP_SUCCESS);
+}
+
+
+static void gas_query_rx_comeback(struct gas_query_ap *gas,
+ struct gas_query_pending *query,
+ const u8 *adv_proto, const u8 *resp,
+ size_t len, u8 frag_id, u8 more_frags,
+ u16 comeback_delay)
+{
+ wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
+ MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
+ "comeback_delay=%u)",
+ MAC2STR(query->addr), query->dialog_token, frag_id,
+ more_frags, comeback_delay);
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
+
+ if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
+ os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
+ wpabuf_len(query->adv_proto)) != 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
+ "between initial and comeback response from "
+ MACSTR, MAC2STR(query->addr));
+ gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
+ return;
+ }
+
+ if (comeback_delay) {
+ if (frag_id) {
+ wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response "
+ "with non-zero frag_id and comeback_delay "
+ "from " MACSTR, MAC2STR(query->addr));
+ gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
+ return;
+ }
+ gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
+ return;
+ }
+
+ if (frag_id != query->next_frag_id) {
+ wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
+ "from " MACSTR, MAC2STR(query->addr));
+ if (frag_id + 1 == query->next_frag_id) {
+ wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible "
+ "retry of previous fragment");
+ return;
+ }
+ gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
+ return;
+ }
+ query->next_frag_id++;
+
+ if (gas_query_append(query, resp, len) < 0) {
+ gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
+ return;
+ }
+
+ if (more_frags) {
+ gas_query_tx_comeback_req(gas, query);
+ return;
+ }
+
+ gas_query_done(gas, query, GAS_QUERY_AP_SUCCESS);
+}
+
+
+/**
+ * gas_query_ap_rx - Indicate reception of a Public Action or Protected Dual
+ * frame
+ * @gas: GAS query data from gas_query_init()
+ * @sa: Source MAC address of the Action frame
+ * @categ: Category of the Action frame
+ * @data: Payload of the Action frame
+ * @len: Length of @data
+ * @freq: Frequency (in MHz) on which the frame was received
+ * Returns: 0 if the Public Action frame was a GAS frame or -1 if not
+ */
+int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ,
+ const u8 *data, size_t len, int freq)
+{
+ struct gas_query_pending *query;
+ u8 action, dialog_token, frag_id = 0, more_frags = 0;
+ u16 comeback_delay, resp_len;
+ const u8 *pos, *adv_proto;
+ int prot, pmf;
+ unsigned int left;
+
+ if (!gas || len < 4)
+ return -1;
+
+ pos = data;
+ action = *pos++;
+ dialog_token = *pos++;
+
+ if (action != WLAN_PA_GAS_INITIAL_RESP &&
+ action != WLAN_PA_GAS_COMEBACK_RESP)
+ return -1; /* Not a GAS response */
+
+ prot = categ == WLAN_ACTION_PROTECTED_DUAL;
+ pmf = pmf_in_use(gas->hapd, sa);
+ if (prot && !pmf) {
+ wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
+ return 0;
+ }
+ if (!prot && pmf) {
+ wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled");
+ return 0;
+ }
+
+ query = gas_query_get_pending(gas, sa, dialog_token);
+ if (query == NULL) {
+ wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
+ " dialog token %u", MAC2STR(sa), dialog_token);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "GAS: Response in %d ms from " MACSTR,
+ ms_from_time(&query->last_oper), MAC2STR(sa));
+
+ if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) {
+ wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from "
+ MACSTR " dialog token %u when waiting for comeback "
+ "response", MAC2STR(sa), dialog_token);
+ return 0;
+ }
+
+ if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) {
+ wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from "
+ MACSTR " dialog token %u when waiting for initial "
+ "response", MAC2STR(sa), dialog_token);
+ return 0;
+ }
+
+ query->status_code = WPA_GET_LE16(pos);
+ pos += 2;
+
+ if (query->status_code == WLAN_STATUS_QUERY_RESP_OUTSTANDING &&
+ action == WLAN_PA_GAS_COMEBACK_RESP) {
+ wpa_printf(MSG_DEBUG, "GAS: Allow non-zero status for outstanding comeback response");
+ } else if (query->status_code != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token "
+ "%u failed - status code %u",
+ MAC2STR(sa), dialog_token, query->status_code);
+ gas_query_done(gas, query, GAS_QUERY_AP_FAILURE);
+ return 0;
+ }
+
+ if (action == WLAN_PA_GAS_COMEBACK_RESP) {
+ if (pos + 1 > data + len)
+ return 0;
+ frag_id = *pos & 0x7f;
+ more_frags = (*pos & 0x80) >> 7;
+ pos++;
+ }
+
+ /* Comeback Delay */
+ if (pos + 2 > data + len)
+ return 0;
+ comeback_delay = WPA_GET_LE16(pos);
+ pos += 2;
+
+ /* Advertisement Protocol element */
+ if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) {
+ wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
+ "Protocol element in the response from " MACSTR,
+ MAC2STR(sa));
+ return 0;
+ }
+
+ if (*pos != WLAN_EID_ADV_PROTO) {
+ wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
+ "Protocol element ID %u in response from " MACSTR,
+ *pos, MAC2STR(sa));
+ return 0;
+ }
+
+ adv_proto = pos;
+ pos += 2 + pos[1];
+
+ /* Query Response Length */
+ if (pos + 2 > data + len) {
+ wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length");
+ return 0;
+ }
+ resp_len = WPA_GET_LE16(pos);
+ pos += 2;
+
+ left = data + len - pos;
+ if (resp_len > left) {
+ wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
+ "response from " MACSTR, MAC2STR(sa));
+ return 0;
+ }
+
+ if (resp_len < left) {
+ wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
+ "after Query Response from " MACSTR,
+ left - resp_len, MAC2STR(sa));
+ }
+
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len,
+ frag_id, more_frags, comeback_delay);
+ else
+ gas_query_rx_initial(gas, query, adv_proto, pos, resp_len,
+ comeback_delay);
+
+ return 0;
+}
+
+
+static void gas_query_timeout(void *eloop_data, void *user_ctx)
+{
+ struct gas_query_ap *gas = eloop_data;
+ struct gas_query_pending *query = user_ctx;
+
+ wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
+ " dialog token %u",
+ MAC2STR(query->addr), query->dialog_token);
+ gas_query_done(gas, query, GAS_QUERY_AP_TIMEOUT);
+}
+
+
+static int gas_query_dialog_token_available(struct gas_query_ap *gas,
+ const u8 *dst, u8 dialog_token)
+{
+ struct gas_query_pending *q;
+ dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
+ if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 &&
+ dialog_token == q->dialog_token)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void gas_query_tx_initial_req(struct gas_query_ap *gas,
+ struct gas_query_pending *query)
+{
+ if (gas_query_tx(gas, query, query->req,
+ GAS_QUERY_WAIT_TIME_INITIAL) < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+ MACSTR, MAC2STR(query->addr));
+ gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
+ return;
+ }
+ gas->current = query;
+
+ wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
+ query->dialog_token);
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+ gas_query_timeout, gas, query);
+}
+
+
+static int gas_query_new_dialog_token(struct gas_query_ap *gas, const u8 *dst)
+{
+ static int next_start = 0;
+ int dialog_token;
+
+ for (dialog_token = 0; dialog_token < 256; dialog_token++) {
+ if (gas_query_dialog_token_available(
+ gas, dst, (next_start + dialog_token) % 256))
+ break;
+ }
+ if (dialog_token == 256)
+ return -1; /* Too many pending queries */
+ dialog_token = (next_start + dialog_token) % 256;
+ next_start = (dialog_token + 1) % 256;
+ return dialog_token;
+}
+
+
+/**
+ * gas_query_ap_req - Request a GAS query
+ * @gas: GAS query data from gas_query_init()
+ * @dst: Destination MAC address for the query
+ * @freq: Frequency (in MHz) for the channel on which to send the query
+ * @req: GAS query payload (to be freed by gas_query module in case of success
+ * return)
+ * @cb: Callback function for reporting GAS query result and response
+ * @ctx: Context pointer to use with the @cb call
+ * Returns: dialog token (>= 0) on success or -1 on failure
+ */
+int gas_query_ap_req(struct gas_query_ap *gas, const u8 *dst, int freq,
+ struct wpabuf *req,
+ void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+ enum gas_query_ap_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code),
+ void *ctx)
+{
+ struct gas_query_pending *query;
+ int dialog_token;
+
+ if (!gas || wpabuf_len(req) < 3)
+ return -1;
+
+ dialog_token = gas_query_new_dialog_token(gas, dst);
+ if (dialog_token < 0)
+ return -1;
+
+ query = os_zalloc(sizeof(*query));
+ if (query == NULL)
+ return -1;
+
+ query->gas = gas;
+ os_memcpy(query->addr, dst, ETH_ALEN);
+ query->dialog_token = dialog_token;
+ query->freq = freq;
+ query->cb = cb;
+ query->ctx = ctx;
+ query->req = req;
+ dl_list_add(&gas->pending, &query->list);
+
+ *(wpabuf_mhead_u8(req) + 2) = dialog_token;
+
+ wpa_msg(gas->msg_ctx, MSG_INFO, GAS_QUERY_START "addr=" MACSTR
+ " dialog_token=%u freq=%d",
+ MAC2STR(query->addr), query->dialog_token, query->freq);
+
+ gas_query_tx_initial_req(gas, query);
+
+ return dialog_token;
+}
diff --git a/contrib/wpa/src/ap/gas_query_ap.h b/contrib/wpa/src/ap/gas_query_ap.h
new file mode 100644
index 0000000..70f1f05
--- /dev/null
+++ b/contrib/wpa/src/ap/gas_query_ap.h
@@ -0,0 +1,43 @@
+/*
+ * Generic advertisement service (GAS) query
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011-2017, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_QUERY_AP_H
+#define GAS_QUERY_AP_H
+
+struct gas_query_ap;
+
+struct gas_query_ap * gas_query_ap_init(struct hostapd_data *hapd,
+ void *msg_ctx);
+void gas_query_ap_deinit(struct gas_query_ap *gas);
+int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ,
+ const u8 *data, size_t len, int freq);
+
+/**
+ * enum gas_query_ap_result - GAS query result
+ */
+enum gas_query_ap_result {
+ GAS_QUERY_AP_SUCCESS,
+ GAS_QUERY_AP_FAILURE,
+ GAS_QUERY_AP_TIMEOUT,
+ GAS_QUERY_AP_PEER_ERROR,
+ GAS_QUERY_AP_INTERNAL_ERROR,
+ GAS_QUERY_AP_DELETED_AT_DEINIT
+};
+
+int gas_query_ap_req(struct gas_query_ap *gas, const u8 *dst, int freq,
+ struct wpabuf *req,
+ void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+ enum gas_query_ap_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code),
+ void *ctx);
+void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst,
+ const u8 *data, size_t data_len, int ok);
+
+#endif /* GAS_QUERY_AP_H */
diff --git a/contrib/wpa/src/ap/gas_serv.c b/contrib/wpa/src/ap/gas_serv.c
index 9d19f98..a7df810 100644
--- a/contrib/wpa/src/ap/gas_serv.c
+++ b/contrib/wpa/src/ap/gas_serv.c
@@ -11,14 +11,31 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
+#include "common/wpa_ctrl.h"
#include "utils/eloop.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "dpp_hostapd.h"
#include "sta_info.h"
#include "gas_serv.h"
+#ifdef CONFIG_DPP
+static void gas_serv_write_dpp_adv_proto(struct wpabuf *buf)
+{
+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(buf, 8); /* Length */
+ wpabuf_put_u8(buf, 0x7f);
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 5);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, DPP_OUI_TYPE);
+ wpabuf_put_u8(buf, 0x01);
+}
+#endif /* CONFIG_DPP */
+
+
static void convert_to_protected_dual(struct wpabuf *msg)
{
u8 *categ = wpabuf_mhead_u8(msg);
@@ -50,9 +67,12 @@ gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
sta->flags |= WLAN_STA_GAS;
/*
* The default inactivity is 300 seconds. We don't need
- * it to be that long.
+ * it to be that long. Use five second timeout and increase this
+ * with the comeback_delay for testing cases.
*/
- ap_sta_session_timeout(hapd, sta, 5);
+ ap_sta_session_timeout(hapd, sta,
+ hapd->conf->gas_comeback_delay / 1024 +
+ 5);
} else {
ap_sta_replenish_timeout(hapd, sta, 5);
}
@@ -101,6 +121,7 @@ gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
if (sta->gas_dialog[i].dialog_token != dialog_token ||
!sta->gas_dialog[i].valid)
continue;
+ ap_sta_replenish_timeout(hapd, sta, 5);
return &sta->gas_dialog[i];
}
wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
@@ -160,34 +181,127 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
if (hapd->conf->hs20_osu_providers_count)
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
+ if (hapd->conf->hs20_osu_providers_nai_count)
+ wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
if (hapd->conf->hs20_icons_count)
wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
+ if (hapd->conf->hs20_operator_icon_count)
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
gas_anqp_set_element_len(buf, len);
}
#endif /* CONFIG_HS20 */
+static struct anqp_element * get_anqp_elem(struct hostapd_data *hapd,
+ u16 infoid)
+{
+ struct anqp_element *elem;
+
+ dl_list_for_each(elem, &hapd->conf->anqp_elem, struct anqp_element,
+ list) {
+ if (elem->infoid == infoid)
+ return elem;
+ }
+
+ return NULL;
+}
+
+
+static void anqp_add_elem(struct hostapd_data *hapd, struct wpabuf *buf,
+ u16 infoid)
+{
+ struct anqp_element *elem;
+
+ elem = get_anqp_elem(hapd, infoid);
+ if (!elem)
+ return;
+ if (wpabuf_tailroom(buf) < 2 + 2 + wpabuf_len(elem->payload)) {
+ wpa_printf(MSG_DEBUG, "ANQP: No room for InfoID %u payload",
+ infoid);
+ return;
+ }
+
+ wpabuf_put_le16(buf, infoid);
+ wpabuf_put_le16(buf, wpabuf_len(elem->payload));
+ wpabuf_put_buf(buf, elem->payload);
+}
+
+
+static int anqp_add_override(struct hostapd_data *hapd, struct wpabuf *buf,
+ u16 infoid)
+{
+ if (get_anqp_elem(hapd, infoid)) {
+ anqp_add_elem(hapd, buf, infoid);
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void anqp_add_capab_list(struct hostapd_data *hapd,
struct wpabuf *buf)
{
u8 *len;
+ u16 id;
+
+ if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST))
+ return;
len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
- if (hapd->conf->venue_name)
+ if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME))
wpabuf_put_le16(buf, ANQP_VENUE_NAME);
- if (hapd->conf->network_auth_type)
+ if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER))
+ wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER);
+ if (hapd->conf->network_auth_type ||
+ get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE))
wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
- if (hapd->conf->roaming_consortium)
+ if (hapd->conf->roaming_consortium ||
+ get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM))
wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
- if (hapd->conf->ipaddr_type_configured)
+ if (hapd->conf->ipaddr_type_configured ||
+ get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY))
wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
- if (hapd->conf->nai_realm_data)
+ if (hapd->conf->nai_realm_data ||
+ get_anqp_elem(hapd, ANQP_NAI_REALM))
wpabuf_put_le16(buf, ANQP_NAI_REALM);
- if (hapd->conf->anqp_3gpp_cell_net)
+ if (hapd->conf->anqp_3gpp_cell_net ||
+ get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK))
wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
- if (hapd->conf->domain_name)
+ if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION))
+ wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION);
+ if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION))
+ wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION);
+ if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI))
+ wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI);
+ if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME))
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+ if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
+ wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
+ if (get_anqp_elem(hapd, ANQP_TDLS_CAPABILITY))
+ wpabuf_put_le16(buf, ANQP_TDLS_CAPABILITY);
+ if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
+ wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
+ if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
+ wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
+#ifdef CONFIG_FILS
+ if (!dl_list_empty(&hapd->conf->fils_realms) ||
+ get_anqp_elem(hapd, ANQP_FILS_REALM_INFO))
+ wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
+#endif /* CONFIG_FILS */
+ if (get_anqp_elem(hapd, ANQP_CAG))
+ wpabuf_put_le16(buf, ANQP_CAG);
+ if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL))
+ wpabuf_put_le16(buf, ANQP_VENUE_URL);
+ if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
+ wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
+ if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
+ wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
+ for (id = 280; id < 300; id++) {
+ if (get_anqp_elem(hapd, id))
+ wpabuf_put_le16(buf, id);
+ }
#ifdef CONFIG_HS20
anqp_add_hs_capab_list(hapd, buf);
#endif /* CONFIG_HS20 */
@@ -197,6 +311,9 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME))
+ return;
+
if (hapd->conf->venue_name) {
u8 *len;
unsigned int i;
@@ -215,9 +332,35 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
}
+static void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+ if (anqp_add_override(hapd, buf, ANQP_VENUE_URL))
+ return;
+
+ if (hapd->conf->venue_url) {
+ u8 *len;
+ unsigned int i;
+
+ len = gas_anqp_add_element(buf, ANQP_VENUE_URL);
+ for (i = 0; i < hapd->conf->venue_url_count; i++) {
+ struct hostapd_venue_url *url;
+
+ url = &hapd->conf->venue_url[i];
+ wpabuf_put_u8(buf, 1 + url->url_len);
+ wpabuf_put_u8(buf, url->venue_number);
+ wpabuf_put_data(buf, url->url, url->url_len);
+ }
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
static void anqp_add_network_auth_type(struct hostapd_data *hapd,
struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_NETWORK_AUTH_TYPE))
+ return;
+
if (hapd->conf->network_auth_type) {
wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
@@ -233,6 +376,9 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
unsigned int i;
u8 *len;
+ if (anqp_add_override(hapd, buf, ANQP_ROAMING_CONSORTIUM))
+ return;
+
len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
struct hostapd_roaming_consortium *rc;
@@ -247,6 +393,9 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_IP_ADDR_TYPE_AVAILABILITY))
+ return;
+
if (hapd->conf->ipaddr_type_configured) {
wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
wpabuf_put_le16(buf, 1);
@@ -309,7 +458,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
pos = home_realm;
end = pos + home_realm_len;
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
home_realm, home_realm_len);
return -1;
@@ -317,7 +466,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
num_realms = *pos++;
for (i = 0; i < num_realms && num_matching < 10; i++) {
- if (pos + 2 > end) {
+ if (end - pos < 2) {
wpa_hexdump(MSG_DEBUG,
"Truncated NAI Home Realm Query",
home_realm, home_realm_len);
@@ -325,7 +474,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
}
encoding = *pos++;
realm_len = *pos++;
- if (pos + realm_len > end) {
+ if (realm_len > end - pos) {
wpa_hexdump(MSG_DEBUG,
"Truncated NAI Home Realm Query",
home_realm, home_realm_len);
@@ -391,6 +540,10 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
const u8 *home_realm, size_t home_realm_len,
int nai_realm, int nai_home_realm)
{
+ if (nai_realm && !nai_home_realm &&
+ anqp_add_override(hapd, buf, ANQP_NAI_REALM))
+ return;
+
if (nai_realm && hapd->conf->nai_realm_data) {
u8 *len;
unsigned int i, j;
@@ -424,6 +577,9 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_3GPP_CELLULAR_NETWORK))
+ return;
+
if (hapd->conf->anqp_3gpp_cell_net) {
wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
wpabuf_put_le16(buf,
@@ -436,6 +592,9 @@ static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
{
+ if (anqp_add_override(hapd, buf, ANQP_DOMAIN_NAME))
+ return;
+
if (hapd->conf->domain_name) {
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
wpabuf_put_le16(buf, hapd->conf->domain_name_len);
@@ -445,6 +604,36 @@ static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
}
+#ifdef CONFIG_FILS
+static void anqp_add_fils_realm_info(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ size_t count;
+
+ if (anqp_add_override(hapd, buf, ANQP_FILS_REALM_INFO))
+ return;
+
+ count = dl_list_len(&hapd->conf->fils_realms);
+ if (count > 10000)
+ count = 10000;
+ if (count) {
+ struct fils_realm *realm;
+
+ wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
+ wpabuf_put_le16(buf, 2 * count);
+
+ dl_list_for_each(realm, &hapd->conf->fils_realms,
+ struct fils_realm, list) {
+ if (count == 0)
+ break;
+ wpabuf_put_data(buf, realm->hash, 2);
+ count--;
+ }
+ }
+}
+#endif /* CONFIG_FILS */
+
+
#ifdef CONFIG_HS20
static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
@@ -518,6 +707,29 @@ static void anqp_add_operating_class(struct hostapd_data *hapd,
}
+static void anqp_add_icon(struct wpabuf *buf, struct hostapd_bss_config *bss,
+ const char *name)
+{
+ size_t j;
+ struct hs20_icon *icon = NULL;
+
+ for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
+ if (os_strcmp(name, bss->hs20_icons[j].name) == 0)
+ icon = &bss->hs20_icons[j];
+ }
+ if (!icon)
+ return; /* icon info not found */
+
+ wpabuf_put_le16(buf, icon->width);
+ wpabuf_put_le16(buf, icon->height);
+ wpabuf_put_data(buf, icon->language, 3);
+ wpabuf_put_u8(buf, os_strlen(icon->type));
+ wpabuf_put_str(buf, icon->type);
+ wpabuf_put_u8(buf, os_strlen(icon->name));
+ wpabuf_put_str(buf, icon->name);
+}
+
+
static void anqp_add_osu_provider(struct wpabuf *buf,
struct hostapd_bss_config *bss,
struct hs20_osu_provider *p)
@@ -546,32 +758,14 @@ static void anqp_add_osu_provider(struct wpabuf *buf,
/* OSU Method List */
count = wpabuf_put(buf, 1);
- for (i = 0; p->method_list[i] >= 0; i++)
+ for (i = 0; p->method_list && p->method_list[i] >= 0; i++)
wpabuf_put_u8(buf, p->method_list[i]);
*count = i;
/* Icons Available */
len2 = wpabuf_put(buf, 2);
- for (i = 0; i < p->icons_count; i++) {
- size_t j;
- struct hs20_icon *icon = NULL;
-
- for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
- if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) ==
- 0)
- icon = &bss->hs20_icons[j];
- }
- if (!icon)
- continue; /* icon info not found */
-
- wpabuf_put_le16(buf, icon->width);
- wpabuf_put_le16(buf, icon->height);
- wpabuf_put_data(buf, icon->language, 3);
- wpabuf_put_u8(buf, os_strlen(icon->type));
- wpabuf_put_str(buf, icon->type);
- wpabuf_put_u8(buf, os_strlen(icon->name));
- wpabuf_put_str(buf, icon->name);
- }
+ for (i = 0; i < p->icons_count; i++)
+ anqp_add_icon(buf, bss, p->icons[i]);
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
/* OSU_NAI */
@@ -625,6 +819,40 @@ static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
}
+static void anqp_add_osu_provider_nai(struct wpabuf *buf,
+ struct hs20_osu_provider *p)
+{
+ /* OSU_NAI for shared BSS (Single SSID) */
+ if (p->osu_nai2) {
+ wpabuf_put_u8(buf, os_strlen(p->osu_nai2));
+ wpabuf_put_str(buf, p->osu_nai2);
+ } else {
+ wpabuf_put_u8(buf, 0);
+ }
+}
+
+
+static void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_osu_providers_nai_count) {
+ size_t i;
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+
+ for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
+ anqp_add_osu_provider_nai(
+ buf, &hapd->conf->hs20_osu_providers[i]);
+ }
+
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
struct wpabuf *buf,
const u8 *name, size_t name_len)
@@ -680,23 +908,89 @@ static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
gas_anqp_set_element_len(buf, len);
}
+
+static void anqp_add_operator_icon_metadata(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ struct hostapd_bss_config *bss = hapd->conf;
+ size_t i;
+ u8 *len;
+
+ if (!bss->hs20_operator_icon_count)
+ return;
+
+ len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+
+ for (i = 0; i < bss->hs20_operator_icon_count; i++)
+ anqp_add_icon(buf, bss, bss->hs20_operator_icon[i]);
+
+ gas_anqp_set_element_len(buf, len);
+}
+
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+static void anqp_add_mbo_cell_data_conn_pref(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->mbo_cell_data_conn_pref >= 0) {
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, MBO_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF);
+ wpabuf_put_u8(buf, hapd->conf->mbo_cell_data_conn_pref);
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+#endif /* CONFIG_MBO */
+
+
+static size_t anqp_get_required_len(struct hostapd_data *hapd,
+ const u16 *infoid,
+ unsigned int num_infoid)
+{
+ size_t len = 0;
+ unsigned int i;
+
+ for (i = 0; i < num_infoid; i++) {
+ struct anqp_element *elem = get_anqp_elem(hapd, infoid[i]);
+
+ if (elem)
+ len += 2 + 2 + wpabuf_len(elem->payload);
+ }
+
+ return len;
+}
+
+
static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
const u8 *home_realm, size_t home_realm_len,
- const u8 *icon_name, size_t icon_name_len)
+ const u8 *icon_name, size_t icon_name_len,
+ const u16 *extra_req,
+ unsigned int num_extra_req)
{
struct wpabuf *buf;
size_t len;
+ unsigned int i;
len = 1400;
if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
len += 1000;
if (request & ANQP_REQ_ICON_REQUEST)
len += 65536;
+#ifdef CONFIG_FILS
+ if (request & ANQP_FILS_REALM_INFO)
+ len += 2 * dl_list_len(&hapd->conf->fils_realms);
+#endif /* CONFIG_FILS */
+ len += anqp_get_required_len(hapd, extra_req, num_extra_req);
buf = wpabuf_alloc(len);
if (buf == NULL)
@@ -706,6 +1000,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
anqp_add_capab_list(hapd, buf);
if (request & ANQP_REQ_VENUE_NAME)
anqp_add_venue_name(hapd, buf);
+ if (request & ANQP_REQ_EMERGENCY_CALL_NUMBER)
+ anqp_add_elem(hapd, buf, ANQP_EMERGENCY_CALL_NUMBER);
if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
anqp_add_network_auth_type(hapd, buf);
if (request & ANQP_REQ_ROAMING_CONSORTIUM)
@@ -718,8 +1014,34 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
request & ANQP_REQ_NAI_HOME_REALM);
if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
anqp_add_3gpp_cellular_network(hapd, buf);
+ if (request & ANQP_REQ_AP_GEOSPATIAL_LOCATION)
+ anqp_add_elem(hapd, buf, ANQP_AP_GEOSPATIAL_LOCATION);
+ if (request & ANQP_REQ_AP_CIVIC_LOCATION)
+ anqp_add_elem(hapd, buf, ANQP_AP_CIVIC_LOCATION);
+ if (request & ANQP_REQ_AP_LOCATION_PUBLIC_URI)
+ anqp_add_elem(hapd, buf, ANQP_AP_LOCATION_PUBLIC_URI);
if (request & ANQP_REQ_DOMAIN_NAME)
anqp_add_domain_name(hapd, buf);
+ if (request & ANQP_REQ_EMERGENCY_ALERT_URI)
+ anqp_add_elem(hapd, buf, ANQP_EMERGENCY_ALERT_URI);
+ if (request & ANQP_REQ_TDLS_CAPABILITY)
+ anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
+ if (request & ANQP_REQ_EMERGENCY_NAI)
+ anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
+
+ for (i = 0; i < num_extra_req; i++) {
+#ifdef CONFIG_FILS
+ if (extra_req[i] == ANQP_FILS_REALM_INFO) {
+ anqp_add_fils_realm_info(hapd, buf);
+ continue;
+ }
+#endif /* CONFIG_FILS */
+ if (extra_req[i] == ANQP_VENUE_URL) {
+ anqp_add_venue_url(hapd, buf);
+ continue;
+ }
+ anqp_add_elem(hapd, buf, extra_req[i]);
+ }
#ifdef CONFIG_HS20
if (request & ANQP_REQ_HS_CAPABILITY_LIST)
@@ -736,12 +1058,23 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
anqp_add_osu_providers_list(hapd, buf);
if (request & ANQP_REQ_ICON_REQUEST)
anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
+ if (request & ANQP_REQ_OPERATOR_ICON_METADATA)
+ anqp_add_operator_icon_metadata(hapd, buf);
+ if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST)
+ anqp_add_osu_providers_nai_list(hapd, buf);
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (request & ANQP_REQ_MBO_CELL_DATA_CONN_PREF)
+ anqp_add_mbo_cell_data_conn_pref(hapd, buf);
+#endif /* CONFIG_MBO */
+
return buf;
}
+#define ANQP_MAX_EXTRA_REQ 20
+
struct anqp_query_info {
unsigned int request;
const u8 *home_realm_query;
@@ -749,6 +1082,8 @@ struct anqp_query_info {
const u8 *icon_name;
size_t icon_name_len;
int p2p_sd;
+ u16 extra_req[ANQP_MAX_EXTRA_REQ];
+ unsigned int num_extra_req;
};
@@ -776,6 +1111,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
hapd->conf->venue_name != NULL, qi);
break;
+ case ANQP_EMERGENCY_CALL_NUMBER:
+ set_anqp_req(ANQP_REQ_EMERGENCY_CALL_NUMBER,
+ "Emergency Call Number",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
case ANQP_NETWORK_AUTH_TYPE:
set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
hapd->conf->network_auth_type != NULL, qi);
@@ -798,13 +1138,65 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
"3GPP Cellular Network",
hapd->conf->anqp_3gpp_cell_net != NULL, qi);
break;
+ case ANQP_AP_GEOSPATIAL_LOCATION:
+ set_anqp_req(ANQP_REQ_AP_GEOSPATIAL_LOCATION,
+ "AP Geospatial Location",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
+ case ANQP_AP_CIVIC_LOCATION:
+ set_anqp_req(ANQP_REQ_AP_CIVIC_LOCATION,
+ "AP Civic Location",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
+ case ANQP_AP_LOCATION_PUBLIC_URI:
+ set_anqp_req(ANQP_REQ_AP_LOCATION_PUBLIC_URI,
+ "AP Location Public URI",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
case ANQP_DOMAIN_NAME:
set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
hapd->conf->domain_name != NULL, qi);
break;
+ case ANQP_EMERGENCY_ALERT_URI:
+ set_anqp_req(ANQP_REQ_EMERGENCY_ALERT_URI,
+ "Emergency Alert URI",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
+ case ANQP_TDLS_CAPABILITY:
+ set_anqp_req(ANQP_REQ_TDLS_CAPABILITY,
+ "TDLS Capability",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
+ case ANQP_EMERGENCY_NAI:
+ set_anqp_req(ANQP_REQ_EMERGENCY_NAI,
+ "Emergency NAI",
+ get_anqp_elem(hapd, info_id) != NULL, qi);
+ break;
default:
- wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
- info_id);
+#ifdef CONFIG_FILS
+ if (info_id == ANQP_FILS_REALM_INFO &&
+ !dl_list_empty(&hapd->conf->fils_realms)) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: FILS Realm Information (local)");
+ } else
+#endif /* CONFIG_FILS */
+ if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Venue URL (local)");
+ } else if (!get_anqp_elem(hapd, info_id)) {
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+ info_id);
+ break;
+ }
+ if (qi->num_extra_req == ANQP_MAX_EXTRA_REQ) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: No more room for extra requests - ignore Info Id %u",
+ info_id);
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "ANQP: Info Id %u (local)", info_id);
+ qi->extra_req[qi->num_extra_req] = info_id;
+ qi->num_extra_req++;
break;
}
}
@@ -817,7 +1209,7 @@ static void rx_anqp_query_list(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
(unsigned int) (end - pos) / 2);
- while (pos + 2 <= end) {
+ while (end - pos >= 2) {
rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
pos += 2;
}
@@ -857,6 +1249,16 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
hapd->conf->hs20_osu_providers_count, qi);
break;
+ case HS20_STYPE_OPERATOR_ICON_METADATA:
+ set_anqp_req(ANQP_REQ_OPERATOR_ICON_METADATA,
+ "Operator Icon Metadata",
+ hapd->conf->hs20_operator_icon_count, qi);
+ break;
+ case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
+ set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST,
+ "OSU Providers NAI List",
+ hapd->conf->hs20_osu_providers_nai_count, qi);
+ break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
subtype);
@@ -899,50 +1301,13 @@ static void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
}
-static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
- const u8 *pos, const u8 *end,
- struct anqp_query_info *qi)
+static void rx_anqp_vendor_specific_hs20(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
{
- u32 oui;
u8 subtype;
- if (pos + 4 > end) {
- wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
- "Query element");
- return;
- }
-
- oui = WPA_GET_BE24(pos);
- pos += 3;
- if (oui != OUI_WFA) {
- wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
- oui);
- return;
- }
-
-#ifdef CONFIG_P2P
- if (*pos == P2P_OUI_TYPE) {
- /*
- * This is for P2P SD and will be taken care of by the P2P
- * implementation. This query needs to be ignored in the generic
- * GAS server to avoid duplicated response.
- */
- wpa_printf(MSG_DEBUG,
- "ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
- *pos);
- qi->p2p_sd = 1;
- return;
- }
-#endif /* CONFIG_P2P */
-
- if (*pos != HS20_ANQP_OUI_TYPE) {
- wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
- *pos);
- return;
- }
- pos++;
-
- if (pos + 1 >= end)
+ if (end - pos <= 1)
return;
subtype = *pos++;
@@ -971,16 +1336,127 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_P2P
+static void rx_anqp_vendor_specific_p2p(struct hostapd_data *hapd,
+ struct anqp_query_info *qi)
+{
+ /*
+ * This is for P2P SD and will be taken care of by the P2P
+ * implementation. This query needs to be ignored in the generic
+ * GAS server to avoid duplicated response.
+ */
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
+ P2P_OUI_TYPE);
+ qi->p2p_sd = 1;
+ return;
+}
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_MBO
+
+static void rx_anqp_mbo_query_list(struct hostapd_data *hapd, u8 subtype,
+ struct anqp_query_info *qi)
+{
+ switch (subtype) {
+ case MBO_ANQP_SUBTYPE_CELL_CONN_PREF:
+ set_anqp_req(ANQP_REQ_MBO_CELL_DATA_CONN_PREF,
+ "Cellular Data Connection Preference",
+ hapd->conf->mbo_cell_data_conn_pref >= 0, qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO subtype %u",
+ subtype);
+ break;
+ }
+}
+
+
+static void rx_anqp_vendor_specific_mbo(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ u8 subtype;
+
+ if (end - pos < 1)
+ return;
+
+ subtype = *pos++;
+ switch (subtype) {
+ case MBO_ANQP_SUBTYPE_QUERY_LIST:
+ wpa_printf(MSG_DEBUG, "ANQP: MBO Query List");
+ while (pos < end) {
+ rx_anqp_mbo_query_list(hapd, *pos, qi);
+ pos++;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO query subtype %u",
+ subtype);
+ break;
+ }
+}
+
+#endif /* CONFIG_MBO */
+
+
+static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ u32 oui;
+
+ if (end - pos < 4) {
+ wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
+ "Query element");
+ return;
+ }
+
+ oui = WPA_GET_BE24(pos);
+ pos += 3;
+ if (oui != OUI_WFA) {
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
+ oui);
+ return;
+ }
+
+ switch (*pos) {
+#ifdef CONFIG_P2P
+ case P2P_OUI_TYPE:
+ rx_anqp_vendor_specific_p2p(hapd, qi);
+ break;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_HS20
+ case HS20_ANQP_OUI_TYPE:
+ rx_anqp_vendor_specific_hs20(hapd, pos + 1, end, qi);
+ break;
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ case MBO_ANQP_OUI_TYPE:
+ rx_anqp_vendor_specific_mbo(hapd, pos + 1, end, qi);
+ break;
+#endif /* CONFIG_MBO */
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
+ *pos);
+ break;
+ }
+}
+
+
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
- struct anqp_query_info *qi, int prot)
+ struct anqp_query_info *qi, int prot,
+ int std_addr3)
{
struct wpabuf *buf, *tx_buf;
buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
qi->home_realm_query,
qi->home_realm_query_len,
- qi->icon_name, qi->icon_name_len);
+ qi->icon_name, qi->icon_name_len,
+ qi->extra_req, qi->num_extra_req);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
buf);
if (!buf)
@@ -994,7 +1470,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P */
- if (wpabuf_len(buf) > hapd->gas_frag_limit ||
+ if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
hapd->conf->gas_comeback_delay) {
struct gas_dialog_info *di;
u16 comeback_delay = 1;
@@ -1033,15 +1509,88 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
return;
if (prot)
convert_to_protected_dual(tx_buf);
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ wpabuf_free(tx_buf);
+}
+
+
+#ifdef CONFIG_DPP
+static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
+ const u8 *sa, u8 dialog_token,
+ int prot, struct wpabuf *buf)
+{
+ struct wpabuf *tx_buf;
+
+ if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
+ hapd->conf->gas_comeback_delay) {
+ struct gas_dialog_info *di;
+ u16 comeback_delay = 1;
+
+ if (hapd->conf->gas_comeback_delay) {
+ /* Testing - allow overriding of the delay value */
+ comeback_delay = hapd->conf->gas_comeback_delay;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Too long response to fit in initial response - use GAS comeback");
+ di = gas_dialog_create(hapd, sa, dialog_token);
+ if (!di) {
+ wpa_printf(MSG_INFO, "DPP: Could not create dialog for "
+ MACSTR " (dialog token %u)",
+ MAC2STR(sa), dialog_token);
+ wpabuf_free(buf);
+ tx_buf = gas_build_initial_resp(
+ dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
+ 0, 10);
+ if (tx_buf)
+ gas_serv_write_dpp_adv_proto(tx_buf);
+ } else {
+ di->prot = prot;
+ di->sd_resp = buf;
+ di->sd_resp_pos = 0;
+ tx_buf = gas_build_initial_resp(
+ dialog_token, WLAN_STATUS_SUCCESS,
+ comeback_delay, 10);
+ if (tx_buf)
+ gas_serv_write_dpp_adv_proto(tx_buf);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: GAS Initial response (no comeback)");
+ tx_buf = gas_build_initial_resp(
+ dialog_token, WLAN_STATUS_SUCCESS, 0,
+ 10 + 2 + wpabuf_len(buf));
+ if (tx_buf) {
+ gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, wpabuf_len(buf));
+ wpabuf_put_buf(tx_buf, buf);
+ hostapd_dpp_gas_status_handler(hapd, 1);
+ }
+ wpabuf_free(buf);
+ }
+ if (!tx_buf)
+ return;
+ if (prot)
+ convert_to_protected_dual(tx_buf);
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
}
+#endif /* CONFIG_DPP */
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len, int prot)
+ const u8 *data, size_t len, int prot,
+ int std_addr3)
{
const u8 *pos = data;
const u8 *end = data + len;
@@ -1050,6 +1599,9 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
u16 slen;
struct anqp_query_info qi;
const u8 *adv_proto;
+#ifdef CONFIG_DPP
+ int dpp = 0;
+#endif /* CONFIG_DPP */
if (len < 1 + 2)
return;
@@ -1069,14 +1621,23 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
adv_proto = pos++;
slen = *pos++;
- next = pos + slen;
- if (next > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"GAS: Invalid IE in GAS Initial Request");
return;
}
+ next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */
+#ifdef CONFIG_DPP
+ if (slen == 8 && *pos == WLAN_EID_VENDOR_SPECIFIC &&
+ pos[1] == 5 && WPA_GET_BE24(&pos[2]) == OUI_WFA &&
+ pos[5] == DPP_OUI_TYPE && pos[6] == 0x01) {
+ wpa_printf(MSG_DEBUG, "DPP: Configuration Request");
+ dpp = 1;
+ } else
+#endif /* CONFIG_DPP */
+
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
struct wpabuf *buf;
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -1093,27 +1654,46 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
wpabuf_put_le16(buf, 0); /* Query Response Length */
if (prot)
convert_to_protected_dual(buf);
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(buf), wpabuf_len(buf));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(buf),
+ wpabuf_len(buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd,
+ hapd->iface->freq, 0,
+ sa, wpabuf_head(buf),
+ wpabuf_len(buf));
wpabuf_free(buf);
return;
}
pos = next;
/* Query Request */
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end)
+ if (slen > end - pos)
return;
end = pos + slen;
+#ifdef CONFIG_DPP
+ if (dpp) {
+ struct wpabuf *msg;
+
+ msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
+ if (!msg)
+ return;
+ gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
+ return;
+ }
+#endif /* CONFIG_DPP */
+
/* ANQP Query Request */
while (pos < end) {
u16 info_id, elen;
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
info_id = WPA_GET_LE16(pos);
@@ -1121,7 +1701,7 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
elen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + elen > end) {
+ if (elen > end - pos) {
wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
return;
}
@@ -1130,11 +1710,9 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
case ANQP_QUERY_LIST:
rx_anqp_query_list(hapd, pos, pos + elen, &qi);
break;
-#ifdef CONFIG_HS20
case ANQP_VENDOR_SPECIFIC:
rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
break;
-#endif /* CONFIG_HS20 */
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
"Request element %u", info_id);
@@ -1144,13 +1722,15 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
pos += elen;
}
- gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
+ gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
+ std_addr3);
}
static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len, int prot)
+ const u8 *data, size_t len, int prot,
+ int std_addr3)
{
struct gas_dialog_info *dialog;
struct wpabuf *buf, *tx_buf;
@@ -1182,8 +1762,8 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
}
frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
- if (frag_len > hapd->gas_frag_limit) {
- frag_len = hapd->gas_frag_limit;
+ if (frag_len > hapd->conf->gas_frag_limit) {
+ frag_len = hapd->conf->gas_frag_limit;
more = 1;
}
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
@@ -1196,6 +1776,18 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
gas_serv_dialog_clear(dialog);
return;
}
+#ifdef CONFIG_DPP
+ if (dialog->dpp) {
+ tx_buf = gas_build_comeback_resp(dialog_token,
+ WLAN_STATUS_SUCCESS,
+ dialog->sd_frag_id, more, 0,
+ 10 + frag_len);
+ if (tx_buf) {
+ gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_buf(tx_buf, buf);
+ }
+ } else
+#endif /* CONFIG_DPP */
tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
WLAN_STATUS_SUCCESS,
dialog->sd_frag_id,
@@ -1219,6 +1811,10 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
} else {
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
"SD response sent");
+#ifdef CONFIG_DPP
+ if (dialog->dpp)
+ hostapd_dpp_gas_status_handler(hapd, 1);
+#endif /* CONFIG_DPP */
gas_serv_dialog_clear(dialog);
gas_serv_free_dialogs(hapd, sa);
}
@@ -1226,8 +1822,14 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
send_resp:
if (prot)
convert_to_protected_dual(tx_buf);
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
}
@@ -1238,7 +1840,7 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
struct hostapd_data *hapd = ctx;
const struct ieee80211_mgmt *mgmt;
const u8 *sa, *data;
- int prot;
+ int prot, std_addr3;
mgmt = (const struct ieee80211_mgmt *) buf;
if (len < IEEE80211_HDRLEN + 2)
@@ -1253,14 +1855,22 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
*/
prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
sa = mgmt->sa;
+ if (hapd->conf->gas_address3 == 1)
+ std_addr3 = 1;
+ else if (hapd->conf->gas_address3 == 2)
+ std_addr3 = 0;
+ else
+ std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
len -= IEEE80211_HDRLEN + 1;
data = buf + IEEE80211_HDRLEN + 1;
switch (data[0]) {
case WLAN_PA_GAS_INITIAL_REQ:
- gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
+ gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
+ std_addr3);
break;
case WLAN_PA_GAS_COMEBACK_REQ:
- gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
+ gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
+ std_addr3);
break;
}
}
@@ -1270,9 +1880,6 @@ int gas_serv_init(struct hostapd_data *hapd)
{
hapd->public_action_cb2 = gas_serv_rx_public_action;
hapd->public_action_cb2_ctx = hapd;
- hapd->gas_frag_limit = 1400;
- if (hapd->conf->gas_frag_limit > 0)
- hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
return 0;
}
diff --git a/contrib/wpa/src/ap/gas_serv.h b/contrib/wpa/src/ap/gas_serv.h
index 4ec3201..2cf1817 100644
--- a/contrib/wpa/src/ap/gas_serv.h
+++ b/contrib/wpa/src/ap/gas_serv.h
@@ -9,10 +9,13 @@
#ifndef GAS_SERV_H
#define GAS_SERV_H
+/* First 16 ANQP InfoIDs can be included in the optimized bitmap */
#define ANQP_REQ_CAPABILITY_LIST \
(1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
#define ANQP_REQ_VENUE_NAME \
(1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_EMERGENCY_CALL_NUMBER \
+ (1 << (ANQP_EMERGENCY_CALL_NUMBER - ANQP_QUERY_LIST))
#define ANQP_REQ_NETWORK_AUTH_TYPE \
(1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
#define ANQP_REQ_ROAMING_CONSORTIUM \
@@ -23,8 +26,24 @@
(1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
(1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_GEOSPATIAL_LOCATION \
+ (1 << (ANQP_AP_GEOSPATIAL_LOCATION - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_CIVIC_LOCATION \
+ (1 << (ANQP_AP_CIVIC_LOCATION - ANQP_QUERY_LIST))
+#define ANQP_REQ_AP_LOCATION_PUBLIC_URI \
+ (1 << (ANQP_AP_LOCATION_PUBLIC_URI - ANQP_QUERY_LIST))
#define ANQP_REQ_DOMAIN_NAME \
(1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_EMERGENCY_ALERT_URI \
+ (1 << (ANQP_EMERGENCY_ALERT_URI - ANQP_QUERY_LIST))
+#define ANQP_REQ_TDLS_CAPABILITY \
+ (1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST))
+#define ANQP_REQ_EMERGENCY_NAI \
+ (1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
+/*
+ * First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
+ * optimized bitmap.
+ */
#define ANQP_REQ_HS_CAPABILITY_LIST \
(0x10000 << HS20_STYPE_CAPABILITY_LIST)
#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
@@ -41,6 +60,13 @@
(0x10000 << HS20_STYPE_OSU_PROVIDERS_LIST)
#define ANQP_REQ_ICON_REQUEST \
(0x10000 << HS20_STYPE_ICON_REQUEST)
+#define ANQP_REQ_OPERATOR_ICON_METADATA \
+ (0x10000 << HS20_STYPE_OPERATOR_ICON_METADATA)
+#define ANQP_REQ_OSU_PROVIDERS_NAI_LIST \
+ (0x10000 << HS20_STYPE_OSU_PROVIDERS_NAI_LIST)
+/* The first MBO ANQP-element can be included in the optimized bitmap. */
+#define ANQP_REQ_MBO_CELL_DATA_CONN_PREF \
+ (BIT(29) << MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
struct gas_dialog_info {
u8 valid;
@@ -49,6 +75,7 @@ struct gas_dialog_info {
size_t sd_resp_pos; /* Offset in sd_resp */
u8 sd_frag_id;
int prot; /* whether Protected Dual of Public Action frame is used */
+ int dpp; /* whether this is a DPP Config Response */
};
struct hostapd_data;
diff --git a/contrib/wpa/src/ap/hostapd.c b/contrib/wpa/src/ap/hostapd.c
index c09c17a..20c8e8f 100644
--- a/contrib/wpa/src/ap/hostapd.c
+++ b/contrib/wpa/src/ap/hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
#include "radius/radius_client.h"
#include "radius/radius_das.h"
#include "eap_server/tncs.h"
@@ -30,6 +31,8 @@
#include "vlan_init.h"
#include "wpa_auth.h"
#include "wps_hostapd.h"
+#include "dpp_hostapd.h"
+#include "gas_query_ap.h"
#include "hw_features.h"
#include "wpa_auth_glue.h"
#include "ap_drv_ops.h"
@@ -42,6 +45,11 @@
#include "x_snoop.h"
#include "dhcp_snoop.h"
#include "ndisc_snoop.h"
+#include "neighbor_db.h"
+#include "rrm.h"
+#include "fils_hlp.h"
+#include "acs.h"
+#include "hs20.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -49,6 +57,8 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
static int setup_interface2(struct hostapd_iface *iface);
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
+static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
+ void *timeout_ctx);
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -68,10 +78,26 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
}
+void hostapd_reconfig_encryption(struct hostapd_data *hapd)
+{
+ if (hapd->wpa_auth)
+ return;
+
+ hostapd_set_privacy(hapd, 0);
+ hostapd_setup_encryption(hapd->conf->iface, hapd);
+}
+
+
static void hostapd_reload_bss(struct hostapd_data *hapd)
{
struct hostapd_ssid *ssid;
+ if (!hapd->started)
+ return;
+
+ if (hapd->conf->wmm_enabled < 0)
+ hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
+
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
#endif /* CONFIG_NO_RADIUS */
@@ -150,8 +176,27 @@ static void hostapd_clear_old(struct hostapd_iface *iface)
}
+static int hostapd_iface_conf_changed(struct hostapd_config *newconf,
+ struct hostapd_config *oldconf)
+{
+ size_t i;
+
+ if (newconf->num_bss != oldconf->num_bss)
+ return 1;
+
+ for (i = 0; i < newconf->num_bss; i++) {
+ if (os_strcmp(newconf->bss[i]->iface,
+ oldconf->bss[i]->iface) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
int hostapd_reload_config(struct hostapd_iface *iface)
{
+ struct hapd_interfaces *interfaces = iface->interfaces;
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_config *newconf, *oldconf;
size_t j;
@@ -174,6 +219,35 @@ int hostapd_reload_config(struct hostapd_iface *iface)
hostapd_clear_old(iface);
oldconf = hapd->iconf;
+ if (hostapd_iface_conf_changed(newconf, oldconf)) {
+ char *fname;
+ int res;
+
+ wpa_printf(MSG_DEBUG,
+ "Configuration changes include interface/BSS modification - force full disable+enable sequence");
+ fname = os_strdup(iface->config_fname);
+ if (!fname) {
+ hostapd_config_free(newconf);
+ return -1;
+ }
+ hostapd_remove_iface(interfaces, hapd->conf->iface);
+ iface = hostapd_init(interfaces, fname);
+ os_free(fname);
+ hostapd_config_free(newconf);
+ if (!iface) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize interface on config reload");
+ return -1;
+ }
+ iface->interfaces = interfaces;
+ interfaces->iface[interfaces->count] = iface;
+ interfaces->count++;
+ res = hostapd_enable_iface(iface);
+ if (res < 0)
+ wpa_printf(MSG_ERROR,
+ "Failed to enable interface on config reload");
+ return res;
+ }
iface->conf = newconf;
for (j = 0; j < iface->num_bss; j++) {
@@ -203,10 +277,12 @@ int hostapd_reload_config(struct hostapd_iface *iface)
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
- char *ifname)
+ const char *ifname)
{
int i;
+ if (!ifname || !hapd->drv_priv)
+ return;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
0, NULL, 0, NULL, 0)) {
@@ -272,10 +348,11 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
if (!hapd->started) {
wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
- __func__, hapd->conf->iface);
+ __func__, hapd->conf ? hapd->conf->iface : "N/A");
return;
}
hapd->started = 0;
+ hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
iapp_deinit(hapd->iapp);
@@ -292,6 +369,10 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#endif /* CONFIG_NO_RADIUS */
hostapd_deinit_wps(hapd);
+#ifdef CONFIG_DPP
+ hostapd_dpp_deinit(hapd);
+ gas_query_ap_deinit(hapd->gas);
+#endif /* CONFIG_DPP */
authsrv_deinit(hapd);
@@ -334,6 +415,23 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
wpabuf_free(hapd->mesh_pending_auth);
hapd->mesh_pending_auth = NULL;
#endif /* CONFIG_MESH */
+
+ hostapd_clean_rrm(hapd);
+ fils_hlp_deinit(hapd);
+
+#ifdef CONFIG_SAE
+ {
+ struct hostapd_sae_commit_queue *q;
+
+ while ((q = dl_list_first(&hapd->sae_commit_queue,
+ struct hostapd_sae_commit_queue,
+ list))) {
+ dl_list_del(&q->list);
+ os_free(q);
+ }
+ }
+ eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
+#endif /* CONFIG_SAE */
}
@@ -348,10 +446,12 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
static void hostapd_cleanup(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
- hapd->conf->iface);
+ hapd->conf ? hapd->conf->iface : "N/A");
if (hapd->iface->interfaces &&
- hapd->iface->interfaces->ctrl_iface_deinit)
+ hapd->iface->interfaces->ctrl_iface_deinit) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
hapd->iface->interfaces->ctrl_iface_deinit(hapd);
+ }
hostapd_free_hapd_data(hapd);
}
@@ -367,7 +467,7 @@ static void sta_track_deinit(struct hostapd_iface *iface)
list))) {
dl_list_del(&info->list);
iface->num_sta_seen--;
- os_free(info);
+ sta_track_del(info);
}
}
@@ -380,8 +480,11 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
hostapd_stop_setup_timers(iface);
#endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211N */
+ if (iface->current_mode)
+ acs_cleanup(iface);
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = NULL;
+ iface->current_mode = NULL;
os_free(iface->current_rates);
iface->current_rates = NULL;
os_free(iface->basic_rates);
@@ -402,6 +505,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
+ NULL);
hostapd_cleanup_iface_partial(iface);
hostapd_config_free(iface->conf);
@@ -416,7 +521,7 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
static void hostapd_clear_wep(struct hostapd_data *hapd)
{
- if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) {
+ if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
}
@@ -477,9 +582,12 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
ret = -1;
}
}
- wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
- os_memset(addr, 0xff, ETH_ALEN);
- hostapd_drv_sta_deauth(hapd, addr, reason);
+ if (hapd->conf && hapd->conf->broadcast_deauth) {
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "Deauthenticate all stations");
+ os_memset(addr, 0xff, ETH_ALEN);
+ hostapd_drv_sta_deauth(hapd, addr, reason);
+ }
hostapd_free_stas(hapd);
return ret;
@@ -511,6 +619,9 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
if (hostapd_drv_none(hapd))
return 0;
+ if (iface->conf->use_driver_iface_addr)
+ return 0;
+
/* Generate BSSID mask that is large enough to cover the BSSIDs. */
/* Determine the bits necessary to cover the number of BSSIDs. */
@@ -520,7 +631,7 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
/* Determine the bits necessary to any configured BSSIDs,
if they are higher than the number of BSSIDs. */
for (j = 0; j < iface->conf->num_bss; j++) {
- if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) {
+ if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) {
if (j)
auto_addr++;
continue;
@@ -562,8 +673,10 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
for (i = 5; i > 5 - j; i--)
mask[i] = 0;
j = bits % 8;
- while (j--)
+ while (j) {
+ j--;
mask[i] <<= 1;
+ }
skip_mask_ext:
wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
@@ -672,7 +785,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
if (attr->acct_session_id) {
num_attr++;
- if (attr->acct_session_id_len != 17) {
+ if (attr->acct_session_id_len != 16) {
wpa_printf(MSG_DEBUG,
"RADIUS DAS: Acct-Session-Id cannot match");
return NULL;
@@ -682,10 +795,9 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!sta->radius_das_match)
continue;
- os_snprintf(buf, sizeof(buf), "%08X-%08X",
- sta->acct_session_id_hi,
- sta->acct_session_id_lo);
- if (os_memcmp(attr->acct_session_id, buf, 17) != 0)
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) sta->acct_session_id);
+ if (os_memcmp(attr->acct_session_id, buf, 16) != 0)
sta->radius_das_match = 0;
else
count++;
@@ -701,7 +813,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
if (attr->acct_multi_session_id) {
num_attr++;
- if (attr->acct_multi_session_id_len != 17) {
+ if (attr->acct_multi_session_id_len != 16) {
wpa_printf(MSG_DEBUG,
"RADIUS DAS: Acct-Multi-Session-Id cannot match");
return NULL;
@@ -712,14 +824,14 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
if (!sta->radius_das_match)
continue;
if (!sta->eapol_sm ||
- !sta->eapol_sm->acct_multi_session_id_hi) {
+ !sta->eapol_sm->acct_multi_session_id) {
sta->radius_das_match = 0;
continue;
}
- os_snprintf(buf, sizeof(buf), "%08X+%08X",
- sta->eapol_sm->acct_multi_session_id_hi,
- sta->eapol_sm->acct_multi_session_id_lo);
- if (os_memcmp(attr->acct_multi_session_id, buf, 17) !=
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long)
+ sta->eapol_sm->acct_multi_session_id);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 16) !=
0)
sta->radius_das_match = 0;
else
@@ -864,6 +976,48 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
return RADIUS_DAS_SUCCESS;
}
+
+#ifdef CONFIG_HS20
+static enum radius_das_res
+hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ int multi;
+
+ if (hostapd_das_nas_mismatch(hapd, attr))
+ return RADIUS_DAS_NAS_MISMATCH;
+
+ sta = hostapd_das_find_sta(hapd, attr, &multi);
+ if (!sta) {
+ if (multi) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Multiple sessions match - not supported");
+ return RADIUS_DAS_MULTI_SESSION_MATCH;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
+ return RADIUS_DAS_SESSION_NOT_FOUND;
+ }
+
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
+ " - CoA", MAC2STR(sta->addr));
+
+ if (attr->hs20_t_c_filtering) {
+ if (attr->hs20_t_c_filtering[0] & BIT(0)) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
+ return RADIUS_DAS_COA_FAILED;
+ }
+
+ hs20_t_c_filtering(hapd, sta, 0);
+ }
+
+ return RADIUS_DAS_SUCCESS;
+}
+#else /* CONFIG_HS20 */
+#define hostapd_das_coa NULL
+#endif /* CONFIG_HS20 */
+
#endif /* CONFIG_NO_RADIUS */
@@ -905,12 +1059,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
hapd->started = 1;
if (!first || first == -1) {
- if (hostapd_mac_comp_empty(conf->bssid) == 0) {
- /* Allocate the next available BSSID. */
- do {
- inc_byte_array(hapd->own_addr, ETH_ALEN);
- } while (mac_in_conf(hapd->iconf, hapd->own_addr));
- } else {
+ u8 *addr = hapd->own_addr;
+
+ if (!is_zero_ether_addr(conf->bssid)) {
/* Allocate the configured BSSID. */
os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
@@ -922,11 +1073,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
"the radio", conf->iface);
return -1;
}
+ } else if (hapd->iconf->use_driver_iface_addr) {
+ addr = NULL;
+ } else {
+ /* Allocate the next available BSSID. */
+ do {
+ inc_byte_array(hapd->own_addr, ETH_ALEN);
+ } while (mac_in_conf(hapd->iconf, hapd->own_addr));
}
hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
- conf->iface, hapd->own_addr, hapd,
+ conf->iface, addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
conf->bridge[0] ? conf->bridge : NULL,
first == -1)) {
@@ -935,13 +1093,21 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
hapd->interface_added = 0;
return -1;
}
+
+ if (!addr)
+ os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
}
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
+#ifdef CONFIG_IEEE80211R_AP
+ if (is_zero_ether_addr(conf->r1_key_holder))
+ os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
+#endif /* CONFIG_IEEE80211R_AP */
+
#ifdef CONFIG_MESH
- if (hapd->iface->mconf == NULL)
+ if ((hapd->conf->mesh & MESH_ENABLED) && hapd->iface->mconf == NULL)
flush_old_stations = 0;
#endif /* CONFIG_MESH */
@@ -1022,8 +1188,11 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
das_conf.time_window = conf->radius_das_time_window;
das_conf.require_event_timestamp =
conf->radius_das_require_event_timestamp;
+ das_conf.require_message_authenticator =
+ conf->radius_das_require_message_authenticator;
das_conf.ctx = hapd;
das_conf.disconnect = hostapd_das_disconnect;
+ das_conf.coa = hostapd_das_coa;
hapd->radius_das = radius_das_init(&das_conf);
if (hapd->radius_das == NULL) {
wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
@@ -1040,6 +1209,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (hostapd_init_wps(hapd, conf))
return -1;
+#ifdef CONFIG_DPP
+ hapd->gas = gas_query_ap_init(hapd, hapd->msg_ctx);
+ if (!hapd->gas)
+ return -1;
+ if (hostapd_dpp_init(hapd))
+ return -1;
+#endif /* CONFIG_DPP */
+
if (authsrv_init(hapd) < 0)
return -1;
@@ -1127,7 +1304,7 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
struct hostapd_tx_queue_params *p;
#ifdef CONFIG_MESH
- if (iface->mconf == NULL)
+ if ((hapd->conf->mesh & MESH_ENABLED) && iface->mconf == NULL)
return;
#endif /* CONFIG_MESH */
@@ -1508,16 +1685,118 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
+#ifdef CONFIG_OWE
-/**
- * hostapd_setup_interface_complete - Complete interface setup
- *
- * This function is called when previous steps in the interface setup has been
- * completed. This can also start operations, e.g., DFS, that will require
- * additional processing before interface is ready to be enabled. Such
- * operations will call this function from eloop callbacks when finished.
- */
-int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
+static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
+{
+ struct hostapd_data *hapd = ctx;
+ size_t i;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *bss = iface->bss[i];
+
+ if (os_strcmp(hapd->conf->owe_transition_ifname,
+ bss->conf->iface) != 0)
+ continue;
+
+ wpa_printf(MSG_DEBUG,
+ "OWE: ifname=%s found transition mode ifname=%s BSSID "
+ MACSTR " SSID %s",
+ hapd->conf->iface, bss->conf->iface,
+ MAC2STR(bss->own_addr),
+ wpa_ssid_txt(bss->conf->ssid.ssid,
+ bss->conf->ssid.ssid_len));
+ if (!bss->conf->ssid.ssid_set || !bss->conf->ssid.ssid_len ||
+ is_zero_ether_addr(bss->own_addr))
+ continue;
+
+ os_memcpy(hapd->conf->owe_transition_bssid, bss->own_addr,
+ ETH_ALEN);
+ os_memcpy(hapd->conf->owe_transition_ssid,
+ bss->conf->ssid.ssid, bss->conf->ssid.ssid_len);
+ hapd->conf->owe_transition_ssid_len = bss->conf->ssid.ssid_len;
+ wpa_printf(MSG_DEBUG,
+ "OWE: Copied transition mode information");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int hostapd_owe_trans_get_info(struct hostapd_data *hapd)
+{
+ if (hapd->conf->owe_transition_ssid_len > 0 &&
+ !is_zero_ether_addr(hapd->conf->owe_transition_bssid))
+ return 0;
+
+ /* Find transition mode SSID/BSSID information from a BSS operated by
+ * this hostapd instance. */
+ if (!hapd->iface->interfaces ||
+ !hapd->iface->interfaces->for_each_interface)
+ return hostapd_owe_iface_iter(hapd->iface, hapd);
+ else
+ return hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, hostapd_owe_iface_iter, hapd);
+}
+
+
+static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
+{
+ size_t i;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *bss = iface->bss[i];
+ int res;
+
+ if (!bss->conf->owe_transition_ifname[0])
+ continue;
+ res = hostapd_owe_trans_get_info(bss);
+ if (res == 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "OWE: Matching transition mode interface enabled - update beacon data for %s",
+ bss->conf->iface);
+ ieee802_11_set_beacon(bss);
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_OWE */
+
+
+static void hostapd_owe_update_trans(struct hostapd_iface *iface)
+{
+#ifdef CONFIG_OWE
+ /* Check whether the enabled BSS can complete OWE transition mode
+ * configuration for any pending interface. */
+ if (!iface->interfaces ||
+ !iface->interfaces->for_each_interface)
+ hostapd_owe_iface_iter2(iface, NULL);
+ else
+ iface->interfaces->for_each_interface(
+ iface->interfaces, hostapd_owe_iface_iter2, NULL);
+#endif /* CONFIG_OWE */
+}
+
+
+static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_iface *iface = eloop_ctx;
+ struct hostapd_data *hapd;
+
+ if (iface->num_bss < 1 || !iface->bss || !iface->bss[0])
+ return;
+ hapd = iface->bss[0];
+ if (hapd->setup_complete_cb)
+ hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+}
+
+
+static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
+ int err)
{
struct hostapd_data *hapd = iface->bss[0];
size_t j;
@@ -1605,15 +1884,17 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
}
}
- if (hapd->iconf->rts_threshold > -1 &&
- hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
+ if (hapd->iconf->rts_threshold >= -1 &&
+ hostapd_set_rts(hapd, hapd->iconf->rts_threshold) &&
+ hapd->iconf->rts_threshold >= -1) {
wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
"kernel driver");
goto fail;
}
- if (hapd->iconf->fragm_threshold > -1 &&
- hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
+ if (hapd->iconf->fragm_threshold >= -1 &&
+ hostapd_set_frag(hapd, hapd->iconf->fragm_threshold) &&
+ hapd->iconf->fragm_threshold != -1) {
wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
"for kernel driver");
goto fail;
@@ -1626,14 +1907,17 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
if (j)
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
if (hostapd_setup_bss(hapd, j == 0)) {
- do {
+ for (;;) {
hapd = iface->bss[j];
hostapd_bss_deinit_no_free(hapd);
hostapd_free_hapd_data(hapd);
- } while (j-- > 0);
+ if (j == 0)
+ break;
+ j--;
+ }
goto fail;
}
- if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+ if (is_zero_ether_addr(hapd->conf->bssid))
prev_addr = hapd->own_addr;
}
hapd = iface->bss[0];
@@ -1641,7 +1925,6 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hostapd_tx_queue_params(iface);
ap_list_init(iface);
- dl_list_init(&iface->sta_seen);
hostapd_set_acl(hapd);
@@ -1692,6 +1975,7 @@ dfs_offload:
#endif /* CONFIG_FST */
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
+ hostapd_owe_update_trans(iface);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
@@ -1701,6 +1985,9 @@ dfs_offload:
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
iface->interfaces->terminate_on_error--;
+ for (j = 0; j < iface->num_bss; j++)
+ hostapd_neighbor_set_own_report(iface->bss[j]);
+
return 0;
fail:
@@ -1713,13 +2000,107 @@ fail:
iface->fst = NULL;
}
#endif /* CONFIG_FST */
- if (iface->interfaces && iface->interfaces->terminate_on_error)
+
+ if (iface->interfaces && iface->interfaces->terminate_on_error) {
eloop_terminate();
+ } else if (hapd->setup_complete_cb) {
+ /*
+ * Calling hapd->setup_complete_cb directly may cause iface
+ * deinitialization which may be accessed later by the caller.
+ */
+ eloop_register_timeout(0, 0,
+ hostapd_interface_setup_failure_handler,
+ iface, NULL);
+ }
+
return -1;
}
/**
+ * hostapd_setup_interface_complete - Complete interface setup
+ *
+ * This function is called when previous steps in the interface setup has been
+ * completed. This can also start operations, e.g., DFS, that will require
+ * additional processing before interface is ready to be enabled. Such
+ * operations will call this function from eloop callbacks when finished.
+ */
+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
+{
+ struct hapd_interfaces *interfaces = iface->interfaces;
+ struct hostapd_data *hapd = iface->bss[0];
+ unsigned int i;
+ int not_ready_in_sync_ifaces = 0;
+
+ if (!iface->need_to_start_in_sync)
+ return hostapd_setup_interface_complete_sync(iface, err);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "Interface initialization failed");
+ hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+ iface->need_to_start_in_sync = 0;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+ if (interfaces && interfaces->terminate_on_error)
+ eloop_terminate();
+ return -1;
+ }
+
+ if (iface->ready_to_start_in_sync) {
+ /* Already in ready and waiting. should never happpen */
+ return 0;
+ }
+
+ for (i = 0; i < interfaces->count; i++) {
+ if (interfaces->iface[i]->need_to_start_in_sync &&
+ !interfaces->iface[i]->ready_to_start_in_sync)
+ not_ready_in_sync_ifaces++;
+ }
+
+ /*
+ * Check if this is the last interface, if yes then start all the other
+ * waiting interfaces. If not, add this interface to the waiting list.
+ */
+ if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) {
+ /*
+ * If this interface went through CAC, do not synchronize, just
+ * start immediately.
+ */
+ iface->need_to_start_in_sync = 0;
+ wpa_printf(MSG_INFO,
+ "%s: Finished CAC - bypass sync and start interface",
+ iface->bss[0]->conf->iface);
+ return hostapd_setup_interface_complete_sync(iface, err);
+ }
+
+ if (not_ready_in_sync_ifaces > 1) {
+ /* need to wait as there are other interfaces still coming up */
+ iface->ready_to_start_in_sync = 1;
+ wpa_printf(MSG_INFO,
+ "%s: Interface waiting to sync with other interfaces",
+ iface->bss[0]->conf->iface);
+ return 0;
+ }
+
+ wpa_printf(MSG_INFO,
+ "%s: Last interface to sync - starting all interfaces",
+ iface->bss[0]->conf->iface);
+ iface->need_to_start_in_sync = 0;
+ hostapd_setup_interface_complete_sync(iface, err);
+ for (i = 0; i < interfaces->count; i++) {
+ if (interfaces->iface[i]->need_to_start_in_sync &&
+ interfaces->iface[i]->ready_to_start_in_sync) {
+ hostapd_setup_interface_complete_sync(
+ interfaces->iface[i], 0);
+ /* Only once the interfaces are sync started */
+ interfaces->iface[i]->need_to_start_in_sync = 0;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
* hostapd_setup_interface - Setup of an interface
* @iface: Pointer to interface data.
* Returns: 0 on success, -1 on failure
@@ -1776,8 +2157,19 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
hapd->iconf = conf;
hapd->conf = bss;
hapd->iface = hapd_iface;
- hapd->driver = hapd->iconf->driver;
+ if (conf)
+ hapd->driver = conf->driver;
hapd->ctrl_sock = -1;
+ dl_list_init(&hapd->ctrl_dst);
+ dl_list_init(&hapd->nr_db);
+ hapd->dhcp_sock = -1;
+#ifdef CONFIG_IEEE80211R_AP
+ dl_list_init(&hapd->l2_queue);
+ dl_list_init(&hapd->l2_oui_queue);
+#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_SAE
+ dl_list_init(&hapd->sae_commit_queue);
+#endif /* CONFIG_SAE */
return hapd;
}
@@ -1785,8 +2177,10 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
static void hostapd_bss_deinit(struct hostapd_data *hapd)
{
+ if (!hapd)
+ return;
wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
- hapd->conf->iface);
+ hapd->conf ? hapd->conf->iface : "N/A");
hostapd_bss_deinit_no_free(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
hostapd_cleanup(hapd);
@@ -1803,12 +2197,6 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
-#ifdef CONFIG_IEEE80211N
-#ifdef NEED_AP_MLME
- hostapd_stop_setup_timers(iface);
- eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
iface->wait_channel_update = 0;
@@ -1819,8 +2207,18 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
}
#endif /* CONFIG_FST */
- for (j = iface->num_bss - 1; j >= 0; j--)
+ for (j = (int) iface->num_bss - 1; j >= 0; j--) {
+ if (!iface->bss)
+ break;
hostapd_bss_deinit(iface->bss[j]);
+ }
+
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ hostapd_stop_setup_timers(iface);
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
}
@@ -1829,6 +2227,8 @@ void hostapd_interface_free(struct hostapd_iface *iface)
size_t j;
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
for (j = 0; j < iface->num_bss; j++) {
+ if (!iface->bss)
+ break;
wpa_printf(MSG_DEBUG, "%s: free hapd %p",
__func__, iface->bss[j]);
os_free(iface->bss[j]);
@@ -1837,6 +2237,20 @@ void hostapd_interface_free(struct hostapd_iface *iface)
}
+struct hostapd_iface * hostapd_alloc_iface(void)
+{
+ struct hostapd_iface *hapd_iface;
+
+ hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ if (!hapd_iface)
+ return NULL;
+
+ dl_list_init(&hapd_iface->sta_seen);
+
+ return hapd_iface;
+}
+
+
/**
* hostapd_init - Allocate and initialize per-interface data
* @config_file: Path to the configuration file
@@ -1854,7 +2268,7 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
struct hostapd_data *hapd;
size_t i;
- hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ hapd_iface = hostapd_alloc_iface();
if (hapd_iface == NULL)
goto fail;
@@ -2158,6 +2572,11 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
!!(hapd_iface->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+#ifdef NEED_AP_MLME
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_cleanup_cs_params(hapd_iface->bss[j]);
+#endif /* NEED_AP_MLME */
+
/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
for (j = 0; j < hapd_iface->num_bss; j++) {
struct hostapd_data *hapd = hapd_iface->bss[j];
@@ -2190,7 +2609,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces)
return NULL;
interfaces->iface = iface;
hapd_iface = interfaces->iface[interfaces->count] =
- os_zalloc(sizeof(*hapd_iface));
+ hostapd_alloc_iface();
if (hapd_iface == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
"the interface", __func__);
@@ -2215,7 +2634,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
if (conf == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
"configuration", __func__);
- return NULL;
+ return NULL;
}
if (driver) {
@@ -2368,6 +2787,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
return -1;
}
}
+ hostapd_owe_update_trans(hapd_iface);
return 0;
}
@@ -2557,6 +2977,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
}
hostapd_prune_associations(hapd, sta->addr);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
/* IEEE 802.11F (IAPP) */
if (hapd->conf->ieee802_11f)
@@ -2584,15 +3005,28 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
ieee802_1x_new_station(hapd, sta);
if (reassoc) {
if (sta->auth_alg != WLAN_AUTH_FT &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
+ sta->auth_alg != WLAN_AUTH_FILS_PK &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
- if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
- wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
- "for " MACSTR " (%d seconds - ap_max_inactivity)",
- __func__, MAC2STR(sta->addr),
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
+ if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: %s: canceled wired ap_handle_timer timeout for "
+ MACSTR,
+ hapd->conf->iface, __func__,
+ MAC2STR(sta->addr));
+ }
+ } else if (!(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
+ wpa_printf(MSG_DEBUG,
+ "%s: %s: reschedule ap_handle_timer timeout for "
+ MACSTR " (%d seconds - ap_max_inactivity)",
+ hapd->conf->iface, __func__, MAC2STR(sta->addr),
hapd->conf->ap_max_inactivity);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
@@ -2627,12 +3061,23 @@ const char * hostapd_state_text(enum hostapd_iface_state s)
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
{
wpa_printf(MSG_INFO, "%s: interface state %s->%s",
- iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
- hostapd_state_text(s));
+ iface->conf ? iface->conf->bss[0]->iface : "N/A",
+ hostapd_state_text(iface->state), hostapd_state_text(s));
iface->state = s;
}
+int hostapd_csa_in_progress(struct hostapd_iface *iface)
+{
+ unsigned int i;
+
+ for (i = 0; i < iface->num_bss; i++)
+ if (iface->bss[i]->csa_in_progress)
+ return 1;
+ return 0;
+}
+
+
#ifdef NEED_AP_MLME
static void free_beacon_data(struct beacon_data *beacon)
@@ -2671,60 +3116,52 @@ static int hostapd_build_beacon_data(struct hostapd_data *hapd,
goto free_ap_params;
ret = -1;
- beacon->head = os_malloc(params.head_len);
+ beacon->head = os_memdup(params.head, params.head_len);
if (!beacon->head)
goto free_ap_extra_ies;
- os_memcpy(beacon->head, params.head, params.head_len);
beacon->head_len = params.head_len;
- beacon->tail = os_malloc(params.tail_len);
+ beacon->tail = os_memdup(params.tail, params.tail_len);
if (!beacon->tail)
goto free_beacon;
- os_memcpy(beacon->tail, params.tail, params.tail_len);
beacon->tail_len = params.tail_len;
if (params.proberesp != NULL) {
- beacon->probe_resp = os_malloc(params.proberesp_len);
+ beacon->probe_resp = os_memdup(params.proberesp,
+ params.proberesp_len);
if (!beacon->probe_resp)
goto free_beacon;
- os_memcpy(beacon->probe_resp, params.proberesp,
- params.proberesp_len);
beacon->probe_resp_len = params.proberesp_len;
}
/* copy the extra ies */
if (beacon_extra) {
- beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra));
+ beacon->beacon_ies = os_memdup(beacon_extra->buf,
+ wpabuf_len(beacon_extra));
if (!beacon->beacon_ies)
goto free_beacon;
- os_memcpy(beacon->beacon_ies,
- beacon_extra->buf, wpabuf_len(beacon_extra));
beacon->beacon_ies_len = wpabuf_len(beacon_extra);
}
if (proberesp_extra) {
- beacon->proberesp_ies =
- os_malloc(wpabuf_len(proberesp_extra));
+ beacon->proberesp_ies = os_memdup(proberesp_extra->buf,
+ wpabuf_len(proberesp_extra));
if (!beacon->proberesp_ies)
goto free_beacon;
- os_memcpy(beacon->proberesp_ies, proberesp_extra->buf,
- wpabuf_len(proberesp_extra));
beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
}
if (assocresp_extra) {
- beacon->assocresp_ies =
- os_malloc(wpabuf_len(assocresp_extra));
+ beacon->assocresp_ies = os_memdup(assocresp_extra->buf,
+ wpabuf_len(assocresp_extra));
if (!beacon->assocresp_ies)
goto free_beacon;
- os_memcpy(beacon->assocresp_ies, assocresp_extra->buf,
- wpabuf_len(assocresp_extra));
beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
}
@@ -2744,9 +3181,9 @@ free_ap_params:
/*
- * TODO: This flow currently supports only changing frequency within the
- * same hw_mode. Any other changes to MAC parameters or provided settings (even
- * width) are not supported.
+ * TODO: This flow currently supports only changing channel and width within
+ * the same hw_mode. Any other changes to MAC parameters or provided settings
+ * are not supported.
*/
static int hostapd_change_config_freq(struct hostapd_data *hapd,
struct hostapd_config *conf,
@@ -2765,15 +3202,44 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
return -1;
/* if a pointer to old_params is provided we save previous state */
- if (old_params) {
- old_params->channel = conf->channel;
- old_params->ht_enabled = conf->ieee80211n;
- old_params->sec_channel_offset = conf->secondary_channel;
+ if (old_params &&
+ hostapd_set_freq_params(old_params, conf->hw_mode,
+ hostapd_hw_get_freq(hapd, conf->channel),
+ conf->channel, conf->ieee80211n,
+ conf->ieee80211ac,
+ conf->secondary_channel,
+ conf->vht_oper_chwidth,
+ conf->vht_oper_centr_freq_seg0_idx,
+ conf->vht_oper_centr_freq_seg1_idx,
+ conf->vht_capab))
+ return -1;
+
+ switch (params->bandwidth) {
+ case 0:
+ case 20:
+ case 40:
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ case 80:
+ if (params->center_freq2)
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+ else
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 160:
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ return -1;
}
conf->channel = channel;
conf->ieee80211n = params->ht_enabled;
conf->secondary_channel = params->sec_channel_offset;
+ ieee80211_freq_to_chan(params->center_freq1,
+ &conf->vht_oper_centr_freq_seg0_idx);
+ ieee80211_freq_to_chan(params->center_freq2,
+ &conf->vht_oper_centr_freq_seg1_idx);
/* TODO: maybe call here hostapd_config_check here? */
@@ -2787,11 +3253,43 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
+ u8 chan, vht_bandwidth;
os_memset(&old_freq, 0, sizeof(old_freq));
if (!iface || !iface->freq || hapd->csa_in_progress)
return -1;
+ switch (settings->freq_params.bandwidth) {
+ case 80:
+ if (settings->freq_params.center_freq2)
+ vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
+ else
+ vht_bandwidth = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 160:
+ vht_bandwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ vht_bandwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ if (ieee80211_freq_to_channel_ext(
+ settings->freq_params.freq,
+ settings->freq_params.sec_channel_offset,
+ vht_bandwidth,
+ &hapd->iface->cs_oper_class,
+ &chan) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
+ settings->freq_params.freq,
+ settings->freq_params.sec_channel_offset,
+ settings->freq_params.vht_enabled);
+ return -1;
+ }
+
+ settings->freq_params.channel = chan;
+
ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
&settings->freq_params,
&old_freq);
@@ -2818,8 +3316,10 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
return ret;
}
- settings->counter_offset_beacon = hapd->cs_c_off_beacon;
- settings->counter_offset_presp = hapd->cs_c_off_proberesp;
+ settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon;
+ settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp;
+ settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon;
+ settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;
return 0;
}
@@ -2833,6 +3333,21 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
hapd->cs_c_off_beacon = 0;
hapd->cs_c_off_proberesp = 0;
hapd->csa_in_progress = 0;
+ hapd->cs_c_off_ecsa_beacon = 0;
+ hapd->cs_c_off_ecsa_proberesp = 0;
+}
+
+
+void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
+{
+ if (vht_enabled)
+ hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
+ else
+ hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
+
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
+ hapd->iconf->ch_switch_vht_config);
}
@@ -2870,7 +3385,6 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
{
int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
- unsigned int i;
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
@@ -2912,14 +3426,14 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
/*
* cs_params must not be cleared earlier because the freq_params
* argument may actually point to one of these.
+ * These params will be cleared during interface disable below.
*/
- for (i = 0; i < iface->num_bss; i++)
- hostapd_cleanup_cs_params(iface->bss[i]);
-
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
}
+#endif /* NEED_AP_MLME */
+
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
const char *ifname)
@@ -2940,8 +3454,6 @@ struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
return NULL;
}
-#endif /* NEED_AP_MLME */
-
void hostapd_periodic_iface(struct hostapd_iface *iface)
{
diff --git a/contrib/wpa/src/ap/hostapd.h b/contrib/wpa/src/ap/hostapd.h
index dcf51f0..790d377 100644
--- a/contrib/wpa/src/ap/hostapd.h
+++ b/contrib/wpa/src/ap/hostapd.h
@@ -14,6 +14,13 @@
#include "ap_config.h"
#include "drivers/driver.h"
+#define OCE_STA_CFON_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_STA_CFON) && \
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON))
+#define OCE_AP_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_AP) && \
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_AP))
+
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
@@ -41,7 +48,7 @@ struct hapd_interfaces {
size_t count;
int global_ctrl_sock;
- struct wpa_ctrl_dst *global_ctrl_dst;
+ struct dl_list global_ctrl_dst;
char *global_iface_path;
char *global_iface_name;
#ifndef CONFIG_NATIVE_WINDOWS
@@ -53,6 +60,14 @@ struct hapd_interfaces {
#ifndef CONFIG_NO_VLAN
struct dynamic_iface *vlan_priv;
#endif /* CONFIG_NO_VLAN */
+#ifdef CONFIG_ETH_P_OUI
+ struct dl_list eth_p_oui; /* OUI Extended EtherType handlers */
+#endif /* CONFIG_ETH_P_OUI */
+ int eloop_initialized;
+
+#ifdef CONFIG_DPP
+ struct dpp_global *dpp;
+#endif /* CONFIG_DPP */
};
enum hostapd_chan_status {
@@ -75,6 +90,7 @@ struct hostapd_rate_data {
};
struct hostapd_frame_info {
+ unsigned int freq;
u32 channel;
u32 datarate;
int ssi_signal; /* dBm */
@@ -99,6 +115,24 @@ struct wps_stat {
u8 peer_addr[ETH_ALEN];
};
+struct hostapd_neighbor_entry {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ struct wpa_ssid_value ssid;
+ struct wpabuf *nr;
+ struct wpabuf *lci;
+ struct wpabuf *civic;
+ /* LCI update time */
+ struct os_time lci_date;
+ int stationary;
+};
+
+struct hostapd_sae_commit_queue {
+ struct dl_list list;
+ int rssi;
+ size_t len;
+ u8 msg[];
+};
/**
* struct hostapd_data - hostapd per-BSS data structure
@@ -138,7 +172,7 @@ struct hostapd_data {
void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
struct radius_client_data *radius;
- u32 acct_session_id_hi, acct_session_id_lo;
+ u64 acct_session_id;
struct radius_das_data *radius_das;
struct iapp_data *iapp;
@@ -155,7 +189,7 @@ struct hostapd_data {
int tkip_countermeasures;
int ctrl_sock;
- struct wpa_ctrl_dst *ctrl_dst;
+ struct dl_list ctrl_dst;
void *ssl_ctx;
void *eap_sim_db_priv;
@@ -173,6 +207,17 @@ struct hostapd_data {
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
struct l2_packet_data *l2;
+
+#ifdef CONFIG_IEEE80211R_AP
+ struct dl_list l2_queue;
+ struct dl_list l2_oui_queue;
+ struct eth_p_oui_ctx *oui_pull;
+ struct eth_p_oui_ctx *oui_resp;
+ struct eth_p_oui_ctx *oui_push;
+ struct eth_p_oui_ctx *oui_sreq;
+ struct eth_p_oui_ctx *oui_sresp;
+#endif /* CONFIG_IEEE80211R_AP */
+
struct wps_context *wps;
int beacon_set_done;
@@ -228,9 +273,8 @@ struct hostapd_data {
unsigned int cs_c_off_beacon;
unsigned int cs_c_off_proberesp;
int csa_in_progress;
-
- /* BSS Load */
- unsigned int bss_load_update_timeout;
+ unsigned int cs_c_off_ecsa_beacon;
+ unsigned int cs_c_off_ecsa_proberesp;
#ifdef CONFIG_P2P
struct p2p_data *p2p;
@@ -246,9 +290,6 @@ struct hostapd_data {
int noa_start;
int noa_duration;
#endif /* CONFIG_P2P */
-#ifdef CONFIG_INTERWORKING
- size_t gas_frag_limit;
-#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_PROXYARP
struct l2_packet_data *sock_dhcp;
struct l2_packet_data *sock_ndisc;
@@ -256,9 +297,11 @@ struct hostapd_data {
#ifdef CONFIG_MESH
int num_plinks;
int max_plinks;
- void (*mesh_sta_free_cb)(struct sta_info *sta);
+ void (*mesh_sta_free_cb)(struct hostapd_data *hapd,
+ struct sta_info *sta);
struct wpabuf *mesh_pending_auth;
struct os_reltime mesh_pending_auth_time;
+ u8 mesh_required_peer[ETH_ALEN];
#endif /* CONFIG_MESH */
#ifdef CONFIG_SQLITE
@@ -269,7 +312,10 @@ struct hostapd_data {
/** Key used for generating SAE anti-clogging tokens */
u8 sae_token_key[8];
struct os_reltime last_sae_token_key_update;
+ u16 sae_token_idx;
+ u16 sae_pending_token_idx[256];
int dot11RSNASAERetransPeriod; /* msec */
+ struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
#endif /* CONFIG_SAE */
#ifdef CONFIG_TESTING_OPTIONS
@@ -277,7 +323,62 @@ struct hostapd_data {
unsigned int ext_eapol_frame_io:1;
struct l2_packet_data *l2_test;
+
+ enum wpa_alg last_gtk_alg;
+ int last_gtk_key_idx;
+ u8 last_gtk[WPA_GTK_MAX_LEN];
+ size_t last_gtk_len;
+
+#ifdef CONFIG_IEEE80211W
+ enum wpa_alg last_igtk_alg;
+ int last_igtk_key_idx;
+ u8 last_igtk[WPA_IGTK_MAX_LEN];
+ size_t last_igtk_len;
+#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_MBO
+ unsigned int mbo_assoc_disallow;
+#endif /* CONFIG_MBO */
+
+ struct dl_list nr_db;
+
+ u8 beacon_req_token;
+ u8 lci_req_token;
+ u8 range_req_token;
+ unsigned int lci_req_active:1;
+ unsigned int range_req_active:1;
+
+ int dhcp_sock; /* UDP socket used with the DHCP server */
+
+#ifdef CONFIG_DPP
+ int dpp_init_done;
+ struct dpp_authentication *dpp_auth;
+ u8 dpp_allowed_roles;
+ int dpp_qr_mutual;
+ int dpp_auth_ok_on_ack;
+ int dpp_in_response_listen;
+ struct gas_query_ap *gas;
+ struct dpp_pkex *dpp_pkex;
+ struct dpp_bootstrap_info *dpp_pkex_bi;
+ char *dpp_pkex_code;
+ char *dpp_pkex_identifier;
+ char *dpp_pkex_auth_cmd;
+ char *dpp_configurator_params;
+ struct os_reltime dpp_last_init;
+ struct os_reltime dpp_init_iter_start;
+ unsigned int dpp_init_max_tries;
+ unsigned int dpp_init_retry_time;
+ unsigned int dpp_resp_wait_time;
+ unsigned int dpp_resp_max_tries;
+ unsigned int dpp_resp_retry_time;
+#ifdef CONFIG_TESTING_OPTIONS
+ char *dpp_config_obj_override;
+ char *dpp_discovery_override;
+ char *dpp_groups_override;
+ unsigned int dpp_ignore_netaccesskey_mismatch:1;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_DPP */
};
@@ -285,6 +386,10 @@ struct hostapd_sta_info {
struct dl_list list;
u8 addr[ETH_ALEN];
struct os_reltime last_seen;
+ int ssi_signal;
+#ifdef CONFIG_TAXONOMY
+ struct wpabuf *probe_ie_taxonomy;
+#endif /* CONFIG_TAXONOMY */
};
/**
@@ -327,6 +432,15 @@ struct hostapd_iface {
*/
unsigned int driver_ap_teardown:1;
+ /*
+ * When set, indicates that this interface is part of list of
+ * interfaces that need to be started together (synchronously).
+ */
+ unsigned int need_to_start_in_sync:1;
+
+ /* Ready to start but waiting for other interfaces to become ready. */
+ unsigned int ready_to_start_in_sync:1;
+
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
@@ -402,6 +516,13 @@ struct hostapd_iface {
u64 last_channel_time_busy;
u8 channel_utilization;
+ unsigned int chan_util_samples_sum;
+ unsigned int chan_util_num_sample_periods;
+ unsigned int chan_util_average;
+
+ /* eCSA IE will be added only if operating class is specified */
+ u8 cs_oper_class;
+
unsigned int dfs_cac_ms;
struct os_reltime dfs_cac_start;
@@ -418,6 +539,8 @@ struct hostapd_iface {
struct dl_list sta_seen; /* struct hostapd_sta_info */
unsigned int num_sta_seen;
+
+ u8 dfs_domain;
};
/* hostapd.c */
@@ -425,6 +548,7 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
int hostapd_reload_config(struct hostapd_iface *iface);
+void hostapd_reconfig_encryption(struct hostapd_data *hapd);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
struct hostapd_config *conf,
@@ -433,6 +557,7 @@ int hostapd_setup_interface(struct hostapd_iface *iface);
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
+struct hostapd_iface * hostapd_alloc_iface(void);
struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
const char *config_file);
struct hostapd_iface *
@@ -449,6 +574,8 @@ int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
+int hostapd_csa_in_progress(struct hostapd_iface *iface);
+void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
@@ -456,6 +583,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params);
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
void hostapd_periodic_iface(struct hostapd_iface *iface);
+int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
@@ -467,6 +595,8 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd,
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
/* drv_callbacks.c (TODO: move to somewhere else?) */
+void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
+ struct sta_info *sta);
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
@@ -478,6 +608,11 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2);
+struct survey_results;
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_results);
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ struct acs_selected_channels *acs_res);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
@@ -485,6 +620,9 @@ hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
const char *ifname);
+void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
+ enum smps_mode smps_mode,
+ enum chan_width chan_width, u8 rx_nss);
#ifdef CONFIG_FST
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
diff --git a/contrib/wpa/src/ap/hs20.c b/contrib/wpa/src/ap/hs20.c
index d7909fa..532580e 100644
--- a/contrib/wpa/src/ap/hs20.c
+++ b/contrib/wpa/src/ap/hs20.c
@@ -11,9 +11,11 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "sta_info.h"
#include "hs20.h"
@@ -23,17 +25,20 @@ u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
if (!hapd->conf->hs20)
return eid;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
- *eid++ = 7;
+ *eid++ = hapd->conf->hs20_release < 2 ? 5 : 7;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = HS20_INDICATION_OUI_TYPE;
- conf = HS20_VERSION; /* Release Number */
- conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
+ conf = (hapd->conf->hs20_release - 1) << 4; /* Release Number */
+ if (hapd->conf->hs20_release >= 2)
+ conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
if (hapd->conf->disable_dgaf)
conf |= HS20_DGAF_DISABLED;
*eid++ = conf;
- WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
- eid += 2;
+ if (hapd->conf->hs20_release >= 2) {
+ WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
+ eid += 2;
+ }
return eid;
}
@@ -82,6 +87,10 @@ u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (hapd->conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
eid += 2;
@@ -175,3 +184,72 @@ int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
return ret;
}
+
+
+int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
+ const u8 *addr, const char *url)
+{
+ struct wpabuf *buf;
+ int ret;
+ size_t url_len;
+
+ if (!url) {
+ wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available");
+ return -1;
+ }
+
+ url_len = os_strlen(url);
+ if (5 + url_len > 255) {
+ wpa_printf(MSG_INFO,
+ "HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'",
+ url);
+ return -1;
+ }
+
+ buf = wpabuf_alloc(4 + 7 + url_len);
+ if (!buf)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+ wpabuf_put_u8(buf, 1); /* Dialog token */
+ wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
+
+ /* Terms and Conditions Acceptance subelement */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + 1 + url_len);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_WNM_T_C_ACCEPTANCE);
+ wpabuf_put_u8(buf, url_len);
+ wpabuf_put_str(buf, url);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
+ int enabled)
+{
+ if (enabled) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Terms and Conditions filtering required for "
+ MACSTR, MAC2STR(sta->addr));
+ sta->hs20_t_c_filtering = 1;
+ /* TODO: Enable firewall filtering for the STA */
+ wpa_msg(hapd->msg_ctx, MSG_INFO, HS20_T_C_FILTERING_ADD MACSTR,
+ MAC2STR(sta->addr));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Terms and Conditions filtering not required for "
+ MACSTR, MAC2STR(sta->addr));
+ sta->hs20_t_c_filtering = 0;
+ /* TODO: Disable firewall filtering for the STA */
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ HS20_T_C_FILTERING_REMOVE MACSTR, MAC2STR(sta->addr));
+ }
+}
diff --git a/contrib/wpa/src/ap/hs20.h b/contrib/wpa/src/ap/hs20.h
index 152439f..e99e26e 100644
--- a/contrib/wpa/src/ap/hs20.h
+++ b/contrib/wpa/src/ap/hs20.h
@@ -18,5 +18,9 @@ int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
const u8 *addr,
const struct wpabuf *payload);
+int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
+ const u8 *addr, const char *url);
+void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
+ int enabled);
#endif /* HS20_H */
diff --git a/contrib/wpa/src/ap/hw_features.c b/contrib/wpa/src/ap/hw_features.c
index fc8786d..9d3d990 100644
--- a/contrib/wpa/src/ap/hw_features.c
+++ b/contrib/wpa/src/ap/hw_features.c
@@ -78,10 +78,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
int i, j;
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
+ u8 dfs_domain;
if (hostapd_drv_none(hapd))
return -1;
- modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
+ modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags,
+ &dfs_domain);
if (modes == NULL) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -91,6 +93,7 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
}
iface->hw_flags = flags;
+ iface->dfs_domain = dfs_domain;
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = modes;
@@ -226,9 +229,6 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
int pri_chan, sec_chan;
- if (!iface->conf->secondary_channel)
- return 1; /* HT40 not used */
-
pri_chan = iface->conf->channel;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
@@ -329,6 +329,10 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
+ iface->conf->vht_oper_centr_freq_seg0_idx = 0;
+ iface->conf->vht_oper_centr_freq_seg1_idx = 0;
+ iface->conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@@ -472,8 +476,9 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
struct wpa_driver_scan_params params;
int ret;
- if (!iface->conf->secondary_channel)
- return 0; /* HT40 not used */
+ /* Check that HT40 is used and PRI / SEC switch is allowed */
+ if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch)
+ return 0;
hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
@@ -619,41 +624,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
#ifdef CONFIG_IEEE80211AC
-
-static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
-{
- u32 req_cap = conf & cap;
-
- /*
- * Make sure we support all requested capabilities.
- * NOTE: We assume that 'cap' represents a capability mask,
- * not a discrete value.
- */
- if ((hw & req_cap) != req_cap) {
- wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
- name);
- return 0;
- }
- return 1;
-}
-
-
-static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
- unsigned int shift,
- const char *name)
-{
- u32 hw_max = hw & mask;
- u32 conf_val = conf & mask;
-
- if (conf_val > hw_max) {
- wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
- name, conf_val >> shift, hw_max >> shift);
- return 0;
- }
- return 1;
-}
-
-
static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
{
struct hostapd_hw_modes *mode = iface->current_mode;
@@ -681,45 +651,7 @@ static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
}
}
-#define VHT_CAP_CHECK(cap) \
- do { \
- if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
- return 0; \
- } while (0)
-
-#define VHT_CAP_CHECK_MAX(cap) \
- do { \
- if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
- #cap)) \
- return 0; \
- } while (0)
-
- VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
- VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
- VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
- VHT_CAP_CHECK(VHT_CAP_RXLDPC);
- VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
- VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
- VHT_CAP_CHECK(VHT_CAP_TXSTBC);
- VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
- VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
- VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
- VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
- VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
- VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
- VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
- VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
- VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
- VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
- VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
-
-#undef VHT_CAP_CHECK
-#undef VHT_CAP_CHECK_MAX
-
- return 1;
+ return ieee80211ac_cap_check(hw, conf);
}
#endif /* CONFIG_IEEE80211AC */
@@ -744,7 +676,8 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
if (!ieee80211n_supported_ht_capab(iface))
return -1;
#ifdef CONFIG_IEEE80211AC
- if (!ieee80211ac_supported_vht_capab(iface))
+ if (iface->conf->ieee80211ac &&
+ !ieee80211ac_supported_vht_capab(iface))
return -1;
#endif /* CONFIG_IEEE80211AC */
ret = ieee80211n_check_40mhz(iface);
@@ -761,42 +694,66 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int channel, int primary)
{
- int i;
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if (chan->chan != channel)
- continue;
-
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
- return 1;
+ chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+ if (!chan)
+ return 0;
- wpa_printf(MSG_DEBUG,
- "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
- primary ? "" : "Configured HT40 secondary ",
- i, chan->chan, chan->flag,
- chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
- chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
- }
+ if ((primary && chan_pri_allowed(chan)) ||
+ (!primary && !(chan->flag & HOSTAPD_CHAN_DISABLED)))
+ return 1;
+ wpa_printf(MSG_INFO,
+ "Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
+ channel, primary ? "primary" : "secondary",
+ chan->flag,
+ chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
+ chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
return 0;
}
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
+ int secondary_chan;
+ struct hostapd_channel_data *pri_chan;
+
+ pri_chan = hw_get_channel_chan(iface->current_mode,
+ iface->conf->channel, NULL);
+ if (!pri_chan)
+ return 0;
+
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
return 0;
if (!iface->conf->secondary_channel)
return 1;
- return hostapd_is_usable_chan(iface, iface->conf->channel +
- iface->conf->secondary_channel * 4, 0);
+ if (!iface->conf->ht40_plus_minus_allowed)
+ return hostapd_is_usable_chan(
+ iface, iface->conf->channel +
+ iface->conf->secondary_channel * 4, 0);
+
+ /* Both HT40+ and HT40- are set, pick a valid secondary channel */
+ secondary_chan = iface->conf->channel + 4;
+ if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
+ iface->conf->secondary_channel = 1;
+ return 1;
+ }
+
+ secondary_chan = iface->conf->channel - 4;
+ if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
+ iface->conf->secondary_channel = -1;
+ return 1;
+ }
+
+ return 0;
}
@@ -976,5 +933,19 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
{
- return hw_get_chan(hapd->iface->current_mode, freq);
+ int i, channel;
+ struct hostapd_hw_modes *mode;
+
+ channel = hw_get_chan(hapd->iface->current_mode, freq);
+ if (channel)
+ return channel;
+ /* Check other available modes since the channel list for the current
+ * mode did not include the specified frequency. */
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ mode = &hapd->iface->hw_features[i];
+ channel = hw_get_chan(mode, freq);
+ if (channel)
+ return channel;
+ }
+ return 0;
}
diff --git a/contrib/wpa/src/ap/iapp.c b/contrib/wpa/src/ap/iapp.c
index 99aa04d..2556da3 100644
--- a/contrib/wpa/src/ap/iapp.c
+++ b/contrib/wpa/src/ap/iapp.c
@@ -34,11 +34,7 @@
#include "utils/includes.h"
#include <net/if.h>
#include <sys/ioctl.h>
-#ifdef USE_KERNEL_HEADERS
-#include <linux/if_packet.h>
-#else /* USE_KERNEL_HEADERS */
#include <netpacket/packet.h>
-#endif /* USE_KERNEL_HEADERS */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -385,6 +381,7 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
struct sockaddr_in *paddr, uaddr;
struct iapp_data *iapp;
struct ip_mreqn mreq;
+ int reuseaddr = 1;
iapp = os_zalloc(sizeof(*iapp));
if (iapp == NULL)
@@ -447,6 +444,18 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
os_memset(&uaddr, 0, sizeof(uaddr));
uaddr.sin_family = AF_INET;
uaddr.sin_port = htons(IAPP_UDP_PORT);
+
+ if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+ sizeof(reuseaddr)) < 0) {
+ wpa_printf(MSG_INFO,
+ "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
+ strerror(errno));
+ /*
+ * Ignore this and try to continue. This is fine for single
+ * BSS cases, but may fail if multiple BSSes enable IAPP.
+ */
+ }
+
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
sizeof(uaddr)) < 0) {
wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
diff --git a/contrib/wpa/src/ap/ieee802_11.c b/contrib/wpa/src/ap/ieee802_11.c
index 7bb18c0..fde19b5 100644
--- a/contrib/wpa/src/ap/ieee802_11.c
+++ b/contrib/wpa/src/ap/ieee802_11.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,11 +14,15 @@
#include "utils/eloop.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/sae.h"
+#include "common/dpp.h"
+#include "common/ocv.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -42,6 +46,41 @@
#include "hw_features.h"
#include "ieee802_11.h"
#include "dfs.h"
+#include "mbo_ap.h"
+#include "rrm.h"
+#include "taxonomy.h"
+#include "fils_hlp.h"
+#include "dpp_hostapd.h"
+#include "gas_query_ap.h"
+
+
+#ifdef CONFIG_FILS
+static struct wpabuf *
+prepare_auth_resp_fils(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 *resp,
+ struct rsn_pmksa_cache_entry *pmksa,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len,
+ int *is_pub);
+#endif /* CONFIG_FILS */
+static void handle_auth(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int rssi, int from_queue);
+
+
+u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 multi_ap_val = 0;
+
+ if (!hapd->conf->multi_ap)
+ return eid;
+ if (hapd->conf->multi_ap & BACKHAUL_BSS)
+ multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
+ if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+ multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
+
+ return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
+}
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
@@ -139,6 +178,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
int capab = WLAN_CAPABILITY_ESS;
int privacy;
int dfs;
+ int i;
/* Check if any of configured channels require DFS */
dfs = hostapd_is_dfs_required(hapd->iface);
@@ -186,8 +226,12 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
(hapd->iconf->spectrum_mgmt_required || dfs))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
- if (hapd->conf->radio_measurements)
- capab |= IEEE80211_CAP_RRM;
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i]) {
+ capab |= IEEE80211_CAP_RRM;
+ break;
+ }
+ }
return capab;
}
@@ -207,16 +251,17 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
if (!sta->challenge) {
/* Generate a pseudo-random challenge */
u8 key[8];
- struct os_time now;
- int r;
+
sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
if (sta->challenge == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- os_get_time(&now);
- r = os_random();
- os_memcpy(key, &now.sec, 4);
- os_memcpy(key + 4, &r, 4);
+ if (os_get_random(key, sizeof(key)) < 0) {
+ os_free(sta->challenge);
+ sta->challenge = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
rc4_skip(key, sizeof(key), 0,
sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
}
@@ -250,19 +295,20 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_NO_RC4 */
-static void send_auth_reply(struct hostapd_data *hapd,
- const u8 *dst, const u8 *bssid,
- u16 auth_alg, u16 auth_transaction, u16 resp,
- const u8 *ies, size_t ies_len)
+static int send_auth_reply(struct hostapd_data *hapd,
+ const u8 *dst, const u8 *bssid,
+ u16 auth_alg, u16 auth_transaction, u16 resp,
+ const u8 *ies, size_t ies_len, const char *dbg)
{
struct ieee80211_mgmt *reply;
u8 *buf;
size_t rlen;
+ int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
buf = os_zalloc(rlen);
if (buf == NULL)
- return;
+ return -1;
reply = (struct ieee80211_mgmt *) buf;
reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -279,71 +325,120 @@ static void send_auth_reply(struct hostapd_data *hapd,
os_memcpy(reply->u.auth.variable, ies, ies_len);
wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
- " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
+ " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
MAC2STR(dst), auth_alg, auth_transaction,
- resp, (unsigned long) ies_len);
+ resp, (unsigned long) ies_len, dbg);
if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
- wpa_printf(MSG_INFO, "send_auth_reply: send");
+ wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+ else
+ reply_res = WLAN_STATUS_SUCCESS;
os_free(buf);
+
+ return reply_res;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 status,
const u8 *ies, size_t ies_len)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int reply_res;
- send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
- status, ies, ies_len);
-
- if (status != WLAN_STATUS_SUCCESS)
- return;
+ reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+ auth_transaction, status, ies, ies_len,
+ "auth-ft-finish");
sta = ap_get_sta(hapd, dst);
if (sta == NULL)
return;
+ if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
+ status != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS)
+ return;
+
hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
sta->flags |= WLAN_STA_AUTH;
mlme_authenticate_indication(hapd, sta);
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
-#define dot11RSNASAESync 5 /* attempts */
+static void sae_set_state(struct sta_info *sta, enum sae_state state,
+ const char *reason)
+{
+ wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
+ sae_state_txt(sta->sae->state), sae_state_txt(state),
+ MAC2STR(sta->addr), reason);
+ sta->sae->state = state;
+}
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
struct sta_info *sta, int update)
{
struct wpabuf *buf;
+ const char *password = NULL;
+ struct sae_password_entry *pw;
+ const char *rx_id = NULL;
- if (hapd->conf->ssid.wpa_passphrase == NULL) {
+ if (sta->sae->tmp)
+ rx_id = sta->sae->tmp->pw_id;
+
+ for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+ if (!is_broadcast_ether_addr(pw->peer_addr) &&
+ os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
+ continue;
+ if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
+ continue;
+ if (rx_id && pw->identifier &&
+ os_strcmp(rx_id, pw->identifier) != 0)
+ continue;
+ password = pw->password;
+ break;
+ }
+ if (!password)
+ password = hapd->conf->ssid.wpa_passphrase;
+ if (!password) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
}
if (update &&
sae_prepare_commit(hapd->own_addr, sta->addr,
- (u8 *) hapd->conf->ssid.wpa_passphrase,
- os_strlen(hapd->conf->ssid.wpa_passphrase),
+ (u8 *) password, os_strlen(password), rx_id,
sta->sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
}
- buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
+ if (pw && pw->vlan_id) {
+ if (!sta->sae->tmp) {
+ wpa_printf(MSG_INFO,
+ "SAE: No temporary data allocated - cannot store VLAN ID");
+ return NULL;
+ }
+ sta->sae->tmp->vlan_id = pw->vlan_id;
+ }
+
+ buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
+ (rx_id ? 3 + os_strlen(rx_id) : 0));
if (buf == NULL)
return NULL;
sae_write_commit(sta->sae, buf, sta->sae->tmp ?
- sta->sae->tmp->anti_clogging_token : NULL);
+ sta->sae->tmp->anti_clogging_token : NULL, rx_id);
return buf;
}
@@ -369,18 +464,21 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
const u8 *bssid, int update)
{
struct wpabuf *data;
+ int reply_res;
data = auth_build_sae_commit(hapd, sta, update);
+ if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
+ return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- send_auth_reply(hapd, sta->addr, bssid,
- WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS,
- wpabuf_head(data), wpabuf_len(data));
+ reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
+ WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ wpabuf_len(data), "sae-send-commit");
wpabuf_free(data);
- return WLAN_STATUS_SUCCESS;
+ return reply_res;
}
@@ -389,18 +487,19 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
const u8 *bssid)
{
struct wpabuf *data;
+ int reply_res;
data = auth_build_sae_confirm(hapd, sta);
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- send_auth_reply(hapd, sta->addr, bssid,
- WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS,
- wpabuf_head(data), wpabuf_len(data));
+ reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+ WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ wpabuf_len(data), "sae-send-confirm");
wpabuf_free(data);
- return WLAN_STATUS_SUCCESS;
+ return reply_res;
}
@@ -423,21 +522,57 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
return 1;
}
+ /* In addition to already existing open SAE sessions, check whether
+ * there are enough pending commit messages in the processing queue to
+ * potentially result in too many open sessions. */
+ if (open + dl_list_len(&hapd->sae_commit_queue) >=
+ hapd->conf->sae_anti_clogging_threshold)
+ return 1;
+
return 0;
}
+static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+{
+ u8 hash[SHA256_MAC_LEN];
+
+ hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, hash);
+ return hash[0];
+}
+
+
static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
const u8 *token, size_t token_len)
{
u8 mac[SHA256_MAC_LEN];
+ const u8 *addrs[2];
+ size_t len[2];
+ u16 token_idx;
+ u8 idx;
if (token_len != SHA256_MAC_LEN)
return -1;
- if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
- addr, ETH_ALEN, mac) < 0 ||
- os_memcmp_const(token, mac, SHA256_MAC_LEN) != 0)
+ idx = sae_token_hash(hapd, addr);
+ token_idx = hapd->sae_pending_token_idx[idx];
+ if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
+ MACSTR " - token_idx 0x%04x, expected 0x%04x",
+ MAC2STR(addr), WPA_GET_BE16(token), token_idx);
return -1;
+ }
+
+ addrs[0] = addr;
+ len[0] = ETH_ALEN;
+ addrs[1] = token;
+ len[1] = 2;
+ if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ 2, addrs, len, mac) < 0 ||
+ os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
+ return -1;
+
+ hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
return 0;
}
@@ -449,16 +584,25 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
struct wpabuf *buf;
u8 *token;
struct os_reltime now;
+ u8 idx[2];
+ const u8 *addrs[2];
+ size_t len[2];
+ u8 p_idx;
+ u16 token_idx;
os_get_reltime(&now);
if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
- os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
+ os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) ||
+ hapd->sae_token_idx == 0xffff) {
if (random_get_bytes(hapd->sae_token_key,
sizeof(hapd->sae_token_key)) < 0)
return NULL;
wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
hapd->sae_token_key, sizeof(hapd->sae_token_key));
hapd->last_sae_token_key_update = now;
+ hapd->sae_token_idx = 0;
+ os_memset(hapd->sae_pending_token_idx, 0,
+ sizeof(hapd->sae_pending_token_idx));
}
buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
@@ -467,18 +611,34 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
+ p_idx = sae_token_hash(hapd, addr);
+ token_idx = hapd->sae_pending_token_idx[p_idx];
+ if (!token_idx) {
+ hapd->sae_token_idx++;
+ token_idx = hapd->sae_token_idx;
+ hapd->sae_pending_token_idx[p_idx] = token_idx;
+ }
+ WPA_PUT_BE16(idx, token_idx);
token = wpabuf_put(buf, SHA256_MAC_LEN);
- hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
- addr, ETH_ALEN, token);
+ addrs[0] = addr;
+ len[0] = ETH_ALEN;
+ addrs[1] = idx;
+ len[1] = sizeof(idx);
+ if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ 2, addrs, len, token) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ WPA_PUT_BE16(token, token_idx);
return buf;
}
-static int sae_check_big_sync(struct sta_info *sta)
+static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
{
- if (sta->sae->sync > dot11RSNASAESync) {
- sta->sae->state = SAE_NOTHING;
+ if (sta->sae->sync > hapd->conf->sae_sync) {
+ sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
sta->sae->sync = 0;
return -1;
}
@@ -492,9 +652,13 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
struct sta_info *sta = eloop_data;
int ret;
- if (sae_check_big_sync(sta))
+ if (sae_check_big_sync(hapd, sta))
return;
sta->sae->sync++;
+ wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
+ " (sync=%d state=%s)",
+ MAC2STR(sta->addr), sta->sae->sync,
+ sae_state_txt(sta->sae->state));
switch (sta->sae->state) {
case SAE_COMMITTED:
@@ -537,21 +701,85 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
}
+static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status)
+{
+ struct external_auth params;
+
+ os_memset(&params, 0, sizeof(params));
+ params.status = status;
+ params.bssid = sta->addr;
+ if (status == WLAN_STATUS_SUCCESS && sta->sae)
+ params.pmkid = sta->sae->pmkid;
+
+ hostapd_drv_send_external_auth_status(hapd, &params);
+}
+
+
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+#ifndef CONFIG_NO_VLAN
+ struct vlan_description vlan_desc;
+
+ if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
+ " to VLAN ID %d",
+ MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = 1;
+ vlan_desc.untagged = sta->sae->tmp->vlan_id;
+ if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ wpa_printf(MSG_INFO,
+ "Invalid VLAN ID %d in sae_password",
+ sta->sae->tmp->vlan_id);
+ return;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
+ ap_sta_bind_vlan(hapd, sta) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to assign VLAN ID %d from sae_password to "
+ MACSTR, sta->sae->tmp->vlan_id,
+ MAC2STR(sta->addr));
+ return;
+ }
+ }
+#endif /* CONFIG_NO_VLAN */
+
+ sta->flags |= WLAN_STA_AUTH;
+ sta->auth_alg = WLAN_AUTH_SAE;
+ mlme_authenticate_indication(hapd, sta);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ sta->sae->pmk, sta->sae->pmkid);
+ sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
+}
+
+
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *bssid, u8 auth_transaction)
+ const u8 *bssid, u8 auth_transaction, int allow_reuse,
+ int *sta_removed)
{
int ret;
+ *sta_removed = 0;
+
if (auth_transaction != 1 && auth_transaction != 2)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
+ MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
+ auth_transaction);
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid,
+ !allow_reuse);
if (ret)
return ret;
- sta->sae->state = SAE_COMMITTED;
+ sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
if (sae_process_commit(sta->sae) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -573,14 +801,15 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
ret = auth_sae_send_confirm(hapd, sta, bssid);
if (ret)
return ret;
- sta->sae->state = SAE_CONFIRMED;
+ sae_set_state(sta, SAE_CONFIRMED,
+ "Sent Confirm (mesh)");
} else {
/*
* For infrastructure BSS, send only the Commit
* message now to get alternating sequence of
* Authentication frames between the AP and STA.
* Confirm will be sent in
- * Commited -> Confirmed/Accepted transition
+ * Committed -> Confirmed/Accepted transition
* when receiving Confirm from STA.
*/
}
@@ -602,7 +831,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
ret = auth_sae_send_confirm(hapd, sta, bssid);
if (ret)
return ret;
- sta->sae->state = SAE_CONFIRMED;
+ sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
sta->sae->sync = 0;
sae_set_retransmit_timer(hapd, sta);
} else if (hapd->conf->mesh & MESH_ENABLED) {
@@ -610,7 +839,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
* In mesh case, follow SAE finite state machine and
* send Commit now, if sync count allows.
*/
- if (sae_check_big_sync(sta))
+ if (sae_check_big_sync(hapd, sta))
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
@@ -629,20 +858,21 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
if (ret)
return ret;
- sta->sae->state = SAE_CONFIRMED;
+ sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
/*
* Since this was triggered on Confirm RX, run another
* step to get to Accepted without waiting for
* additional events.
*/
- return sae_sm_step(hapd, sta, bssid, auth_transaction);
+ return sae_sm_step(hapd, sta, bssid, auth_transaction,
+ 0, sta_removed);
}
break;
case SAE_CONFIRMED:
sae_clear_retransmit_timer(hapd, sta);
if (auth_transaction == 1) {
- if (sae_check_big_sync(sta))
+ if (sae_check_big_sync(hapd, sta))
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
@@ -659,23 +889,32 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
sae_set_retransmit_timer(hapd, sta);
} else {
- sta->flags |= WLAN_STA_AUTH;
- sta->auth_alg = WLAN_AUTH_SAE;
- mlme_authenticate_indication(hapd, sta);
- wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->sae->state = SAE_ACCEPTED;
- wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
- sta->sae->pmk);
+ sta->sae->send_confirm = 0xffff;
+ sae_accept_sta(hapd, sta);
}
break;
case SAE_ACCEPTED:
- if (auth_transaction == 1) {
+ if (auth_transaction == 1 &&
+ (hapd->conf->mesh & MESH_ENABLED)) {
wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
") doing reauthentication",
MAC2STR(sta->addr));
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
ap_free_sta(hapd, sta);
+ *sta_removed = 1;
+ } else if (auth_transaction == 1) {
+ wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+ sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
+
+ if (sae_process_commit(sta->sae) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
} else {
- if (sae_check_big_sync(sta))
+ if (sae_check_big_sync(hapd, sta))
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
@@ -694,26 +933,109 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
}
+static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct sae_data *sae = sta->sae;
+ int i, *groups = hapd->conf->sae_groups;
+ int default_groups[] = { 19, 0 };
+
+ if (sae->state != SAE_COMMITTED)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
+
+ if (!groups)
+ groups = default_groups;
+ for (i = 0; groups[i] > 0; i++) {
+ if (sae->group == groups[i])
+ break;
+ }
+
+ if (groups[i] <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Previously selected group not found from the current configuration");
+ return;
+ }
+
+ for (;;) {
+ i++;
+ if (groups[i] <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No alternative group enabled");
+ return;
+ }
+
+ if (sae_set_group(sae, groups[i]) < 0)
+ continue;
+
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 auth_transaction, u16 status_code)
{
- u16 resp = WLAN_STATUS_SUCCESS;
+ int resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
+ int *groups = hapd->conf->sae_groups;
+ int default_groups[] = { 19, 0 };
+ const u8 *pos, *end;
+ int sta_removed = 0;
+ if (!groups)
+ groups = default_groups;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
+ wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
+ pos = mgmt->u.auth.variable;
+ end = ((const u8 *) mgmt) + len;
+ send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ auth_transaction, resp, pos, end - pos,
+ "auth-sae-reflection-attack");
+ goto remove_sta;
+ }
+
+ if (hapd->conf->sae_commit_override && auth_transaction == 1) {
+ wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
+ send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ auth_transaction, resp,
+ wpabuf_head(hapd->conf->sae_commit_override),
+ wpabuf_len(hapd->conf->sae_commit_override),
+ "sae-commit-override");
+ goto remove_sta;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (!sta->sae) {
- if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
- return;
+ if (auth_transaction != 1 ||
+ status_code != WLAN_STATUS_SUCCESS) {
+ resp = -1;
+ goto remove_sta;
+ }
sta->sae = os_zalloc(sizeof(*sta->sae));
- if (sta->sae == NULL)
- return;
- sta->sae->state = SAE_NOTHING;
+ if (!sta->sae) {
+ resp = -1;
+ goto remove_sta;
+ }
+ sae_set_state(sta, SAE_NOTHING, "Init");
sta->sae->sync = 0;
}
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ sta->mesh_sae_pmksa_caching = 0;
+ }
+
if (auth_transaction == 1) {
- const u8 *token = NULL, *pos, *end;
+ const u8 *token = NULL;
size_t token_len = 0;
+ int allow_reuse = 0;
+
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"start SAE authentication (RX commit, status=%u)",
@@ -730,8 +1052,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
- resp = sae_group_allowed(sta->sae,
- hapd->conf->sae_groups,
+ resp = sae_group_allowed(sta->sae, groups,
WPA_GET_LE16(pos));
if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
@@ -746,7 +1067,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->sae->tmp->anti_clogging_token == NULL) {
wpa_printf(MSG_ERROR,
"SAE: Failed to alloc for anti-clogging token");
- return;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto remove_sta;
}
/*
@@ -756,42 +1078,93 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- if (auth_sae_send_commit(hapd, sta, mgmt->bssid, 0)) {
+ resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+ if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SAE: Failed to send commit message");
- return;
+ goto remove_sta;
}
- sta->sae->state = SAE_COMMITTED;
+ sae_set_state(sta, SAE_COMMITTED,
+ "Sent Commit (anti-clogging token case in mesh)");
sta->sae->sync = 0;
sae_set_retransmit_timer(hapd, sta);
return;
}
+ if ((hapd->conf->mesh & MESH_ENABLED) &&
+ status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ sta->sae->tmp) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Peer did not accept our SAE group");
+ sae_pick_next_group(hapd, sta);
+ goto remove_sta;
+ }
+
if (status_code != WLAN_STATUS_SUCCESS)
- return;
+ goto remove_sta;
+
+ if (!(hapd->conf->mesh & MESH_ENABLED) &&
+ sta->sae->state == SAE_COMMITTED) {
+ /* This is needed in the infrastructure BSS case to
+ * address a sequence where a STA entry may remain in
+ * hostapd across two attempts to do SAE authentication
+ * by the same STA. The second attempt may end up trying
+ * to use a different group and that would not be
+ * allowed if we remain in Committed state with the
+ * previously set parameters. */
+ pos = mgmt->u.auth.variable;
+ end = ((const u8 *) mgmt) + len;
+ if (end - pos >= (int) sizeof(le16) &&
+ sae_group_allowed(sta->sae, groups,
+ WPA_GET_LE16(pos)) ==
+ WLAN_STATUS_SUCCESS) {
+ /* Do not waste resources deriving the same PWE
+ * again since the same group is reused. */
+ sae_set_state(sta, SAE_NOTHING,
+ "Allow previous PWE to be reused");
+ allow_reuse = 1;
+ } else {
+ sae_set_state(sta, SAE_NOTHING,
+ "Clear existing state to allow restart");
+ sae_clear_data(sta->sae);
+ }
+ }
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
- &token_len, hapd->conf->sae_groups);
+ &token_len, groups);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
MAC2STR(sta->addr));
- return;
+ goto remove_sta;
+ }
+
+ if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
+ MACSTR, MAC2STR(sta->addr));
+ sae_clear_retransmit_timer(hapd, sta);
+ sae_set_state(sta, SAE_NOTHING,
+ "Unknown Password Identifier");
+ goto remove_sta;
}
+
if (token && check_sae_token(hapd, sta->addr, token, token_len)
< 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
"incorrect token from " MACSTR,
MAC2STR(sta->addr));
- return;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto remove_sta;
}
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
- if (!token && use_sae_anti_clogging(hapd)) {
+ if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
wpa_printf(MSG_DEBUG,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
@@ -799,44 +1172,89 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
sta->addr);
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
if (hapd->conf->mesh & MESH_ENABLED)
- sta->sae->state = SAE_NOTHING;
+ sae_set_state(sta, SAE_NOTHING,
+ "Request anti-clogging token case in mesh");
goto reply;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+ allow_reuse, &sta_removed);
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"SAE authentication (RX confirm, status=%u)",
status_code);
if (status_code != WLAN_STATUS_SUCCESS)
- return;
+ goto remove_sta;
if (sta->sae->state >= SAE_CONFIRMED ||
!(hapd->conf->mesh & MESH_ENABLED)) {
- if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
- ((u8 *) mgmt) + len -
- mgmt->u.auth.variable) < 0) {
+ const u8 *var;
+ size_t var_len;
+ u16 peer_send_confirm;
+
+ var = mgmt->u.auth.variable;
+ var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
+ if (var_len < 2) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
+
+ peer_send_confirm = WPA_GET_LE16(var);
+
+ if (sta->sae->state == SAE_ACCEPTED &&
+ (peer_send_confirm <= sta->sae->rc ||
+ peer_send_confirm == 0xffff)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Silently ignore unexpected Confirm from peer "
+ MACSTR
+ " (peer-send-confirm=%u Rc=%u)",
+ MAC2STR(sta->addr),
+ peer_send_confirm, sta->sae->rc);
+ return;
+ }
+
+ if (sae_check_confirm(sta->sae, var, var_len) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
+ sta->sae->rc = peer_send_confirm;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
+ &sta_removed);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"unexpected SAE authentication transaction %u (status=%u)",
auth_transaction, status_code);
if (status_code != WLAN_STATUS_SUCCESS)
- return;
+ goto remove_sta;
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
}
reply:
- if (resp != WLAN_STATUS_SUCCESS) {
+ if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
+ pos = mgmt->u.auth.variable;
+ end = ((const u8 *) mgmt) + len;
+
+ /* Copy the Finite Cyclic Group field from the request if we
+ * rejected it as unsupported group. */
+ if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ !data && end - pos >= 2)
+ data = wpabuf_alloc_copy(pos, 2);
+
+ sae_sme_send_external_auth_status(hapd, sta, resp);
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
- data ? wpabuf_len(data) : 0);
+ data ? wpabuf_len(data) : 0, "auth-sae");
+ }
+
+remove_sta:
+ if (!sta_removed && sta->added_unassoc &&
+ (resp != WLAN_STATUS_SUCCESS ||
+ status_code != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
}
wpabuf_free(data);
}
@@ -866,27 +1284,756 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
if (ret)
return -1;
- sta->sae->state = SAE_COMMITTED;
+ sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
sta->sae->sync = 0;
sae_set_retransmit_timer(hapd, sta);
return 0;
}
+
+void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct hostapd_sae_commit_queue *q;
+ unsigned int queue_len;
+
+ q = dl_list_first(&hapd->sae_commit_queue,
+ struct hostapd_sae_commit_queue, list);
+ if (!q)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "SAE: Process next available message from queue");
+ dl_list_del(&q->list);
+ handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
+ q->rssi, 1);
+ os_free(q);
+
+ if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
+ return;
+ queue_len = dl_list_len(&hapd->sae_commit_queue);
+ eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
+ hapd, NULL);
+}
+
+
+static void auth_sae_queue(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int rssi)
+{
+ struct hostapd_sae_commit_queue *q, *q2;
+ unsigned int queue_len;
+ const struct ieee80211_mgmt *mgmt2;
+
+ queue_len = dl_list_len(&hapd->sae_commit_queue);
+ if (queue_len >= 15) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No more room in message queue - drop the new frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
+ MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
+ queue_len);
+ q = os_zalloc(sizeof(*q) + len);
+ if (!q)
+ return;
+ q->rssi = rssi;
+ q->len = len;
+ os_memcpy(q->msg, mgmt, len);
+
+ /* Check whether there is already a queued Authentication frame from the
+ * same station with the same transaction number and if so, replace that
+ * queue entry with the new one. This avoids issues with a peer that
+ * sends multiple times (e.g., due to frequent SAE retries). There is no
+ * point in us trying to process the old attempts after a new one has
+ * obsoleted them. */
+ dl_list_for_each(q2, &hapd->sae_commit_queue,
+ struct hostapd_sae_commit_queue, list) {
+ mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
+ if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
+ mgmt->u.auth.auth_transaction ==
+ mgmt2->u.auth.auth_transaction) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Replace queued message from same STA with same transaction number");
+ dl_list_add(&q2->list, &q->list);
+ dl_list_del(&q2->list);
+ os_free(q2);
+ goto queued;
+ }
+ }
+
+ /* No pending identical entry, so add to the end of the queue */
+ dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
+
+queued:
+ if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
+ return;
+ eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
+ hapd, NULL);
+}
+
+
+static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct hostapd_sae_commit_queue *q;
+ const struct ieee80211_mgmt *mgmt;
+
+ dl_list_for_each(q, &hapd->sae_commit_queue,
+ struct hostapd_sae_commit_queue, list) {
+ mgmt = (const struct ieee80211_mgmt *) q->msg;
+ if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_SAE */
+static u16 wpa_res_to_status_code(int res)
+{
+ if (res == WPA_INVALID_GROUP)
+ return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ if (res == WPA_INVALID_PAIRWISE)
+ return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ if (res == WPA_INVALID_AKMP)
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ if (res == WPA_ALLOC_FAIL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+#ifdef CONFIG_IEEE80211W
+ if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+ return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+ if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+ return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+#endif /* CONFIG_IEEE80211W */
+ if (res == WPA_INVALID_MDIE)
+ return WLAN_STATUS_INVALID_MDIE;
+ if (res == WPA_INVALID_PMKID)
+ return WLAN_STATUS_INVALID_PMKID;
+ if (res != WPA_IE_OK)
+ return WLAN_STATUS_INVALID_IE;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+#ifdef CONFIG_FILS
+
+static void handle_auth_fils_finish(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 resp,
+ struct wpabuf *data, int pub);
+
+void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, size_t len, u16 auth_alg,
+ u16 auth_transaction, u16 status_code,
+ void (*cb)(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 resp,
+ struct wpabuf *data, int pub))
+{
+ u16 resp = WLAN_STATUS_SUCCESS;
+ const u8 *end;
+ struct ieee802_11_elems elems;
+ int res;
+ struct wpa_ie_data rsn;
+ struct rsn_pmksa_cache_entry *pmksa = NULL;
+
+ if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
+ return;
+
+ end = pos + len;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
+ pos, end - pos);
+
+ /* TODO: FILS PK */
+#ifdef CONFIG_FILS_SK_PFS
+ if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
+ u16 group;
+ struct wpabuf *pub;
+ size_t elem_len;
+
+ /* Using FILS PFS */
+
+ /* Finite Cyclic Group */
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No room for Finite Cyclic Group");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ if (group != hapd->conf->fils_dh_group) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
+ group, hapd->conf->fils_dh_group);
+ resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ goto fail;
+ }
+
+ crypto_ecdh_deinit(sta->fils_ecdh);
+ sta->fils_ecdh = crypto_ecdh_init(group);
+ if (!sta->fils_ecdh) {
+ wpa_printf(MSG_INFO,
+ "FILS: Could not initialize ECDH with group %d",
+ group);
+ resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ goto fail;
+ }
+
+ pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
+ if (!pub) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to derive ECDH public key");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ elem_len = wpabuf_len(pub);
+ wpabuf_free(pub);
+
+ /* Element */
+ if ((size_t) (end - pos) < elem_len) {
+ wpa_printf(MSG_DEBUG, "FILS: No room for Element");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ wpabuf_free(sta->fils_g_sta);
+ sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len);
+ wpabuf_clear_free(sta->fils_dh_ss);
+ sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
+ pos, elem_len);
+ if (!sta->fils_dh_ss) {
+ wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
+ pos += elem_len;
+ } else {
+ crypto_ecdh_deinit(sta->fils_ecdh);
+ sta->fils_ecdh = NULL;
+ wpabuf_clear_free(sta->fils_dh_ss);
+ sta->fils_dh_ss = NULL;
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
+ if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ /* RSNE */
+ wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
+ elems.rsn_ie, elems.rsn_ie_len);
+ if (!elems.rsn_ie ||
+ wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
+ NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to initialize RSN state machine");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq,
+ elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ elems.mdie, elems.mdie_len, NULL, 0);
+ resp = wpa_res_to_status_code(res);
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ if (!elems.fils_nonce) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
+ FILS_NONCE_LEN);
+ os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+ /* PMKID List */
+ if (rsn.pmkid && rsn.num_pmkid > 0) {
+ u8 num;
+ const u8 *pmkid;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
+ rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
+
+ pmkid = rsn.pmkid;
+ num = rsn.num_pmkid;
+ while (num) {
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
+ pmkid);
+ if (pmksa)
+ break;
+ pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth,
+ sta->addr,
+ pmkid);
+ if (pmksa)
+ break;
+ pmkid += PMKID_LEN;
+ num--;
+ }
+ }
+ if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
+ wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
+ pmksa = NULL;
+ }
+ if (pmksa)
+ wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
+
+ /* FILS Session */
+ if (!elems.fils_session) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
+ FILS_SESSION_LEN);
+ os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
+
+ /* FILS Wrapped Data */
+ if (elems.fils_wrapped_data) {
+ wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
+ elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len);
+ if (!pmksa) {
+#ifndef CONFIG_NO_RADIUS
+ if (!sta->eapol_sm) {
+ sta->eapol_sm =
+ ieee802_1x_alloc_eapol_sm(hapd, sta);
+ }
+ wpa_printf(MSG_DEBUG,
+ "FILS: Forward EAP-Initiate/Re-auth to authentication server");
+ ieee802_1x_encapsulate_radius(
+ hapd, sta, elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len);
+ sta->fils_pending_cb = cb;
+ wpa_printf(MSG_DEBUG,
+ "FILS: Will send Authentication frame once the response from authentication server is available");
+ sta->flags |= WLAN_STA_PENDING_FILS_ERP;
+ /* Calculate pending PMKID here so that we do not need
+ * to maintain a copy of the EAP-Initiate/Reauth
+ * message. */
+ if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
+ elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len,
+ sta->fils_erp_pmkid) == 0)
+ sta->fils_erp_pmkid_set = 1;
+ return;
+#else /* CONFIG_NO_RADIUS */
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+#endif /* CONFIG_NO_RADIUS */
+ }
+ }
+
+fail:
+ if (cb) {
+ struct wpabuf *data;
+ int pub = 0;
+
+ data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL,
+ NULL, 0, &pub);
+ if (!data) {
+ wpa_printf(MSG_DEBUG,
+ "%s: prepare_auth_resp_fils() returned failure",
+ __func__);
+ }
+
+ cb(hapd, sta, resp, data, pub);
+ }
+}
+
+
+static struct wpabuf *
+prepare_auth_resp_fils(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 *resp,
+ struct rsn_pmksa_cache_entry *pmksa,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len,
+ int *is_pub)
+{
+ u8 fils_nonce[FILS_NONCE_LEN];
+ size_t ielen;
+ struct wpabuf *data = NULL;
+ const u8 *ie;
+ u8 *ie_buf = NULL;
+ const u8 *pmk = NULL;
+ size_t pmk_len = 0;
+ u8 pmk_buf[PMK_LEN_MAX];
+ struct wpabuf *pub = NULL;
+
+ if (*resp != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
+ if (!ie) {
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (pmksa) {
+ /* Add PMKID of the selected PMKSA into RSNE */
+ ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
+ if (!ie_buf) {
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ os_memcpy(ie_buf, ie, ielen);
+ if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ ie = ie_buf;
+ }
+
+ if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
+ fils_nonce, FILS_NONCE_LEN);
+
+#ifdef CONFIG_FILS_SK_PFS
+ if (sta->fils_dh_ss && sta->fils_ecdh) {
+ pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
+ if (!pub) {
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
+ if (!data) {
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ /* TODO: FILS PK */
+#ifdef CONFIG_FILS_SK_PFS
+ if (pub) {
+ /* Finite Cyclic Group */
+ wpabuf_put_le16(data, hapd->conf->fils_dh_group);
+
+ /* Element */
+ wpabuf_put_buf(data, pub);
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ /* RSNE */
+ wpabuf_put_data(data, ie, ielen);
+
+ /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */
+
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
+ /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
+ int res;
+ int use_sha384 = wpa_key_mgmt_sha384(
+ wpa_auth_sta_key_mgmt(sta->wpa_sm));
+
+ res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384,
+ wpabuf_put(data, 0),
+ wpabuf_tailroom(data));
+ if (res < 0) {
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpabuf_put(data, res);
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+
+ /* FILS Nonce */
+ wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
+
+ /* FILS Wrapped Data */
+ if (!pmksa && erp_resp) {
+ wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_buf(data, erp_resp);
+
+ if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
+ msk, msk_len, sta->fils_snonce, fils_nonce,
+ sta->fils_dh_ss ?
+ wpabuf_head(sta->fils_dh_ss) : NULL,
+ sta->fils_dh_ss ?
+ wpabuf_len(sta->fils_dh_ss) : 0,
+ pmk_buf, &pmk_len)) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(data);
+ data = NULL;
+ goto fail;
+ }
+ pmk = pmk_buf;
+
+ /* Don't use DHss in PTK derivation if PMKSA caching is not
+ * used. */
+ wpabuf_clear_free(sta->fils_dh_ss);
+ sta->fils_dh_ss = NULL;
+
+ if (sta->fils_erp_pmkid_set) {
+ /* TODO: get PMKLifetime from WPA parameters */
+ unsigned int dot11RSNAConfigPMKLifetime = 43200;
+ int session_timeout;
+
+ session_timeout = dot11RSNAConfigPMKLifetime;
+ if (sta->session_timeout_set) {
+ struct os_reltime now, diff;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&sta->session_timeout, &now,
+ &diff);
+ session_timeout = diff.sec;
+ }
+
+ sta->fils_erp_pmkid_set = 0;
+ wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
+ sta->fils_erp_pmkid);
+ if (!hapd->conf->disable_pmksa_caching &&
+ wpa_auth_pmksa_add2(
+ hapd->wpa_auth, sta->addr,
+ pmk, pmk_len,
+ sta->fils_erp_pmkid,
+ session_timeout,
+ wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Failed to add PMKSA cache entry based on ERP");
+ }
+ }
+ } else if (pmksa) {
+ pmk = pmksa->pmk;
+ pmk_len = pmksa->pmk_len;
+ }
+
+ if (!pmk) {
+ wpa_printf(MSG_DEBUG, "FILS: No PMK available");
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(data);
+ data = NULL;
+ goto fail;
+ }
+
+ if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
+ sta->fils_snonce, fils_nonce,
+ sta->fils_dh_ss ?
+ wpabuf_head(sta->fils_dh_ss) : NULL,
+ sta->fils_dh_ss ?
+ wpabuf_len(sta->fils_dh_ss) : 0,
+ sta->fils_g_sta, pub) < 0) {
+ *resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(data);
+ data = NULL;
+ goto fail;
+ }
+
+fail:
+ if (is_pub)
+ *is_pub = pub != NULL;
+ os_free(ie_buf);
+ wpabuf_free(pub);
+ wpabuf_clear_free(sta->fils_dh_ss);
+ sta->fils_dh_ss = NULL;
+#ifdef CONFIG_FILS_SK_PFS
+ crypto_ecdh_deinit(sta->fils_ecdh);
+ sta->fils_ecdh = NULL;
+#endif /* CONFIG_FILS_SK_PFS */
+ return data;
+}
+
+
+static void handle_auth_fils_finish(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 resp,
+ struct wpabuf *data, int pub)
+{
+ u16 auth_alg;
+
+ auth_alg = (pub ||
+ resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
+ WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
+ send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
+ data ? wpabuf_head(data) : (u8 *) "",
+ data ? wpabuf_len(data) : 0, "auth-fils-finish");
+ wpabuf_free(data);
+
+ if (resp == WLAN_STATUS_SUCCESS) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "authentication OK (FILS)");
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
+ mlme_authenticate_indication(hapd, sta);
+ }
+}
+
+
+void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
+ struct sta_info *sta, int success,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len)
+{
+ struct wpabuf *data;
+ int pub = 0;
+ u16 resp;
+
+ sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+
+ if (!sta->fils_pending_cb)
+ return;
+ resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
+ data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
+ msk, msk_len, &pub);
+ if (!data) {
+ wpa_printf(MSG_DEBUG,
+ "%s: prepare_auth_resp_fils() returned failure",
+ __func__);
+ }
+ sta->fils_pending_cb(hapd, sta, resp, data, pub);
+}
+
+#endif /* CONFIG_FILS */
+
+
+int
+ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len, u32 *session_timeout,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui, int is_probe_req)
+{
+ int res;
+
+ os_memset(vlan_id, 0, sizeof(*vlan_id));
+ res = hostapd_allowed_address(hapd, addr, msg, len,
+ session_timeout, acct_interim_interval,
+ vlan_id, psk, identity, radius_cui,
+ is_probe_req);
+
+ if (res == HOSTAPD_ACL_REJECT) {
+ if (!is_probe_req)
+ wpa_printf(MSG_DEBUG,
+ "Station " MACSTR
+ " not allowed to authenticate",
+ MAC2STR(addr));
+ return HOSTAPD_ACL_REJECT;
+ }
+
+ if (res == HOSTAPD_ACL_PENDING) {
+ wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
+ " waiting for an external authentication",
+ MAC2STR(addr));
+ /* Authentication code will re-send the authentication frame
+ * after it has received (and cached) information from the
+ * external source. */
+ return HOSTAPD_ACL_PENDING;
+ }
+
+ return res;
+}
+
+
+static int
+ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+ int res, u32 session_timeout,
+ u32 acct_interim_interval,
+ struct vlan_description *vlan_id,
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
+{
+ if (vlan_id->notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from RADIUS server",
+ vlan_id->untagged,
+ vlan_id->tagged[0] ? "+" : "");
+ return -1;
+ }
+ if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
+ return -1;
+ if (sta->vlan_id)
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+
+ hostapd_free_psk_list(sta->psk);
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+ sta->psk = *psk;
+ *psk = NULL;
+ } else {
+ sta->psk = NULL;
+ }
+
+ os_free(sta->identity);
+ sta->identity = *identity;
+ *identity = NULL;
+
+ os_free(sta->radius_cui);
+ sta->radius_cui = *radius_cui;
+ *radius_cui = NULL;
+
+ if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
+ sta->acct_interim_interval = acct_interim_interval;
+ if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
+ sta->session_timeout_set = 1;
+ os_get_reltime(&sta->session_timeout);
+ sta->session_timeout.sec += session_timeout;
+ ap_sta_session_timeout(hapd, sta, session_timeout);
+ } else {
+ sta->session_timeout_set = 0;
+ ap_sta_no_session_timeout(hapd, sta);
+ }
+
+ return 0;
+}
+
+
static void handle_auth(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int rssi, int from_queue)
{
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
struct sta_info *sta = NULL;
- int res;
+ int res, reply_res;
u16 fc;
const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval;
- int vlan_id = 0;
+ struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
@@ -924,11 +2071,12 @@ static void handle_auth(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
"auth_transaction=%d status_code=%d wep=%d%s "
- "seq_ctrl=0x%x%s",
+ "seq_ctrl=0x%x%s%s",
MAC2STR(mgmt->sa), auth_alg, auth_transaction,
status_code, !!(fc & WLAN_FC_ISWEP),
challenge ? " challenge" : "",
- seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
+ seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
+ from_queue ? " (from queue)" : "");
#ifdef CONFIG_NO_RC4
if (auth_alg == WLAN_AUTH_SHARED_KEY) {
@@ -941,20 +2089,29 @@ static void handle_auth(struct hostapd_data *hapd,
#endif /* CONFIG_NO_RC4 */
if (hapd->tkip_countermeasures) {
- resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+ wpa_printf(MSG_DEBUG,
+ "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
auth_alg == WLAN_AUTH_OPEN) ||
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
(hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
auth_alg == WLAN_AUTH_FT) ||
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
(hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
auth_alg == WLAN_AUTH_SAE) ||
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
+ auth_alg == WLAN_AUTH_FILS_SK) ||
+ (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
+ hapd->conf->fils_dh_group &&
+ auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
+#endif /* CONFIG_FILS */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
@@ -1033,29 +2190,40 @@ static void handle_auth(struct hostapd_data *hapd,
}
}
- res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
- &session_timeout,
- &acct_interim_interval, &vlan_id,
- &psk, &identity, &radius_cui);
-
+ res = ieee802_11_allowed_address(
+ hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
+ &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
+ 0);
if (res == HOSTAPD_ACL_REJECT) {
- wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
- MAC2STR(mgmt->sa));
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Ignore Authentication frame from " MACSTR
+ " due to ACL reject", MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- if (res == HOSTAPD_ACL_PENDING) {
- wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
- " waiting for an external authentication",
- MAC2STR(mgmt->sa));
- /* Authentication code will re-send the authentication frame
- * after it has received (and cached) information from the
- * external source. */
+ if (res == HOSTAPD_ACL_PENDING)
+ return;
+
+#ifdef CONFIG_SAE
+ if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
+ (auth_transaction == 1 ||
+ (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
+ /* Handle SAE Authentication commit message through a queue to
+ * provide more control for postponing the needed heavy
+ * processing under a possible DoS attack scenario. In addition,
+ * queue SAE Authentication confirm message if there happens to
+ * be a queued commit message from the same peer. This is needed
+ * to avoid reordering Authentication frames within the same
+ * SAE exchange. */
+ auth_sae_queue(hapd, mgmt, len, rssi);
return;
}
+#endif /* CONFIG_SAE */
sta = ap_get_sta(hapd, mgmt->sa);
if (sta) {
+ sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+ sta->ft_over_ds = 0;
if ((fc & WLAN_FC_RETRY) &&
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
sta->last_seq_ctrl == seq_ctrl &&
@@ -1067,13 +2235,22 @@ static void handle_auth(struct hostapd_data *hapd,
seq_ctrl);
return;
}
+#ifdef CONFIG_MESH
+ if ((hapd->conf->mesh & MESH_ENABLED) &&
+ sta->plink_state == PLINK_BLOCKED) {
+ wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
+ " is blocked - drop Authentication frame",
+ MAC2STR(mgmt->sa));
+ return;
+ }
+#endif /* CONFIG_MESH */
} else {
#ifdef CONFIG_MESH
if (hapd->conf->mesh & MESH_ENABLED) {
/* if the mesh peer is not available, we don't do auth.
*/
wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
- " not yet known - drop Authentiation frame",
+ " not yet known - drop Authentication frame",
MAC2STR(mgmt->sa));
/*
* Save a copy of the frame so that it can be processed
@@ -1088,49 +2265,76 @@ static void handle_auth(struct hostapd_data *hapd,
sta = ap_sta_add(hapd, mgmt->sa);
if (!sta) {
+ wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
}
sta->last_seq_ctrl = seq_ctrl;
sta->last_subtype = WLAN_FC_STYPE_AUTH;
-
- if (vlan_id > 0) {
- if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
- "%d received from RADIUS server",
- vlan_id);
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- sta->vlan_id = vlan_id;
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
- }
-
- hostapd_free_psk_list(sta->psk);
- if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- sta->psk = psk;
- psk = NULL;
- } else {
- sta->psk = NULL;
+#ifdef CONFIG_MBO
+ sta->auth_rssi = rssi;
+#endif /* CONFIG_MBO */
+
+ res = ieee802_11_set_radius_info(
+ hapd, sta, res, session_timeout, acct_interim_interval,
+ &vlan_id, &psk, &identity, &radius_cui);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
}
- sta->identity = identity;
- identity = NULL;
- sta->radius_cui = radius_cui;
- radius_cui = NULL;
-
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
- if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
- sta->acct_interim_interval = acct_interim_interval;
- if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- ap_sta_session_timeout(hapd, sta, session_timeout);
- else
- ap_sta_no_session_timeout(hapd, sta);
+ /*
+ * If the driver supports full AP client state, add a station to the
+ * driver before sending authentication reply to make sure the driver
+ * has resources, and not to go through the entire authentication and
+ * association handshake, and fail it at the end.
+ *
+ * If this is not the first transaction, in a multi-step authentication
+ * algorithm, the station already exists in the driver
+ * (sta->added_unassoc = 1) so skip it.
+ *
+ * In mesh mode, the station was already added to the driver when the
+ * NEW_PEER_CANDIDATE event is received.
+ *
+ * If PMF was negotiated for the existing association, skip this to
+ * avoid dropping the STA entry and the associated keys. This is needed
+ * to allow the original connection work until the attempt can complete
+ * (re)association, so that unprotected Authentication frame cannot be
+ * used to bypass PMF protection.
+ */
+ if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+ (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
+ !(hapd->conf->mesh & MESH_ENABLED) &&
+ !(sta->added_unassoc)) {
+ /*
+ * If a station that is already associated to the AP, is trying
+ * to authenticate again, remove the STA entry, in order to make
+ * sure the STA PS state gets cleared and configuration gets
+ * updated. To handle this, station's added_unassoc flag is
+ * cleared once the station has completed association.
+ */
+ ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
+ WLAN_STA_AUTHORIZED);
+
+ if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
+ NULL, NULL, sta->flags, 0, 0, 0, 0)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_NOTICE,
+ "Could not add STA to kernel driver");
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+
+ sta->added_unassoc = 1;
+ }
switch (auth_alg) {
case WLAN_AUTH_OPEN:
@@ -1146,6 +2350,9 @@ static void handle_auth(struct hostapd_data *hapd,
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
fc & WLAN_FC_ISWEP);
+ if (resp != 0)
+ wpa_printf(MSG_DEBUG,
+ "auth_shared_key() failed: status=%d", resp);
sta->auth_alg = WLAN_AUTH_SHARED_KEY;
mlme_authenticate_indication(hapd, sta);
if (sta->challenge && auth_transaction == 1) {
@@ -1157,7 +2364,7 @@ static void handle_auth(struct hostapd_data *hapd,
}
break;
#endif /* CONFIG_NO_RC4 */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT;
if (sta->wpa_sm == NULL)
@@ -1176,7 +2383,7 @@ static void handle_auth(struct hostapd_data *hapd,
handle_auth_ft_finish, hapd);
/* handle_auth_ft_finish() callback will complete auth. */
return;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
case WLAN_AUTH_SAE:
#ifdef CONFIG_MESH
@@ -1198,6 +2405,15 @@ static void handle_auth(struct hostapd_data *hapd,
status_code);
return;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WLAN_AUTH_FILS_SK:
+ case WLAN_AUTH_FILS_SK_PFS:
+ handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
+ len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
+ auth_alg, auth_transaction, status_code,
+ handle_auth_fils_finish);
+ return;
+#endif /* CONFIG_FILS */
}
fail:
@@ -1205,12 +2421,19 @@ static void handle_auth(struct hostapd_data *hapd,
os_free(radius_cui);
hostapd_free_psk_list(psk);
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
- auth_transaction + 1, resp, resp_ies, resp_ies_len);
+ reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+ auth_transaction + 1, resp, resp_ies,
+ resp_ies_len, "handle-auth");
+
+ if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
+ reply_res != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
}
-static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
{
int i, j = 32, aid;
@@ -1220,6 +2443,9 @@ static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
return 0;
}
+ if (TEST_FAIL())
+ return -1;
+
for (i = 0; i < AID_WORDS; i++) {
if (hapd->sta_aid[i] == (u32) -1)
continue;
@@ -1286,10 +2512,68 @@ static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
}
+static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *multi_ap_ie, size_t multi_ap_len)
+{
+ u8 multi_ap_value = 0;
+
+ sta->flags &= ~WLAN_STA_MULTI_AP;
+
+ if (!hapd->conf->multi_ap)
+ return WLAN_STATUS_SUCCESS;
+
+ if (multi_ap_ie) {
+ const u8 *multi_ap_subelem;
+
+ multi_ap_subelem = get_ie(multi_ap_ie + 4,
+ multi_ap_len - 4,
+ MULTI_AP_SUB_ELEM_TYPE);
+ if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
+ multi_ap_value = multi_ap_subelem[2];
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Multi-AP IE has missing or invalid Multi-AP subelement");
+ return WLAN_STATUS_INVALID_IE;
+ }
+ }
+
+ if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Multi-AP IE with unexpected value 0x%02x",
+ multi_ap_value);
+
+ if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
+ if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+ return WLAN_STATUS_SUCCESS;
+
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Non-Multi-AP STA tries to associate with backhaul-only BSS");
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+
+ if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Backhaul STA tries to associate with fronthaul-only BSS");
+
+ sta->flags |= WLAN_STA_MULTI_AP;
+ return WLAN_STATUS_SUCCESS;
+}
+
static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
struct ieee802_11_elems *elems)
{
+ /* Supported rates not used in IEEE 802.11ad/DMG */
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
+ return WLAN_STATUS_SUCCESS;
+
if (!elems->supp_rates) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1327,9 +2611,187 @@ static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_INTERWORKING */
+ if (ext_capab_ie_len > 0) {
+ sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
+ os_free(sta->ext_capability);
+ sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
+ if (sta->ext_capability) {
+ sta->ext_capability[0] = ext_capab_ie_len;
+ os_memcpy(sta->ext_capability + 1, ext_capab_ie,
+ ext_capab_ie_len);
+ }
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+#ifdef CONFIG_OWE
+
+static int owe_group_supported(struct hostapd_data *hapd, u16 group)
+{
+ int i;
+ int *groups = hapd->conf->owe_groups;
+
+ if (group != 19 && group != 20 && group != 21)
+ return 0;
+
+ if (!groups)
+ return 1;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static u16 owe_process_assoc_req(struct hostapd_data *hapd,
+ struct sta_info *sta, const u8 *owe_dh,
+ u8 owe_dh_len)
+{
+ struct wpabuf *secret, *pub, *hkey;
+ int res;
+ u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
+ const char *info = "OWE Key Generation";
+ const u8 *addr[2];
+ size_t len[2];
+ u16 group;
+ size_t hash_len, prime_len;
+
+ if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
+ wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ group = WPA_GET_LE16(owe_dh);
+ if (!owe_group_supported(hapd, group)) {
+ wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group);
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+ if (group == 19)
+ prime_len = 32;
+ else if (group == 20)
+ prime_len = 48;
+ else if (group == 21)
+ prime_len = 66;
+ else
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+
+ crypto_ecdh_deinit(sta->owe_ecdh);
+ sta->owe_ecdh = crypto_ecdh_init(group);
+ if (!sta->owe_ecdh)
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ sta->owe_group = group;
+
+ secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2,
+ owe_dh_len - 2);
+ secret = wpabuf_zeropad(secret, prime_len);
+ if (!secret) {
+ wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
+
+ /* prk = HKDF-extract(C | A | group, z) */
+
+ pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+ if (!pub) {
+ wpabuf_clear_free(secret);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ /* PMKID = Truncate-128(Hash(C | A)) */
+ addr[0] = owe_dh + 2;
+ len[0] = owe_dh_len - 2;
+ addr[1] = wpabuf_head(pub);
+ len[1] = wpabuf_len(pub);
+ if (group == 19) {
+ res = sha256_vector(2, addr, len, pmkid);
+ hash_len = SHA256_MAC_LEN;
+ } else if (group == 20) {
+ res = sha384_vector(2, addr, len, pmkid);
+ hash_len = SHA384_MAC_LEN;
+ } else if (group == 21) {
+ res = sha512_vector(2, addr, len, pmkid);
+ hash_len = SHA512_MAC_LEN;
+ } else {
+ wpabuf_free(pub);
+ wpabuf_clear_free(secret);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ pub = wpabuf_zeropad(pub, prime_len);
+ if (res < 0 || !pub) {
+ wpabuf_free(pub);
+ wpabuf_clear_free(secret);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2);
+ if (!hkey) {
+ wpabuf_free(pub);
+ wpabuf_clear_free(secret);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */
+ wpabuf_put_buf(hkey, pub); /* A */
+ wpabuf_free(pub);
+ wpabuf_put_le16(hkey, group); /* group */
+ if (group == 19)
+ res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
+ wpabuf_head(secret), wpabuf_len(secret), prk);
+ else if (group == 20)
+ res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
+ wpabuf_head(secret), wpabuf_len(secret), prk);
+ else if (group == 21)
+ res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
+ wpabuf_head(secret), wpabuf_len(secret), prk);
+ wpabuf_clear_free(hkey);
+ wpabuf_clear_free(secret);
+ if (res < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
+
+ /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
+
+ os_free(sta->owe_pmk);
+ sta->owe_pmk = os_malloc(hash_len);
+ if (!sta->owe_pmk) {
+ os_memset(prk, 0, SHA512_MAC_LEN);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (group == 19)
+ res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
+ os_strlen(info), sta->owe_pmk, hash_len);
+ else if (group == 20)
+ res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
+ os_strlen(info), sta->owe_pmk, hash_len);
+ else if (group == 21)
+ res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
+ os_strlen(info), sta->owe_pmk, hash_len);
+ os_memset(prk, 0, SHA512_MAC_LEN);
+ if (res < 0) {
+ os_free(sta->owe_pmk);
+ sta->owe_pmk = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ sta->owe_pmk_len = hash_len;
+
+ wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
+ wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
+ wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
+ sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE);
+
return WLAN_STATUS_SUCCESS;
}
+#endif /* CONFIG_OWE */
+
static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ies, size_t ies_len, int reassoc)
@@ -1359,6 +2821,11 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
resp = copy_supp_rates(hapd, sta, &elems);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+
+ resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
#ifdef CONFIG_IEEE80211N
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
@@ -1378,6 +2845,10 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+ resp = copy_sta_vht_oper(hapd, sta, elems.vht_operation);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -1470,34 +2941,24 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"state machine");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+ wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq,
wpa_ie, wpa_ie_len,
- elems.mdie, elems.mdie_len);
- if (res == WPA_INVALID_GROUP)
- resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- else if (res == WPA_INVALID_PAIRWISE)
- resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- else if (res == WPA_INVALID_AKMP)
- resp = WLAN_STATUS_AKMP_NOT_VALID;
- else if (res == WPA_ALLOC_FAIL)
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-#ifdef CONFIG_IEEE80211W
- else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
- resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
- else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
- resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
-#endif /* CONFIG_IEEE80211W */
- else if (res == WPA_INVALID_MDIE)
- resp = WLAN_STATUS_INVALID_MDIE;
- else if (res != WPA_IE_OK)
- resp = WLAN_STATUS_INVALID_IE;
+ elems.mdie, elems.mdie_len,
+ elems.owe_dh, elems.owe_dh_len);
+ resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
#ifdef CONFIG_IEEE80211W
- if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+ (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+ !sta->sa_query_timed_out &&
sta->sa_query_count > 0)
ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
+ (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
+ !sta->sa_query_timed_out &&
(!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
/*
* STA has already been associated with MFP and SA
@@ -1518,7 +2979,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
sta->flags &= ~WLAN_STA_MFP;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
if (!reassoc) {
wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
@@ -1533,9 +2994,13 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
+ if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
+ sta->sae->state == SAE_ACCEPTED)
+ wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
+
if (wpa_auth_uses_sae(sta->wpa_sm) &&
sta->auth_alg == WLAN_AUTH_OPEN) {
struct rsn_pmksa_cache_entry *sa;
@@ -1559,6 +3024,48 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OWE
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
+ elems.owe_dh) {
+ resp = owe_process_assoc_req(hapd, sta, elems.owe_dh,
+ elems.owe_dh_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
+ elems.owe_dh) {
+ sta->dpp_pfs = dpp_pfs_init(
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey));
+ if (!sta->dpp_pfs) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not initialize PFS");
+ /* Try to continue without PFS */
+ goto pfs_fail;
+ }
+
+ if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
+ elems.owe_dh_len) < 0) {
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ }
+
+ wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
+ sta->dpp_pfs->secret : NULL);
+ pfs_fail:
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_IEEE80211N
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
@@ -1603,10 +3110,28 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
if (elems.hs20 && elems.hs20_len > 4) {
+ int release;
+
sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
elems.hs20_len - 4);
- } else
+ release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
+ if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: PMF not negotiated by release %d station "
+ MACSTR, release, MAC2STR(sta->addr));
+ return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+ }
+ } else {
sta->hs20_ie = NULL;
+ }
+
+ wpabuf_free(sta->roaming_consortium);
+ if (elems.roaming_cons_sel)
+ sta->roaming_consortium = wpabuf_alloc_copy(
+ elems.roaming_cons_sel + 4,
+ elems.roaming_cons_sel_len - 4);
+ else
+ sta->roaming_consortium = NULL;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
@@ -1617,6 +3142,64 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
sta->mb_ies = NULL;
#endif /* CONFIG_FST */
+#ifdef CONFIG_MBO
+ mbo_ap_check_sta_assoc(hapd, sta, &elems);
+
+ if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
+ elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
+ hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_INFO,
+ "MBO: Reject WPA2 association without PMF");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+#endif /* CONFIG_MBO */
+
+#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
+ if (wpa_auth_uses_ocv(sta->wpa_sm) &&
+ (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (get_sta_tx_parameters(sta->wpa_sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ }
+#endif /* CONFIG_FILS && CONFIG_OCV */
+
+ ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
+ elems.supp_op_classes_len);
+
+ if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
+ elems.rrm_enabled &&
+ elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+ os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+ sizeof(sta->rrm_enabled_capa));
+
+ if (elems.power_capab) {
+ sta->min_tx_power = elems.power_capab[0];
+ sta->max_tx_power = elems.power_capab[1];
+ sta->power_capab = 1;
+ } else {
+ sta->power_capab = 0;
+ }
+
return WLAN_STATUS_SUCCESS;
}
@@ -1643,22 +3226,131 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
}
-static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
- u16 status_code, int reassoc, const u8 *ies,
- size_t ies_len)
+static int add_associated_sta(struct hostapd_data *hapd,
+ struct sta_info *sta, int reassoc)
+{
+ struct ieee80211_ht_capabilities ht_cap;
+ struct ieee80211_vht_capabilities vht_cap;
+ int set = 1;
+
+ /*
+ * Remove the STA entry to ensure the STA PS state gets cleared and
+ * configuration gets updated. This is relevant for cases, such as
+ * FT-over-the-DS, where a station re-associates back to the same AP but
+ * skips the authentication flow, or if working with a driver that
+ * does not support full AP client state.
+ *
+ * Skip this if the STA has already completed FT reassociation and the
+ * TK has been configured since the TX/RX PN must not be reset to 0 for
+ * the same key.
+ *
+ * FT-over-the-DS has a special case where the STA entry (and as such,
+ * the TK) has not yet been configured to the driver depending on which
+ * driver interface is used. For that case, allow add-STA operation to
+ * be used (instead of set-STA). This is needed to allow mac80211-based
+ * drivers to accept the STA parameter configuration. Since this is
+ * after a new FT-over-DS exchange, a new TK has been derived, so key
+ * reinstallation is not a concern for this case.
+ */
+ wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
+ " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
+ MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
+ sta->ft_over_ds, reassoc,
+ !!(sta->flags & WLAN_STA_AUTHORIZED),
+ wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
+ wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
+
+ if (!sta->added_unassoc &&
+ (!(sta->flags & WLAN_STA_AUTHORIZED) ||
+ (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
+ (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
+ !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
+ set = 0;
+
+ /* Do not allow the FT-over-DS exception to be used more than
+ * once per authentication exchange to guarantee a new TK is
+ * used here */
+ sta->ft_over_ds = 0;
+ }
+
+#ifdef CONFIG_IEEE80211N
+ if (sta->flags & WLAN_STA_HT)
+ hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
+#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (sta->flags & WLAN_STA_VHT)
+ hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
+#endif /* CONFIG_IEEE80211AC */
+
+ /*
+ * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
+ * will be set when the ACK frame for the (Re)Association Response frame
+ * is processed (TX status driver event).
+ */
+ if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
+ sta->supported_rates, sta->supported_rates_len,
+ sta->listen_interval,
+ sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+ sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
+ sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
+ sta->vht_opmode, sta->p2p_ie ? 1 : 0,
+ set)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
+ "Could not %s STA to kernel driver",
+ set ? "set" : "add");
+
+ if (sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
+
+ return -1;
+ }
+
+ sta->added_unassoc = 0;
+
+ return 0;
+}
+
+
+static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *addr, u16 status_code, int reassoc,
+ const u8 *ies, size_t ies_len, int rssi)
{
int send_len;
- u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+ u8 *buf;
+ size_t buflen;
struct ieee80211_mgmt *reply;
u8 *p;
-
- os_memset(buf, 0, sizeof(buf));
+ u16 res = WLAN_STATUS_SUCCESS;
+
+ buflen = sizeof(struct ieee80211_mgmt) + 1024;
+#ifdef CONFIG_FILS
+ if (sta && sta->fils_hlp_resp)
+ buflen += wpabuf_len(sta->fils_hlp_resp);
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
+ buflen += 150;
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ if (sta && sta->dpp_pfs)
+ buflen += 5 + sta->dpp_pfs->curve->prime_len;
+#endif /* CONFIG_DPP2 */
+ buf = os_zalloc(buflen);
+ if (!buf) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
reply = (struct ieee80211_mgmt *) buf;
reply->frame_control =
IEEE80211_FC(WLAN_FC_TYPE_MGMT,
(reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
WLAN_FC_STYPE_ASSOC_RESP));
- os_memcpy(reply->da, sta->addr, ETH_ALEN);
+ os_memcpy(reply->da, addr, ETH_ALEN);
os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
@@ -1667,24 +3359,50 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
reply->u.assoc_resp.capab_info =
host_to_le16(hostapd_own_capab_info(hapd));
reply->u.assoc_resp.status_code = host_to_le16(status_code);
- reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
+
+ reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
+ BIT(14) | BIT(15));
/* Supported rates */
p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
-#ifdef CONFIG_IEEE80211R
- if (status_code == WLAN_STATUS_SUCCESS) {
+#ifdef CONFIG_MBO
+ if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+ rssi != 0) {
+ int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
+
+ p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
+ delta);
+ }
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_IEEE80211R_AP
+ if (sta && status_code == WLAN_STATUS_SUCCESS) {
/* IEEE 802.11r: Mobility Domain Information, Fast BSS
* Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
- buf + sizeof(buf) - p,
+ buf + buflen - p,
sta->auth_alg, ies, ies_len);
+ if (!p) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to write AssocResp IEs");
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_OWE
+ if (sta && status_code == WLAN_STATUS_SUCCESS &&
+ (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
+ p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
+ buf + buflen - p,
+ ies, ies_len);
+#endif /* CONFIG_OWE */
#ifdef CONFIG_IEEE80211W
- if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
+ if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
#endif /* CONFIG_IEEE80211W */
@@ -1695,14 +3413,30 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- p = hostapd_eid_vht_capabilities(hapd, p);
+ u32 nsts = 0, sta_nsts;
+
+ if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
+ struct ieee80211_vht_capabilities *capa;
+
+ nsts = (hapd->iface->conf->vht_capab >>
+ VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+ capa = sta->vht_capabilities;
+ sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
+ VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+
+ if (nsts < sta_nsts)
+ nsts = 0;
+ else
+ nsts = sta_nsts;
+ }
+ p = hostapd_eid_vht_capabilities(hapd, p, nsts);
p = hostapd_eid_vht_operation(hapd, p);
}
#endif /* CONFIG_IEEE80211AC */
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
- if (sta->qos_map_enabled)
+ if (sta && sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
#ifdef CONFIG_FST
@@ -1713,17 +3447,51 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FST */
+#ifdef CONFIG_OWE
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
+ sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
+ struct wpabuf *pub;
+
+ pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+ if (!pub) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
+ /* OWE Diffie-Hellman Parameter element */
+ *p++ = WLAN_EID_EXTENSION; /* Element ID */
+ *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
+ *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
+ WPA_PUT_LE16(p, sta->owe_group);
+ p += 2;
+ os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
+ p += wpabuf_len(pub);
+ wpabuf_free(pub);
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
+ os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
+ wpabuf_len(sta->dpp_pfs->ie));
+ p += wpabuf_len(sta->dpp_pfs->ie);
+ }
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_IEEE80211AC
- if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
+ if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
p = hostapd_eid_vendor_vht(hapd, p);
#endif /* CONFIG_IEEE80211AC */
- if (sta->flags & WLAN_STA_WMM)
+ if (sta && (sta->flags & WLAN_STA_WMM))
p = hostapd_eid_wmm(hapd, p);
#ifdef CONFIG_WPS
- if ((sta->flags & WLAN_STA_WPS) ||
- ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
+ if (sta &&
+ ((sta->flags & WLAN_STA_WPS) ||
+ ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
struct wpabuf *wps = wps_build_assoc_resp_ie();
if (wps) {
os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
@@ -1733,8 +3501,11 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_WPS */
+ if (sta && (sta->flags & WLAN_STA_MULTI_AP))
+ p = hostapd_eid_multi_ap(hapd, p);
+
#ifdef CONFIG_P2P
- if (sta->p2p_ie) {
+ if (sta && sta->p2p_ie && hapd->p2p_group) {
struct wpabuf *p2p_resp_ie;
enum p2p_status_code status;
switch (status_code) {
@@ -1763,23 +3534,180 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
p = hostapd_eid_p2p_manage(hapd, p);
#endif /* CONFIG_P2P_MANAGER */
+ p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
+
+ if (hapd->conf->assocresp_elements &&
+ (size_t) (buf + buflen - p) >=
+ wpabuf_len(hapd->conf->assocresp_elements)) {
+ os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
+ wpabuf_len(hapd->conf->assocresp_elements));
+ p += wpabuf_len(hapd->conf->assocresp_elements);
+ }
+
send_len += p - reply->u.assoc_resp.variable;
- if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
+#ifdef CONFIG_FILS
+ if (sta &&
+ (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) &&
+ status_code == WLAN_STATUS_SUCCESS) {
+ struct ieee802_11_elems elems;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
+ ParseFailed || !elems.fils_session) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
+
+ /* FILS Session */
+ *p++ = WLAN_EID_EXTENSION; /* Element ID */
+ *p++ = 1 + FILS_SESSION_LEN; /* Length */
+ *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
+ os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
+ send_len += 2 + 1 + FILS_SESSION_LEN;
+
+ send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
+ buflen, sta->fils_hlp_resp);
+ if (send_len < 0) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
+ }
+#endif /* CONFIG_FILS */
+
+ if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+done:
+ os_free(buf);
+ return res;
+}
+
+
+#ifdef CONFIG_OWE
+u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *owe_dh, u8 owe_dh_len,
+ u8 *owe_buf, size_t owe_buf_len, u16 *reason)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->own_ie_override) {
+ wpa_printf(MSG_DEBUG, "OWE: Using IE override");
+ *reason = WLAN_STATUS_SUCCESS;
+ return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+ owe_buf_len, NULL, 0);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
+ wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
+ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+ owe_buf_len, NULL, 0);
+ *reason = WLAN_STATUS_SUCCESS;
+ return owe_buf;
+ }
+
+ *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (*reason != WLAN_STATUS_SUCCESS)
+ return NULL;
+
+ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+ owe_buf_len, NULL, 0);
+
+ if (sta->owe_ecdh && owe_buf) {
+ struct wpabuf *pub;
+
+ pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+ if (!pub) {
+ *reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return owe_buf;
+ }
+
+ /* OWE Diffie-Hellman Parameter element */
+ *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
+ *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
+ *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
+ */
+ WPA_PUT_LE16(owe_buf, sta->owe_group);
+ owe_buf += 2;
+ os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
+ owe_buf += wpabuf_len(pub);
+ wpabuf_free(pub);
+ }
+
+ return owe_buf;
+}
+#endif /* CONFIG_OWE */
+
+
+#ifdef CONFIG_FILS
+
+void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ u16 reply_res;
+
+ wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
+ MAC2STR(sta->addr));
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ if (!sta->fils_pending_assoc_req)
+ return;
+ reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
+ sta->fils_pending_assoc_is_reassoc,
+ sta->fils_pending_assoc_req,
+ sta->fils_pending_assoc_req_len, 0);
+ os_free(sta->fils_pending_assoc_req);
+ sta->fils_pending_assoc_req = NULL;
+ sta->fils_pending_assoc_req_len = 0;
+ wpabuf_free(sta->fils_hlp_resp);
+ sta->fils_hlp_resp = NULL;
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+
+ /*
+ * Remove the station in case transmission of a success response fails.
+ * At this point the station was already added associated to the driver.
+ */
+ if (reply_res != WLAN_STATUS_SUCCESS)
+ hostapd_drv_sta_remove(hapd, sta->addr);
+}
+
+
+void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = eloop_data;
+
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP response timeout - continue with association response for "
+ MACSTR, MAC2STR(sta->addr));
+ if (sta->fils_drv_assoc_finish)
+ hostapd_notify_assoc_fils_finish(hapd, sta);
+ else
+ fils_hlp_finish_assoc(hapd, sta);
}
+#endif /* CONFIG_FILS */
+
static void handle_assoc(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
- int reassoc)
+ int reassoc, int rssi)
{
u16 capab_info, listen_interval, seq_ctrl, fc;
- u16 resp = WLAN_STATUS_SUCCESS;
+ u16 resp = WLAN_STATUS_SUCCESS, reply_res;
const u8 *pos;
int left, i;
struct sta_info *sta;
+ u8 *tmp = NULL;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
+ char *identity = NULL;
+ char *radius_cui = NULL;
+#ifdef CONFIG_FILS
+ int delay_assoc = 0;
+#endif /* CONFIG_FILS */
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
@@ -1837,31 +3765,89 @@ static void handle_assoc(struct hostapd_data *hapd,
}
sta = ap_get_sta(hapd, mgmt->sa);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sta && sta->auth_alg == WLAN_AUTH_FT &&
(sta->flags & WLAN_STA_AUTH) == 0) {
wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
"prior to authentication since it is using "
"over-the-DS FT", MAC2STR(mgmt->sa));
+
+ /*
+ * Mark station as authenticated, to avoid adding station
+ * entry in the driver as associated and not authenticated
+ */
+ sta->flags |= WLAN_STA_AUTH;
} else
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
- hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "Station tried to "
- "associate before authentication "
- "(aid=%d flags=0x%x)",
- sta ? sta->aid : -1,
- sta ? sta->flags : 0);
- send_deauth(hapd, mgmt->sa,
- WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
- return;
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode ==
+ HOSTAPD_MODE_IEEE80211AD) {
+ int acl_res;
+ u32 session_timeout, acct_interim_interval;
+ struct vlan_description vlan_id;
+
+ acl_res = ieee802_11_allowed_address(
+ hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &session_timeout, &acct_interim_interval,
+ &vlan_id, &psk, &identity, &radius_cui, 0);
+ if (acl_res == HOSTAPD_ACL_REJECT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Ignore Association Request frame from "
+ MACSTR " due to ACL reject",
+ MAC2STR(mgmt->sa));
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if (acl_res == HOSTAPD_ACL_PENDING)
+ return;
+
+ /* DMG/IEEE 802.11ad does not use authentication.
+ * Allocate sta entry upon association. */
+ sta = ap_sta_add(hapd, mgmt->sa);
+ if (!sta) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Failed to add STA");
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+
+ acl_res = ieee802_11_set_radius_info(
+ hapd, sta, acl_res, session_timeout,
+ acct_interim_interval, &vlan_id, &psk,
+ &identity, &radius_cui);
+ if (acl_res) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Skip authentication for DMG/IEEE 802.11ad");
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->auth_alg = WLAN_AUTH_OPEN;
+ } else {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station tried to associate before authentication (aid=%d flags=0x%x)",
+ sta ? sta->aid : -1,
+ sta ? sta->flags : 0);
+ send_deauth(hapd, mgmt->sa,
+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+ return;
+ }
}
if ((fc & WLAN_FC_RETRY) &&
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
sta->last_seq_ctrl == seq_ctrl &&
- sta->last_subtype == reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
- WLAN_FC_STYPE_ASSOC_REQ) {
+ sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
+ WLAN_FC_STYPE_ASSOC_REQ)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Drop repeated association frame seq_ctrl=0x%x",
@@ -1873,7 +3859,7 @@ static void handle_assoc(struct hostapd_data *hapd,
WLAN_FC_STYPE_ASSOC_REQ;
if (hapd->tkip_countermeasures) {
- resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -1886,6 +3872,53 @@ static void handle_assoc(struct hostapd_data *hapd,
goto fail;
}
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+
+ if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
+ rssi < hapd->iconf->rssi_reject_assoc_rssi &&
+ (sta->auth_rssi == 0 ||
+ sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
+ resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
+ goto fail;
+ }
+#endif /* CONFIG_MBO */
+
+ /*
+ * sta->capability is used in check_assoc_ies() for RRM enabled
+ * capability element.
+ */
+ sta->capability = capab_info;
+
+#ifdef CONFIG_FILS
+ if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ int res;
+
+ /* The end of the payload is encrypted. Need to decrypt it
+ * before parsing. */
+
+ tmp = os_memdup(pos, left);
+ if (!tmp) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
+ len, tmp, left);
+ if (res < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ pos = tmp;
+ left = res;
+ }
+#endif /* CONFIG_FILS */
+
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
* is used */
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
@@ -1899,10 +3932,10 @@ static void handle_assoc(struct hostapd_data *hapd,
goto fail;
}
- sta->capability = capab_info;
sta->listen_interval = listen_interval;
- if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
sta->flags |= WLAN_STA_NONERP;
for (i = 0; i < sta->supported_rates_len; i++) {
if ((sta->supported_rates[i] & 0x7f) > 22) {
@@ -1921,7 +3954,8 @@ static void handle_assoc(struct hostapd_data *hapd,
!sta->no_short_slot_time_set) {
sta->no_short_slot_time_set = 1;
hapd->iface->num_sta_no_short_slot_time++;
- if (hapd->iface->current_mode->mode ==
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode ==
HOSTAPD_MODE_IEEE80211G &&
hapd->iface->num_sta_no_short_slot_time == 1)
ieee802_11_set_beacons(hapd->iface);
@@ -1936,7 +3970,8 @@ static void handle_assoc(struct hostapd_data *hapd,
!sta->no_short_preamble_set) {
sta->no_short_preamble_set = 1;
hapd->iface->num_sta_no_short_preamble++;
- if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_preamble == 1)
ieee802_11_set_beacons(hapd->iface);
}
@@ -1969,8 +4004,99 @@ static void handle_assoc(struct hostapd_data *hapd,
* remove the STA immediately. */
sta->timeout_next = STA_NULLFUNC;
+#ifdef CONFIG_TAXONOMY
+ taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
+#endif /* CONFIG_TAXONOMY */
+
+ sta->pending_wds_enable = 0;
+
+#ifdef CONFIG_FILS
+ if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ if (fils_process_hlp(hapd, sta, pos, left) > 0)
+ delay_assoc = 1;
+ }
+#endif /* CONFIG_FILS */
+
fail:
- send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+ os_free(identity);
+ os_free(radius_cui);
+ hostapd_free_psk_list(psk);
+
+ /*
+ * In case of a successful response, add the station to the driver.
+ * Otherwise, the kernel may ignore Data frames before we process the
+ * ACK frame (TX status). In case of a failure, this station will be
+ * removed.
+ *
+ * Note that this is not compliant with the IEEE 802.11 standard that
+ * states that a non-AP station should transition into the
+ * authenticated/associated state only after the station acknowledges
+ * the (Re)Association Response frame. However, still do this as:
+ *
+ * 1. In case the station does not acknowledge the (Re)Association
+ * Response frame, it will be removed.
+ * 2. Data frames will be dropped in the kernel until the station is
+ * set into authorized state, and there are no significant known
+ * issues with processing other non-Data Class 3 frames during this
+ * window.
+ */
+ if (resp == WLAN_STATUS_SUCCESS && sta &&
+ add_associated_sta(hapd, sta, reassoc))
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+#ifdef CONFIG_FILS
+ if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
+ eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
+ sta->fils_pending_assoc_req) {
+ /* Do not reschedule fils_hlp_timeout in case the station
+ * retransmits (Re)Association Request frame while waiting for
+ * the previously started FILS HLP wait, so that the timeout can
+ * be determined from the first pending attempt. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
+ MACSTR, MAC2STR(sta->addr));
+ os_free(tmp);
+ return;
+ }
+ if (sta) {
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ os_free(sta->fils_pending_assoc_req);
+ sta->fils_pending_assoc_req = NULL;
+ sta->fils_pending_assoc_req_len = 0;
+ wpabuf_free(sta->fils_hlp_resp);
+ sta->fils_hlp_resp = NULL;
+ }
+ if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
+ sta->fils_pending_assoc_req = tmp;
+ sta->fils_pending_assoc_req_len = left;
+ sta->fils_pending_assoc_is_reassoc = reassoc;
+ sta->fils_drv_assoc_finish = 0;
+ wpa_printf(MSG_DEBUG,
+ "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
+ MACSTR, MAC2STR(sta->addr));
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
+ fils_hlp_timeout, hapd, sta);
+ return;
+ }
+#endif /* CONFIG_FILS */
+
+ reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
+ left, rssi);
+ os_free(tmp);
+
+ /*
+ * Remove the station in case tranmission of a success response fails
+ * (the STA was added associated to the driver) or if the station was
+ * previously added unassociated.
+ */
+ if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
+ resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
}
@@ -2007,11 +4133,12 @@ static void handle_disassoc(struct hostapd_data *hapd,
/* Stop Accounting and IEEE 802.1X sessions, but leave the STA
* authenticated. */
accounting_sta_stop(hapd, sta);
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
if (sta->ipaddr)
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
ap_sta_ip6addr_del(hapd, sta);
hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
if (sta->timeout_next == STA_NULLFUNC ||
sta->timeout_next == STA_DISASSOC) {
@@ -2023,6 +4150,17 @@ static void handle_disassoc(struct hostapd_data *hapd,
mlme_disassociate_indication(
hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
+
+ /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
+ * disassociation. */
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ sta->flags &= ~WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "deauthenticated");
+ ap_free_sta(hapd, sta);
+ }
}
@@ -2086,28 +4224,6 @@ static void handle_beacon(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211W
-
-static int hostapd_sa_query_action(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- const u8 *end;
-
- end = mgmt->u.action.u.sa_query_resp.trans_id +
- WLAN_SA_QUERY_TR_ID_LEN;
- if (((u8 *) mgmt) + len < end) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
- "frame (len=%lu)", (unsigned long) len);
- return 0;
- }
-
- ieee802_11_sa_query_action(hapd, mgmt->sa,
- mgmt->u.action.u.sa_query_resp.action,
- mgmt->u.action.u.sa_query_resp.trans_id);
- return 1;
-}
-
-
static int robust_action_frame(u8 category)
{
return category != WLAN_ACTION_PUBLIC &&
@@ -2117,12 +4233,13 @@ static int robust_action_frame(u8 category)
static int handle_action(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ unsigned int freq)
{
struct sta_info *sta;
- sta = ap_get_sta(hapd, mgmt->sa);
+ u8 *action __maybe_unused;
- if (len < IEEE80211_HDRLEN + 1) {
+ if (len < IEEE80211_HDRLEN + 2 + 1) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"handle_action - too short payload (len=%lu)",
@@ -2130,11 +4247,19 @@ static int handle_action(struct hostapd_data *hapd,
return 0;
}
+ action = (u8 *) &mgmt->u.action.u;
+ wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
+ " da " MACSTR " len %d freq %u",
+ mgmt->u.action.category, *action,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
(sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
"frame (category=%u) from unassociated STA " MACSTR,
- MAC2STR(mgmt->sa), mgmt->u.action.category);
+ mgmt->u.action.category, MAC2STR(mgmt->sa));
return 0;
}
@@ -2171,26 +4296,27 @@ static int handle_action(struct hostapd_data *hapd,
}
switch (mgmt->u.action.category) {
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
case WLAN_ACTION_FT:
if (!sta ||
wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
len - IEEE80211_HDRLEN))
break;
return 1;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
return 1;
#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
- return hostapd_sa_query_action(hapd, mgmt, len);
+ ieee802_11_sa_query_action(hapd, mgmt, len);
+ return 1;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
case WLAN_ACTION_WNM:
ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
return 1;
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
#ifdef CONFIG_FST
case WLAN_ACTION_FST:
if (hapd->iface->fst)
@@ -2206,12 +4332,41 @@ static int handle_action(struct hostapd_data *hapd,
if (len >= IEEE80211_HDRLEN + 2 &&
mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) {
- wpa_printf(MSG_DEBUG,
- "HT20/40 coex mgmt frame received from STA "
- MACSTR, MAC2STR(mgmt->sa));
hostapd_2040_coex_action(hapd, mgmt, len);
+ return 1;
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_DPP
+ if (len >= IEEE80211_HDRLEN + 6 &&
+ mgmt->u.action.u.vs_public_action.action ==
+ WLAN_PA_VENDOR_SPECIFIC &&
+ WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
+ OUI_WFA &&
+ mgmt->u.action.u.vs_public_action.variable[0] ==
+ DPP_OUI_TYPE) {
+ const u8 *pos, *end;
+
+ pos = mgmt->u.action.u.vs_public_action.oui;
+ end = ((const u8 *) mgmt) + len;
+ hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
+ freq);
+ return 1;
+ }
+ if (len >= IEEE80211_HDRLEN + 2 &&
+ (mgmt->u.action.u.public_action.action ==
+ WLAN_PA_GAS_INITIAL_RESP ||
+ mgmt->u.action.u.public_action.action ==
+ WLAN_PA_GAS_COMEBACK_RESP)) {
+ const u8 *pos, *end;
+
+ pos = &mgmt->u.action.u.public_action.action;
+ end = ((const u8 *) mgmt) + len;
+ gas_query_ap_rx(hapd->gas, mgmt->sa,
+ mgmt->u.action.category,
+ pos, end - pos, hapd->iface->freq);
+ return 1;
+ }
+#endif /* CONFIG_DPP */
if (hapd->public_action_cb) {
hapd->public_action_cb(hapd->public_action_cb_ctx,
(u8 *) mgmt, len,
@@ -2233,6 +4388,9 @@ static int handle_action(struct hostapd_data *hapd,
return 1;
}
break;
+ case WLAN_ACTION_RADIO_MEASUREMENT:
+ hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
+ return 1;
}
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -2240,8 +4398,9 @@ static int handle_action(struct hostapd_data *hapd,
"handle_action - unknown action category %d or invalid "
"frame",
mgmt->u.action.category);
- if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) &&
- !(mgmt->sa[0] & 0x01)) {
+ if (!is_multicast_ether_addr(mgmt->da) &&
+ !(mgmt->u.action.category & 0x80) &&
+ !is_multicast_ether_addr(mgmt->sa)) {
struct ieee80211_mgmt *resp;
/*
@@ -2251,10 +4410,9 @@ static int handle_action(struct hostapd_data *hapd,
*/
wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
"frame back to sender");
- resp = os_malloc(len);
+ resp = os_memdup(mgmt, len);
if (resp == NULL)
return 0;
- os_memcpy(resp, mgmt, len);
os_memcpy(resp->da, resp->sa, ETH_ALEN);
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
@@ -2288,13 +4446,19 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi)
{
struct ieee80211_mgmt *mgmt;
- int broadcast;
u16 fc, stype;
int ret = 0;
+ unsigned int freq;
+ int ssi_signal = fi ? fi->ssi_signal : 0;
if (len < 24)
return 0;
+ if (fi && fi->freq)
+ freq = fi->freq;
+ else
+ freq = hapd->iface->freq;
+
mgmt = (struct ieee80211_mgmt *) buf;
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
@@ -2304,11 +4468,7 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
return 1;
}
- broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
- mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
- mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
-
- if (!broadcast &&
+ if (!is_broadcast_ether_addr(mgmt->bssid) &&
#ifdef CONFIG_P2P
/* Invitation responses can be sent with the peer MAC as BSSID */
!((hapd->conf->p2p & P2P_GROUP_OWNER) &&
@@ -2325,11 +4485,13 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
- handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
+ handle_probe_req(hapd, mgmt, len, ssi_signal);
return 1;
}
- if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
+ if ((!is_broadcast_ether_addr(mgmt->da) ||
+ stype != WLAN_FC_STYPE_ACTION) &&
+ os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"MGMT: DA=" MACSTR " not our address",
@@ -2338,22 +4500,22 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
}
if (hapd->iconf->track_sta_max_num)
- sta_track_add(hapd->iface, mgmt->sa);
+ sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
- handle_auth(hapd, mgmt, len);
+ handle_auth(hapd, mgmt, len, ssi_signal, 0);
ret = 1;
break;
case WLAN_FC_STYPE_ASSOC_REQ:
wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
- handle_assoc(hapd, mgmt, len, 0);
+ handle_assoc(hapd, mgmt, len, 0, ssi_signal);
ret = 1;
break;
case WLAN_FC_STYPE_REASSOC_REQ:
wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
- handle_assoc(hapd, mgmt, len, 1);
+ handle_assoc(hapd, mgmt, len, 1, ssi_signal);
ret = 1;
break;
case WLAN_FC_STYPE_DISASSOC:
@@ -2368,7 +4530,7 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
break;
case WLAN_FC_STYPE_ACTION:
wpa_printf(MSG_DEBUG, "mgmt::action");
- ret = handle_action(hapd, mgmt, len);
+ ret = handle_action(hapd, mgmt, len, freq);
break;
default:
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -2388,28 +4550,29 @@ static void handle_auth_cb(struct hostapd_data *hapd,
u16 auth_alg, auth_transaction, status_code;
struct sta_info *sta;
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
+ " not found",
+ MAC2STR(mgmt->da));
+ return;
+ }
+
+ auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+ status_code = le_to_host16(mgmt->u.auth.status_code);
+
if (!ok) {
hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
"did not acknowledge authentication response");
- return;
+ goto fail;
}
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
(unsigned long) len);
- return;
- }
-
- auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
- auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
- status_code = le_to_host16(mgmt->u.auth.status_code);
-
- sta = ap_get_sta(hapd, mgmt->da);
- if (!sta) {
- wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
- MAC2STR(mgmt->da));
- return;
+ goto fail;
}
if (status_code == WLAN_STATUS_SUCCESS &&
@@ -2418,6 +4581,15 @@ static void handle_auth_cb(struct hostapd_data *hapd,
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "authenticated");
sta->flags |= WLAN_STA_AUTH;
+ if (sta->added_unassoc)
+ hostapd_set_sta_flags(hapd, sta);
+ return;
+ }
+
+fail:
+ if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
}
}
@@ -2453,15 +4625,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
u16 status;
struct sta_info *sta;
int new_assoc = 1;
- struct ieee80211_ht_capabilities ht_cap;
- struct ieee80211_vht_capabilities vht_cap;
-
- if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
- sizeof(mgmt->u.assoc_resp))) {
- wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
- reassoc, (unsigned long) len);
- return;
- }
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -2470,11 +4633,12 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
return;
}
- if (!ok) {
- hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG,
- "did not acknowledge association response");
- sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
+ if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
+ sizeof(mgmt->u.assoc_resp))) {
+ wpa_printf(MSG_INFO,
+ "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
+ reassoc, (unsigned long) len);
+ hostapd_drv_sta_remove(hapd, sta->addr);
return;
}
@@ -2483,6 +4647,18 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
else
status = le_to_host16(mgmt->u.assoc_resp.status_code);
+ if (!ok) {
+ hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "did not acknowledge association response");
+ sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
+ /* The STA is added only in case of SUCCESS */
+ if (status == WLAN_STATUS_SUCCESS)
+ hostapd_drv_sta_remove(hapd, sta->addr);
+
+ return;
+ }
+
if (status != WLAN_STATUS_SUCCESS)
return;
@@ -2499,11 +4675,15 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
new_assoc = 0;
sta->flags |= WLAN_STA_ASSOC;
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
- if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) ||
+ if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
+ !hapd->conf->osen) ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK ||
sta->auth_alg == WLAN_AUTH_FT) {
/*
- * Open, static WEP, or FT protocol; no separate authorization
- * step.
+ * Open, static WEP, FT protocol, or FILS; no separate
+ * authorization step.
*/
ap_sta_set_authorized(hapd, sta, 1);
}
@@ -2517,48 +4697,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
sta->sa_query_timed_out = 0;
#endif /* CONFIG_IEEE80211W */
- /*
- * Remove the STA entry in order to make sure the STA PS state gets
- * cleared and configuration gets updated in case of reassociation back
- * to the same AP.
- */
- hostapd_drv_sta_remove(hapd, sta->addr);
-
-#ifdef CONFIG_IEEE80211N
- if (sta->flags & WLAN_STA_HT)
- hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
-#endif /* CONFIG_IEEE80211N */
-#ifdef CONFIG_IEEE80211AC
- if (sta->flags & WLAN_STA_VHT)
- hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
-#endif /* CONFIG_IEEE80211AC */
-
- if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
- sta->supported_rates, sta->supported_rates_len,
- sta->listen_interval,
- sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
- sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
- sta->flags, sta->qosinfo, sta->vht_opmode)) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_NOTICE,
- "Could not add STA to kernel driver");
-
- ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_DISASSOC_AP_BUSY);
-
- return;
- }
-
- if (sta->flags & WLAN_STA_WDS) {
- int ret;
- char ifname_wds[IFNAMSIZ + 1];
-
- ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
- sta->aid, 1);
- if (!ret)
- hostapd_set_wds_encryption(hapd, sta, ifname_wds);
- }
-
if (sta->eapol_sm == NULL) {
/*
* This STA does not use RADIUS server for EAP authentication,
@@ -2575,13 +4713,64 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
hostapd_set_sta_flags(hapd, sta);
+ if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
+ wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
+ MACSTR " based on pending request",
+ MAC2STR(sta->addr));
+ sta->pending_wds_enable = 0;
+ sta->flags |= WLAN_STA_WDS;
+ }
+
+ if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
+ int ret;
+ char ifname_wds[IFNAMSIZ + 1];
+
+ wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
+ MACSTR " (aid %u)",
+ MAC2STR(sta->addr), sta->aid);
+ ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
+ sta->aid, 1);
+ if (!ret)
+ hostapd_set_wds_encryption(hapd, sta, ifname_wds);
+ }
+
if (sta->auth_alg == WLAN_AUTH_FT)
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
else
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
-
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+#ifdef CONFIG_FILS
+ if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) &&
+ fils_set_tk(sta->wpa_sm) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ return;
+ }
+#endif /* CONFIG_FILS */
+
+ if (sta->pending_eapol_rx) {
+ struct os_reltime now, age;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
+ if (age.sec == 0 && age.usec < 200000) {
+ wpa_printf(MSG_DEBUG,
+ "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
+ MAC2STR(sta->addr));
+ ieee802_1x_receive(
+ hapd, mgmt->da,
+ wpabuf_head(sta->pending_eapol_rx->buf),
+ wpabuf_len(sta->pending_eapol_rx->buf));
+ }
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ }
}
@@ -2590,7 +4779,7 @@ static void handle_deauth_cb(struct hostapd_data *hapd,
size_t len, int ok)
{
struct sta_info *sta;
- if (mgmt->da[0] & 0x01)
+ if (is_multicast_ether_addr(mgmt->da))
return;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -2614,7 +4803,7 @@ static void handle_disassoc_cb(struct hostapd_data *hapd,
size_t len, int ok)
{
struct sta_info *sta;
- if (mgmt->da[0] & 0x01)
+ if (is_multicast_ether_addr(mgmt->da))
return;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -2633,6 +4822,65 @@ static void handle_disassoc_cb(struct hostapd_data *hapd,
}
+static void handle_action_cb(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok)
+{
+ struct sta_info *sta;
+ const struct rrm_measurement_report_element *report;
+
+ if (is_multicast_ether_addr(mgmt->da))
+ return;
+#ifdef CONFIG_DPP
+ if (len >= IEEE80211_HDRLEN + 6 &&
+ mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
+ mgmt->u.action.u.vs_public_action.action ==
+ WLAN_PA_VENDOR_SPECIFIC &&
+ WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
+ OUI_WFA &&
+ mgmt->u.action.u.vs_public_action.variable[0] ==
+ DPP_OUI_TYPE) {
+ const u8 *pos, *end;
+
+ pos = &mgmt->u.action.u.vs_public_action.variable[1];
+ end = ((const u8 *) mgmt) + len;
+ hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok);
+ return;
+ }
+ if (len >= IEEE80211_HDRLEN + 2 &&
+ mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
+ (mgmt->u.action.u.public_action.action ==
+ WLAN_PA_GAS_INITIAL_REQ ||
+ mgmt->u.action.u.public_action.action ==
+ WLAN_PA_GAS_COMEBACK_REQ)) {
+ const u8 *pos, *end;
+
+ pos = mgmt->u.action.u.public_action.variable;
+ end = ((const u8 *) mgmt) + len;
+ gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok);
+ return;
+ }
+#endif /* CONFIG_DPP */
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
+ " not found", MAC2STR(mgmt->da));
+ return;
+ }
+
+ if (len < 24 + 5 + sizeof(*report))
+ return;
+ report = (const struct rrm_measurement_report_element *)
+ &mgmt->u.action.u.rrm.variable[2];
+ if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
+ mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
+ report->eid == WLAN_EID_MEASURE_REQUEST &&
+ report->len >= 3 &&
+ report->type == MEASURE_TYPE_BEACON)
+ hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
+}
+
+
/**
* ieee802_11_mgmt_cb - Process management frame TX status callback
* @hapd: hostapd BSS data structure (the BSS from which the management frame
@@ -2650,8 +4898,16 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->ext_mgmt_frame_handling) {
- wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-TX-STATUS stype=%u ok=%d",
- stype, ok);
+ size_t hex_len = 2 * len + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex) {
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "MGMT-TX-STATUS stype=%u ok=%d buf=%s",
+ stype, ok, hex);
+ os_free(hex);
+ }
return;
}
#endif /* CONFIG_TESTING_OPTIONS */
@@ -2670,7 +4926,7 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
handle_assoc_cb(hapd, mgmt, len, 1, ok);
break;
case WLAN_FC_STYPE_PROBE_RESP:
- wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
+ wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok);
break;
case WLAN_FC_STYPE_DEAUTH:
wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
@@ -2681,7 +4937,8 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
handle_disassoc_cb(hapd, mgmt, len, ok);
break;
case WLAN_FC_STYPE_ACTION:
- wpa_printf(MSG_DEBUG, "mgmt::action cb");
+ wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
+ handle_action_cb(hapd, mgmt, len, ok);
break;
default:
wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
@@ -2779,6 +5036,8 @@ void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
}
if (sta == NULL)
return;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
+ MAC2STR(sta->addr));
if (!(sta->flags & WLAN_STA_PENDING_POLL))
return;
@@ -2794,10 +5053,22 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
struct sta_info *sta;
sta = ap_get_sta(hapd, src);
- if (sta && (sta->flags & WLAN_STA_ASSOC)) {
+ if (sta &&
+ ((sta->flags & WLAN_STA_ASSOC) ||
+ ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
if (!hapd->conf->wds_sta)
return;
+ if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
+ WLAN_STA_ASSOC_REQ_OK) {
+ wpa_printf(MSG_DEBUG,
+ "Postpone 4-address WDS mode enabling for STA "
+ MACSTR " since TX status for AssocResp is not yet known",
+ MAC2STR(sta->addr));
+ sta->pending_wds_enable = 1;
+ return;
+ }
+
if (wds && !(sta->flags & WLAN_STA_WDS)) {
int ret;
char ifname_wds[IFNAMSIZ + 1];
@@ -2817,7 +5088,7 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
MACSTR, MAC2STR(src));
- if (src[0] & 0x01) {
+ if (is_multicast_ether_addr(src)) {
/* Broadcast bit set in SA?! Ignore the frame silently. */
return;
}
diff --git a/contrib/wpa/src/ap/ieee802_11.h b/contrib/wpa/src/ap/ieee802_11.h
index 44c1bff..db7badc 100644
--- a/contrib/wpa/src/ap/ieee802_11.h
+++ b/contrib/wpa/src/ap/ieee802_11.h
@@ -16,6 +16,8 @@ struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
+struct vlan_description;
+struct hostapd_sta_wpa_psk_short;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
@@ -49,9 +51,16 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
+
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id);
@@ -61,6 +70,7 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap);
+int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab);
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
@@ -71,6 +81,8 @@ void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab);
+u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
@@ -82,8 +94,8 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid);
void ieee802_11_sa_query_action(struct hostapd_data *hapd,
- const u8 *sa, const u8 action_type,
- const u8 *trans_id);
+ const struct ieee80211_mgmt *mgmt,
+ size_t len);
u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
@@ -97,6 +109,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_SAE
void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta);
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta);
#else /* CONFIG_SAE */
static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta)
@@ -104,4 +117,64 @@ static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_MBO
+
+u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len);
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd);
+
+u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
+ size_t len, int delta);
+
+#else /* CONFIG_MBO */
+
+static inline u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ return eid;
+}
+
+static inline u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
+#endif /* CONFIG_MBO */
+
+void ap_copy_sta_supp_op_classes(struct sta_info *sta,
+ const u8 *supp_op_classes,
+ size_t supp_op_classes_len);
+
+u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid);
+void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
+ struct sta_info *sta, int success,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len);
+u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *owe_dh, u8 owe_dh_len,
+ u8 *owe_buf, size_t owe_buf_len, u16 *reason);
+void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
+void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
+void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, size_t len, u16 auth_alg,
+ u16 auth_transaction, u16 status_code,
+ void (*cb)(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ u16 resp, struct wpabuf *data, int pub));
+
+size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
+int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len, u32 *session_timeout,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui,
+ int is_probe_req);
+
+int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx);
+
+void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
+
#endif /* IEEE802_11_H */
diff --git a/contrib/wpa/src/ap/ieee802_11_auth.c b/contrib/wpa/src/ap/ieee802_11_auth.c
index 531a67d..931d4d0 100644
--- a/contrib/wpa/src/ap/ieee802_11_auth.c
+++ b/contrib/wpa/src/ap/ieee802_11_auth.c
@@ -15,7 +15,6 @@
#include "utils/common.h"
#include "utils/eloop.h"
-#include "crypto/sha1.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
@@ -35,7 +34,7 @@ struct hostapd_cached_radius_acl {
struct hostapd_cached_radius_acl *next;
u32 session_timeout;
u32 acct_interim_interval;
- int vlan_id;
+ struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk;
char *identity;
char *radius_cui;
@@ -77,29 +76,20 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src)
{
- struct hostapd_sta_wpa_psk_short **copy_to;
- struct hostapd_sta_wpa_psk_short *copy_from;
-
- /* Copy PSK linked list */
- copy_to = psk;
- copy_from = src;
- while (copy_from && copy_to) {
- *copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
- if (*copy_to == NULL)
- break;
- os_memcpy(*copy_to, copy_from,
- sizeof(struct hostapd_sta_wpa_psk_short));
- copy_from = copy_from->next;
- copy_to = &((*copy_to)->next);
- }
- if (copy_to)
- *copy_to = NULL;
+ if (!psk)
+ return;
+
+ if (src)
+ src->ref++;
+
+ *psk = src;
}
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui)
{
@@ -165,7 +155,10 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
if (msg == NULL)
return -1;
- radius_msg_make_authenticator(msg, addr, ETH_ALEN);
+ if (radius_msg_make_authenticator(msg) < 0) {
+ wpa_printf(MSG_INFO, "Could not make Request Authenticator");
+ goto fail;
+ }
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
@@ -213,6 +206,33 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
/**
+ * hostapd_check_acl - Check a specified STA against accept/deny ACLs
+ * @hapd: hostapd BSS data
+ * @addr: MAC address of the STA
+ * @vlan_id: Buffer for returning VLAN ID
+ * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
+ */
+int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
+ struct vlan_description *vlan_id)
+{
+ if (hostapd_maclist_found(hapd->conf->accept_mac,
+ hapd->conf->num_accept_mac, addr, vlan_id))
+ return HOSTAPD_ACL_ACCEPT;
+
+ if (hostapd_maclist_found(hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac, addr, vlan_id))
+ return HOSTAPD_ACL_REJECT;
+
+ if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
+ return HOSTAPD_ACL_ACCEPT;
+ if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
+ return HOSTAPD_ACL_REJECT;
+
+ return HOSTAPD_ACL_PENDING;
+}
+
+
+/**
* hostapd_allowed_address - Check whether a specified STA can be authenticated
* @hapd: hostapd BSS data
* @addr: MAC address of the STA
@@ -224,6 +244,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
* @psk: Linked list buffer for returning WPA PSK
* @identity: Buffer for returning identity (from RADIUS)
* @radius_cui: Buffer for returning CUI (from RADIUS)
+ * @is_probe_req: Whether this query for a Probe Request frame
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*
* The caller is responsible for freeing the returned *identity and *radius_cui
@@ -231,16 +252,20 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ char **identity, char **radius_cui,
+ int is_probe_req)
{
+ int res;
+
if (session_timeout)
*session_timeout = 0;
if (acct_interim_interval)
*acct_interim_interval = 0;
if (vlan_id)
- *vlan_id = 0;
+ os_memset(vlan_id, 0, sizeof(*vlan_id));
if (psk)
*psk = NULL;
if (identity)
@@ -248,18 +273,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
if (radius_cui)
*radius_cui = NULL;
- if (hostapd_maclist_found(hapd->conf->accept_mac,
- hapd->conf->num_accept_mac, addr, vlan_id))
- return HOSTAPD_ACL_ACCEPT;
-
- if (hostapd_maclist_found(hapd->conf->deny_mac,
- hapd->conf->num_deny_mac, addr, vlan_id))
- return HOSTAPD_ACL_REJECT;
-
- if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
- return HOSTAPD_ACL_ACCEPT;
- if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
- return HOSTAPD_ACL_REJECT;
+ res = hostapd_check_acl(hapd, addr, vlan_id);
+ if (res != HOSTAPD_ACL_PENDING)
+ return res;
if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
#ifdef CONFIG_NO_RADIUS
@@ -267,11 +283,19 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
#else /* CONFIG_NO_RADIUS */
struct hostapd_acl_query_data *query;
+ if (is_probe_req) {
+ /* Skip RADIUS queries for Probe Request frames to avoid
+ * excessive load on the authentication server. */
+ return HOSTAPD_ACL_ACCEPT;
+ };
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ vlan_id = NULL;
+
/* Check whether ACL cache has an entry for this station */
- int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
- acct_interim_interval,
- vlan_id, psk,
- identity, radius_cui);
+ res = hostapd_acl_cache_get(hapd, addr, session_timeout,
+ acct_interim_interval, vlan_id, psk,
+ identity, radius_cui);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -314,14 +338,13 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
return HOSTAPD_ACL_REJECT;
}
- query->auth_msg = os_malloc(len);
+ query->auth_msg = os_memdup(msg, len);
if (query->auth_msg == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"auth frame.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
- os_memcpy(query->auth_msg, msg, len);
query->auth_msg_len = len;
query->next = hapd->acl_queries;
hapd->acl_queries = query;
@@ -419,7 +442,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
struct hostapd_cached_radius_acl *cache)
{
int passphraselen;
- char *passphrase, *strpassphrase;
+ char *passphrase;
size_t i;
struct hostapd_sta_wpa_psk_short *psk;
@@ -436,24 +459,42 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
*/
if (passphrase == NULL)
break;
+
+ /*
+ * Passphase should be 8..63 chars (to be hashed with SSID)
+ * or 64 chars hex string (no separate hashing with SSID).
+ */
+
+ if (passphraselen < MIN_PASSPHRASE_LEN ||
+ passphraselen > MAX_PASSPHRASE_LEN + 1)
+ goto free_pass;
+
/*
* passphrase does not contain the NULL termination.
* Add it here as pbkdf2_sha1() requires it.
*/
- strpassphrase = os_zalloc(passphraselen + 1);
psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
- if (strpassphrase && psk) {
- os_memcpy(strpassphrase, passphrase, passphraselen);
- pbkdf2_sha1(strpassphrase,
- hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len, 4096,
- psk->psk, PMK_LEN);
+ if (psk) {
+ if ((passphraselen == MAX_PASSPHRASE_LEN + 1) &&
+ (hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0)) {
+ hostapd_logger(hapd, cache->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_WARNING,
+ "invalid hex string (%d chars) in Tunnel-Password",
+ passphraselen);
+ goto skip;
+ } else if (passphraselen <= MAX_PASSPHRASE_LEN) {
+ os_memcpy(psk->passphrase, passphrase,
+ passphraselen);
+ psk->is_passphrase = 1;
+ }
psk->next = cache->psk;
cache->psk = psk;
psk = NULL;
}
- os_free(strpassphrase);
+skip:
os_free(psk);
+free_pass:
os_free(passphrase);
}
}
@@ -535,7 +576,10 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->acct_interim_interval = 0;
}
- cache->vlan_id = radius_msg_get_vlanid(msg);
+ if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
+ cache->vlan_id.notempty = !!radius_msg_get_vlanid(
+ msg, &cache->vlan_id.untagged,
+ MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
@@ -558,17 +602,18 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
!cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
- if (cache->vlan_id &&
- !hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
+ if (cache->vlan_id.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "Invalid VLAN ID %d received from RADIUS server",
- cache->vlan_id);
- cache->vlan_id = 0;
+ "Invalid VLAN %d%s received from RADIUS server",
+ cache->vlan_id.untagged,
+ cache->vlan_id.tagged[0] ? "+" : "");
+ os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !cache->vlan_id)
+ !cache->vlan_id.notempty)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@@ -627,9 +672,11 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
#ifndef CONFIG_NO_RADIUS
hostapd_acl_cache_free(hapd->acl_cache);
+ hapd->acl_cache = NULL;
#endif /* CONFIG_NO_RADIUS */
query = hapd->acl_queries;
+ hapd->acl_queries = NULL;
while (query) {
prev = query;
query = query->next;
@@ -640,6 +687,12 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
{
+ if (psk && psk->ref) {
+ /* This will be freed when the last reference is dropped. */
+ psk->ref--;
+ return;
+ }
+
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
diff --git a/contrib/wpa/src/ap/ieee802_11_auth.h b/contrib/wpa/src/ap/ieee802_11_auth.h
index b66f244..5aece51 100644
--- a/contrib/wpa/src/ap/ieee802_11_auth.h
+++ b/contrib/wpa/src/ap/ieee802_11_auth.h
@@ -16,11 +16,15 @@ enum {
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
+int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
+ struct vlan_description *vlan_id);
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui);
+ char **identity, char **radius_cui,
+ int is_probe_req);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
diff --git a/contrib/wpa/src/ap/ieee802_11_he.c b/contrib/wpa/src/ap/ieee802_11_he.c
new file mode 100644
index 0000000..0721358
--- /dev/null
+++ b/contrib/wpa/src/ap/ieee802_11_he.c
@@ -0,0 +1,119 @@
+/*
+ * hostapd / IEEE 802.11ax HE
+ * Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+#include "dfs.h"
+
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_capabilities *cap;
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sizeof(struct ieee80211_he_capabilities);
+ *pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
+
+ cap = (struct ieee80211_he_capabilities *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+
+ if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
+ HE_PHYCAP_SU_BEAMFORMER_CAPAB;
+
+ if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
+ HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
+
+ if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
+ cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
+ HE_PHYCAP_MU_BEAMFORMER_CAPAB;
+
+ pos += sizeof(*cap);
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_operation *oper;
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sizeof(struct ieee80211_he_operation);
+ *pos++ = WLAN_EID_EXT_HE_OPERATION;
+
+ oper = (struct ieee80211_he_operation *) pos;
+ os_memset(oper, 0, sizeof(*oper));
+
+ if (hapd->iface->conf->he_op.he_bss_color)
+ oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
+
+ if (hapd->iface->conf->he_op.he_default_pe_duration)
+ oper->he_oper_params |=
+ (hapd->iface->conf->he_op.he_default_pe_duration <<
+ HE_OPERATION_DFLT_PE_DURATION_OFFSET);
+
+ if (hapd->iface->conf->he_op.he_twt_required)
+ oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
+
+ if (hapd->iface->conf->he_op.he_rts_threshold)
+ oper->he_oper_params |=
+ (hapd->iface->conf->he_op.he_rts_threshold <<
+ HE_OPERATION_RTS_THRESHOLD_OFFSET);
+
+ /* TODO: conditional MaxBSSID Indicator subfield */
+
+ pos += sizeof(*oper);
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_mu_edca_parameter_set *edca;
+ u8 *pos;
+ size_t i;
+
+ pos = (u8 *) &hapd->iface->conf->he_mu_edca;
+ for (i = 0; i < sizeof(*edca); i++) {
+ if (pos[i])
+ break;
+ }
+ if (i == sizeof(*edca))
+ return eid; /* no MU EDCA Parameters configured */
+
+ pos = eid;
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sizeof(*edca);
+ *pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS;
+
+ edca = (struct ieee80211_he_mu_edca_parameter_set *) pos;
+ os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca));
+
+ wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element",
+ pos, sizeof(*edca));
+
+ pos += sizeof(*edca);
+
+ return pos;
+}
diff --git a/contrib/wpa/src/ap/ieee802_11_ht.c b/contrib/wpa/src/ap/ieee802_11_ht.c
index 11fde2a..214855d 100644
--- a/contrib/wpa/src/ap/ieee802_11_ht.c
+++ b/contrib/wpa/src/ap/ieee802_11_ht.c
@@ -108,6 +108,29 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
}
+u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 sec_ch;
+
+ if (!hapd->cs_freq_params.channel ||
+ !hapd->cs_freq_params.sec_channel_offset)
+ return eid;
+
+ if (hapd->cs_freq_params.sec_channel_offset == -1)
+ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
+ else if (hapd->cs_freq_params.sec_channel_offset == 1)
+ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
+ else
+ return eid;
+
+ *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
+ *eid++ = 1;
+ *eid++ = sec_ch;
+
+ return eid;
+}
+
+
/*
op_mode
Set to 0 (HT pure) under the followign conditions
@@ -213,17 +236,29 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
int i;
const u8 *start = (const u8 *) mgmt;
const u8 *data = start + IEEE80211_HDRLEN + 2;
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG,
+ "HT: Received 20/40 BSS Coexistence Management frame from "
+ MACSTR, MAC2STR(mgmt->sa));
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
mgmt->u.action.u.public_action.action);
- if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore 20/40 BSS Coexistence Management frame since 40 MHz capability is not enabled");
return;
+ }
- if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
+ if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore too short 20/40 BSS Coexistence Management frame");
return;
+ }
+ /* 20/40 BSS Coexistence element */
bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
bc_ie->length < 1) {
@@ -231,13 +266,35 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
bc_ie->element_id, bc_ie->length);
return;
}
- if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
+ if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length) {
+ wpa_printf(MSG_DEBUG,
+ "Truncated 20/40 BSS Coexistence element");
return;
+ }
data += 2 + bc_ie->length;
- wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
- bc_ie->coex_param);
+ wpa_printf(MSG_DEBUG,
+ "20/40 BSS Coexistence Information field: 0x%x (%s%s%s%s%s%s)",
+ bc_ie->coex_param,
+ (bc_ie->coex_param & BIT(0)) ? "[InfoReq]" : "",
+ (bc_ie->coex_param & BIT(1)) ? "[40MHzIntolerant]" : "",
+ (bc_ie->coex_param & BIT(2)) ? "[20MHzBSSWidthReq]" : "",
+ (bc_ie->coex_param & BIT(3)) ? "[OBSSScanExemptionReq]" : "",
+ (bc_ie->coex_param & BIT(4)) ?
+ "[OBSSScanExemptionGrant]" : "",
+ (bc_ie->coex_param & (BIT(5) | BIT(6) | BIT(7))) ?
+ "[Reserved]" : "");
+
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
+ /* Intra-BSS communication prohibiting 20/40 MHz BSS operation
+ */
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore intra-BSS 20/40 BSS Coexistence Management frame from not-associated STA");
+ return;
+ }
+
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -246,6 +303,8 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
}
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+ /* Inter-BSS communication prohibiting 20/40 MHz BSS operation
+ */
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -253,12 +312,16 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
is_ht40_allowed = 0;
}
- if (start + len - data >= 3 &&
- data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
+ /* 20/40 BSS Intolerant Channel Report element (zero or more times) */
+ while (start + len - data >= 3 &&
+ data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
u8 ielen = data[1];
- if (ielen > start + len - data - 2)
+ if (ielen > start + len - data - 2) {
+ wpa_printf(MSG_DEBUG,
+ "Truncated 20/40 BSS Intolerant Channel Report element");
return;
+ }
ic_report = (struct ieee80211_2040_intol_chan_report *) data;
wpa_printf(MSG_DEBUG,
"20/40 BSS Intolerant Channel Report: Operating Class %u",
@@ -269,8 +332,10 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
for (i = 0; i < ielen - 1; i++) {
u8 chan = ic_report->variable[i];
+ if (chan == iface->conf->channel)
+ continue; /* matching own primary channel */
if (is_40_allowed(iface, chan))
- continue;
+ continue; /* not within affected channels */
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -278,6 +343,8 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
chan);
is_ht40_allowed = 0;
}
+
+ data += 2 + ielen;
}
wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
is_ht40_allowed, iface->num_sta_ht40_intolerant);
@@ -317,8 +384,8 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
* that did not specify a valid WMM IE in the (Re)Association Request
* frame.
*/
- if (!ht_capab ||
- !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
+ if (!ht_capab || !(sta->flags & WLAN_STA_WMM) ||
+ !hapd->iconf->ieee80211n || hapd->conf->disable_11n) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;
diff --git a/contrib/wpa/src/ap/ieee802_11_shared.c b/contrib/wpa/src/ap/ieee802_11_shared.c
index d462ac8..707381f 100644
--- a/contrib/wpa/src/ap/ieee802_11_shared.c
+++ b/contrib/wpa/src/ap/ieee802_11_shared.c
@@ -10,10 +10,12 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ocv.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "wpa_auth.h"
#include "ieee802_11.h"
@@ -49,7 +51,12 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id)
{
- struct ieee80211_mgmt mgmt;
+#ifdef CONFIG_OCV
+ struct sta_info *sta;
+#endif /* CONFIG_OCV */
+ struct ieee80211_mgmt *mgmt;
+ u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
u8 *end;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
@@ -57,19 +64,61 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(mgmt.da, addr, ETH_ALEN);
- os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
- mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
- os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+#ifdef CONFIG_OCV
+ sta = ap_get_sta(hapd, addr);
+ if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Request");
+ return;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for OCI element in SA Query Request");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(oci_ie);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ mgmt = os_zalloc(sizeof(*mgmt) + oci_ie_len);
+ if (!mgmt) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate buffer for SA Query Response frame");
+ os_free(oci_ie);
+ return;
+ }
+
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
+ mgmt->u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+ os_memcpy(mgmt->u.action.u.sa_query_req.trans_id, trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
- end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+ end = mgmt->u.action.u.sa_query_req.variable;
+#ifdef CONFIG_OCV
+ if (oci_ie_len > 0) {
+ os_memcpy(end, oci_ie, oci_ie_len);
+ end += oci_ie_len;
+ }
+#endif /* CONFIG_OCV */
+ if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
+
+ os_free(mgmt);
+ os_free(oci_ie);
}
@@ -77,7 +126,9 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
const u8 *sa, const u8 *trans_id)
{
struct sta_info *sta;
- struct ieee80211_mgmt resp;
+ struct ieee80211_mgmt *resp;
+ u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
u8 *end;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
@@ -92,30 +143,123 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
return;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Response");
+ return;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for for OCI element in SA Query Response");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(oci_ie);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ resp = os_zalloc(sizeof(*resp) + oci_ie_len);
+ if (!resp) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate buffer for SA Query Response frame");
+ os_free(oci_ie);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
MACSTR, MAC2STR(sa));
- os_memset(&resp, 0, sizeof(resp));
- resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(resp.da, sa, ETH_ALEN);
- os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
- resp.u.action.category = WLAN_ACTION_SA_QUERY;
- resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
- os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(resp->da, sa, ETH_ALEN);
+ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+ resp->u.action.category = WLAN_ACTION_SA_QUERY;
+ resp->u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+ os_memcpy(resp->u.action.u.sa_query_req.trans_id, trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
- end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
+ end = resp->u.action.u.sa_query_req.variable;
+#ifdef CONFIG_OCV
+ if (oci_ie_len > 0) {
+ os_memcpy(end, oci_ie, oci_ie_len);
+ end += oci_ie_len;
+ }
+#endif /* CONFIG_OCV */
+ if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
+
+ os_free(resp);
+ os_free(oci_ie);
}
-void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
- const u8 action_type, const u8 *trans_id)
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
{
struct sta_info *sta;
int i;
+ const u8 *sa = mgmt->sa;
+ const u8 action_type = mgmt->u.action.u.sa_query_resp.action;
+ const u8 *trans_id = mgmt->u.action.u.sa_query_resp.trans_id;
+
+ if (((const u8 *) mgmt) + len <
+ mgmt->u.action.u.sa_query_resp.variable) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.11: Too short SA Query Action frame (len=%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ sta = ap_get_sta(hapd, sa);
+
+#ifdef CONFIG_OCV
+ if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct ieee802_11_elems elems;
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+ size_t ies_len;
+ const u8 *ies;
+
+ ies = mgmt->u.action.u.sa_query_resp.variable;
+ ies_len = len - (ies - (u8 *) mgmt);
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "SA Query: Failed to parse elements");
+ return;
+ }
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in SA Query Action frame");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sta->wpa_sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
if (action_type == WLAN_SA_QUERY_REQUEST) {
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
@@ -135,7 +279,6 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
/* MLME-SAQuery.confirm */
- sta = ap_get_sta(hapd, sa);
if (sta == NULL || sta->sa_query_trans_id == NULL) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
"pending SA Query request found");
@@ -172,10 +315,16 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
case 0: /* Bits 0-7 */
if (hapd->iconf->obss_interval)
*pos |= 0x01; /* Bit 0 - Coexistence management */
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)
+ *pos |= 0x04; /* Bit 2 - Extended Channel Switching */
break;
case 1: /* Bits 8-15 */
if (hapd->conf->proxy_arp)
*pos |= 0x10; /* Bit 12 - Proxy ARP */
+ if (hapd->conf->coloc_intf_reporting) {
+ /* Bit 13 - Collocated Interference Reporting */
+ *pos |= 0x20;
+ }
break;
case 2: /* Bits 16-23 */
if (hapd->conf->wnm_sleep_mode)
@@ -184,9 +333,9 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
*pos |= 0x08; /* Bit 19 - BSS Transition */
break;
case 3: /* Bits 24-31 */
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
*pos |= 0x02; /* Bit 25 - SSID List */
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
if (hapd->conf->time_advertisement == 2)
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
if (hapd->conf->interworking)
@@ -207,11 +356,45 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
if (hapd->conf->hs20)
*pos |= 0x40; /* Bit 46 - WNM-Notification */
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled)
+ *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_MBO */
break;
case 6: /* Bits 48-55 */
if (hapd->conf->ssid.utf8_ssid)
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
break;
+ case 7: /* Bits 56-63 */
+ break;
+ case 8: /* Bits 64-71 */
+ if (hapd->conf->ftm_responder)
+ *pos |= 0x40; /* Bit 70 - FTM responder */
+ if (hapd->conf->ftm_initiator)
+ *pos |= 0x80; /* Bit 71 - FTM initiator */
+ break;
+ case 9: /* Bits 72-79 */
+#ifdef CONFIG_FILS
+ if ((hapd->conf->wpa & WPA_PROTO_RSN) &&
+ wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
+ *pos |= 0x01;
+#endif /* CONFIG_FILS */
+ break;
+ case 10: /* Bits 80-87 */
+#ifdef CONFIG_SAE
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
+ int in_use = hostapd_sae_pw_id_in_use(hapd->conf);
+
+ if (in_use)
+ *pos |= 0x02; /* Bit 81 - SAE Password
+ * Identifiers In Use */
+ if (in_use == 2)
+ *pos |= 0x04; /* Bit 82 - SAE Password
+ * Identifiers Used Exclusively */
+ }
+#endif /* CONFIG_SAE */
+ break;
}
}
@@ -231,14 +414,32 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
len = 1;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
-#ifdef CONFIG_WNM
+ if (len < 9 &&
+ (hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
+ len = 9;
+#ifdef CONFIG_WNM_AP
if (len < 4)
len = 4;
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
#ifdef CONFIG_HS20
if (hapd->conf->hs20 && len < 6)
len = 6;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled && len < 6)
+ len = 6;
+#endif /* CONFIG_MBO */
+#ifdef CONFIG_FILS
+ if ((!(hapd->conf->wpa & WPA_PROTO_RSN) ||
+ !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
+ len = 10;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_SAE
+ if (len < 11 && hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pw_id_in_use(hapd->conf))
+ len = 11;
+#endif /* CONFIG_SAE */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -413,7 +614,7 @@ u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
{
size_t len;
- if (hapd->conf->time_advertisement != 2)
+ if (hapd->conf->time_advertisement != 2 || !hapd->conf->time_zone)
return eid;
len = os_strlen(hapd->conf->time_zone);
@@ -484,7 +685,7 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
if (hapd->conf->ap_max_inactivity > 0) {
unsigned int val;
*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
@@ -502,7 +703,300 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
pos += 2;
*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
}
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
+
+ return pos;
+}
+
+
+#ifdef CONFIG_MBO
+
+u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
+ size_t len, int delta)
+{
+ u8 mbo[4];
+
+ mbo[0] = OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT;
+ mbo[1] = 2;
+ /* Delta RSSI */
+ mbo[2] = delta;
+ /* Retry delay */
+ mbo[3] = hapd->iconf->rssi_reject_assoc_timeout;
+
+ return eid + mbo_add_ie(eid, len, mbo, 4);
+}
+
+
+u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 mbo[9], *mbo_pos = mbo;
+ u8 *pos = eid;
+
+ if (!hapd->conf->mbo_enabled &&
+ !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
+ return eid;
+
+ if (hapd->conf->mbo_enabled) {
+ *mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
+ *mbo_pos++ = 1;
+ /* Not Cellular aware */
+ *mbo_pos++ = 0;
+ }
+
+ if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = hapd->mbo_assoc_disallow;
+ }
+
+ if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
+ u8 ctrl;
+
+ ctrl = OCE_RELEASE;
+ if (OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
+ ctrl |= OCE_IS_STA_CFON;
+
+ *mbo_pos++ = OCE_ATTR_ID_CAPA_IND;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = ctrl;
+ }
+
+ pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo);
+
+ return pos;
+}
+
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+ u8 len;
+
+ if (!hapd->conf->mbo_enabled &&
+ !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
+ return 0;
+
+ /*
+ * MBO IE header (6) + Capability Indication attribute (3) +
+ * Association Disallowed attribute (3) = 12
+ */
+ len = 6;
+ if (hapd->conf->mbo_enabled)
+ len += 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
+
+ /* OCE capability indication attribute (3) */
+ if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd))
+ len += 3;
+
+ return len;
+}
+
+#endif /* CONFIG_MBO */
+
+
+#ifdef CONFIG_OWE
+static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd)
+{
+ return hapd->conf->owe_transition_ssid_len > 0 &&
+ !is_zero_ether_addr(hapd->conf->owe_transition_bssid);
+}
+#endif /* CONFIG_OWE */
+
+
+size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_OWE
+ if (!hostapd_eid_owe_trans_enabled(hapd))
+ return 0;
+ return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len;
+#else /* CONFIG_OWE */
+ return 0;
+#endif /* CONFIG_OWE */
+}
+
+
+u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+#ifdef CONFIG_OWE
+ u8 *pos = eid;
+ size_t elen;
+
+ if (hapd->conf->owe_transition_ifname[0] &&
+ !hostapd_eid_owe_trans_enabled(hapd))
+ hostapd_owe_trans_get_info(hapd);
+
+ if (!hostapd_eid_owe_trans_enabled(hapd))
+ return pos;
+
+ elen = hostapd_eid_owe_trans_len(hapd);
+ if (len < elen) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Not enough room in the buffer for OWE IE");
+ return pos;
+ }
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = elen - 2;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = OWE_OUI_TYPE;
+ os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN);
+ pos += ETH_ALEN;
+ *pos++ = hapd->conf->owe_transition_ssid_len;
+ os_memcpy(pos, hapd->conf->owe_transition_ssid,
+ hapd->conf->owe_transition_ssid_len);
+ pos += hapd->conf->owe_transition_ssid_len;
+
+ return pos;
+#else /* CONFIG_OWE */
+ return eid;
+#endif /* CONFIG_OWE */
+}
+
+
+void ap_copy_sta_supp_op_classes(struct sta_info *sta,
+ const u8 *supp_op_classes,
+ size_t supp_op_classes_len)
+{
+ if (!supp_op_classes)
+ return;
+ os_free(sta->supp_op_classes);
+ sta->supp_op_classes = os_malloc(1 + supp_op_classes_len);
+ if (!sta->supp_op_classes)
+ return;
+
+ sta->supp_op_classes[0] = supp_op_classes_len;
+ os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
+ supp_op_classes_len);
+}
+
+
+u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid)
+{
+ u8 *pos = eid;
+#ifdef CONFIG_FILS
+ u8 *len;
+ u16 fils_info = 0;
+ size_t realms;
+ struct fils_realm *realm;
+
+ if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
+ !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
+ return pos;
+
+ realms = dl_list_len(&hapd->conf->fils_realms);
+ if (realms > 7)
+ realms = 7; /* 3 bit count field limits this to max 7 */
+
+ *pos++ = WLAN_EID_FILS_INDICATION;
+ len = pos++;
+ /* TODO: B0..B2: Number of Public Key Identifiers */
+ if (hapd->conf->erp_domain) {
+ /* B3..B5: Number of Realm Identifiers */
+ fils_info |= realms << 3;
+ }
+ /* TODO: B6: FILS IP Address Configuration */
+ if (hapd->conf->fils_cache_id_set)
+ fils_info |= BIT(7);
+ if (hessid && !is_zero_ether_addr(hapd->conf->hessid))
+ fils_info |= BIT(8); /* HESSID Included */
+ /* FILS Shared Key Authentication without PFS Supported */
+ fils_info |= BIT(9);
+ if (hapd->conf->fils_dh_group) {
+ /* FILS Shared Key Authentication with PFS Supported */
+ fils_info |= BIT(10);
+ }
+ /* TODO: B11: FILS Public Key Authentication Supported */
+ /* B12..B15: Reserved */
+ WPA_PUT_LE16(pos, fils_info);
+ pos += 2;
+ if (hapd->conf->fils_cache_id_set) {
+ os_memcpy(pos, hapd->conf->fils_cache_id, FILS_CACHE_ID_LEN);
+ pos += FILS_CACHE_ID_LEN;
+ }
+ if (hessid && !is_zero_ether_addr(hapd->conf->hessid)) {
+ os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
+ pos += ETH_ALEN;
+ }
+
+ dl_list_for_each(realm, &hapd->conf->fils_realms, struct fils_realm,
+ list) {
+ if (realms == 0)
+ break;
+ realms--;
+ os_memcpy(pos, realm->hash, 2);
+ pos += 2;
+ }
+ *len = pos - len - 1;
+#endif /* CONFIG_FILS */
return pos;
}
+
+
+#ifdef CONFIG_OCV
+int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx)
+{
+ int ht_40mhz = 0;
+ int vht_80p80 = 0;
+ int requested_bw;
+
+ if (sta->ht_capabilities)
+ ht_40mhz = !!(sta->ht_capabilities->ht_capabilities_info &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
+
+ if (sta->vht_operation) {
+ struct ieee80211_vht_operation *oper = sta->vht_operation;
+
+ /*
+ * If a VHT Operation element was present, use it to determine
+ * the supported channel bandwidth.
+ */
+ if (oper->vht_op_info_chwidth == 0) {
+ requested_bw = ht_40mhz ? 40 : 20;
+ } else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
+ requested_bw = 80;
+ } else {
+ int diff;
+
+ requested_bw = 160;
+ diff = abs((int)
+ oper->vht_op_info_chan_center_freq_seg0_idx -
+ (int)
+ oper->vht_op_info_chan_center_freq_seg1_idx);
+ vht_80p80 = oper->vht_op_info_chan_center_freq_seg1_idx
+ != 0 && diff > 16;
+ }
+ } else if (sta->vht_capabilities) {
+ struct ieee80211_vht_capabilities *capab;
+ int vht_chanwidth;
+
+ capab = sta->vht_capabilities;
+
+ /*
+ * If only the VHT Capabilities element is present (e.g., for
+ * normal clients), use it to determine the supported channel
+ * bandwidth.
+ */
+ vht_chanwidth = capab->vht_capabilities_info &
+ VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+ vht_80p80 = capab->vht_capabilities_info &
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+
+ /* TODO: Also take into account Extended NSS BW Support field */
+ requested_bw = vht_chanwidth ? 160 : 80;
+ } else {
+ requested_bw = ht_40mhz ? 40 : 20;
+ }
+
+ *bandwidth = requested_bw < ap_max_chanwidth ?
+ requested_bw : ap_max_chanwidth;
+
+ *seg1_idx = 0;
+ if (ap_seg1_idx && vht_80p80)
+ *seg1_idx = ap_seg1_idx;
+
+ return 0;
+}
+#endif /* CONFIG_OCV */
diff --git a/contrib/wpa/src/ap/ieee802_11_vht.c b/contrib/wpa/src/ap/ieee802_11_vht.c
index 5bf1b5d..54ee080 100644
--- a/contrib/wpa/src/ap/ieee802_11_vht.c
+++ b/contrib/wpa/src/ap/ieee802_11_vht.c
@@ -17,9 +17,10 @@
#include "sta_info.h"
#include "beacon.h"
#include "ieee802_11.h"
+#include "dfs.h"
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
{
struct ieee80211_vht_capabilities *cap;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
@@ -49,6 +50,18 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
cap->vht_capabilities_info = host_to_le32(
hapd->iface->conf->vht_capab);
+ if (nsts != 0) {
+ u32 hapd_nsts;
+
+ hapd_nsts = le_to_host32(cap->vht_capabilities_info);
+ hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+ cap->vht_capabilities_info &=
+ ~(host_to_le32(hapd_nsts <<
+ VHT_CAP_BEAMFORMEE_STS_OFFSET));
+ cap->vht_capabilities_info |=
+ host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+ }
+
/* Supported MCS set comes from hw */
os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
@@ -80,6 +93,26 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
hapd->iconf->vht_oper_centr_freq_seg1_idx;
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
+ if (hapd->iconf->vht_oper_chwidth == 2) {
+ /*
+ * Convert 160 MHz channel width to new style as interop
+ * workaround.
+ */
+ oper->vht_op_info_chwidth = 1;
+ oper->vht_op_info_chan_center_freq_seg1_idx =
+ oper->vht_op_info_chan_center_freq_seg0_idx;
+ if (hapd->iconf->channel <
+ hapd->iconf->vht_oper_centr_freq_seg0_idx)
+ oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
+ else
+ oper->vht_op_info_chan_center_freq_seg0_idx += 8;
+ } else if (hapd->iconf->vht_oper_chwidth == 3) {
+ /*
+ * Convert 80+80 MHz channel width to new style as interop
+ * workaround.
+ */
+ oper->vht_op_info_chwidth = 1;
+ }
/* VHT Basic MCS set comes from hw */
/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
@@ -131,12 +164,177 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
}
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 bw, chan1, chan2 = 0;
+ int freq1;
+
+ if (!hapd->cs_freq_params.channel ||
+ !hapd->cs_freq_params.vht_enabled)
+ return eid;
+
+ /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
+ switch (hapd->cs_freq_params.bandwidth) {
+ case 40:
+ bw = 0;
+ break;
+ case 80:
+ /* check if it's 80+80 */
+ if (!hapd->cs_freq_params.center_freq2)
+ bw = 1;
+ else
+ bw = 3;
+ break;
+ case 160:
+ bw = 2;
+ break;
+ default:
+ /* not valid VHT bandwidth or not in CSA */
+ return eid;
+ }
+
+ freq1 = hapd->cs_freq_params.center_freq1 ?
+ hapd->cs_freq_params.center_freq1 :
+ hapd->cs_freq_params.freq;
+ if (ieee80211_freq_to_chan(freq1, &chan1) !=
+ HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ if (hapd->cs_freq_params.center_freq2 &&
+ ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
+ &chan2) != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
+ *eid++ = 5; /* Length of Channel Switch Wrapper */
+ *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
+ *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
+ *eid++ = bw; /* New Channel Width */
+ *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
+ *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
+
+ return eid;
+}
+
+
+u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ struct hostapd_channel_data *chan;
+ int dfs, i;
+ u8 channel, tx_pwr_count, local_pwr_constraint;
+ int max_tx_power;
+ u8 tx_pwr;
+
+ if (!mode)
+ return eid;
+
+ if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
+ return eid;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].freq == iface->freq)
+ break;
+ }
+ if (i == mode->num_channels)
+ return eid;
+
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ if (iconf->secondary_channel == 0) {
+ /* Max Transmit Power count = 0 (20 MHz) */
+ tx_pwr_count = 0;
+ } else {
+ /* Max Transmit Power count = 1 (20, 40 MHz) */
+ tx_pwr_count = 1;
+ }
+ break;
+ case VHT_CHANWIDTH_80MHZ:
+ /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
+ tx_pwr_count = 2;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ case VHT_CHANWIDTH_160MHZ:
+ /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
+ tx_pwr_count = 3;
+ break;
+ default:
+ return eid;
+ }
+
+ /*
+ * Below local_pwr_constraint logic is referred from
+ * hostapd_eid_pwr_constraint.
+ *
+ * Check if DFS is required by regulatory.
+ */
+ dfs = hostapd_is_dfs_required(hapd->iface);
+ if (dfs < 0)
+ dfs = 0;
+
+ /*
+ * In order to meet regulations when TPC is not implemented using
+ * a transmit power that is below the legal maximum (including any
+ * mitigation factor) should help. In this case, indicate 3 dB below
+ * maximum allowed transmit power.
+ */
+ if (hapd->iconf->local_pwr_constraint == -1)
+ local_pwr_constraint = (dfs == 0) ? 0 : 3;
+ else
+ local_pwr_constraint = hapd->iconf->local_pwr_constraint;
+
+ /*
+ * A STA that is not an AP shall use a transmit power less than or
+ * equal to the local maximum transmit power level for the channel.
+ * The local maximum transmit power can be calculated from the formula:
+ * local max TX pwr = max TX pwr - local pwr constraint
+ * Where max TX pwr is maximum transmit power level specified for
+ * channel in Country element and local pwr constraint is specified
+ * for channel in this Power Constraint element.
+ */
+ chan = &mode->channels[i];
+ max_tx_power = chan->max_tx_power - local_pwr_constraint;
+
+ /*
+ * Local Maximum Transmit power is encoded as two's complement
+ * with a 0.5 dB step.
+ */
+ max_tx_power *= 2; /* in 0.5 dB steps */
+ if (max_tx_power > 127) {
+ /* 63.5 has special meaning of 63.5 dBm or higher */
+ max_tx_power = 127;
+ }
+ if (max_tx_power < -128)
+ max_tx_power = -128;
+ if (max_tx_power < 0)
+ tx_pwr = 0x80 + max_tx_power + 128;
+ else
+ tx_pwr = max_tx_power;
+
+ *eid++ = WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE;
+ *eid++ = 2 + tx_pwr_count;
+
+ /*
+ * Max Transmit Power count and
+ * Max Transmit Power units = 0 (EIRP)
+ */
+ *eid++ = tx_pwr_count;
+
+ for (i = 0; i <= tx_pwr_count; i++)
+ *eid++ = tx_pwr;
+
+ return eid;
+}
+
+
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab)
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
- hapd->conf->disable_11ac ||
+ !hapd->iconf->ieee80211ac || hapd->conf->disable_11ac ||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
os_free(sta->vht_capabilities);
@@ -159,6 +357,29 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
}
+u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper)
+{
+ if (!vht_oper) {
+ os_free(sta->vht_operation);
+ sta->vht_operation = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (!sta->vht_operation) {
+ sta->vht_operation =
+ os_zalloc(sizeof(struct ieee80211_vht_operation));
+ if (!sta->vht_operation)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ os_memcpy(sta->vht_operation, vht_oper,
+ sizeof(struct ieee80211_vht_operation));
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ie, size_t len)
{
@@ -212,7 +433,7 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
pos += 4;
*pos++ = VENDOR_VHT_SUBTYPE;
- pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
return pos;
diff --git a/contrib/wpa/src/ap/ieee802_1x.c b/contrib/wpa/src/ap/ieee802_1x.c
index 0f2d428..97f503f 100644
--- a/contrib/wpa/src/ap/ieee802_1x.c
+++ b/contrib/wpa/src/ap/ieee802_1x.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -31,9 +31,14 @@
#include "ap_drv_ops.h"
#include "wps_hostapd.h"
#include "hs20.h"
+/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
+#include "ieee802_11.h"
#include "ieee802_1x.h"
+#ifdef CONFIG_HS20
+static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_HS20 */
static void ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
int remediation);
@@ -219,7 +224,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
MAC2STR(sta->addr));
#ifndef CONFIG_NO_VLAN
- if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) {
+ if (sta->vlan_id > 0) {
wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
return;
}
@@ -313,6 +318,7 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
hdr->code != EAP_CODE_INITIATE))
return;
+ eap_erp_update_identity(sm->eap, eap, len);
identity = eap_get_identity(sm->eap, &identity_len);
if (identity == NULL)
return;
@@ -402,7 +408,16 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
char buf[128];
if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_SERVICE_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
+ RADIUS_SERVICE_TYPE_FRAMED)) {
+ wpa_printf(MSG_ERROR, "Could not add Service-Type");
+ return -1;
+ }
+
+ if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_PORT) &&
+ sta->aid > 0 &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
wpa_printf(MSG_ERROR, "Could not add NAS-Port");
return -1;
@@ -435,9 +450,9 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
return -1;
}
- if (sta->acct_session_id_hi || sta->acct_session_id_lo) {
- os_snprintf(buf, sizeof(buf), "%08X-%08X",
- sta->acct_session_id_hi, sta->acct_session_id_lo);
+ if (sta->acct_session_id) {
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) sta->acct_session_id);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
@@ -445,7 +460,22 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
}
}
-#ifdef CONFIG_IEEE80211R
+ if ((hapd->conf->wpa & 2) &&
+ !hapd->conf->disable_pmksa_caching &&
+ sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) {
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long)
+ sta->eapol_sm->acct_multi_session_id);
+ if (!radius_msg_add_attr(
+ msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_INFO,
+ "Could not add Acct-Multi-Session-Id");
+ return -1;
+ }
+ }
+
+#ifdef CONFIG_IEEE80211R_AP
if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
sta->wpa_sm &&
(wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) ||
@@ -458,7 +488,7 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id");
return -1;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
@@ -475,6 +505,7 @@ int add_common_radius_attr(struct hostapd_data *hapd,
{
char buf[128];
struct hostapd_radius_attr *attr;
+ int len;
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IP_ADDRESS) &&
@@ -506,15 +537,15 @@ int add_common_radius_attr(struct hostapd_data *hapd,
return -1;
}
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr),
- wpa_ssid_txt(hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len));
- buf[sizeof(buf) - 1] = '\0';
+ len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":",
+ MAC2STR(hapd->own_addr));
+ os_memcpy(&buf[len], hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len);
+ len += hapd->conf->ssid.ssid_len;
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_CALLED_STATION_ID) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
+ (u8 *) buf, len)) {
wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
return -1;
}
@@ -560,9 +591,9 @@ int add_common_radius_attr(struct hostapd_data *hapd,
}
-static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
- struct sta_info *sta,
- const u8 *eap, size_t len)
+void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *eap, size_t len)
{
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
@@ -583,7 +614,10 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
return;
}
- radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+ if (radius_msg_make_authenticator(msg) < 0) {
+ wpa_printf(MSG_INFO, "Could not make Request Authenticator");
+ goto fail;
+ }
if (sm->identity &&
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
@@ -648,7 +682,8 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
if (hapd->conf->hs20) {
- u8 ver = 1; /* Release 2 */
+ u8 ver = hapd->conf->hs20_release - 1;
+
if (!radius_msg_add_wfa(
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
&ver, 1)) {
@@ -678,6 +713,41 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
goto fail;
}
}
+
+ if (sta->roaming_consortium &&
+ !radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM,
+ wpabuf_head(sta->roaming_consortium),
+ wpabuf_len(sta->roaming_consortium))) {
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 Roaming Consortium");
+ goto fail;
+ }
+
+ if (hapd->conf->t_c_filename) {
+ be32 timestamp;
+
+ if (!radius_msg_add_wfa(
+ msg,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME,
+ (const u8 *) hapd->conf->t_c_filename,
+ os_strlen(hapd->conf->t_c_filename))) {
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 T&C Filename");
+ goto fail;
+ }
+
+ timestamp = host_to_be32(hapd->conf->t_c_timestamp);
+ if (!radius_msg_add_wfa(
+ msg,
+ RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP,
+ (const u8 *) &timestamp,
+ sizeof(timestamp))) {
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 Timestamp");
+ goto fail;
+ }
+ }
}
#endif /* CONFIG_HS20 */
@@ -814,7 +884,7 @@ static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
}
-static struct eapol_state_machine *
+struct eapol_state_machine *
ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
{
int flags = 0;
@@ -831,6 +901,29 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
}
+static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
+ size_t len)
+{
+ if (sta->pending_eapol_rx) {
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ } else {
+ sta->pending_eapol_rx =
+ os_malloc(sizeof(*sta->pending_eapol_rx));
+ if (!sta->pending_eapol_rx)
+ return;
+ }
+
+ sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
+ if (!sta->pending_eapol_rx->buf) {
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ return;
+ }
+
+ os_get_reltime(&sta->pending_eapol_rx->rx_time);
+}
+
+
/**
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
* @hapd: hostapd BSS data
@@ -861,6 +954,13 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
"associated/Pre-authenticating STA");
+
+ if (sta && (sta->flags & WLAN_STA_AUTH)) {
+ wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
+ " for later use", MAC2STR(sta->addr));
+ ieee802_1x_save_eapol(sta, buf, len);
+ }
+
return;
}
@@ -909,7 +1009,9 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
}
key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
- if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
+ if (key_mgmt != -1 &&
+ (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
+ key_mgmt == WPA_KEY_MGMT_DPP)) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
"STA is using PSK");
return;
@@ -1047,18 +1149,20 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPS to PSK.
*/
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
return;
}
key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
- if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
+ if (key_mgmt != -1 &&
+ (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
+ key_mgmt == WPA_KEY_MGMT_DPP)) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
/*
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPA-EAP to PSK.
*/
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
return;
}
@@ -1093,7 +1197,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->eap_if->portEnabled = TRUE;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
@@ -1106,12 +1210,36 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
sta->eapol_sm->authSuccess = TRUE;
sta->eapol_sm->authFail = FALSE;
+ sta->eapol_sm->portValid = TRUE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
- /* TODO: get vlan_id from R0KH using RRB message */
+ ap_sta_bind_vlan(hapd, sta);
return;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_FILS
+ if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG,
+ "PMK from FILS - skip IEEE 802.1X/EAP");
+ /* Setup EAPOL state machines to already authenticated state
+ * because of existing FILS information. */
+ sta->eapol_sm->keyRun = TRUE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+ sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
+ sta->eapol_sm->authSuccess = TRUE;
+ sta->eapol_sm->authFail = FALSE;
+ sta->eapol_sm->portValid = TRUE;
+ if (sta->eapol_sm->eap)
+ eap_sm_notify_cached(sta->eapol_sm->eap);
+ wpa_auth_set_ptk_rekey_timer(sta->wpa_sm);
+ return;
+ }
+#endif /* CONFIG_FILS */
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
@@ -1128,7 +1256,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->authFail = FALSE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
- pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
+ pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
ap_sta_bind_vlan(hapd, sta);
} else {
if (reassoc) {
@@ -1144,10 +1272,20 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
}
-void ieee802_1x_free_station(struct sta_info *sta)
+void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
+#ifdef CONFIG_HS20
+ eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
+#endif /* CONFIG_HS20 */
+
+ if (sta->pending_eapol_rx) {
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ }
+
if (sm == NULL)
return;
@@ -1156,10 +1294,8 @@ void ieee802_1x_free_station(struct sta_info *sta)
#ifndef CONFIG_NO_RADIUS
radius_msg_free(sm->last_recv_radius);
radius_free_class(&sm->radius_class);
- wpabuf_free(sm->radius_cui);
#endif /* CONFIG_NO_RADIUS */
- os_free(sm->identity);
eapol_auth_free(sm);
}
@@ -1325,11 +1461,10 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
}
} while (class_len < 1);
- nclass[nclass_count].data = os_malloc(class_len);
+ nclass[nclass_count].data = os_memdup(attr_class, class_len);
if (nclass[nclass_count].data == NULL)
break;
- os_memcpy(nclass[nclass_count].data, attr_class, class_len);
nclass[nclass_count].len = class_len;
nclass_count++;
}
@@ -1489,6 +1624,33 @@ static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd,
ap_sta_session_warning_timeout(hapd, sta, warning_time);
}
+
+static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *pos,
+ size_t len)
+{
+ if (len < 4)
+ return; /* Malformed information */
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x",
+ pos[0], pos[1], pos[2], pos[3]);
+ hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0));
+}
+
+
+static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *pos, size_t len)
+{
+ os_free(sta->t_c_url);
+ sta->t_c_url = os_malloc(len + 1);
+ if (!sta->t_c_url)
+ return;
+ os_memcpy(sta->t_c_url, pos, len);
+ sta->t_c_url[len] = '\0';
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Terms and Conditions URL %s", sta->t_c_url);
+}
+
#endif /* CONFIG_HS20 */
@@ -1536,6 +1698,12 @@ static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
ieee802_1x_hs20_session_info(hapd, sta, pos, sublen,
session_timeout);
break;
+ case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING:
+ ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen);
+ break;
+ case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL:
+ ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen);
+ break;
}
}
#endif /* CONFIG_HS20 */
@@ -1575,6 +1743,45 @@ ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
}
+#ifndef CONFIG_NO_VLAN
+static int ieee802_1x_update_vlan(struct radius_msg *msg,
+ struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct vlan_description vlan_desc;
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged,
+ MAX_NUM_TAGGED_VLAN,
+ vlan_desc.tagged);
+
+ if (vlan_desc.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from RADIUS server",
+ vlan_desc.untagged,
+ vlan_desc.tagged[0] ? "+" : "");
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ ap_sta_set_vlan(hapd, sta, &vlan_desc);
+ return -1;
+ }
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+ !vlan_desc.notempty) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_INFO,
+ "authentication server did not include required VLAN ID in Access-Accept");
+ return -1;
+ }
+
+ return ap_sta_set_vlan(hapd, sta, &vlan_desc);
+}
+#endif /* CONFIG_NO_VLAN */
+
+
/**
* ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
* @msg: RADIUS response message
@@ -1592,7 +1799,8 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct sta_info *sta;
u32 session_timeout = 0, termination_action, acct_interim_interval;
- int session_timeout_set, vlan_id = 0;
+ int session_timeout_set;
+ u32 reason_code;
struct eapol_state_machine *sm;
int override_eapReq = 0;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
@@ -1659,51 +1867,35 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_id = 0;
#ifndef CONFIG_NO_VLAN
- else
- vlan_id = radius_msg_get_vlanid(msg);
- if (vlan_id > 0 &&
- hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO,
- "VLAN ID %d", vlan_id);
- } else if (vlan_id > 0) {
- sta->eapol_sm->authFail = TRUE;
+ if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+ ieee802_1x_update_vlan(msg, hapd, sta) < 0)
+ break;
+
+ if (sta->vlan_id > 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "Invalid VLAN ID %d received from RADIUS server",
- vlan_id);
- break;
- } else if (hapd->conf->ssid.dynamic_vlan ==
- DYNAMIC_VLAN_REQUIRED) {
- sta->eapol_sm->authFail = TRUE;
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_INFO, "authentication "
- "server did not include required VLAN "
- "ID in Access-Accept");
- break;
+ "VLAN ID %d", sta->vlan_id);
}
-#endif /* CONFIG_NO_VLAN */
- sta->vlan_id = vlan_id;
if ((sta->flags & WLAN_STA_ASSOC) &&
ap_sta_bind_vlan(hapd, sta) < 0)
break;
+#endif /* CONFIG_NO_VLAN */
sta->session_timeout_set = !!session_timeout_set;
- sta->session_timeout = session_timeout;
+ os_get_reltime(&sta->session_timeout);
+ sta->session_timeout.sec += session_timeout;
/* RFC 3580, Ch. 3.17 */
if (session_timeout_set && termination_action ==
- RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
+ RADIUS_TERMINATION_ACTION_RADIUS_REQUEST)
sm->reAuthPeriod = session_timeout;
- } else if (session_timeout_set)
+ else if (session_timeout_set)
ap_sta_session_timeout(hapd, sta, session_timeout);
+ else
+ ap_sta_no_session_timeout(hapd, sta);
sm->eap_if->aaaSuccess = TRUE;
override_eapReq = 1;
@@ -1715,19 +1907,17 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
ieee802_1x_check_hs20(hapd, sta, msg,
session_timeout_set ?
(int) session_timeout : -1);
- if (sm->eap_if->eapKeyAvailable && !sta->remediation &&
- !sta->hs20_deauth_requested &&
- wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
- session_timeout_set ?
- (int) session_timeout : -1, sm) == 0) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
- HOSTAPD_LEVEL_DEBUG,
- "Added PMKSA cache entry");
- }
break;
case RADIUS_CODE_ACCESS_REJECT:
sm->eap_if->aaaFail = TRUE;
override_eapReq = 1;
+ if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
+ &reason_code) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for "
+ MACSTR, reason_code, MAC2STR(sta->addr));
+ sta->disconnect_reason_code = reason_code;
+ }
break;
case RADIUS_CODE_ACCESS_CHALLENGE:
sm->eap_if->aaaEapReq = TRUE;
@@ -1754,6 +1944,19 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
if (override_eapReq)
sm->eap_if->aaaEapReq = FALSE;
+#ifdef CONFIG_FILS
+#ifdef NEED_AP_MLME
+ if (sta->flags & WLAN_STA_PENDING_FILS_ERP) {
+ /* TODO: Add a PMKSA entry on success? */
+ ieee802_11_finish_fils_auth(
+ hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
+ sm->eap_if->aaaEapReqData,
+ sm->eap_if->aaaEapKeyData,
+ sm->eap_if->aaaEapKeyDataLen);
+ }
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_FILS */
+
eapol_auth_step(sm);
return RADIUS_RX_QUEUED;
@@ -1841,7 +2044,7 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
eapol->default_wep_key_idx);
-
+
if (ieee802_1x_rekey_broadcast(hapd)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, "failed to generate a "
@@ -1951,13 +2154,19 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
}
if (eap_user->password) {
- user->password = os_malloc(eap_user->password_len);
+ user->password = os_memdup(eap_user->password,
+ eap_user->password_len);
if (user->password == NULL)
goto out;
- os_memcpy(user->password, eap_user->password,
- eap_user->password_len);
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
+ if (eap_user->salt && eap_user->salt_len) {
+ user->salt = os_memdup(eap_user->salt,
+ eap_user->salt_len);
+ if (!user->salt)
+ goto out;
+ user->salt_len = eap_user->salt_len;
+ }
}
user->force_version = eap_user->force_version;
user->macacl = eap_user->macacl;
@@ -2107,6 +2316,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.erp_domain = hapd->conf->erp_domain;
conf.erp = hapd->conf->eap_server_erp;
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ conf.tls_flags = hapd->conf->tls_flags;
conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
@@ -2190,7 +2400,7 @@ void ieee802_1x_deinit(struct hostapd_data *hapd)
{
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
- if (hapd->driver != NULL &&
+ if (hapd->driver && hapd->drv_priv &&
(hapd->conf->ieee802_1x || hapd->conf->wpa))
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
@@ -2243,6 +2453,16 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
MAC2STR(sta->addr), xhdr->version, xhdr->type,
be_to_host16(xhdr->length), ack);
+#ifdef CONFIG_WPS
+ if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack &&
+ (sta->flags & WLAN_STA_WPS) &&
+ ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Indicate EAP completion on ACK for EAP-Failure");
+ hostapd_wps_eap_completed(hapd);
+ }
+#endif /* CONFIG_WPS */
+
if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
return 0;
@@ -2375,6 +2595,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
struct os_reltime diff;
const char *name1;
const char *name2;
+ char *identity_buf = NULL;
if (sm == NULL)
return 0;
@@ -2490,31 +2711,41 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
/* dot1xAuthSessionStatsTable */
os_reltime_age(&sta->acct_session_start, &diff);
+ if (sm->eap && !sm->identity) {
+ const u8 *id;
+ size_t id_len;
+
+ id = eap_get_identity(sm->eap, &id_len);
+ if (id)
+ identity_buf = dup_binstr(id, id_len);
+ }
ret = os_snprintf(buf + len, buflen - len,
/* TODO: dot1xAuthSessionOctetsRx */
/* TODO: dot1xAuthSessionOctetsTx */
/* TODO: dot1xAuthSessionFramesRx */
/* TODO: dot1xAuthSessionFramesTx */
- "dot1xAuthSessionId=%08X-%08X\n"
+ "dot1xAuthSessionId=%016llX\n"
"dot1xAuthSessionAuthenticMethod=%d\n"
"dot1xAuthSessionTime=%u\n"
"dot1xAuthSessionTerminateCause=999\n"
"dot1xAuthSessionUserName=%s\n",
- sta->acct_session_id_hi, sta->acct_session_id_lo,
+ (unsigned long long) sta->acct_session_id,
(wpa_key_mgmt_wpa_ieee8021x(
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
1 : 2,
(unsigned int) diff.sec,
- sm->identity);
+ sm->identity ? (char *) sm->identity :
+ (identity_buf ? identity_buf : "N/A"));
+ os_free(identity_buf);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
- if (sm->acct_multi_session_id_hi) {
+ if (sm->acct_multi_session_id) {
ret = os_snprintf(buf + len, buflen - len,
- "authMultiSessionId=%08X+%08X\n",
- sm->acct_multi_session_id_hi,
- sm->acct_multi_session_id_lo);
+ "authMultiSessionId=%016llX\n",
+ (unsigned long long)
+ sm->acct_multi_session_id);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2535,6 +2766,43 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
}
+#ifdef CONFIG_HS20
+static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+
+ if (sta->remediation) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+ MACSTR " to indicate Subscription Remediation",
+ MAC2STR(sta->addr));
+ hs20_send_wnm_notification(hapd, sta->addr,
+ sta->remediation_method,
+ sta->remediation_url);
+ os_free(sta->remediation_url);
+ sta->remediation_url = NULL;
+ }
+
+ if (sta->hs20_deauth_req) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+ MACSTR " to indicate imminent deauthentication",
+ MAC2STR(sta->addr));
+ hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
+ sta->hs20_deauth_req);
+ }
+
+ if (sta->hs20_t_c_filtering) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+ MACSTR " to indicate Terms and Conditions filtering",
+ MAC2STR(sta->addr));
+ hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url);
+ os_free(sta->t_c_url);
+ sta->t_c_url = NULL;
+ }
+}
+#endif /* CONFIG_HS20 */
+
+
static void ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
int remediation)
@@ -2544,6 +2812,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
/* TODO: get PMKLifetime from WPA parameters */
static const int dot11RSNAConfigPMKLifetime = 43200;
unsigned int session_timeout;
+ struct os_reltime now, remaining;
#ifdef CONFIG_HS20
if (remediation && !sta->remediation) {
@@ -2554,37 +2823,27 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
sta->remediation_method = 1; /* SOAP-XML SPP */
}
- if (success) {
- if (sta->remediation) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
- "to " MACSTR " to indicate Subscription "
- "Remediation",
- MAC2STR(sta->addr));
- hs20_send_wnm_notification(hapd, sta->addr,
- sta->remediation_method,
- sta->remediation_url);
- os_free(sta->remediation_url);
- sta->remediation_url = NULL;
- }
-
- if (sta->hs20_deauth_req) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
- "to " MACSTR " to indicate imminent "
- "deauthentication", MAC2STR(sta->addr));
- hs20_send_wnm_notification_deauth_req(
- hapd, sta->addr, sta->hs20_deauth_req);
- }
+ if (success && (sta->remediation || sta->hs20_deauth_req ||
+ sta->hs20_t_c_filtering)) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
+ MACSTR " in 100 ms", MAC2STR(sta->addr));
+ eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
+ eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send,
+ hapd, sta);
}
#endif /* CONFIG_HS20 */
key = ieee802_1x_get_key(sta->eapol_sm, &len);
- if (sta->session_timeout_set)
- session_timeout = sta->session_timeout;
- else
+ if (sta->session_timeout_set) {
+ os_get_reltime(&now);
+ os_reltime_sub(&sta->session_timeout, &now, &remaining);
+ session_timeout = (remaining.sec > 0) ? remaining.sec : 1;
+ } else {
session_timeout = dot11RSNAConfigPMKLifetime;
+ }
if (success && key && len >= PMK_LEN && !sta->remediation &&
!sta->hs20_deauth_requested &&
- wpa_auth_pmksa_add(sta->wpa_sm, key, session_timeout,
+ wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
sta->eapol_sm) == 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
@@ -2602,15 +2861,6 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
* EAP-FAST with anonymous provisioning, may require another
* EAPOL authentication to be started to complete connection.
*/
- wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
- "disconnection after EAP-Failure");
- /* Add a small sleep to increase likelihood of previously
- * requested EAP-Failure TX getting out before this should the
- * driver reorder operations.
- */
- os_sleep(0, 10000);
- ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
- hostapd_wps_eap_completed(hapd);
+ ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
}
}
diff --git a/contrib/wpa/src/ap/ieee802_1x.h b/contrib/wpa/src/ap/ieee802_1x.h
index 14d6955..9594661 100644
--- a/contrib/wpa/src/ap/ieee802_1x.h
+++ b/contrib/wpa/src/ap/ieee802_1x.h
@@ -21,7 +21,7 @@ struct radius_msg;
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
size_t len);
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
-void ieee802_1x_free_station(struct sta_info *sta);
+void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
@@ -57,5 +57,10 @@ int add_common_radius_attr(struct hostapd_data *hapd,
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg);
+void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *eap, size_t len);
+struct eapol_state_machine *
+ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* IEEE802_1X_H */
diff --git a/contrib/wpa/src/ap/mbo_ap.c b/contrib/wpa/src/ap/mbo_ap.c
new file mode 100644
index 0000000..43b0bf1
--- /dev/null
+++ b/contrib/wpa/src/ap/mbo_ap.c
@@ -0,0 +1,244 @@
+/*
+ * hostapd - MBO
+ * Copyright (c) 2016, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "mbo_ap.h"
+
+
+void mbo_ap_sta_free(struct sta_info *sta)
+{
+ struct mbo_non_pref_chan_info *info, *prev;
+
+ info = sta->non_pref_chan;
+ sta->non_pref_chan = NULL;
+ while (info) {
+ prev = info;
+ info = info->next;
+ os_free(prev);
+ }
+}
+
+
+static void mbo_ap_parse_non_pref_chan(struct sta_info *sta,
+ const u8 *buf, size_t len)
+{
+ struct mbo_non_pref_chan_info *info, *tmp;
+ char channels[200], *pos, *end;
+ size_t num_chan, i;
+ int ret;
+
+ if (len <= 3)
+ return; /* Not enough room for any channels */
+
+ num_chan = len - 3;
+ info = os_zalloc(sizeof(*info) + num_chan);
+ if (!info)
+ return;
+ info->op_class = buf[0];
+ info->pref = buf[len - 2];
+ info->reason_code = buf[len - 1];
+ info->num_channels = num_chan;
+ buf++;
+ os_memcpy(info->channels, buf, num_chan);
+ if (!sta->non_pref_chan) {
+ sta->non_pref_chan = info;
+ } else {
+ tmp = sta->non_pref_chan;
+ while (tmp->next)
+ tmp = tmp->next;
+ tmp->next = info;
+ }
+
+ pos = channels;
+ end = pos + sizeof(channels);
+ *pos = '\0';
+ for (i = 0; i < num_chan; i++) {
+ ret = os_snprintf(pos, end - pos, "%s%u",
+ i == 0 ? "" : " ", buf[i]);
+ if (os_snprintf_error(end - pos, ret)) {
+ *pos = '\0';
+ break;
+ }
+ pos += ret;
+ }
+
+ wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
+ " non-preferred channel list (op class %u, pref %u, reason code %u, channels %s)",
+ MAC2STR(sta->addr), info->op_class, info->pref,
+ info->reason_code, channels);
+}
+
+
+void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
+ struct ieee802_11_elems *elems)
+{
+ const u8 *pos, *attr, *end;
+ size_t len;
+
+ if (!hapd->conf->mbo_enabled || !elems->mbo)
+ return;
+
+ pos = elems->mbo + 4;
+ len = elems->mbo_len - 4;
+ wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len);
+
+ attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA);
+ if (attr && attr[1] >= 1)
+ sta->cell_capa = attr[2];
+
+ mbo_ap_sta_free(sta);
+ end = pos + len;
+ while (end - pos > 1) {
+ u8 ie_len = pos[1];
+
+ if (2 + ie_len > end - pos)
+ break;
+
+ if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT)
+ mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len);
+ pos += 2 + pos[1];
+ }
+}
+
+
+int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen)
+{
+ char *pos = buf, *end = buf + buflen;
+ int ret;
+ struct mbo_non_pref_chan_info *info;
+ u8 i;
+ unsigned int count = 0;
+
+ if (!sta->cell_capa)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos, "mbo_cell_capa=%u\n", sta->cell_capa);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ for (info = sta->non_pref_chan; info; info = info->next) {
+ char *pos2 = pos;
+
+ ret = os_snprintf(pos2, end - pos2,
+ "non_pref_chan[%u]=%u:%u:%u:",
+ count, info->op_class, info->pref,
+ info->reason_code);
+ count++;
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ for (i = 0; i < info->num_channels; i++) {
+ ret = os_snprintf(pos2, end - pos2, "%u%s",
+ info->channels[i],
+ i + 1 < info->num_channels ?
+ "," : "");
+ if (os_snprintf_error(end - pos2, ret)) {
+ pos2 = NULL;
+ break;
+ }
+ pos2 += ret;
+ }
+
+ if (!pos2)
+ break;
+ ret = os_snprintf(pos2, end - pos2, "\n");
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+ pos = pos2;
+ }
+
+ return pos - buf;
+}
+
+
+static void mbo_ap_wnm_notif_req_cell_capa(struct sta_info *sta,
+ const u8 *buf, size_t len)
+{
+ if (len < 1)
+ return;
+ wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
+ " updated cellular data capability: %u",
+ MAC2STR(sta->addr), buf[0]);
+ sta->cell_capa = buf[0];
+}
+
+
+static void mbo_ap_wnm_notif_req_elem(struct sta_info *sta, u8 type,
+ const u8 *buf, size_t len,
+ int *first_non_pref_chan)
+{
+ switch (type) {
+ case WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT:
+ if (*first_non_pref_chan) {
+ /*
+ * Need to free the previously stored entries now to
+ * allow the update to replace all entries.
+ */
+ *first_non_pref_chan = 0;
+ mbo_ap_sta_free(sta);
+ }
+ mbo_ap_parse_non_pref_chan(sta, buf, len);
+ break;
+ case WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA:
+ mbo_ap_wnm_notif_req_cell_capa(sta, buf, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "MBO: Ignore unknown WNM Notification WFA subelement %u",
+ type);
+ break;
+ }
+}
+
+
+void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *buf, size_t len)
+{
+ const u8 *pos, *end;
+ u8 ie_len;
+ struct sta_info *sta;
+ int first_non_pref_chan = 1;
+
+ if (!hapd->conf->mbo_enabled)
+ return;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return;
+
+ pos = buf;
+ end = buf + len;
+
+ while (end - pos > 1) {
+ ie_len = pos[1];
+
+ if (2 + ie_len > end - pos)
+ break;
+
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA)
+ mbo_ap_wnm_notif_req_elem(sta, pos[5],
+ pos + 6, ie_len - 4,
+ &first_non_pref_chan);
+ else
+ wpa_printf(MSG_DEBUG,
+ "MBO: Ignore unknown WNM Notification element %u (len=%u)",
+ pos[0], pos[1]);
+
+ pos += 2 + pos[1];
+ }
+}
diff --git a/contrib/wpa/src/ap/mbo_ap.h b/contrib/wpa/src/ap/mbo_ap.h
new file mode 100644
index 0000000..9f37f28
--- /dev/null
+++ b/contrib/wpa/src/ap/mbo_ap.h
@@ -0,0 +1,51 @@
+/*
+ * MBO related functions and structures
+ * Copyright (c) 2016, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MBO_AP_H
+#define MBO_AP_H
+
+struct hostapd_data;
+struct sta_info;
+struct ieee802_11_elems;
+
+#ifdef CONFIG_MBO
+
+void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
+ struct ieee802_11_elems *elems);
+int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen);
+void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *buf, size_t len);
+void mbo_ap_sta_free(struct sta_info *sta);
+
+#else /* CONFIG_MBO */
+
+static inline void mbo_ap_check_sta_assoc(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct ieee802_11_elems *elems)
+{
+}
+
+static inline int mbo_ap_get_info(struct sta_info *sta, char *buf,
+ size_t buflen)
+{
+ return 0;
+}
+
+static inline void mbo_ap_wnm_notification_req(struct hostapd_data *hapd,
+ const u8 *addr,
+ const u8 *buf, size_t len)
+{
+}
+
+static inline void mbo_ap_sta_free(struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_MBO */
+
+#endif /* MBO_AP_H */
diff --git a/contrib/wpa/src/ap/ndisc_snoop.c b/contrib/wpa/src/ap/ndisc_snoop.c
index 4a87721..4d6a92e 100644
--- a/contrib/wpa/src/ap/ndisc_snoop.c
+++ b/contrib/wpa/src/ap/ndisc_snoop.c
@@ -17,6 +17,7 @@
#include "ap_drv_ops.h"
#include "list.h"
#include "x_snoop.h"
+#include "ndisc_snoop.h"
struct ip6addr {
struct in6_addr addr;
@@ -181,4 +182,5 @@ int ndisc_snoop_init(struct hostapd_data *hapd)
void ndisc_snoop_deinit(struct hostapd_data *hapd)
{
l2_packet_deinit(hapd->sock_ndisc);
+ hapd->sock_ndisc = NULL;
}
diff --git a/contrib/wpa/src/ap/neighbor_db.c b/contrib/wpa/src/ap/neighbor_db.c
new file mode 100644
index 0000000..2b6f727
--- /dev/null
+++ b/contrib/wpa/src/ap/neighbor_db.c
@@ -0,0 +1,257 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "neighbor_db.h"
+
+
+struct hostapd_neighbor_entry *
+hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
+ (!ssid ||
+ (ssid->ssid_len == nr->ssid.ssid_len &&
+ os_memcmp(ssid->ssid, nr->ssid.ssid,
+ ssid->ssid_len) == 0)))
+ return nr;
+ }
+ return NULL;
+}
+
+
+static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
+{
+ wpabuf_free(nr->nr);
+ nr->nr = NULL;
+ wpabuf_free(nr->lci);
+ nr->lci = NULL;
+ wpabuf_free(nr->civic);
+ nr->civic = NULL;
+ os_memset(nr->bssid, 0, sizeof(nr->bssid));
+ os_memset(&nr->ssid, 0, sizeof(nr->ssid));
+ nr->stationary = 0;
+}
+
+
+static struct hostapd_neighbor_entry *
+hostapd_neighbor_add(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ nr = os_zalloc(sizeof(struct hostapd_neighbor_entry));
+ if (!nr)
+ return NULL;
+
+ dl_list_add(&hapd->nr_db, &nr->list);
+
+ return nr;
+}
+
+
+int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid,
+ const struct wpabuf *nr, const struct wpabuf *lci,
+ const struct wpabuf *civic, int stationary)
+{
+ struct hostapd_neighbor_entry *entry;
+
+ entry = hostapd_neighbor_get(hapd, bssid, ssid);
+ if (!entry)
+ entry = hostapd_neighbor_add(hapd);
+ if (!entry)
+ return -1;
+
+ hostapd_neighbor_clear_entry(entry);
+
+ os_memcpy(entry->bssid, bssid, ETH_ALEN);
+ os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
+
+ entry->nr = wpabuf_dup(nr);
+ if (!entry->nr)
+ goto fail;
+
+ if (lci && wpabuf_len(lci)) {
+ entry->lci = wpabuf_dup(lci);
+ if (!entry->lci || os_get_time(&entry->lci_date))
+ goto fail;
+ }
+
+ if (civic && wpabuf_len(civic)) {
+ entry->civic = wpabuf_dup(civic);
+ if (!entry->civic)
+ goto fail;
+ }
+
+ entry->stationary = stationary;
+
+ return 0;
+
+fail:
+ hostapd_neighbor_remove(hapd, bssid, ssid);
+ return -1;
+}
+
+
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ nr = hostapd_neighbor_get(hapd, bssid, ssid);
+ if (!nr)
+ return -1;
+
+ hostapd_neighbor_clear_entry(nr);
+ dl_list_del(&nr->list);
+ os_free(nr);
+
+ return 0;
+}
+
+
+void hostapd_free_neighbor_db(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr, *prev;
+
+ dl_list_for_each_safe(nr, prev, &hapd->nr_db,
+ struct hostapd_neighbor_entry, list) {
+ hostapd_neighbor_clear_entry(nr);
+ dl_list_del(&nr->list);
+ os_free(nr);
+ }
+}
+
+
+#ifdef NEED_AP_MLME
+static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
+ int ht, int vht)
+{
+ if (!ht && !vht)
+ return NR_CHAN_WIDTH_20;
+ if (!hapd->iconf->secondary_channel)
+ return NR_CHAN_WIDTH_20;
+ if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
+ return NR_CHAN_WIDTH_40;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ return NR_CHAN_WIDTH_80;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
+ return NR_CHAN_WIDTH_160;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ return NR_CHAN_WIDTH_80P80;
+ return NR_CHAN_WIDTH_20;
+}
+#endif /* NEED_AP_MLME */
+
+
+void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
+{
+#ifdef NEED_AP_MLME
+ u16 capab = hostapd_own_capab_info(hapd);
+ int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
+ int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
+ struct wpa_ssid_value ssid;
+ u8 channel, op_class;
+ u8 center_freq1_idx = 0, center_freq2_idx = 0;
+ enum nr_chan_width width;
+ u32 bssid_info;
+ struct wpabuf *nr;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+ return;
+
+ bssid_info = 3; /* AP is reachable */
+ bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
+ bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
+
+ if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+
+ bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
+
+ if (hapd->conf->wmm_enabled) {
+ bssid_info |= NEI_REP_BSSID_INFO_QOS;
+
+ if (hapd->conf->wmm_uapsd &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
+ bssid_info |= NEI_REP_BSSID_INFO_APSD;
+ }
+
+ if (ht) {
+ bssid_info |= NEI_REP_BSSID_INFO_HT |
+ NEI_REP_BSSID_INFO_DELAYED_BA;
+
+ /* VHT bit added in IEEE P802.11-REVmc/D4.3 */
+ if (vht)
+ bssid_info |= NEI_REP_BSSID_INFO_VHT;
+ }
+
+ /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
+
+ if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ &op_class, &channel) ==
+ NUM_HOSTAPD_MODES)
+ return;
+ width = hostapd_get_nr_chan_width(hapd, ht, vht);
+ if (vht) {
+ center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
+ if (width == NR_CHAN_WIDTH_80P80)
+ center_freq2_idx =
+ hapd->iconf->vht_oper_centr_freq_seg1_idx;
+ } else if (ht) {
+ ieee80211_freq_to_chan(hapd->iface->freq +
+ 10 * hapd->iconf->secondary_channel,
+ &center_freq1_idx);
+ }
+
+ ssid.ssid_len = hapd->conf->ssid.ssid_len;
+ os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+
+ /*
+ * Neighbor Report element size = BSSID + BSSID info + op_class + chan +
+ * phy type + wide bandwidth channel subelement.
+ */
+ nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
+ if (!nr)
+ return;
+
+ wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
+ wpabuf_put_le32(nr, bssid_info);
+ wpabuf_put_u8(nr, op_class);
+ wpabuf_put_u8(nr, channel);
+ wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
+
+ /*
+ * Wide Bandwidth Channel subelement may be needed to allow the
+ * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
+ * Figure 9-301.
+ */
+ wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
+ wpabuf_put_u8(nr, 3);
+ wpabuf_put_u8(nr, width);
+ wpabuf_put_u8(nr, center_freq1_idx);
+ wpabuf_put_u8(nr, center_freq2_idx);
+
+ hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
+ hapd->iconf->civic, hapd->iconf->stationary_ap);
+
+ wpabuf_free(nr);
+#endif /* NEED_AP_MLME */
+}
diff --git a/contrib/wpa/src/ap/neighbor_db.h b/contrib/wpa/src/ap/neighbor_db.h
new file mode 100644
index 0000000..9c8f4f2
--- /dev/null
+++ b/contrib/wpa/src/ap/neighbor_db.h
@@ -0,0 +1,25 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NEIGHBOR_DB_H
+#define NEIGHBOR_DB_H
+
+struct hostapd_neighbor_entry *
+hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid);
+int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid,
+ const struct wpabuf *nr, const struct wpabuf *lci,
+ const struct wpabuf *civic, int stationary);
+void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid);
+void hostapd_free_neighbor_db(struct hostapd_data *hapd);
+
+#endif /* NEIGHBOR_DB_H */
diff --git a/contrib/wpa/src/ap/peerkey_auth.c b/contrib/wpa/src/ap/peerkey_auth.c
deleted file mode 100644
index efc1d7e..0000000
--- a/contrib/wpa/src/ap/peerkey_auth.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * hostapd - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "crypto/random.h"
-#include "wpa_auth.h"
-#include "wpa_auth_i.h"
-#include "wpa_auth_ie.h"
-
-#ifdef CONFIG_PEERKEY
-
-static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
-{
-#if 0
- struct wpa_authenticator *wpa_auth = eloop_ctx;
- struct wpa_stsl_negotiation *neg = timeout_ctx;
-#endif
-
- /* TODO: ? */
-}
-
-
-struct wpa_stsl_search {
- const u8 *addr;
- struct wpa_state_machine *sm;
-};
-
-
-static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
-{
- struct wpa_stsl_search *search = ctx;
- if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
- search->sm = sm;
- return 1;
- }
- return 0;
-}
-
-
-static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, const u8 *peer,
- u16 mui, u16 error_type)
-{
- u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
- 2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
- u8 *pos;
- struct rsn_error_kde error;
-
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "Sending SMK Error");
-
- pos = kde;
-
- if (peer) {
- pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
- NULL, 0);
- }
-
- error.mui = host_to_be16(mui);
- error.error_type = host_to_be16(error_type);
- pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
- (u8 *) &error, sizeof(error), NULL, 0);
-
- __wpa_send_eapol(wpa_auth, sm,
- WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
- WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
- NULL, NULL, kde, pos - kde, 0, 0, 0);
-}
-
-
-void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key,
- const u8 *key_data, size_t key_data_len)
-{
- struct wpa_eapol_ie_parse kde;
- struct wpa_stsl_search search;
- u8 *buf, *pos;
- size_t buf_len;
-
- if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
- wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
- return;
- }
-
- if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
- kde.mac_addr_len < ETH_ALEN) {
- wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
- "SMK M1");
- return;
- }
-
- /* Initiator = sm->addr; Peer = kde.mac_addr */
-
- search.addr = kde.mac_addr;
- search.sm = NULL;
- if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
- 0 || search.sm == NULL) {
- wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
- " aborted - STA not associated anymore",
- MAC2STR(kde.mac_addr));
- wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
- STK_ERR_STA_NR);
- /* FIX: wpa_stsl_remove(wpa_auth, neg); */
- return;
- }
-
- buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
- buf = os_malloc(buf_len);
- if (buf == NULL)
- return;
- /* Initiator RSN IE */
- os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
- pos = buf + kde.rsn_ie_len;
- /* Initiator MAC Address */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
- NULL, 0);
-
- /* SMK M2:
- * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
- * MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
- */
-
- wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
- "Sending SMK M2");
-
- __wpa_send_eapol(wpa_auth, search.sm,
- WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
- WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
- NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
-
- os_free(buf);
-}
-
-
-static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
- struct wpa_eapol_key *key,
- struct wpa_eapol_ie_parse *kde,
- const u8 *smk)
-{
- u8 *buf, *pos;
- size_t buf_len;
- u32 lifetime;
-
- /* SMK M4:
- * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
- * MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
- * Lifetime KDE)
- */
-
- buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
- 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
- 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
- 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
- pos = buf = os_malloc(buf_len);
- if (buf == NULL)
- return;
-
- /* Initiator MAC Address */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
- NULL, 0);
-
- /* Initiator Nonce */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
- NULL, 0);
-
- /* SMK with PNonce */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
- key->key_nonce, WPA_NONCE_LEN);
-
- /* Lifetime */
- lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
- (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
-
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "Sending SMK M4");
-
- __wpa_send_eapol(wpa_auth, sm,
- WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
- WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
- NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
-
- os_free(buf);
-}
-
-
-static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
- struct wpa_eapol_key *key,
- struct wpa_eapol_ie_parse *kde,
- const u8 *smk, const u8 *peer)
-{
- u8 *buf, *pos;
- size_t buf_len;
- u32 lifetime;
-
- /* SMK M5:
- * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
- * MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
- * Lifetime KDE))
- */
-
- buf_len = kde->rsn_ie_len +
- 2 + RSN_SELECTOR_LEN + ETH_ALEN +
- 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
- 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
- 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
- pos = buf = os_malloc(buf_len);
- if (buf == NULL)
- return;
-
- /* Peer RSN IE */
- os_memcpy(pos, kde->rsn_ie, kde->rsn_ie_len);
- pos += kde->rsn_ie_len;
-
- /* Peer MAC Address */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
-
- /* PNonce */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
- WPA_NONCE_LEN, NULL, 0);
-
- /* SMK and INonce */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
- kde->nonce, WPA_NONCE_LEN);
-
- /* Lifetime */
- lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
- (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
-
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "Sending SMK M5");
-
- __wpa_send_eapol(wpa_auth, sm,
- WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
- WPA_KEY_INFO_SMK_MESSAGE,
- NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
-
- os_free(buf);
-}
-
-
-void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key,
- const u8 *key_data, size_t key_data_len)
-{
- struct wpa_eapol_ie_parse kde;
- struct wpa_stsl_search search;
- u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
-
- if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
- wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
- return;
- }
-
- if (kde.rsn_ie == NULL ||
- kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
- kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
- wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
- "Nonce KDE in SMK M3");
- return;
- }
-
- /* Peer = sm->addr; Initiator = kde.mac_addr;
- * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
-
- search.addr = kde.mac_addr;
- search.sm = NULL;
- if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
- 0 || search.sm == NULL) {
- wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
- " aborted - STA not associated anymore",
- MAC2STR(kde.mac_addr));
- wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
- STK_ERR_STA_NR);
- /* FIX: wpa_stsl_remove(wpa_auth, neg); */
- return;
- }
-
- if (random_get_bytes(smk, PMK_LEN)) {
- wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
- return;
- }
-
- /* SMK = PRF-256(Random number, "SMK Derivation",
- * AA || Time || INonce || PNonce)
- */
- os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
- pos = buf + ETH_ALEN;
- wpa_get_ntp_timestamp(pos);
- pos += 8;
- os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
- pos += WPA_NONCE_LEN;
- os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
-#ifdef CONFIG_IEEE80211W
- sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
- smk, PMK_LEN);
-#else /* CONFIG_IEEE80211W */
- sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
- smk, PMK_LEN);
-#endif /* CONFIG_IEEE80211W */
-
- wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
-
- wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
- wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
-
- /* Authenticator does not need SMK anymore and it is required to forget
- * it. */
- os_memset(smk, 0, sizeof(*smk));
-}
-
-
-void wpa_smk_error(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
- const u8 *key_data, size_t key_data_len)
-{
- struct wpa_eapol_ie_parse kde;
- struct wpa_stsl_search search;
- struct rsn_error_kde error;
- u16 mui, error_type;
-
- if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
- wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
- return;
- }
-
- if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
- kde.error == NULL || kde.error_len < sizeof(error)) {
- wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
- "SMK Error");
- return;
- }
-
- search.addr = kde.mac_addr;
- search.sm = NULL;
- if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
- 0 || search.sm == NULL) {
- wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
- "associated for SMK Error message from " MACSTR,
- MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
- return;
- }
-
- os_memcpy(&error, kde.error, sizeof(error));
- mui = be_to_host16(error.mui);
- error_type = be_to_host16(error.error_type);
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "STA reported SMK Error: Peer " MACSTR
- " MUI %d Error Type %d",
- MAC2STR(kde.mac_addr), mui, error_type);
-
- wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
-}
-
-
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
- struct wpa_stsl_negotiation *neg)
-{
- struct wpa_stsl_negotiation *pos, *prev;
-
- if (wpa_auth == NULL)
- return -1;
- pos = wpa_auth->stsl_negotiations;
- prev = NULL;
- while (pos) {
- if (pos == neg) {
- if (prev)
- prev->next = pos->next;
- else
- wpa_auth->stsl_negotiations = pos->next;
-
- eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
- os_free(pos);
- return 0;
- }
- prev = pos;
- pos = pos->next;
- }
-
- return -1;
-}
-
-#endif /* CONFIG_PEERKEY */
diff --git a/contrib/wpa/src/ap/pmksa_cache_auth.c b/contrib/wpa/src/ap/pmksa_cache_auth.c
index 877affe..15e2c49 100644
--- a/contrib/wpa/src/ap/pmksa_cache_auth.c
+++ b/contrib/wpa/src/ap/pmksa_cache_auth.c
@@ -38,6 +38,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
+ os_free(entry->vlan_desc);
os_free(entry->identity);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
@@ -91,6 +92,20 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
}
+/**
+ * pmksa_cache_auth_flush - Flush all PMKSA cache entries
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ */
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
+{
+ while (pmksa->pmksa) {
+ wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
+ MACSTR, MAC2STR(pmksa->pmksa->spa));
+ pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+ }
+}
+
+
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
@@ -126,6 +141,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
+ struct vlan_description *vlan_desc;
+
if (eapol == NULL)
return;
@@ -146,14 +163,22 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = eapol->eap_type_authsrv;
- entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
- entry->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
- entry->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo;
+ vlan_desc = ((struct sta_info *) eapol->sta)->vlan_desc;
+ if (vlan_desc && vlan_desc->notempty) {
+ entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+ if (entry->vlan_desc)
+ *entry->vlan_desc = *vlan_desc;
+ } else {
+ entry->vlan_desc = NULL;
+ }
+
+ entry->acct_multi_session_id = eapol->acct_multi_session_id;
}
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+ struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
if (entry == NULL || eapol == NULL)
@@ -186,10 +211,11 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
- ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+#ifndef CONFIG_NO_VLAN
+ ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
+#endif /* CONFIG_NO_VLAN */
- eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
- eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
+ eapol->acct_multi_session_id = entry->acct_multi_session_id;
}
@@ -234,6 +260,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @pmkid: Calculated PMKID
* @kck: Key confirmation key or %NULL if not yet derived
* @kck_len: KCK length in bytes
* @aa: Authenticator address
@@ -250,15 +277,50 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
- const u8 *pmk, size_t pmk_len,
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
{
- struct rsn_pmksa_cache_entry *entry, *pos;
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, kck, kck_len,
+ aa, spa, session_timeout, eapol,
+ akmp);
+
+ if (pmksa_cache_auth_add_entry(pmksa, entry) < 0)
+ return NULL;
+
+ return entry;
+}
+
+
+/**
+ * pmksa_cache_auth_create_entry - Create a PMKSA cache entry
+ * @pmk: The new pairwise master key
+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @pmkid: Calculated PMKID
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @session_timeout: Session timeout
+ * @eapol: Pointer to EAPOL state machine data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function creates a PMKSA entry.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, int session_timeout,
+ struct eapol_state_machine *eapol, int akmp)
+{
+ struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
- if (pmk_len > PMK_LEN)
+ if (pmk_len > PMK_LEN_MAX)
return NULL;
if (wpa_key_mgmt_suite_b(akmp) && !kck)
@@ -269,13 +331,14 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ if (pmkid)
+ os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+ else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
else if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
else
- rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
- wpa_key_mgmt_sha256(akmp));
+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, akmp);
os_get_reltime(&now);
entry->expiration = now.sec;
if (session_timeout > 0)
@@ -286,9 +349,30 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
os_memcpy(entry->spa, spa, ETH_ALEN);
pmksa_cache_from_eapol_data(entry, eapol);
+ return entry;
+}
+
+
+/**
+ * pmksa_cache_auth_add_entry - Add a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @entry: Pointer to PMKSA cache entry
+ *
+ * This function adds PMKSA cache entry to the PMKSA cache. If an old entry is
+ * already in the cache for the same Supplicant, this entry will be replaced
+ * with the new entry. PMKID will be calculated based on the PMK.
+ */
+int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ struct rsn_pmksa_cache_entry *pos;
+
+ if (entry == NULL)
+ return -1;
+
/* Replace an old entry for the same STA (if found) with the new entry
*/
- pos = pmksa_cache_auth_get(pmksa, spa, NULL);
+ pos = pmksa_cache_auth_get(pmksa, entry->spa, NULL);
if (pos)
pmksa_cache_free_entry(pmksa, pos);
@@ -302,7 +386,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
pmksa_cache_link_entry(pmksa, entry);
- return entry;
+ return 0;
}
@@ -337,7 +421,13 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = old_entry->eap_type_authsrv;
- entry->vlan_id = old_entry->vlan_id;
+ if (old_entry->vlan_desc) {
+ entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+ if (entry->vlan_desc)
+ *entry->vlan_desc = *old_entry->vlan_desc;
+ } else {
+ entry->vlan_desc = NULL;
+ }
entry->opportunistic = 1;
pmksa_cache_link_entry(pmksa, entry);
@@ -427,7 +517,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
- wpa_key_mgmt_sha256(entry->akmp));
+ entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
return entry;
}
@@ -471,12 +561,11 @@ static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
if (attr->acct_multi_session_id) {
char buf[20];
- if (attr->acct_multi_session_id_len != 17)
+ if (attr->acct_multi_session_id_len != 16)
return 0;
- os_snprintf(buf, sizeof(buf), "%08X+%08X",
- entry->acct_multi_session_id_hi,
- entry->acct_multi_session_id_lo);
- if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) entry->acct_multi_session_id);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 0)
return 0;
match++;
}
@@ -526,3 +615,115 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
return found ? 0 : -1;
}
+
+
+/**
+ * pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
+{
+ int i, ret;
+ char *pos = buf;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ ret = os_snprintf(pos, buf + len - pos,
+ "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ i = 0;
+ entry = pmksa->pmksa;
+ while (entry) {
+ ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+ i, MAC2STR(entry->spa));
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
+ PMKID_LEN);
+ ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+ (int) (entry->expiration - now.sec),
+ entry->opportunistic);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ entry = entry->next;
+ }
+ return pos - buf;
+}
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+/**
+ * pmksa_cache_auth_list_mesh - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @addr: MAC address of the peer (NULL means any)
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA_GET command to store
+ * in external storage.
+ */
+int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
+ char *buf, size_t len)
+{
+ int ret;
+ char *pos, *end;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ pos = buf;
+ end = buf + len;
+ os_get_reltime(&now);
+
+
+ /*
+ * Entry format:
+ * <BSSID> <PMKID> <PMK> <expiration in seconds>
+ */
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
+ if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0)
+ continue;
+
+ ret = os_snprintf(pos, end - pos, MACSTR " ",
+ MAC2STR(entry->spa));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos, entry->pmkid,
+ PMKID_LEN);
+
+ ret = os_snprintf(pos, end - pos, " ");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos, entry->pmk,
+ entry->pmk_len);
+
+ ret = os_snprintf(pos, end - pos, " %d\n",
+ (int) (entry->expiration - now.sec));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
diff --git a/contrib/wpa/src/ap/pmksa_cache_auth.h b/contrib/wpa/src/ap/pmksa_cache_auth.h
index 8b7be12..2ef2174 100644
--- a/contrib/wpa/src/ap/pmksa_cache_auth.h
+++ b/contrib/wpa/src/ap/pmksa_cache_auth.h
@@ -17,7 +17,7 @@
struct rsn_pmksa_cache_entry {
struct rsn_pmksa_cache_entry *next, *hnext;
u8 pmkid[PMKID_LEN];
- u8 pmk[PMK_LEN];
+ u8 pmk[PMK_LEN_MAX];
size_t pmk_len;
os_time_t expiration;
int akmp; /* WPA_KEY_MGMT_* */
@@ -28,14 +28,14 @@ struct rsn_pmksa_cache_entry {
struct wpabuf *cui;
struct radius_class_data radius_class;
u8 eap_type_authsrv;
- int vlan_id;
+ struct vlan_description *vlan_desc;
int opportunistic;
- u32 acct_multi_session_id_hi;
- u32 acct_multi_session_id_lo;
+ u64 acct_multi_session_id;
};
struct rsn_pmksa_cache;
+struct radius_das_attrs;
struct rsn_pmksa_cache *
pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -49,19 +49,31 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
const u8 *pmkid);
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
- const u8 *pmk, size_t pmk_len,
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, int session_timeout,
+ struct eapol_state_machine *eapol, int akmp);
+int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry);
+struct rsn_pmksa_cache_entry *
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
const u8 *aa, const u8 *pmkid);
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+ struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol);
void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry);
int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
struct radius_das_attrs *attr);
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
+int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
+ char *buf, size_t len);
#endif /* PMKSA_CACHE_H */
diff --git a/contrib/wpa/src/ap/rrm.c b/contrib/wpa/src/ap/rrm.c
new file mode 100644
index 0000000..f2d5cd1
--- /dev/null
+++ b/contrib/wpa/src/ap/rrm.c
@@ -0,0 +1,674 @@
+/*
+ * hostapd / Radio Measurement (RRM)
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ * Copyright (c) 2016-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "eloop.h"
+#include "neighbor_db.h"
+#include "rrm.h"
+
+#define HOSTAPD_RRM_REQUEST_TIMEOUT 5
+
+
+static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "RRM: LCI request (token %u) timed out",
+ hapd->lci_req_token);
+ hapd->lci_req_active = 0;
+}
+
+
+static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token,
+ const u8 *pos, size_t len)
+{
+ if (!hapd->lci_req_active || hapd->lci_req_token != token) {
+ wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %u", token);
+ return;
+ }
+
+ hapd->lci_req_active = 0;
+ eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
+ wpa_printf(MSG_DEBUG, "LCI report token %u len %zu", token, len);
+}
+
+
+static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "RRM: Range request (token %u) timed out",
+ hapd->range_req_token);
+ hapd->range_req_active = 0;
+}
+
+
+static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token,
+ const u8 *pos, size_t len)
+{
+ if (!hapd->range_req_active || hapd->range_req_token != token) {
+ wpa_printf(MSG_DEBUG, "Unexpected range report, token %u",
+ token);
+ return;
+ }
+
+ hapd->range_req_active = 0;
+ eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
+ wpa_printf(MSG_DEBUG, "Range report token %u len %zu", token, len);
+}
+
+
+static void hostapd_handle_beacon_report(struct hostapd_data *hapd,
+ const u8 *addr, u8 token, u8 rep_mode,
+ const u8 *pos, size_t len)
+{
+ char report[2 * 255 + 1];
+
+ wpa_printf(MSG_DEBUG, "Beacon report token %u len %zu from " MACSTR,
+ token, len, MAC2STR(addr));
+ /* Skip to the beginning of the Beacon report */
+ if (len < 3)
+ return;
+ pos += 3;
+ len -= 3;
+ report[0] = '\0';
+ if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0)
+ return;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
+ MAC2STR(addr), token, rep_mode, report);
+}
+
+
+static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+ const u8 *pos, *ie, *end;
+ u8 token, rep_mode;
+
+ end = buf + len;
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+
+ while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
+ if (ie[1] < 3) {
+ wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
+ break;
+ }
+
+ rep_mode = ie[3];
+ wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u",
+ rep_mode, ie[4]);
+
+ switch (ie[4]) {
+ case MEASURE_TYPE_LCI:
+ hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]);
+ break;
+ case MEASURE_TYPE_FTM_RANGE:
+ hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
+ break;
+ case MEASURE_TYPE_BEACON:
+ hostapd_handle_beacon_report(hapd, mgmt->sa, token,
+ rep_mode, ie + 2, ie[1]);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Measurement report type %u is not supported",
+ ie[4]);
+ break;
+ }
+
+ pos = ie + ie[1] + 2;
+ }
+}
+
+
+static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len)
+{
+ const u8 *subelem;
+
+ /* Range Request element + Location Subject + Maximum Age subelement */
+ if (len < 3 + 1 + 4)
+ return 0;
+
+ /* Subelements are arranged as IEs */
+ subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
+ if (subelem && subelem[1] == 2)
+ return WPA_GET_LE16(subelem + 2);
+
+ return 0;
+}
+
+
+static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age)
+{
+ struct os_time curr, diff;
+ unsigned long diff_l;
+
+ if (nr->stationary || max_age == 0xffff)
+ return 1;
+
+ if (!max_age)
+ return 0;
+
+ if (os_get_time(&curr))
+ return 0;
+
+ os_time_sub(&curr, &nr->lci_date, &diff);
+
+ /* avoid overflow */
+ if (diff.sec > 0xffff)
+ return 0;
+
+ /* LCI age is calculated in 10th of a second units. */
+ diff_l = diff.sec * 10 + diff.usec / 100000;
+
+ return max_age > diff_l;
+}
+
+
+static size_t hostapd_neighbor_report_len(struct wpabuf *buf,
+ struct hostapd_neighbor_entry *nr,
+ int send_lci, int send_civic)
+{
+ size_t len = 2 + wpabuf_len(nr->nr);
+
+ if (send_lci && nr->lci)
+ len += 2 + wpabuf_len(nr->lci);
+
+ if (send_civic && nr->civic)
+ len += 2 + wpabuf_len(nr->civic);
+
+ return len;
+}
+
+
+static void hostapd_send_nei_report_resp(struct hostapd_data *hapd,
+ const u8 *addr, u8 dialog_token,
+ struct wpa_ssid_value *ssid, u8 lci,
+ u8 civic, u16 lci_max_age)
+{
+ struct hostapd_neighbor_entry *nr;
+ struct wpabuf *buf;
+ u8 *msmt_token;
+
+ /*
+ * The number and length of the Neighbor Report elements in a Neighbor
+ * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes
+ * of RRM header.
+ */
+ buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE);
+ if (!buf)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE);
+ wpabuf_put_u8(buf, dialog_token);
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ int send_lci;
+ size_t len;
+
+ if (ssid->ssid_len != nr->ssid.ssid_len ||
+ os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0)
+ continue;
+
+ send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age);
+ len = hostapd_neighbor_report_len(buf, nr, send_lci, civic);
+
+ if (len - 2 > 0xff) {
+ wpa_printf(MSG_DEBUG,
+ "NR entry for " MACSTR " exceeds 0xFF bytes",
+ MAC2STR(nr->bssid));
+ continue;
+ }
+
+ if (len > wpabuf_tailroom(buf))
+ break;
+
+ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
+ wpabuf_put_u8(buf, len - 2);
+ wpabuf_put_buf(buf, nr->nr);
+
+ if (send_lci && nr->lci) {
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->lci));
+ /*
+ * Override measurement token - the first byte of the
+ * Measurement Report element.
+ */
+ msmt_token = wpabuf_put(buf, 0);
+ wpabuf_put_buf(buf, nr->lci);
+ *msmt_token = lci;
+ }
+
+ if (civic && nr->civic) {
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->civic));
+ /*
+ * Override measurement token - the first byte of the
+ * Measurement Report element.
+ */
+ msmt_token = wpabuf_put(buf, 0);
+ wpabuf_put_buf(buf, nr->civic);
+ *msmt_token = civic;
+ }
+ }
+
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+}
+
+
+static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+ const u8 *pos, *ie, *end;
+ struct wpa_ssid_value ssid = {
+ .ssid_len = 0
+ };
+ u8 token;
+ u8 lci = 0, civic = 0; /* Measurement tokens */
+ u16 lci_max_age = 0;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+ return;
+
+ end = buf + len;
+
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+ len = end - pos;
+
+ ie = get_ie(pos, len, WLAN_EID_SSID);
+ if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) {
+ ssid.ssid_len = ie[1];
+ os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len);
+ } else {
+ ssid.ssid_len = hapd->conf->ssid.ssid_len;
+ os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+ }
+
+ while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) {
+ if (ie[1] < 3)
+ break;
+
+ wpa_printf(MSG_DEBUG,
+ "Neighbor report request, measure type %u",
+ ie[4]);
+
+ switch (ie[4]) { /* Measurement Type */
+ case MEASURE_TYPE_LCI:
+ lci = ie[2]; /* Measurement Token */
+ lci_max_age = hostapd_parse_location_lci_req_age(ie + 2,
+ ie[1]);
+ break;
+ case MEASURE_TYPE_LOCATION_CIVIC:
+ civic = ie[2]; /* Measurement token */
+ break;
+ }
+
+ pos = ie + ie[1] + 2;
+ len = end - pos;
+ }
+
+ hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic,
+ lci_max_age);
+}
+
+
+void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+
+ /*
+ * Check for enough bytes: header + (1B)Category + (1B)Action +
+ * (1B)Dialog Token.
+ */
+ if (len < IEEE80211_HDRLEN + 3)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR,
+ mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
+
+ switch (mgmt->u.action.u.rrm.action) {
+ case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
+ hostapd_handle_radio_msmt_report(hapd, buf, len);
+ break;
+ case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
+ hostapd_handle_nei_report_req(hapd, buf, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
+ mgmt->u.action.u.rrm.action);
+ break;
+ }
+}
+
+
+int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ int ret;
+
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Request LCI: Destination address is not connected");
+ return -1;
+ }
+
+ if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) {
+ wpa_printf(MSG_INFO,
+ "Request LCI: Station does not support LCI in RRM");
+ return -1;
+ }
+
+ if (hapd->lci_req_active) {
+ wpa_printf(MSG_DEBUG,
+ "Request LCI: LCI request is already in process, overriding");
+ hapd->lci_req_active = 0;
+ eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd,
+ NULL);
+ }
+
+ /* Measurement request (5) + Measurement element with LCI (10) */
+ buf = wpabuf_alloc(5 + 10);
+ if (!buf)
+ return -1;
+
+ hapd->lci_req_token++;
+ /* For wraparounds - the token must be nonzero */
+ if (!hapd->lci_req_token)
+ hapd->lci_req_token++;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->lci_req_token);
+ wpabuf_put_le16(buf, 0); /* Number of repetitions */
+
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, 3 + 1 + 4);
+
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+ /*
+ * Parallel and Enable bits are 0, Duration, Request, and Report are
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_u8(buf, MEASURE_TYPE_LCI);
+
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+ wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+ wpabuf_put_u8(buf, 2);
+ wpabuf_put_le16(buf, 0xffff);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret)
+ return ret;
+
+ hapd->lci_req_active = 1;
+
+ eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+ hostapd_lci_rep_timeout_handler, hapd, NULL);
+
+ return 0;
+}
+
+
+int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
+ u16 random_interval, u8 min_ap,
+ const u8 *responders, unsigned int n_responders)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta;
+ u8 *len;
+ unsigned int i;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR
+ " rand interval %u min AP %u n_responders %u", MAC2STR(addr),
+ random_interval, min_ap, n_responders);
+
+ if (min_ap == 0 || min_ap > n_responders) {
+ wpa_printf(MSG_INFO, "Request range: Wrong min AP count");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Request range: Destination address is not connected");
+ return -1;
+ }
+
+ if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "Request range: Destination station does not support FTM range report in RRM");
+ return -1;
+ }
+
+ if (hapd->range_req_active) {
+ wpa_printf(MSG_DEBUG,
+ "Request range: Range request is already in process; overriding");
+ hapd->range_req_active = 0;
+ eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd,
+ NULL);
+ }
+
+ /* Action + measurement type + token + reps + EID + len = 7 */
+ buf = wpabuf_alloc(7 + 255);
+ if (!buf)
+ return -1;
+
+ hapd->range_req_token++;
+ if (!hapd->range_req_token) /* For wraparounds */
+ hapd->range_req_token++;
+
+ /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */
+ wpabuf_put_le16(buf, 0); /* Number of Repetitions */
+
+ /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ len = wpabuf_put(buf, 1); /* Length will be set later */
+
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+ /*
+ * Parallel and Enable bits are 0; Duration, Request, and Report are
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */
+
+ /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */
+ wpabuf_put_le16(buf, random_interval); /* Randomization Interval */
+ wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */
+
+ /* FTM Range Subelements */
+
+ /*
+ * Taking the neighbor report part of the range request from neighbor
+ * database instead of requesting the separate bits of data from the
+ * user.
+ */
+ for (i = 0; i < n_responders; i++) {
+ struct hostapd_neighbor_entry *nr;
+
+ nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i,
+ NULL);
+ if (!nr) {
+ wpa_printf(MSG_INFO, "Missing neighbor report for "
+ MACSTR, MAC2STR(responders + ETH_ALEN * i));
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) {
+ wpa_printf(MSG_ERROR, "Too long range request");
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->nr));
+ wpabuf_put_buf(buf, nr->nr);
+ }
+
+ /* Action + measurement type + token + reps + EID + len = 7 */
+ *len = wpabuf_len(buf) - 7;
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret)
+ return ret;
+
+ hapd->range_req_active = 1;
+
+ eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+ hostapd_range_rep_timeout_handler, hapd, NULL);
+
+ return 0;
+}
+
+
+void hostapd_clean_rrm(struct hostapd_data *hapd)
+{
+ hostapd_free_neighbor_db(hapd);
+ eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
+ hapd->lci_req_active = 0;
+ eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
+ hapd->range_req_active = 0;
+}
+
+
+int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
+ u8 req_mode, const struct wpabuf *req)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ int ret;
+ enum beacon_report_mode mode;
+ const u8 *pos;
+
+ /* Request data:
+ * Operating Class (1), Channel Number (1), Randomization Interval (2),
+ * Measurement Duration (2), Measurement Mode (1), BSSID (6),
+ * Optional Subelements (variable)
+ */
+ if (wpabuf_len(req) < 13) {
+ wpa_printf(MSG_INFO, "Beacon request: Too short request data");
+ return -1;
+ }
+ pos = wpabuf_head(req);
+ mode = pos[6];
+
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Beacon request: " MACSTR " is not connected",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ switch (mode) {
+ case BEACON_REPORT_MODE_PASSIVE:
+ if (!(sta->rrm_enabled_capa[0] &
+ WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) {
+ wpa_printf(MSG_INFO,
+ "Beacon request: " MACSTR
+ " does not support passive beacon report",
+ MAC2STR(addr));
+ return -1;
+ }
+ break;
+ case BEACON_REPORT_MODE_ACTIVE:
+ if (!(sta->rrm_enabled_capa[0] &
+ WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) {
+ wpa_printf(MSG_INFO,
+ "Beacon request: " MACSTR
+ " does not support active beacon report",
+ MAC2STR(addr));
+ return -1;
+ }
+ break;
+ case BEACON_REPORT_MODE_TABLE:
+ if (!(sta->rrm_enabled_capa[0] &
+ WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) {
+ wpa_printf(MSG_INFO,
+ "Beacon request: " MACSTR
+ " does not support table beacon report",
+ MAC2STR(addr));
+ return -1;
+ }
+ break;
+ default:
+ wpa_printf(MSG_INFO,
+ "Beacon request: Unknown measurement mode %d", mode);
+ return -1;
+ }
+
+ buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req));
+ if (!buf)
+ return -1;
+
+ hapd->beacon_req_token++;
+ if (!hapd->beacon_req_token)
+ hapd->beacon_req_token++;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->beacon_req_token);
+ wpabuf_put_le16(buf, 0); /* Number of repetitions */
+
+ /* Measurement Request element */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, 3 + wpabuf_len(req));
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+ wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */
+ wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */
+ wpabuf_put_buf(buf, req);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret < 0)
+ return ret;
+
+ return hapd->beacon_req_token;
+}
+
+
+void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok)
+{
+ if (len < 24 + 3)
+ return;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR
+ " %u ack=%d", MAC2STR(mgmt->da),
+ mgmt->u.action.u.rrm.dialog_token, ok);
+}
diff --git a/contrib/wpa/src/ap/rrm.h b/contrib/wpa/src/ap/rrm.h
new file mode 100644
index 0000000..02cd522
--- /dev/null
+++ b/contrib/wpa/src/ap/rrm.h
@@ -0,0 +1,33 @@
+/*
+ * hostapd / Radio Measurement (RRM)
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RRM_H
+#define RRM_H
+
+/*
+ * Max measure request length is 255, -6 of the body we have 249 for the
+ * neighbor report elements. Each neighbor report element is at least 2 + 13
+ * bytes, so we can't have more than 16 responders in the request.
+ */
+#define RRM_RANGE_REQ_MAX_RESPONDERS 16
+
+void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
+ const u8 *buf, size_t len);
+int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr);
+int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
+ u16 random_interval, u8 min_ap,
+ const u8 *responders, unsigned int n_responders);
+void hostapd_clean_rrm(struct hostapd_data *hapd);
+int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
+ u8 req_mode, const struct wpabuf *req);
+void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok);
+
+#endif /* RRM_H */
diff --git a/contrib/wpa/src/ap/sta_info.c b/contrib/wpa/src/ap/sta_info.c
index d64307c..4f9eae8 100644
--- a/contrib/wpa/src/ap/sta_info.c
+++ b/contrib/wpa/src/ap/sta_info.c
@@ -1,6 +1,6 @@
/*
* hostapd / Station table
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,10 +13,12 @@
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/sae.h"
+#include "common/dpp.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
#include "fst/fst.h"
+#include "crypto/crypto.h"
#include "hostapd.h"
#include "accounting.h"
#include "ieee802_1x.h"
@@ -32,8 +34,11 @@
#include "ap_drv_ops.h"
#include "gas_serv.h"
#include "wnm_ap.h"
+#include "mbo_ap.h"
#include "ndisc_snoop.h"
#include "sta_info.h"
+#include "vlan.h"
+#include "wps_hostapd.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
@@ -45,6 +50,7 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_IEEE80211W */
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
+static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -161,7 +167,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
- if (sta->flags & WLAN_STA_WDS)
+ if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
if (sta->ipaddr)
@@ -169,21 +175,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
ap_sta_ip6addr_del(hapd, sta);
if (!hapd->iface->driver_ap_teardown &&
- !(sta->flags & WLAN_STA_PREAUTH))
+ !(sta->flags & WLAN_STA_PREAUTH)) {
hostapd_drv_sta_remove(hapd, sta->addr);
-
-#ifndef CONFIG_NO_VLAN
- if (sta->vlan_id_bound) {
- /*
- * Need to remove the STA entry before potentially removing the
- * VLAN.
- */
- if (hapd->iface->driver_ap_teardown &&
- !(sta->flags & WLAN_STA_PREAUTH))
- hostapd_drv_sta_remove(hapd, sta->addr);
- vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+ sta->added_unassoc = 0;
}
-#endif /* CONFIG_NO_VLAN */
ap_sta_hash_del(hapd, sta);
ap_sta_list_del(hapd, sta);
@@ -203,7 +198,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->no_short_slot_time_set) {
sta->no_short_slot_time_set = 0;
hapd->iface->num_sta_no_short_slot_time--;
- if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_slot_time == 0)
set_beacon++;
}
@@ -211,7 +207,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->no_short_preamble_set) {
sta->no_short_preamble_set = 0;
hapd->iface->num_sta_no_short_preamble--;
- if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_preamble == 0)
set_beacon++;
}
@@ -231,6 +228,13 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
hapd->iface->num_sta_ht_20mhz--;
}
+#ifdef CONFIG_TAXONOMY
+ wpabuf_free(sta->probe_ie_taxonomy);
+ sta->probe_ie_taxonomy = NULL;
+ wpabuf_free(sta->assoc_ie_taxonomy);
+ sta->assoc_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+
#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta);
#endif /* CONFIG_IEEE80211N */
@@ -251,7 +255,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#ifdef CONFIG_MESH
if (hapd->mesh_sta_free_cb)
- hapd->mesh_sta_free_cb(sta);
+ hapd->mesh_sta_free_cb(hapd, sta);
#endif /* CONFIG_MESH */
if (set_beacon)
@@ -262,11 +266,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
- eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
- eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+ ap_sta_clear_disconnect_timeouts(hapd, sta);
sae_clear_retransmit_timer(hapd, sta);
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
wpa_auth_sta_deinit(sta->wpa_sm);
rsn_preauth_free_station(hapd, sta);
#ifndef CONFIG_NO_RADIUS
@@ -274,6 +277,28 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
radius_client_flush_auth(hapd->radius, sta->addr);
#endif /* CONFIG_NO_RADIUS */
+#ifndef CONFIG_NO_VLAN
+ /*
+ * sta->wpa_sm->group needs to be released before so that
+ * vlan_remove_dynamic() can check that no stations are left on the
+ * AP_VLAN netdev.
+ */
+ if (sta->vlan_id)
+ vlan_remove_dynamic(hapd, sta->vlan_id);
+ if (sta->vlan_id_bound) {
+ /*
+ * Need to remove the STA entry before potentially removing the
+ * VLAN.
+ */
+ if (hapd->iface->driver_ap_teardown &&
+ !(sta->flags & WLAN_STA_PREAUTH)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
+ vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+ }
+#endif /* CONFIG_NO_VLAN */
+
os_free(sta->challenge);
#ifdef CONFIG_IEEE80211W
@@ -297,16 +322,19 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
wpabuf_free(sta->hs20_ie);
+ wpabuf_free(sta->roaming_consortium);
#ifdef CONFIG_FST
wpabuf_free(sta->mb_ies);
#endif /* CONFIG_FST */
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
+ os_free(sta->vht_operation);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
os_free(sta->remediation_url);
+ os_free(sta->t_c_url);
wpabuf_free(sta->hs20_deauth_req);
os_free(sta->hs20_session_info_url);
@@ -315,6 +343,39 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->sae);
#endif /* CONFIG_SAE */
+ mbo_ap_sta_free(sta);
+ os_free(sta->supp_op_classes);
+
+#ifdef CONFIG_FILS
+ os_free(sta->fils_pending_assoc_req);
+ wpabuf_free(sta->fils_hlp_resp);
+ wpabuf_free(sta->hlp_dhcp_discover);
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+#ifdef CONFIG_FILS_SK_PFS
+ crypto_ecdh_deinit(sta->fils_ecdh);
+ wpabuf_clear_free(sta->fils_dh_ss);
+ wpabuf_free(sta->fils_g_sta);
+#endif /* CONFIG_FILS_SK_PFS */
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+ bin_clear_free(sta->owe_pmk, sta->owe_pmk_len);
+ crypto_ecdh_deinit(sta->owe_ecdh);
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+#endif /* CONFIG_DPP2 */
+
+ os_free(sta->ext_capability);
+
+#ifdef CONFIG_WNM_AP
+ eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
+#endif /* CONFIG_WNM_AP */
+
+ os_free(sta->ifname_wds);
+
os_free(sta);
}
@@ -354,8 +415,8 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
unsigned long next_time = 0;
int reason;
- wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
- __func__, MAC2STR(sta->addr), sta->flags,
+ wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
+ hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
sta->timeout_next);
if (sta->timeout_next == STA_REMOVE) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -446,6 +507,13 @@ skip_poll:
} else if (sta->timeout_next != STA_REMOVE) {
int deauth = sta->timeout_next == STA_DEAUTH;
+ if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) {
+ /* Cannot disassociate not-associated STA, so move
+ * directly to deauthentication. */
+ sta->timeout_next = STA_DEAUTH;
+ deauth = 1;
+ }
+
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
"Timeout, sending %s info to STA " MACSTR,
deauth ? "deauthentication" : "disassociation",
@@ -482,7 +550,7 @@ skip_poll:
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
accounting_sta_stop(hapd, sta);
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
@@ -519,6 +587,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
+ wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
if (!(sta->flags & WLAN_STA_AUTH)) {
if (sta->flags & WLAN_STA_GAS) {
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
@@ -573,18 +643,18 @@ void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
{
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
- wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR,
- MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for "
+ MACSTR, hapd->conf->iface, MAC2STR(sta->addr));
if (sta->hs20_session_info_url == NULL)
return;
wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url,
sta->hs20_disassoc_timer);
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
}
@@ -619,7 +689,10 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
return NULL;
}
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
- accounting_sta_get_id(hapd, sta);
+ if (accounting_sta_get_id(hapd, sta) < 0) {
+ os_free(sta);
+ return NULL;
+ }
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
@@ -640,6 +713,11 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
dl_list_init(&sta->ip6addr);
+#ifdef CONFIG_TAXONOMY
+ sta_track_claim_taxonomy_info(hapd->iface, addr,
+ &sta->probe_ie_taxonomy);
+#endif /* CONFIG_TAXONOMY */
+
return sta;
}
@@ -652,14 +730,16 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
ap_sta_ip6addr_del(hapd, sta);
- wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
- MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
+ hapd->conf->iface, MAC2STR(sta->addr));
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
sta->flags & WLAN_STA_ASSOC) {
- wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
- " from kernel driver.", MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
+ " from kernel driver",
+ hapd->conf->iface, MAC2STR(sta->addr));
return -1;
}
+ sta->added_unassoc = 0;
return 0;
}
@@ -683,6 +763,10 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
if (!sta2)
continue;
+ wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR
+ " association from another BSS %s",
+ hapd->conf->iface, MAC2STR(sta2->addr),
+ bss->conf->iface);
ap_sta_disconnect(bss, sta2, sta2->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
@@ -694,6 +778,8 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
+ wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
ap_sta_remove(hapd, sta);
mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
}
@@ -705,9 +791,17 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
- sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ /* Skip deauthentication in DMG/IEEE 802.11ad */
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_ASSOC_REQ_OK);
+ sta->timeout_next = STA_REMOVE;
+ } else {
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ sta->timeout_next = STA_DEAUTH;
+ }
ap_sta_set_authorized(hapd, sta, 0);
- sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
@@ -717,7 +811,9 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
+ wpa_auth_sta_deinit(sta->wpa_sm);
+ sta->wpa_sm = NULL;
sta->disassoc_reason = reason;
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
@@ -733,6 +829,8 @@ static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
+ wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
ap_sta_remove(hapd, sta);
mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
}
@@ -741,6 +839,14 @@ static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ /* Deauthentication is not used in DMG/IEEE 802.11ad;
+ * disassociate the STA instead. */
+ ap_sta_disassociate(hapd, sta, reason);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
@@ -756,7 +862,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
- ieee802_1x_free_station(sta);
+ ieee802_1x_free_station(hapd, sta);
sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
@@ -784,6 +890,125 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
#endif /* CONFIG_WPS */
+static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd)
+{
+ struct hostapd_vlan *vlan;
+ int vlan_id = MAX_VLAN_ID + 2;
+
+retry:
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (vlan->vlan_id == vlan_id) {
+ vlan_id++;
+ goto retry;
+ }
+ }
+ return vlan_id;
+}
+
+
+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+ struct vlan_description *vlan_desc)
+{
+ struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
+ int old_vlan_id, vlan_id = 0, ret = 0;
+
+ /* Check if there is something to do */
+ if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
+ /* This sta is lacking its own vif */
+ } else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED &&
+ !hapd->conf->ssid.per_sta_vif && sta->vlan_id) {
+ /* sta->vlan_id needs to be reset */
+ } else if (!vlan_compare(vlan_desc, sta->vlan_desc)) {
+ return 0; /* nothing to change */
+ }
+
+ /* Now the real VLAN changed or the STA just needs its own vif */
+ if (hapd->conf->ssid.per_sta_vif) {
+ /* Assign a new vif, always */
+ /* find a free vlan_id sufficiently big */
+ vlan_id = ap_sta_get_free_vlan_id(hapd);
+ /* Get wildcard VLAN */
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ break;
+ }
+ if (!vlan) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "per_sta_vif missing wildcard");
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+ } else if (vlan_desc && vlan_desc->notempty) {
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
+ break;
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ wildcard_vlan = vlan;
+ }
+ if (vlan) {
+ vlan_id = vlan->vlan_id;
+ } else if (wildcard_vlan) {
+ vlan = wildcard_vlan;
+ vlan_id = vlan_desc->untagged;
+ if (vlan_desc->tagged[0]) {
+ /* Tagged VLAN configuration */
+ vlan_id = ap_sta_get_free_vlan_id(hapd);
+ }
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "missing vlan and wildcard for vlan=%d%s",
+ vlan_desc->untagged,
+ vlan_desc->tagged[0] ? "+" : "");
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+ }
+
+ if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
+ vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
+ if (vlan == NULL) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "could not add dynamic VLAN interface for vlan=%d%s",
+ vlan_desc ? vlan_desc->untagged : -1,
+ (vlan_desc && vlan_desc->tagged[0]) ?
+ "+" : "");
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "added new dynamic VLAN interface '%s'",
+ vlan->ifname);
+ } else if (vlan && vlan->dynamic_vlan > 0) {
+ vlan->dynamic_vlan++;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "updated existing dynamic VLAN interface '%s'",
+ vlan->ifname);
+ }
+done:
+ old_vlan_id = sta->vlan_id;
+ sta->vlan_id = vlan_id;
+ sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
+
+ if (vlan_id != old_vlan_id && old_vlan_id)
+ vlan_remove_dynamic(hapd, old_vlan_id);
+
+ return ret;
+}
+
+
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
{
#ifndef CONFIG_NO_VLAN
@@ -796,20 +1021,11 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan;
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- sta->vlan_id = 0;
- else if (sta->vlan_id > 0) {
- struct hostapd_vlan *wildcard_vlan = NULL;
- vlan = hapd->conf->vlan;
- while (vlan) {
+ if (sta->vlan_id > 0) {
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == sta->vlan_id)
break;
- if (vlan->vlan_id == VLAN_ID_WILDCARD)
- wildcard_vlan = vlan;
- vlan = vlan->next;
}
- if (!vlan)
- vlan = wildcard_vlan;
if (vlan)
iface = vlan->ifname;
}
@@ -829,54 +1045,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
sta->vlan_id);
ret = -1;
goto done;
- } else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
- vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
- if (vlan == NULL) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG, "could not add "
- "dynamic VLAN interface for vlan_id=%d",
- sta->vlan_id);
- ret = -1;
- goto done;
- }
-
- iface = vlan->ifname;
- if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG, "could not "
- "configure encryption for dynamic VLAN "
- "interface for vlan_id=%d",
- sta->vlan_id);
- }
-
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
- "interface '%s'", iface);
- } else if (vlan && vlan->vlan_id == sta->vlan_id) {
- if (vlan->dynamic_vlan > 0) {
- vlan->dynamic_vlan++;
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG, "updated existing "
- "dynamic VLAN interface '%s'", iface);
- }
-
- /*
- * Update encryption configuration for statically generated
- * VLAN interface. This is only used for static WEP
- * configuration for the case where hostapd did not yet know
- * which keys are to be used when the interface was added.
- */
- if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG, "could not "
- "configure encryption for VLAN "
- "interface for vlan_id=%d",
- sta->vlan_id);
- }
+ } else if (vlan && vlan->dynamic_vlan > 0) {
+ vlan->dynamic_vlan++;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "updated existing dynamic VLAN interface '%s'",
+ iface);
}
/* ref counters have been increased, so mark the station */
@@ -942,6 +1117,10 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
unsigned int timeout, sec, usec;
u8 *trans_id, *nbuf;
+ wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR
+ " (count=%d)",
+ hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count);
+
if (sta->sa_query_count > 0 &&
ap_check_sa_query_timeout(hapd, sta))
return;
@@ -999,6 +1178,32 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_IEEE80211W */
+const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct hostapd_wpa_psk *psk;
+ struct hostapd_ssid *ssid;
+ const u8 *pmk;
+ int pmk_len;
+
+ ssid = &hapd->conf->ssid;
+
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+ if (!pmk || pmk_len != PMK_LEN)
+ return NULL;
+
+ for (psk = ssid->wpa_psk; psk; psk = psk->next)
+ if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
+ break;
+ if (!psk)
+ return NULL;
+ if (!psk || !psk->keyid[0])
+ return NULL;
+
+ return psk->keyid;
+}
+
+
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
@@ -1037,7 +1242,11 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
sta->addr, authorized, dev_addr);
if (authorized) {
+ const char *keyid;
+ char keyid_buf[100];
char ip_addr[100];
+
+ keyid_buf[0] = '\0';
ip_addr[0] = '\0';
#ifdef CONFIG_P2P
if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
@@ -1048,14 +1257,20 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_P2P */
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
- buf, ip_addr);
+ keyid = ap_sta_wpa_get_keyid(hapd, sta);
+ if (keyid) {
+ os_snprintf(keyid_buf, sizeof(keyid_buf),
+ " keyid=%s", keyid);
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
+ buf, ip_addr, keyid_buf);
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_CONNECTED "%s%s",
- buf, ip_addr);
+ AP_STA_CONNECTED "%s%s%s",
+ buf, ip_addr, keyid_buf);
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
@@ -1080,6 +1295,14 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason)
{
+ if (sta)
+ wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u",
+ hapd->conf->iface, __func__, MAC2STR(sta->addr),
+ reason);
+ else if (addr)
+ wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u",
+ hapd->conf->iface, __func__, MAC2STR(addr),
+ reason);
if (sta == NULL && addr)
sta = ap_get_sta(hapd, addr);
@@ -1093,16 +1316,30 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
- __func__, MAC2STR(sta->addr),
+ hapd->conf->iface, __func__, MAC2STR(sta->addr),
AP_MAX_INACTIVITY_AFTER_DEAUTH);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
sta->timeout_next = STA_REMOVE;
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ /* Deauthentication is not used in DMG/IEEE 802.11ad;
+ * disassociate the STA instead. */
+ sta->disassoc_reason = reason;
+ sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+ eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+ eloop_register_timeout(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ?
+ 2 : 0, 0, ap_sta_disassoc_cb_timeout,
+ hapd, sta);
+ return;
+ }
+
sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
@@ -1136,12 +1373,37 @@ void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
}
+void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0)
+ wpa_printf(MSG_DEBUG,
+ "%s: Removed ap_sta_deauth_cb_timeout timeout for "
+ MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+ if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0)
+ wpa_printf(MSG_DEBUG,
+ "%s: Removed ap_sta_disassoc_cb_timeout timeout for "
+ MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+ if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for "
+ MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+ if (sta->flags & WLAN_STA_WPS)
+ hostapd_wps_eap_completed(hapd);
+ }
+}
+
+
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
{
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1158,6 +1420,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
(flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
+ (flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
@@ -1167,3 +1430,48 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
return res;
}
+
+
+static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+ u16 reason;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "IEEE 802.1X: Scheduled disconnection of " MACSTR
+ " after EAP-Failure", MAC2STR(sta->addr));
+
+ reason = sta->disconnect_reason_code;
+ if (!reason)
+ reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
+ ap_sta_disconnect(hapd, sta, sta->addr, reason);
+ if (sta->flags & WLAN_STA_WPS)
+ hostapd_wps_eap_completed(hapd);
+}
+
+
+void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "IEEE 802.1X: Force disconnection of " MACSTR
+ " after EAP-Failure in 10 ms", MAC2STR(sta->addr));
+
+ /*
+ * Add a small sleep to increase likelihood of previously requested
+ * EAP-Failure TX getting out before this should the driver reorder
+ * operations.
+ */
+ eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
+ eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
+ hapd, sta);
+}
+
+
+int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
+ hapd, sta);
+}
diff --git a/contrib/wpa/src/ap/sta_info.h b/contrib/wpa/src/ap/sta_info.h
index 420d64e..ece0c60 100644
--- a/contrib/wpa/src/ap/sta_info.h
+++ b/contrib/wpa/src/ap/sta_info.h
@@ -1,6 +1,6 @@
/*
* hostapd / Station table
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,12 +9,11 @@
#ifndef STA_INFO_H
#define STA_INFO_H
-#ifdef CONFIG_MESH
-/* needed for mesh_plink_state enum */
#include "common/defs.h"
-#endif /* CONFIG_MESH */
-
#include "list.h"
+#include "vlan.h"
+#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -36,6 +35,8 @@
#define WLAN_STA_WNM_SLEEP_MODE BIT(19)
#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
#define WLAN_STA_VENDOR_VHT BIT(21)
+#define WLAN_STA_PENDING_FILS_ERP BIT(22)
+#define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -44,6 +45,21 @@
* Supported Rates IEs). */
#define WLAN_SUPP_RATES_MAX 32
+struct hostapd_data;
+
+struct mbo_non_pref_chan_info {
+ struct mbo_non_pref_chan_info *next;
+ u8 op_class;
+ u8 pref;
+ u8 reason_code;
+ u8 num_channels;
+ u8 channels[];
+};
+
+struct pending_eapol_rx {
+ struct wpabuf *buf;
+ struct os_reltime rx_time;
+};
struct sta_info {
struct sta_info *next; /* next entry in sta list */
@@ -52,6 +68,7 @@ struct sta_info {
be32 ipaddr;
struct dl_list ip6addr; /* list head for struct ip6addr */
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+ u16 disconnect_reason_code; /* RADIUS server override */
u32 flags; /* Bitfield of WLAN_STA_* */
u16 capability;
u16 listen_interval; /* or beacon_int for APs */
@@ -63,13 +80,22 @@ struct sta_info {
enum mesh_plink_state plink_state;
u16 peer_lid;
u16 my_lid;
+ u16 peer_aid;
u16 mpm_close_reason;
int mpm_retries;
- u8 my_nonce[32];
- u8 peer_nonce[32];
+ u8 my_nonce[WPA_NONCE_LEN];
+ u8 peer_nonce[WPA_NONCE_LEN];
u8 aek[32]; /* SHA256 digest length */
- u8 mtk[16];
- u8 mgtk[16];
+ u8 mtk[WPA_TK_MAX_LEN];
+ size_t mtk_len;
+ u8 mgtk_rsc[6];
+ u8 mgtk_key_id;
+ u8 mgtk[WPA_TK_MAX_LEN];
+ size_t mgtk_len;
+ u8 igtk_rsc[6];
+ u8 igtk[WPA_TK_MAX_LEN];
+ size_t igtk_len;
+ u16 igtk_key_id;
u8 sae_auth_retry;
#endif /* CONFIG_MESH */
@@ -86,6 +112,13 @@ struct sta_info {
unsigned int hs20_deauth_requested:1;
unsigned int session_timeout_set:1;
unsigned int radius_das_match:1;
+ unsigned int ecsa_supported:1;
+ unsigned int added_unassoc:1;
+ unsigned int pending_wds_enable:1;
+ unsigned int power_capab:1;
+ unsigned int agreed_to_steer:1;
+ unsigned int hs20_t_c_filtering:1;
+ unsigned int ft_over_ds:1;
u16 auth_alg;
@@ -100,17 +133,20 @@ struct sta_info {
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
- u32 acct_session_id_hi;
- u32 acct_session_id_lo;
+ struct pending_eapol_rx *pending_eapol_rx;
+
+ u64 acct_session_id;
struct os_reltime acct_session_start;
int acct_session_started;
int acct_terminate_cause; /* Acct-Terminate-Cause */
int acct_interim_interval; /* Acct-Interim-Interval */
+ unsigned int acct_interim_errors;
- unsigned long last_rx_bytes;
- unsigned long last_tx_bytes;
- u32 acct_input_gigawords; /* Acct-Input-Gigawords */
- u32 acct_output_gigawords; /* Acct-Output-Gigawords */
+ /* For extending 32-bit driver counters to 64-bit counters */
+ u32 last_rx_bytes_hi;
+ u32 last_rx_bytes_lo;
+ u32 last_tx_bytes_hi;
+ u32 last_tx_bytes_lo;
u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
@@ -118,6 +154,7 @@ struct sta_info {
struct rsn_preauth_interface *preauth_iface;
int vlan_id; /* 0: none, >0: VID */
+ struct vlan_description *vlan_desc;
int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
/* PSKs from RADIUS authentication server */
struct hostapd_sta_wpa_psk_short *psk;
@@ -127,6 +164,7 @@ struct sta_info {
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
+ struct ieee80211_vht_operation *vht_operation;
u8 vht_opmode;
#ifdef CONFIG_IEEE80211W
@@ -139,17 +177,20 @@ struct sta_info {
struct os_reltime sa_query_start;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_INTERWORKING
+#if defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
struct gas_dialog_info *gas_dialog;
u8 gas_dialog_next;
-#endif /* CONFIG_INTERWORKING */
+#endif /* CONFIG_INTERWORKING || CONFIG_DPP */
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+ /* Hotspot 2.0 Roaming Consortium from (Re)Association Request */
+ struct wpabuf *roaming_consortium;
u8 remediation_method;
char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
+ char *t_c_url; /* HS 2.0 Terms and Conditions Server URL */
struct wpabuf *hs20_deauth_req;
char *hs20_session_info_url;
int hs20_disassoc_timer;
@@ -161,15 +202,79 @@ struct sta_info {
#ifdef CONFIG_SAE
struct sae_data *sae;
+ unsigned int mesh_sae_pmksa_caching:1;
#endif /* CONFIG_SAE */
- u32 session_timeout; /* valid only if session_timeout_set == 1 */
+ /* valid only if session_timeout_set == 1 */
+ struct os_reltime session_timeout;
/* Last Authentication/(Re)Association Request/Action frame sequence
* control */
u16 last_seq_ctrl;
/* Last Authentication/(Re)Association Request/Action frame subtype */
u8 last_subtype;
+
+#ifdef CONFIG_MBO
+ u8 cell_capa; /* 0 = unknown (not an MBO STA); otherwise,
+ * enum mbo_cellular_capa values */
+ struct mbo_non_pref_chan_info *non_pref_chan;
+ int auth_rssi; /* Last Authentication frame RSSI */
+#endif /* CONFIG_MBO */
+
+ u8 *supp_op_classes; /* Supported Operating Classes element, if
+ * received, starting from the Length field */
+
+ u8 rrm_enabled_capa[5];
+
+ s8 min_tx_power;
+ s8 max_tx_power;
+
+#ifdef CONFIG_TAXONOMY
+ struct wpabuf *probe_ie_taxonomy;
+ struct wpabuf *assoc_ie_taxonomy;
+#endif /* CONFIG_TAXONOMY */
+
+#ifdef CONFIG_FILS
+ u8 fils_snonce[FILS_NONCE_LEN];
+ u8 fils_session[FILS_SESSION_LEN];
+ u8 fils_erp_pmkid[PMKID_LEN];
+ u8 *fils_pending_assoc_req;
+ size_t fils_pending_assoc_req_len;
+ unsigned int fils_pending_assoc_is_reassoc:1;
+ unsigned int fils_dhcp_rapid_commit_proxy:1;
+ unsigned int fils_erp_pmkid_set:1;
+ unsigned int fils_drv_assoc_finish:1;
+ struct wpabuf *fils_hlp_resp;
+ struct wpabuf *hlp_dhcp_discover;
+ void (*fils_pending_cb)(struct hostapd_data *hapd, struct sta_info *sta,
+ u16 resp, struct wpabuf *data, int pub);
+#ifdef CONFIG_FILS_SK_PFS
+ struct crypto_ecdh *fils_ecdh;
+#endif /* CONFIG_FILS_SK_PFS */
+ struct wpabuf *fils_dh_ss;
+ struct wpabuf *fils_g_sta;
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+ u8 *owe_pmk;
+ size_t owe_pmk_len;
+ struct crypto_ecdh *owe_ecdh;
+ u16 owe_group;
+#endif /* CONFIG_OWE */
+
+ u8 *ext_capability;
+ char *ifname_wds; /* WDS ifname, if in use */
+
+#ifdef CONFIG_DPP2
+ struct dpp_pfs *dpp_pfs;
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ enum wpa_alg last_tk_alg;
+ int last_tk_key_idx;
+ u8 last_tk[WPA_TK_MAX_LEN];
+ size_t last_tk_len;
+#endif /* CONFIG_TESTING_OPTIONS */
};
@@ -180,7 +285,7 @@ struct sta_info {
* AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
* after AP_DEAUTH_DELAY seconds has passed after disassociation. */
#define AP_MAX_INACTIVITY (5 * 60)
-#define AP_DISASSOC_DELAY (1)
+#define AP_DISASSOC_DELAY (3)
#define AP_DEAUTH_DELAY (1)
/* Number of seconds to keep STA entry with Authenticated flag after it has
* been disassociated. */
@@ -189,8 +294,6 @@ struct sta_info {
#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
-struct hostapd_data;
-
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
void *ctx),
@@ -220,9 +323,13 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx);
#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+ struct vlan_description *vlan_desc);
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
+const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
+ struct sta_info *sta);
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason);
@@ -235,7 +342,13 @@ static inline int ap_sta_is_authorized(struct sta_info *sta)
void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
+ struct sta_info *sta);
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
+void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta);
+int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta);
#endif /* STA_INFO_H */
diff --git a/contrib/wpa/src/ap/taxonomy.c b/contrib/wpa/src/ap/taxonomy.c
new file mode 100644
index 0000000..ae157a7
--- /dev/null
+++ b/contrib/wpa/src/ap/taxonomy.c
@@ -0,0 +1,292 @@
+/*
+ * hostapd / Client taxonomy
+ * Copyright (c) 2015 Google, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Parse a series of IEs, as in Probe Request or (Re)Association Request frames,
+ * and render them to a descriptive string. The tag number of standard options
+ * is written to the string, while the vendor ID and subtag are written for
+ * vendor options.
+ *
+ * Example strings:
+ * 0,1,50,45,221(00904c,51)
+ * 0,1,33,36,48,45,221(00904c,51),221(0050f2,2)
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "taxonomy.h"
+
+
+/* Copy a string with no funny schtuff allowed; only alphanumerics. */
+static void no_mischief_strncpy(char *dst, const char *src, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ unsigned char s = src[i];
+ int is_lower = s >= 'a' && s <= 'z';
+ int is_upper = s >= 'A' && s <= 'Z';
+ int is_digit = s >= '0' && s <= '9';
+
+ if (is_lower || is_upper || is_digit) {
+ /* TODO: if any manufacturer uses Unicode within the
+ * WPS header, it will get mangled here. */
+ dst[i] = s;
+ } else {
+ /* Note that even spaces will be transformed to
+ * underscores, so 'Nexus 7' will turn into 'Nexus_7'.
+ * This is deliberate, to make the string easier to
+ * parse. */
+ dst[i] = '_';
+ }
+ }
+}
+
+
+static int get_wps_name(char *name, size_t name_len,
+ const u8 *data, size_t data_len)
+{
+ /* Inside the WPS IE are a series of attributes, using two byte IDs
+ * and two byte lengths. We're looking for the model name, if
+ * present. */
+ while (data_len >= 4) {
+ u16 id, elen;
+
+ id = WPA_GET_BE16(data);
+ elen = WPA_GET_BE16(data + 2);
+ data += 4;
+ data_len -= 4;
+
+ if (elen > data_len)
+ return 0;
+
+ if (id == 0x1023) {
+ /* Model name, like 'Nexus 7' */
+ size_t n = (elen < name_len) ? elen : name_len;
+ no_mischief_strncpy(name, (const char *) data, n);
+ return n;
+ }
+
+ data += elen;
+ data_len -= elen;
+ }
+
+ return 0;
+}
+
+
+static void ie_to_string(char *fstr, size_t fstr_len, const struct wpabuf *ies)
+{
+ char *fpos = fstr;
+ char *fend = fstr + fstr_len;
+ char htcap[7 + 4 + 1]; /* ",htcap:" + %04hx + trailing NUL */
+ char htagg[7 + 2 + 1]; /* ",htagg:" + %02hx + trailing NUL */
+ char htmcs[7 + 8 + 1]; /* ",htmcs:" + %08x + trailing NUL */
+ char vhtcap[8 + 8 + 1]; /* ",vhtcap:" + %08x + trailing NUL */
+ char vhtrxmcs[10 + 8 + 1]; /* ",vhtrxmcs:" + %08x + trailing NUL */
+ char vhttxmcs[10 + 8 + 1]; /* ",vhttxmcs:" + %08x + trailing NUL */
+#define MAX_EXTCAP 254
+ char extcap[8 + 2 * MAX_EXTCAP + 1]; /* ",extcap:" + hex + trailing NUL
+ */
+ char txpow[7 + 4 + 1]; /* ",txpow:" + %04hx + trailing NUL */
+#define WPS_NAME_LEN 32
+ char wps[WPS_NAME_LEN + 5 + 1]; /* room to prepend ",wps:" + trailing
+ * NUL */
+ int num = 0;
+ const u8 *ie;
+ size_t ie_len;
+ int ret;
+
+ os_memset(htcap, 0, sizeof(htcap));
+ os_memset(htagg, 0, sizeof(htagg));
+ os_memset(htmcs, 0, sizeof(htmcs));
+ os_memset(vhtcap, 0, sizeof(vhtcap));
+ os_memset(vhtrxmcs, 0, sizeof(vhtrxmcs));
+ os_memset(vhttxmcs, 0, sizeof(vhttxmcs));
+ os_memset(extcap, 0, sizeof(extcap));
+ os_memset(txpow, 0, sizeof(txpow));
+ os_memset(wps, 0, sizeof(wps));
+ *fpos = '\0';
+
+ if (!ies)
+ return;
+ ie = wpabuf_head(ies);
+ ie_len = wpabuf_len(ies);
+
+ while (ie_len >= 2) {
+ u8 id, elen;
+ char *sep = (num++ == 0) ? "" : ",";
+
+ id = *ie++;
+ elen = *ie++;
+ ie_len -= 2;
+
+ if (elen > ie_len)
+ break;
+
+ if (id == WLAN_EID_VENDOR_SPECIFIC && elen >= 4) {
+ /* Vendor specific */
+ if (WPA_GET_BE32(ie) == WPS_IE_VENDOR_TYPE) {
+ /* WPS */
+ char model_name[WPS_NAME_LEN + 1];
+ const u8 *data = &ie[4];
+ size_t data_len = elen - 4;
+
+ os_memset(model_name, 0, sizeof(model_name));
+ if (get_wps_name(model_name, WPS_NAME_LEN, data,
+ data_len)) {
+ os_snprintf(wps, sizeof(wps),
+ ",wps:%s", model_name);
+ }
+ }
+
+ ret = os_snprintf(fpos, fend - fpos,
+ "%s%d(%02x%02x%02x,%d)",
+ sep, id, ie[0], ie[1], ie[2], ie[3]);
+ } else {
+ if (id == WLAN_EID_HT_CAP && elen >= 2) {
+ /* HT Capabilities (802.11n) */
+ os_snprintf(htcap, sizeof(htcap),
+ ",htcap:%04hx",
+ WPA_GET_LE16(ie));
+ }
+ if (id == WLAN_EID_HT_CAP && elen >= 3) {
+ /* HT Capabilities (802.11n), A-MPDU information
+ */
+ os_snprintf(htagg, sizeof(htagg),
+ ",htagg:%02hx", (u16) ie[2]);
+ }
+ if (id == WLAN_EID_HT_CAP && elen >= 7) {
+ /* HT Capabilities (802.11n), MCS information */
+ os_snprintf(htmcs, sizeof(htmcs),
+ ",htmcs:%08hx",
+ (u16) WPA_GET_LE32(ie + 3));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 4) {
+ /* VHT Capabilities (802.11ac) */
+ os_snprintf(vhtcap, sizeof(vhtcap),
+ ",vhtcap:%08x",
+ WPA_GET_LE32(ie));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 8) {
+ /* VHT Capabilities (802.11ac), RX MCS
+ * information */
+ os_snprintf(vhtrxmcs, sizeof(vhtrxmcs),
+ ",vhtrxmcs:%08x",
+ WPA_GET_LE32(ie + 4));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 12) {
+ /* VHT Capabilities (802.11ac), TX MCS
+ * information */
+ os_snprintf(vhttxmcs, sizeof(vhttxmcs),
+ ",vhttxmcs:%08x",
+ WPA_GET_LE32(ie + 8));
+ }
+ if (id == WLAN_EID_EXT_CAPAB) {
+ /* Extended Capabilities */
+ int i;
+ int len = (elen < MAX_EXTCAP) ? elen :
+ MAX_EXTCAP;
+ char *p = extcap;
+
+ p += os_snprintf(extcap, sizeof(extcap),
+ ",extcap:");
+ for (i = 0; i < len; i++) {
+ int lim;
+
+ lim = sizeof(extcap) -
+ os_strlen(extcap);
+ if (lim <= 0)
+ break;
+ p += os_snprintf(p, lim, "%02x",
+ *(ie + i));
+ }
+ }
+ if (id == WLAN_EID_PWR_CAPABILITY && elen == 2) {
+ /* TX Power */
+ os_snprintf(txpow, sizeof(txpow),
+ ",txpow:%04hx",
+ WPA_GET_LE16(ie));
+ }
+
+ ret = os_snprintf(fpos, fend - fpos, "%s%d", sep, id);
+ }
+ if (os_snprintf_error(fend - fpos, ret))
+ goto fail;
+ fpos += ret;
+
+ ie += elen;
+ ie_len -= elen;
+ }
+
+ ret = os_snprintf(fpos, fend - fpos, "%s%s%s%s%s%s%s%s%s",
+ htcap, htagg, htmcs, vhtcap, vhtrxmcs, vhttxmcs,
+ txpow, extcap, wps);
+ if (os_snprintf_error(fend - fpos, ret)) {
+ fail:
+ fstr[0] = '\0';
+ }
+}
+
+
+int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
+ struct sta_info *sta, char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+
+ if (!sta->probe_ie_taxonomy || !sta->assoc_ie_taxonomy)
+ return 0;
+
+ ret = os_snprintf(buf, buflen, "wifi4|probe:");
+ if (os_snprintf_error(buflen, ret))
+ return 0;
+ pos = buf + ret;
+ end = buf + buflen;
+
+ ie_to_string(pos, end - pos, sta->probe_ie_taxonomy);
+ pos = os_strchr(pos, '\0');
+ if (pos >= end)
+ return 0;
+ ret = os_snprintf(pos, end - pos, "|assoc:");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie_to_string(pos, end - pos, sta->assoc_ie_taxonomy);
+ pos = os_strchr(pos, '\0');
+ return pos - buf;
+}
+
+
+void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(sta->probe_ie_taxonomy);
+ sta->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
+
+
+void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct hostapd_sta_info *info,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(info->probe_ie_taxonomy);
+ info->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
+
+
+void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(sta->assoc_ie_taxonomy);
+ sta->assoc_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
diff --git a/contrib/wpa/src/ap/taxonomy.h b/contrib/wpa/src/ap/taxonomy.h
new file mode 100644
index 0000000..80f245c
--- /dev/null
+++ b/contrib/wpa/src/ap/taxonomy.h
@@ -0,0 +1,24 @@
+/*
+ * hostapd / Station client taxonomy
+ * Copyright (c) 2015 Google, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TAXONOMY_H
+#define TAXONOMY_H
+
+void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len);
+void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct hostapd_sta_info *sta,
+ const u8 *ie, size_t ie_len);
+void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len);
+int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
+ struct sta_info *sta, char *buf, size_t buflen);
+
+#endif /* TAXONOMY_H */
diff --git a/contrib/wpa/src/ap/tkip_countermeasures.c b/contrib/wpa/src/ap/tkip_countermeasures.c
index 4725e2b..557570c 100644
--- a/contrib/wpa/src/ap/tkip_countermeasures.c
+++ b/contrib/wpa/src/ap/tkip_countermeasures.c
@@ -71,6 +71,11 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
struct os_reltime now;
int ret = 0;
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Michael MIC failure detected in received frame%s",
+ local ? " (local)" : "");
+
if (addr && local) {
struct sta_info *sta = ap_get_sta(hapd, addr);
if (sta != NULL) {
diff --git a/contrib/wpa/src/ap/vlan.c b/contrib/wpa/src/ap/vlan.c
new file mode 100644
index 0000000..b6f6bb1
--- /dev/null
+++ b/contrib/wpa/src/ap/vlan.c
@@ -0,0 +1,34 @@
+/*
+ * hostapd / VLAN definition
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "ap/vlan.h"
+
+/* compare the two arguments, NULL is treated as empty
+ * return zero iff they are equal
+ */
+int vlan_compare(struct vlan_description *a, struct vlan_description *b)
+{
+ int i;
+ const int a_empty = !a || !a->notempty;
+ const int b_empty = !b || !b->notempty;
+
+ if (a_empty && b_empty)
+ return 0;
+ if (a_empty || b_empty)
+ return 1;
+ if (a->untagged != b->untagged)
+ return 1;
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN; i++) {
+ if (a->tagged[i] != b->tagged[i])
+ return 1;
+ }
+ return 0;
+}
diff --git a/contrib/wpa/src/ap/vlan.h b/contrib/wpa/src/ap/vlan.h
new file mode 100644
index 0000000..af84929
--- /dev/null
+++ b/contrib/wpa/src/ap/vlan.h
@@ -0,0 +1,30 @@
+/*
+ * hostapd / VLAN definition
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_H
+#define VLAN_H
+
+#define MAX_NUM_TAGGED_VLAN 32
+
+struct vlan_description {
+ int notempty; /* 0 : no vlan information present, 1: else */
+ int untagged; /* >0 802.1q vid */
+ int tagged[MAX_NUM_TAGGED_VLAN]; /* first k items, ascending order */
+};
+
+#ifndef CONFIG_NO_VLAN
+int vlan_compare(struct vlan_description *a, struct vlan_description *b);
+#else /* CONFIG_NO_VLAN */
+static inline int
+vlan_compare(struct vlan_description *a, struct vlan_description *b)
+{
+ return 0;
+}
+#endif /* CONFIG_NO_VLAN */
+
+#endif /* VLAN_H */
diff --git a/contrib/wpa/src/ap/vlan_full.c b/contrib/wpa/src/ap/vlan_full.c
new file mode 100644
index 0000000..19aa3c6
--- /dev/null
+++ b/contrib/wpa/src/ap/vlan_full.c
@@ -0,0 +1,801 @@
+/*
+ * hostapd / VLAN initialization - full dynamic VLAN
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+/* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
+#undef if_type
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "drivers/priv_netlink.h"
+#include "drivers/linux_ioctl.h"
+#include "common/linux_bridge.h"
+#include "common/linux_vlan.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "wpa_auth.h"
+#include "vlan_init.h"
+#include "vlan_util.h"
+
+
+struct full_dynamic_vlan {
+ int s; /* socket on which to listen for new/removed interfaces. */
+};
+
+#define DVLAN_CLEAN_BR 0x1
+#define DVLAN_CLEAN_VLAN 0x2
+#define DVLAN_CLEAN_VLAN_PORT 0x4
+
+struct dynamic_iface {
+ char ifname[IFNAMSIZ + 1];
+ int usage;
+ int clean;
+ struct dynamic_iface *next;
+};
+
+
+/* Increment ref counter for ifname and add clean flag.
+ * If not in list, add it only if some flags are given.
+ */
+static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
+ int clean)
+{
+ struct dynamic_iface *next, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ }
+
+ if (next) {
+ next->usage++;
+ next->clean |= clean;
+ return;
+ }
+
+ if (!clean)
+ return;
+
+ next = os_zalloc(sizeof(*next));
+ if (!next)
+ return;
+ os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
+ next->usage = 1;
+ next->clean = clean;
+ next->next = *dynamic_ifaces;
+ *dynamic_ifaces = next;
+}
+
+
+/* Decrement reference counter for given ifname.
+ * Return clean flag iff reference counter was decreased to zero, else zero
+ */
+static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
+{
+ struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+ int clean;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ prev = next;
+ }
+
+ if (!next)
+ return 0;
+
+ next->usage--;
+ if (next->usage)
+ return 0;
+
+ if (prev)
+ prev->next = next->next;
+ else
+ *dynamic_ifaces = next->next;
+ clean = next->clean;
+ os_free(next);
+
+ return clean;
+}
+
+
+static int ifconfig_down(const char *if_name)
+{
+ wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
+ return ifconfig_helper(if_name, 0);
+}
+
+
+/* This value should be 256 ONLY. If it is something else, then hostapd
+ * might crash!, as this value has been hard-coded in 2.4.x kernel
+ * bridging code.
+ */
+#define MAX_BR_PORTS 256
+
+static int br_delif(const char *br_name, const char *if_name)
+{
+ int fd;
+ struct ifreq ifr;
+ unsigned long args[2];
+ int if_index;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if (linux_br_del_if(fd, br_name, if_name) == 0)
+ goto done;
+
+ if_index = if_nametoindex(if_name);
+
+ if (if_index == 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+ "interface index for '%s'",
+ __func__, if_name);
+ close(fd);
+ return -1;
+ }
+
+ args[0] = BRCTL_DEL_IF;
+ args[1] = if_index;
+
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) args;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
+ /* No error if interface already removed. */
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+ "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
+ "%s", __func__, br_name, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+done:
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add interface 'if_name' to the bridge 'br_name'
+
+ returns -1 on error
+ returns 1 if the interface is already part of the bridge
+ returns 0 otherwise
+*/
+static int br_addif(const char *br_name, const char *if_name)
+{
+ int fd;
+ struct ifreq ifr;
+ unsigned long args[2];
+ int if_index;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if (linux_br_add_if(fd, br_name, if_name) == 0)
+ goto done;
+ if (errno == EBUSY) {
+ /* The interface is already added. */
+ close(fd);
+ return 1;
+ }
+
+ if_index = if_nametoindex(if_name);
+
+ if (if_index == 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+ "interface index for '%s'",
+ __func__, if_name);
+ close(fd);
+ return -1;
+ }
+
+ args[0] = BRCTL_ADD_IF;
+ args[1] = if_index;
+
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) args;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ if (errno == EBUSY) {
+ /* The interface is already added. */
+ close(fd);
+ return 1;
+ }
+
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+ "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
+ "%s", __func__, br_name, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+done:
+ close(fd);
+ return 0;
+}
+
+
+static int br_delbr(const char *br_name)
+{
+ int fd;
+ unsigned long arg[2];
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if (linux_br_del(fd, br_name) == 0)
+ goto done;
+
+ arg[0] = BRCTL_DEL_BRIDGE;
+ arg[1] = (unsigned long) br_name;
+
+ if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
+ /* No error if bridge already removed. */
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
+ "%s: %s", __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+done:
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add a bridge with the name 'br_name'.
+
+ returns -1 on error
+ returns 1 if the bridge already exists
+ returns 0 otherwise
+*/
+static int br_addbr(const char *br_name)
+{
+ int fd;
+ unsigned long arg[4];
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if (linux_br_add(fd, br_name) == 0)
+ goto done;
+ if (errno == EEXIST) {
+ /* The bridge is already added. */
+ close(fd);
+ return 1;
+ }
+
+ arg[0] = BRCTL_ADD_BRIDGE;
+ arg[1] = (unsigned long) br_name;
+
+ if (ioctl(fd, SIOCGIFBR, arg) < 0) {
+ if (errno == EEXIST) {
+ /* The bridge is already added. */
+ close(fd);
+ return 1;
+ } else {
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
+ "failed for %s: %s",
+ __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ }
+
+done:
+ /* Decrease forwarding delay to avoid EAPOL timeouts. */
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
+ arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
+ arg[1] = 1;
+ arg[2] = 0;
+ arg[3] = 0;
+ ifr.ifr_data = (char *) &arg;
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: "
+ "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
+ "%s: %s", __func__, br_name, strerror(errno));
+ /* Continue anyway */
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+static int br_getnumports(const char *br_name)
+{
+ int fd;
+ int i;
+ int port_cnt = 0;
+ unsigned long arg[4];
+ int ifindices[MAX_BR_PORTS];
+ struct ifreq ifr;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ arg[0] = BRCTL_GET_PORT_LIST;
+ arg[1] = (unsigned long) ifindices;
+ arg[2] = MAX_BR_PORTS;
+ arg[3] = 0;
+
+ os_memset(ifindices, 0, sizeof(ifindices));
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) arg;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
+ "failed for %s: %s",
+ __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ for (i = 1; i < MAX_BR_PORTS; i++) {
+ if (ifindices[i] > 0) {
+ port_cnt++;
+ }
+ }
+
+ close(fd);
+ return port_cnt;
+}
+
+
+static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
+ const char *br_name, int vid,
+ struct hostapd_data *hapd)
+{
+ char vlan_ifname[IFNAMSIZ];
+ int clean;
+ int ret;
+
+ if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
+ else
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
+ vid);
+ if (ret >= (int) sizeof(vlan_ifname))
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ vlan_ifname);
+
+ clean = 0;
+ ifconfig_up(tagged_interface);
+ if (!vlan_add(tagged_interface, vid, vlan_ifname))
+ clean |= DVLAN_CLEAN_VLAN;
+
+ if (!br_addif(br_name, vlan_ifname))
+ clean |= DVLAN_CLEAN_VLAN_PORT;
+
+ dyn_iface_get(hapd, vlan_ifname, clean);
+
+ ifconfig_up(vlan_ifname);
+}
+
+
+static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd,
+ struct hostapd_vlan *vlan, int vid)
+{
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int ret;
+
+ if (vlan->bridge[0]) {
+ os_strlcpy(br_name, vlan->bridge, IFNAMSIZ);
+ ret = 0;
+ } else if (hapd->conf->vlan_bridge[0]) {
+ ret = os_snprintf(br_name, IFNAMSIZ, "%s%d",
+ hapd->conf->vlan_bridge, vid);
+ } else if (tagged_interface) {
+ ret = os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
+ tagged_interface, vid);
+ } else {
+ ret = os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
+ }
+ if (ret >= IFNAMSIZ)
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ br_name);
+}
+
+
+static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
+ int vid)
+{
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+ dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
+
+ ifconfig_up(br_name);
+
+ if (tagged_interface)
+ vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
+ vid, hapd);
+}
+
+
+void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
+{
+ char br_name[IFNAMSIZ];
+ struct hostapd_vlan *vlan;
+ int untagged, *tagged, i, notempty;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
+
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (vlan->configured ||
+ os_strcmp(ifname, vlan->ifname) != 0)
+ continue;
+ break;
+ }
+ if (!vlan)
+ return;
+
+ vlan->configured = 1;
+
+ notempty = vlan->vlan_desc.notempty;
+ untagged = vlan->vlan_desc.untagged;
+ tagged = vlan->vlan_desc.tagged;
+
+ if (!notempty) {
+ /* Non-VLAN STA */
+ if (hapd->conf->bridge[0] &&
+ !br_addif(hapd->conf->bridge, ifname))
+ vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+ } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+ vlan_bridge_name(br_name, hapd, vlan, untagged);
+
+ vlan_get_bridge(br_name, hapd, untagged);
+
+ if (!br_addif(br_name, ifname))
+ vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+ }
+
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
+ if (tagged[i] == untagged ||
+ tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
+ (i > 0 && tagged[i] == tagged[i - 1]))
+ continue;
+ vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
+ vlan_get_bridge(br_name, hapd, tagged[i]);
+ vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
+ ifname, br_name, tagged[i], hapd);
+ }
+
+ ifconfig_up(ifname);
+}
+
+
+static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
+ const char *br_name, int vid,
+ struct hostapd_data *hapd)
+{
+ char vlan_ifname[IFNAMSIZ];
+ int clean;
+ int ret;
+
+ if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
+ else
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
+ vid);
+ if (ret >= (int) sizeof(vlan_ifname))
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ vlan_ifname);
+
+
+ clean = dyn_iface_put(hapd, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN_PORT)
+ br_delif(br_name, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN) {
+ ifconfig_down(vlan_ifname);
+ vlan_rem(vlan_ifname);
+ }
+}
+
+
+static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
+ int vid)
+{
+ int clean;
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+ if (tagged_interface)
+ vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
+ vid, hapd);
+
+ clean = dyn_iface_put(hapd, br_name);
+ if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
+ ifconfig_down(br_name);
+ br_delbr(br_name);
+ }
+}
+
+
+void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
+{
+ struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
+
+ first = prev = vlan;
+
+ while (vlan) {
+ if (os_strcmp(ifname, vlan->ifname) != 0) {
+ prev = vlan;
+ vlan = vlan->next;
+ continue;
+ }
+ break;
+ }
+ if (!vlan)
+ return;
+
+ if (vlan->configured) {
+ int notempty = vlan->vlan_desc.notempty;
+ int untagged = vlan->vlan_desc.untagged;
+ int *tagged = vlan->vlan_desc.tagged;
+ char br_name[IFNAMSIZ];
+ int i;
+
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
+ if (tagged[i] == untagged ||
+ tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
+ (i > 0 && tagged[i] == tagged[i - 1]))
+ continue;
+ vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
+ vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
+ ifname, br_name, tagged[i], hapd);
+ vlan_put_bridge(br_name, hapd, tagged[i]);
+ }
+
+ if (!notempty) {
+ /* Non-VLAN STA */
+ if (hapd->conf->bridge[0] &&
+ (vlan->clean & DVLAN_CLEAN_WLAN_PORT))
+ br_delif(hapd->conf->bridge, ifname);
+ } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+ vlan_bridge_name(br_name, hapd, vlan, untagged);
+
+ if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+ br_delif(br_name, vlan->ifname);
+
+ vlan_put_bridge(br_name, hapd, untagged);
+ }
+ }
+
+ /*
+ * Ensure this VLAN interface is actually removed even if
+ * NEWLINK message is only received later.
+ */
+ if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
+ wpa_printf(MSG_ERROR,
+ "VLAN: Could not remove VLAN iface: %s: %s",
+ vlan->ifname, strerror(errno));
+
+ if (vlan == first)
+ hapd->conf->vlan = vlan->next;
+ else
+ prev->next = vlan->next;
+
+ os_free(vlan);
+}
+
+
+static void
+vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
+ struct hostapd_data *hapd)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr *attr;
+ char ifname[IFNAMSIZ + 1];
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ os_memset(ifname, 0, sizeof(ifname));
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ int n = attr->rta_len - rta_len;
+ if (n < 0)
+ break;
+
+ if ((size_t) n >= sizeof(ifname))
+ n = sizeof(ifname) - 1;
+ os_memcpy(ifname, ((char *) attr) + rta_len, n);
+
+ }
+
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ if (!ifname[0])
+ return;
+ if (del && if_nametoindex(ifname)) {
+ /* interface still exists, race condition ->
+ * iface has just been recreated */
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ del ? "DEL" : "NEW",
+ ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ if (del)
+ vlan_dellink(ifname, hapd);
+ else
+ vlan_newlink(ifname, hapd);
+}
+
+
+static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct hostapd_data *hapd = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
+ __func__, strerror(errno));
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (NLMSG_OK(h, left)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
+ "message: len=%d left=%d plen=%d",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ vlan_read_ifnames(h, plen, 0, hapd);
+ break;
+ case RTM_DELLINK:
+ vlan_read_ifnames(h, plen, 1, hapd);
+ break;
+ }
+
+ h = NLMSG_NEXT(h, left);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
+ "netlink message", __func__, left);
+ }
+}
+
+
+struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd)
+{
+ struct sockaddr_nl local;
+ struct full_dynamic_vlan *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+
+ vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+
+ priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (priv->s < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
+ "NETLINK_ROUTE) failed: %s",
+ __func__, strerror(errno));
+ os_free(priv);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
+ __func__, strerror(errno));
+ close(priv->s);
+ os_free(priv);
+ return NULL;
+ }
+
+ if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
+ {
+ close(priv->s);
+ os_free(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+
+void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
+{
+ if (priv == NULL)
+ return;
+ eloop_unregister_read_sock(priv->s);
+ close(priv->s);
+ os_free(priv);
+}
diff --git a/contrib/wpa/src/ap/vlan_ifconfig.c b/contrib/wpa/src/ap/vlan_ifconfig.c
new file mode 100644
index 0000000..ef953a5
--- /dev/null
+++ b/contrib/wpa/src/ap/vlan_ifconfig.c
@@ -0,0 +1,69 @@
+/*
+ * hostapd / VLAN ifconfig helpers
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "vlan_util.h"
+
+
+int ifconfig_helper(const char *if_name, int up)
+{
+ int fd;
+ struct ifreq ifr;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
+ "for interface %s: %s",
+ __func__, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ if (up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
+ "for interface %s (up=%d): %s",
+ __func__, if_name, up, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+int ifconfig_up(const char *if_name)
+{
+ wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
+ return ifconfig_helper(if_name, 1);
+}
+
+
+int iface_exists(const char *ifname)
+{
+ return if_nametoindex(ifname);
+}
diff --git a/contrib/wpa/src/ap/vlan_init.c b/contrib/wpa/src/ap/vlan_init.c
index fd1c8dd..e293a00 100644
--- a/contrib/wpa/src/ap/vlan_init.c
+++ b/contrib/wpa/src/ap/vlan_init.c
@@ -9,902 +9,72 @@
*/
#include "utils/includes.h"
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <linux/if_bridge.h>
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
#include "utils/common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "wpa_auth.h"
#include "vlan_init.h"
#include "vlan_util.h"
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-
-#include "drivers/priv_netlink.h"
-#include "utils/eloop.h"
-
-
-struct full_dynamic_vlan {
- int s; /* socket on which to listen for new/removed interfaces. */
-};
-
-#define DVLAN_CLEAN_BR 0x1
-#define DVLAN_CLEAN_VLAN 0x2
-#define DVLAN_CLEAN_VLAN_PORT 0x4
-
-struct dynamic_iface {
- char ifname[IFNAMSIZ + 1];
- int usage;
- int clean;
- struct dynamic_iface *next;
-};
-
-
-/* Increment ref counter for ifname and add clean flag.
- * If not in list, add it only if some flags are given.
- */
-static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
- int clean)
-{
- struct dynamic_iface *next, **dynamic_ifaces;
- struct hapd_interfaces *interfaces;
-
- interfaces = hapd->iface->interfaces;
- dynamic_ifaces = &interfaces->vlan_priv;
-
- for (next = *dynamic_ifaces; next; next = next->next) {
- if (os_strcmp(ifname, next->ifname) == 0)
- break;
- }
-
- if (next) {
- next->usage++;
- next->clean |= clean;
- return;
- }
-
- if (!clean)
- return;
-
- next = os_zalloc(sizeof(*next));
- if (!next)
- return;
- os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
- next->usage = 1;
- next->clean = clean;
- next->next = *dynamic_ifaces;
- *dynamic_ifaces = next;
-}
-
-
-/* Decrement reference counter for given ifname.
- * Return clean flag iff reference counter was decreased to zero, else zero
- */
-static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
-{
- struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
- struct hapd_interfaces *interfaces;
- int clean;
-
- interfaces = hapd->iface->interfaces;
- dynamic_ifaces = &interfaces->vlan_priv;
-
- for (next = *dynamic_ifaces; next; next = next->next) {
- if (os_strcmp(ifname, next->ifname) == 0)
- break;
- prev = next;
- }
-
- if (!next)
- return 0;
-
- next->usage--;
- if (next->usage)
- return 0;
-
- if (prev)
- prev->next = next->next;
- else
- *dynamic_ifaces = next->next;
- clean = next->clean;
- os_free(next);
-
- return clean;
-}
-
-
-static int ifconfig_helper(const char *if_name, int up)
-{
- int fd;
- struct ifreq ifr;
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
-
- if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
- "for interface %s: %s",
- __func__, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- if (up)
- ifr.ifr_flags |= IFF_UP;
- else
- ifr.ifr_flags &= ~IFF_UP;
-
- if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
- "for interface %s (up=%d): %s",
- __func__, if_name, up, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int ifconfig_up(const char *if_name)
-{
- wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
- return ifconfig_helper(if_name, 1);
-}
-
-
-static int ifconfig_down(const char *if_name)
-{
- wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
- return ifconfig_helper(if_name, 0);
-}
-
-
-/*
- * These are only available in recent linux headers (without the leading
- * underscore).
- */
-#define _GET_VLAN_REALDEV_NAME_CMD 8
-#define _GET_VLAN_VID_CMD 9
-
-/* This value should be 256 ONLY. If it is something else, then hostapd
- * might crash!, as this value has been hard-coded in 2.4.x kernel
- * bridging code.
- */
-#define MAX_BR_PORTS 256
-
-static int br_delif(const char *br_name, const char *if_name)
-{
- int fd;
- struct ifreq ifr;
- unsigned long args[2];
- int if_index;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- if_index = if_nametoindex(if_name);
-
- if (if_index == 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
- "interface index for '%s'",
- __func__, if_name);
- close(fd);
- return -1;
- }
-
- args[0] = BRCTL_DEL_IF;
- args[1] = if_index;
-
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) args;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
- /* No error if interface already removed. */
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
- "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
- "%s", __func__, br_name, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add interface 'if_name' to the bridge 'br_name'
-
- returns -1 on error
- returns 1 if the interface is already part of the bridge
- returns 0 otherwise
-*/
-static int br_addif(const char *br_name, const char *if_name)
-{
- int fd;
- struct ifreq ifr;
- unsigned long args[2];
- int if_index;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- if_index = if_nametoindex(if_name);
-
- if (if_index == 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
- "interface index for '%s'",
- __func__, if_name);
- close(fd);
- return -1;
- }
-
- args[0] = BRCTL_ADD_IF;
- args[1] = if_index;
-
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) args;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- if (errno == EBUSY) {
- /* The interface is already added. */
- close(fd);
- return 1;
- }
-
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
- "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
- "%s", __func__, br_name, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int br_delbr(const char *br_name)
-{
- int fd;
- unsigned long arg[2];
-
- wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_DEL_BRIDGE;
- arg[1] = (unsigned long) br_name;
-
- if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
- /* No error if bridge already removed. */
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
- "%s: %s", __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add a bridge with the name 'br_name'.
-
- returns -1 on error
- returns 1 if the bridge already exists
- returns 0 otherwise
-*/
-static int br_addbr(const char *br_name)
-{
- int fd;
- unsigned long arg[4];
- struct ifreq ifr;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_ADD_BRIDGE;
- arg[1] = (unsigned long) br_name;
-
- if (ioctl(fd, SIOCGIFBR, arg) < 0) {
- if (errno == EEXIST) {
- /* The bridge is already added. */
- close(fd);
- return 1;
- } else {
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
- "failed for %s: %s",
- __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
- }
-
- /* Decrease forwarding delay to avoid EAPOL timeouts. */
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
- arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
- arg[1] = 1;
- arg[2] = 0;
- arg[3] = 0;
- ifr.ifr_data = (char *) &arg;
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: "
- "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
- "%s: %s", __func__, br_name, strerror(errno));
- /* Continue anyway */
- }
-
- close(fd);
- return 0;
-}
-
-
-static int br_getnumports(const char *br_name)
-{
- int fd;
- int i;
- int port_cnt = 0;
- unsigned long arg[4];
- int ifindices[MAX_BR_PORTS];
- struct ifreq ifr;
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_GET_PORT_LIST;
- arg[1] = (unsigned long) ifindices;
- arg[2] = MAX_BR_PORTS;
- arg[3] = 0;
-
- os_memset(ifindices, 0, sizeof(ifindices));
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) arg;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
- "failed for %s: %s",
- __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- for (i = 1; i < MAX_BR_PORTS; i++) {
- if (ifindices[i] > 0) {
- port_cnt++;
- }
- }
-
- close(fd);
- return port_cnt;
-}
-
-
-#ifndef CONFIG_VLAN_NETLINK
-
-int vlan_rem(const char *if_name)
-{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
- if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
- wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
- if_name);
- return -1;
- }
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&if_request, 0, sizeof(if_request));
-
- os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
- if_request.cmd = DEL_VLAN_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
- "%s", __func__, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add a vlan interface with VLAN ID 'vid' and tagged interface
- 'if_name'.
-
- returns -1 on error
- returns 1 if the interface already exists
- returns 0 otherwise
-*/
-int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
-{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
- if_name, vid);
- ifconfig_up(if_name);
-
- if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
- wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
- if_name);
- return -1;
- }
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&if_request, 0, sizeof(if_request));
-
- /* Determine if a suitable vlan device already exists. */
-
- os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
- vid);
-
- if_request.cmd = _GET_VLAN_VID_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
-
- if (if_request.u.VID == vid) {
- if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
- os_strncmp(if_request.u.device2, if_name,
- sizeof(if_request.u.device2)) == 0) {
- close(fd);
- wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
- "if_name %s exists already",
- if_request.device1);
- return 1;
- }
- }
- }
-
- /* A suitable vlan device does not already exist, add one. */
-
- os_memset(&if_request, 0, sizeof(if_request));
- os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
- if_request.u.VID = vid;
- if_request.cmd = ADD_VLAN_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
- "%s",
- __func__, if_request.device1, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int vlan_set_name_type(unsigned int name_type)
+static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+ int existsok)
{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
- name_type);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
+ int ret, i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (!hapd->conf->ssid.wep.key[i])
+ continue;
+ wpa_printf(MSG_ERROR,
+ "VLAN: Refusing to set up VLAN iface %s with WEP",
+ vlan->ifname);
return -1;
}
- os_memset(&if_request, 0, sizeof(if_request));
-
- if_request.u.name_type = name_type;
- if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
- "name_type=%u failed: %s",
- __func__, name_type, strerror(errno));
- close(fd);
+ if (!iface_exists(vlan->ifname))
+ ret = hostapd_vlan_if_add(hapd, vlan->ifname);
+ else if (!existsok)
return -1;
- }
-
- close(fd);
- return 0;
-}
-
-#endif /* CONFIG_VLAN_NETLINK */
-
-
-static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
-{
- char vlan_ifname[IFNAMSIZ];
- char br_name[IFNAMSIZ];
- struct hostapd_vlan *vlan = hapd->conf->vlan;
- char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
- int vlan_naming = hapd->conf->ssid.vlan_naming;
- int clean;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
-
- while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
- vlan->configured = 1;
-
- if (hapd->conf->vlan_bridge[0]) {
- os_snprintf(br_name, sizeof(br_name), "%s%d",
- hapd->conf->vlan_bridge,
- vlan->vlan_id);
- } else if (tagged_interface) {
- os_snprintf(br_name, sizeof(br_name),
- "br%s.%d", tagged_interface,
- vlan->vlan_id);
- } else {
- os_snprintf(br_name, sizeof(br_name),
- "brvlan%d", vlan->vlan_id);
- }
-
- dyn_iface_get(hapd, br_name,
- br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
-
- ifconfig_up(br_name);
-
- if (tagged_interface) {
- if (vlan_naming ==
- DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname,
- sizeof(vlan_ifname),
- "%s.%d", tagged_interface,
- vlan->vlan_id);
- else
- os_snprintf(vlan_ifname,
- sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
-
- clean = 0;
- ifconfig_up(tagged_interface);
- if (!vlan_add(tagged_interface, vlan->vlan_id,
- vlan_ifname))
- clean |= DVLAN_CLEAN_VLAN;
-
- if (!br_addif(br_name, vlan_ifname))
- clean |= DVLAN_CLEAN_VLAN_PORT;
-
- dyn_iface_get(hapd, vlan_ifname, clean);
-
- ifconfig_up(vlan_ifname);
- }
-
- if (!br_addif(br_name, ifname))
- vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
-
- ifconfig_up(ifname);
-
- break;
- }
- vlan = vlan->next;
- }
-}
-
-
-static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
-{
- char vlan_ifname[IFNAMSIZ];
- char br_name[IFNAMSIZ];
- struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
- char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
- int vlan_naming = hapd->conf->ssid.vlan_naming;
- int clean;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
-
- first = prev = vlan;
-
- while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) == 0 &&
- vlan->configured) {
- if (hapd->conf->vlan_bridge[0]) {
- os_snprintf(br_name, sizeof(br_name), "%s%d",
- hapd->conf->vlan_bridge,
- vlan->vlan_id);
- } else if (tagged_interface) {
- os_snprintf(br_name, sizeof(br_name),
- "br%s.%d", tagged_interface,
- vlan->vlan_id);
- } else {
- os_snprintf(br_name, sizeof(br_name),
- "brvlan%d", vlan->vlan_id);
- }
-
- if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
- br_delif(br_name, vlan->ifname);
-
- if (tagged_interface) {
- if (vlan_naming ==
- DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname,
- sizeof(vlan_ifname),
- "%s.%d", tagged_interface,
- vlan->vlan_id);
- else
- os_snprintf(vlan_ifname,
- sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
-
- clean = dyn_iface_put(hapd, vlan_ifname);
-
- if (clean & DVLAN_CLEAN_VLAN_PORT)
- br_delif(br_name, vlan_ifname);
-
- if (clean & DVLAN_CLEAN_VLAN) {
- ifconfig_down(vlan_ifname);
- vlan_rem(vlan_ifname);
- }
- }
-
- clean = dyn_iface_put(hapd, br_name);
- if ((clean & DVLAN_CLEAN_BR) &&
- br_getnumports(br_name) == 0) {
- ifconfig_down(br_name);
- br_delbr(br_name);
- }
- }
-
- if (os_strcmp(ifname, vlan->ifname) == 0) {
- if (vlan == first) {
- hapd->conf->vlan = vlan->next;
- } else {
- prev->next = vlan->next;
- }
- os_free(vlan);
-
- break;
- }
- prev = vlan;
- vlan = vlan->next;
- }
-}
-
-
-static void
-vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
- struct hostapd_data *hapd)
-{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr *attr;
- char ifname[IFNAMSIZ + 1];
-
- if (len < sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return;
-
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
-
- os_memset(ifname, 0, sizeof(ifname));
- rta_len = RTA_ALIGN(sizeof(struct rtattr));
- while (RTA_OK(attr, attrlen)) {
- if (attr->rta_type == IFLA_IFNAME) {
- int n = attr->rta_len - rta_len;
- if (n < 0)
- break;
-
- if ((size_t) n >= sizeof(ifname))
- n = sizeof(ifname) - 1;
- os_memcpy(ifname, ((char *) attr) + rta_len, n);
-
- }
-
- attr = RTA_NEXT(attr, attrlen);
- }
-
- if (!ifname[0])
- return;
- if (del && if_nametoindex(ifname)) {
- /* interface still exists, race condition ->
- * iface has just been recreated */
- return;
- }
-
- wpa_printf(MSG_DEBUG,
- "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
- del ? "DEL" : "NEW",
- ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
- (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
- (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
- (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
- (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
-
- if (del)
- vlan_dellink(ifname, hapd);
else
- vlan_newlink(ifname, hapd);
-}
+ ret = 0;
+ if (ret)
+ return ret;
-static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
- char buf[8192];
- int left;
- struct sockaddr_nl from;
- socklen_t fromlen;
- struct nlmsghdr *h;
- struct hostapd_data *hapd = eloop_ctx;
+ ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
- fromlen = sizeof(from);
- left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *) &from, &fromlen);
- if (left < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
- __func__, strerror(errno));
- return;
- }
+ if (hapd->wpa_auth)
+ ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
- h = (struct nlmsghdr *) buf;
- while (NLMSG_OK(h, left)) {
- int len, plen;
+ if (ret == 0)
+ return ret;
- len = h->nlmsg_len;
- plen = len - sizeof(*h);
- if (len > left || plen < 0) {
- wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
- "message: len=%d left=%d plen=%d",
- len, left, plen);
- break;
- }
+ wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)",
+ vlan->vlan_id, ret);
+ if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
+ wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
- switch (h->nlmsg_type) {
- case RTM_NEWLINK:
- vlan_read_ifnames(h, plen, 0, hapd);
- break;
- case RTM_DELLINK:
- vlan_read_ifnames(h, plen, 1, hapd);
- break;
- }
-
- h = NLMSG_NEXT(h, left);
- }
+ /* group state machine setup failed */
+ if (hostapd_vlan_if_remove(hapd, vlan->ifname))
+ wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
- if (left > 0) {
- wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
- "netlink message", __func__, left);
- }
+ return ret;
}
-static struct full_dynamic_vlan *
-full_dynamic_vlan_init(struct hostapd_data *hapd)
+int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
{
- struct sockaddr_nl local;
- struct full_dynamic_vlan *priv;
-
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
+ int ret;
-#ifndef CONFIG_VLAN_NETLINK
- vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
- DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
- VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
- VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
-#endif /* CONFIG_VLAN_NETLINK */
+ ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id);
+ if (ret)
+ wpa_printf(MSG_ERROR,
+ "WPA deinitialization for VLAN %d failed (%d)",
+ vlan->vlan_id, ret);
- priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (priv->s < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
- "NETLINK_ROUTE) failed: %s",
- __func__, strerror(errno));
- os_free(priv);
- return NULL;
- }
-
- os_memset(&local, 0, sizeof(local));
- local.nl_family = AF_NETLINK;
- local.nl_groups = RTMGRP_LINK;
- if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
- __func__, strerror(errno));
- close(priv->s);
- os_free(priv);
- return NULL;
- }
-
- if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
- {
- close(priv->s);
- os_free(priv);
- return NULL;
- }
-
- return priv;
-}
-
-
-static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
-{
- if (priv == NULL)
- return;
- eloop_unregister_read_sock(priv->s);
- close(priv->s);
- os_free(priv);
-}
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-
-int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
-{
- int i;
-
- if (dyn_vlan == NULL)
- return 0;
-
- /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
- * functions for setting up dynamic broadcast keys. */
- for (i = 0; i < 4; i++) {
- if (hapd->conf->ssid.wep.key[i] &&
- hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
- i == hapd->conf->ssid.wep.idx, NULL, 0,
- hapd->conf->ssid.wep.key[i],
- hapd->conf->ssid.wep.len[i]))
- {
- wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
- "encryption for dynamic VLAN");
- return -1;
- }
- }
-
- return 0;
+ return hostapd_vlan_if_remove(hapd, vlan->ifname);
}
@@ -913,17 +83,14 @@ static int vlan_dynamic_add(struct hostapd_data *hapd,
{
while (vlan) {
if (vlan->vlan_id != VLAN_ID_WILDCARD) {
- if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
- if (errno != EEXIST) {
- wpa_printf(MSG_ERROR, "VLAN: Could "
- "not add VLAN %s: %s",
- vlan->ifname,
- strerror(errno));
- return -1;
- }
+ if (vlan_if_add(hapd, vlan, 1)) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: Could not add VLAN %s: %s",
+ vlan->ifname, strerror(errno));
+ return -1;
}
#ifdef CONFIG_FULL_DYNAMIC_VLAN
- ifconfig_up(vlan->ifname);
+ vlan_newlink(vlan->ifname, hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
}
@@ -942,15 +109,17 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd,
while (vlan) {
next = vlan->next;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ /* vlan_dellink() takes care of cleanup and interface removal */
+ if (vlan->vlan_id != VLAN_ID_WILDCARD)
+ vlan_dellink(vlan->ifname, hapd);
+#else /* CONFIG_FULL_DYNAMIC_VLAN */
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
- hostapd_vlan_if_remove(hapd, vlan->ifname)) {
+ vlan_if_remove(hapd, vlan)) {
wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
"iface: %s: %s",
vlan->ifname, strerror(errno));
}
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
- if (vlan->clean)
- vlan_dellink(vlan->ifname, hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
vlan = next;
@@ -964,10 +133,13 @@ int vlan_init(struct hostapd_data *hapd)
hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
- if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+ if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
+ hapd->conf->ssid.per_sta_vif) &&
!hapd->conf->vlan) {
/* dynamic vlans enabled but no (or empty) vlan_file given */
struct hostapd_vlan *vlan;
+ int ret;
+
vlan = os_zalloc(sizeof(*vlan));
if (vlan == NULL) {
wpa_printf(MSG_ERROR, "Out of memory while assigning "
@@ -976,8 +148,16 @@ int vlan_init(struct hostapd_data *hapd)
}
vlan->vlan_id = VLAN_ID_WILDCARD;
- os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
- hapd->conf->iface);
+ ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
+ hapd->conf->iface);
+ if (ret >= (int) sizeof(vlan->ifname)) {
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ vlan->ifname);
+ } else if (ret < 0) {
+ os_free(vlan);
+ return ret;
+ }
vlan->next = hapd->conf->vlan;
hapd->conf->vlan = vlan;
}
@@ -1002,50 +182,51 @@ void vlan_deinit(struct hostapd_data *hapd)
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
- int vlan_id)
+ int vlan_id,
+ struct vlan_description *vlan_desc)
{
- struct hostapd_vlan *n = NULL;
- char *ifname, *pos;
+ struct hostapd_vlan *n;
+ char ifname[IFNAMSIZ + 1], *pos;
+ int ret;
- if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
- vlan->vlan_id != VLAN_ID_WILDCARD)
+ if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
return NULL;
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
__func__, vlan_id, vlan->ifname);
- ifname = os_strdup(vlan->ifname);
- if (ifname == NULL)
- return NULL;
+ os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
pos = os_strchr(ifname, '#');
if (pos == NULL)
- goto free_ifname;
+ return NULL;
*pos++ = '\0';
n = os_zalloc(sizeof(*n));
if (n == NULL)
- goto free_ifname;
+ return NULL;
n->vlan_id = vlan_id;
+ if (vlan_desc)
+ n->vlan_desc = *vlan_desc;
n->dynamic_vlan = 1;
- os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
- pos);
-
- if (hostapd_vlan_if_add(hapd, n->ifname)) {
+ ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
+ ifname, vlan_id, pos);
+ if (os_snprintf_error(sizeof(n->ifname), ret)) {
os_free(n);
- n = NULL;
- goto free_ifname;
+ return NULL;
}
+ os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
n->next = hapd->conf->vlan;
hapd->conf->vlan = n;
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
- ifconfig_up(n->ifname);
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ /* hapd->conf->vlan needs this new VLAN here for WPA setup */
+ if (vlan_if_add(hapd, n, 0)) {
+ hapd->conf->vlan = n->next;
+ os_free(n);
+ n = NULL;
+ }
-free_ifname:
- os_free(ifname);
return n;
}
@@ -1054,7 +235,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
{
struct hostapd_vlan *vlan;
- if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
+ if (vlan_id <= 0)
return 1;
wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
@@ -1073,7 +254,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
return 1;
if (vlan->dynamic_vlan == 0) {
- hostapd_vlan_if_remove(hapd, vlan->ifname);
+ vlan_if_remove(hapd, vlan);
#ifdef CONFIG_FULL_DYNAMIC_VLAN
vlan_dellink(vlan->ifname, hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
diff --git a/contrib/wpa/src/ap/vlan_init.h b/contrib/wpa/src/ap/vlan_init.h
index fc39443..d17c82c 100644
--- a/contrib/wpa/src/ap/vlan_init.h
+++ b/contrib/wpa/src/ap/vlan_init.h
@@ -15,10 +15,9 @@ int vlan_init(struct hostapd_data *hapd);
void vlan_deinit(struct hostapd_data *hapd);
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
- int vlan_id);
+ int vlan_id,
+ struct vlan_description *vlan_desc);
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
-int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
- const char *dyn_vlan);
#else /* CONFIG_NO_VLAN */
static inline int vlan_init(struct hostapd_data *hapd)
{
@@ -29,9 +28,9 @@ static inline void vlan_deinit(struct hostapd_data *hapd)
{
}
-static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
- struct hostapd_vlan *vlan,
- int vlan_id)
+static inline struct hostapd_vlan *
+vlan_add_dynamic(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+ int vlan_id, struct vlan_description *vlan_desc)
{
return NULL;
}
@@ -40,12 +39,6 @@ static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
{
return -1;
}
-
-static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
- const char *dyn_vlan)
-{
- return -1;
-}
#endif /* CONFIG_NO_VLAN */
#endif /* VLAN_INIT_H */
diff --git a/contrib/wpa/src/ap/vlan_ioctl.c b/contrib/wpa/src/ap/vlan_ioctl.c
new file mode 100644
index 0000000..987b612
--- /dev/null
+++ b/contrib/wpa/src/ap/vlan_ioctl.c
@@ -0,0 +1,155 @@
+/*
+ * hostapd / VLAN ioctl API
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "common/linux_vlan.h"
+#include "vlan_util.h"
+
+
+int vlan_rem(const char *if_name)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
+ if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ if_name);
+ return -1;
+ }
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+ if_request.cmd = DEL_VLAN_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
+ "%s", __func__, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add a vlan interface with VLAN ID 'vid' and tagged interface
+ 'if_name'.
+
+ returns -1 on error
+ returns 1 if the interface already exists
+ returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
+ if_name, vid);
+ ifconfig_up(if_name);
+
+ if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ if_name);
+ return -1;
+ }
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ /* Determine if a suitable vlan device already exists. */
+
+ os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
+ vid);
+
+ if_request.cmd = GET_VLAN_VID_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+ if_request.u.VID == vid) {
+ if_request.cmd = GET_VLAN_REALDEV_NAME_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+ os_strncmp(if_request.u.device2, if_name,
+ sizeof(if_request.u.device2)) == 0) {
+ close(fd);
+ wpa_printf(MSG_DEBUG,
+ "VLAN: vlan_add: if_name %s exists already",
+ if_request.device1);
+ return 1;
+ }
+ }
+
+ /* A suitable vlan device does not already exist, add one. */
+
+ os_memset(&if_request, 0, sizeof(if_request));
+ os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+ if_request.u.VID = vid;
+ if_request.cmd = ADD_VLAN_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: ADD_VLAN_CMD failed for %s: %s",
+ __func__, if_request.device1, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+int vlan_set_name_type(unsigned int name_type)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
+ name_type);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ if_request.u.name_type = name_type;
+ if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s",
+ __func__, name_type, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/contrib/wpa/src/ap/vlan_util.c b/contrib/wpa/src/ap/vlan_util.c
index d4e0efb..56d1d3d 100644
--- a/contrib/wpa/src/ap/vlan_util.c
+++ b/contrib/wpa/src/ap/vlan_util.c
@@ -7,18 +7,10 @@
*/
#include "utils/includes.h"
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>
#include "utils/common.h"
-#include "utils/eloop.h"
-#include "hostapd.h"
#include "vlan_util.h"
/*
@@ -33,7 +25,6 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
{
int err, ret = -1;
struct nl_sock *handle = NULL;
- struct nl_cache *cache = NULL;
struct rtnl_link *rlink = NULL;
int if_idx = 0;
@@ -65,22 +56,19 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
goto vlan_add_error;
}
- err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
+ err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
if (err < 0) {
- cache = NULL;
- wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
- nl_geterror(err));
- goto vlan_add_error;
- }
-
- if (!(if_idx = rtnl_link_name2i(cache, if_name))) {
/* link does not exist */
wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
if_name);
goto vlan_add_error;
}
+ if_idx = rtnl_link_get_ifindex(rlink);
+ rtnl_link_put(rlink);
+ rlink = NULL;
- if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) {
+ err = rtnl_link_get_kernel(handle, 0, vlan_if_name, &rlink);
+ if (err >= 0) {
/* link does exist */
rtnl_link_put(rlink);
rlink = NULL;
@@ -127,8 +115,6 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
vlan_add_error:
if (rlink)
rtnl_link_put(rlink);
- if (cache)
- nl_cache_free(cache);
if (handle)
nl_socket_free(handle);
return ret;
@@ -139,7 +125,6 @@ int vlan_rem(const char *if_name)
{
int err, ret = -1;
struct nl_sock *handle = NULL;
- struct nl_cache *cache = NULL;
struct rtnl_link *rlink = NULL;
wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
@@ -157,15 +142,8 @@ int vlan_rem(const char *if_name)
goto vlan_rem_error;
}
- err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
+ err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
if (err < 0) {
- cache = NULL;
- wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
- nl_geterror(err));
- goto vlan_rem_error;
- }
-
- if (!(rlink = rtnl_link_get_by_name(cache, if_name))) {
/* link does not exist */
wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
if_name);
@@ -184,9 +162,13 @@ int vlan_rem(const char *if_name)
vlan_rem_error:
if (rlink)
rtnl_link_put(rlink);
- if (cache)
- nl_cache_free(cache);
if (handle)
nl_socket_free(handle);
return ret;
}
+
+
+int vlan_set_name_type(unsigned int name_type)
+{
+ return 0;
+}
diff --git a/contrib/wpa/src/ap/vlan_util.h b/contrib/wpa/src/ap/vlan_util.h
index bef5a16..2446859 100644
--- a/contrib/wpa/src/ap/vlan_util.h
+++ b/contrib/wpa/src/ap/vlan_util.h
@@ -1,5 +1,5 @@
/*
- * hostapd / VLAN netlink api
+ * hostapd / VLAN netlink/ioctl api
* Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
*
* This software may be distributed under the terms of the BSD license.
@@ -9,7 +9,23 @@
#ifndef VLAN_UTIL_H
#define VLAN_UTIL_H
+struct hostapd_data;
+struct hostapd_vlan;
+struct full_dynamic_vlan;
+
int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
int vlan_rem(const char *if_name);
+int vlan_set_name_type(unsigned int name_type);
+
+int ifconfig_helper(const char *if_name, int up);
+int ifconfig_up(const char *if_name);
+int iface_exists(const char *ifname);
+int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+
+struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd);
+void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv);
+void vlan_newlink(const char *ifname, struct hostapd_data *hapd);
+void vlan_dellink(const char *ifname, struct hostapd_data *hapd);
#endif /* VLAN_UTIL_H */
diff --git a/contrib/wpa/src/ap/wmm.c b/contrib/wpa/src/ap/wmm.c
index 314e244..8054c5d 100644
--- a/contrib/wpa/src/ap/wmm.c
+++ b/contrib/wpa/src/ap/wmm.c
@@ -21,11 +21,6 @@
#include "wmm.h"
-/* TODO: maintain separate sequence and fragment numbers for each AC
- * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
- * if only WMM stations are receiving a certain group */
-
-
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
{
u8 ret;
@@ -157,8 +152,9 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
int wmm_process_tspec(struct wmm_tspec_element *tspec)
{
- int medium_time, pps, duration;
- int up, psb, dir, tid;
+ u64 medium_time;
+ unsigned int pps, duration;
+ unsigned int up, psb, dir, tid;
u16 val, surplus;
up = (tspec->ts_info[1] >> 3) & 0x07;
@@ -206,8 +202,9 @@ int wmm_process_tspec(struct wmm_tspec_element *tspec)
return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
}
- medium_time = surplus * pps * duration / 0x2000;
- wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
+ medium_time = (u64) surplus * pps * duration / 0x2000;
+ wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %lu",
+ (unsigned long) medium_time);
/*
* TODO: store list of granted (and still active) TSPECs and check
diff --git a/contrib/wpa/src/ap/wnm_ap.c b/contrib/wpa/src/ap/wnm_ap.c
index 4c8bc10..27c69d3 100644
--- a/contrib/wpa/src/ap/wnm_ap.c
+++ b/contrib/wpa/src/ap/wnm_ap.c
@@ -12,11 +12,13 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/ocv.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
#include "ap/wpa_auth.h"
+#include "mbo_ap.h"
#include "wnm_ap.h"
#define MAX_TFS_IE_LEN 1024
@@ -53,8 +55,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
- u8 *wnmtfs_ie;
- u8 wnmsleep_ie_len;
+ u8 *wnmtfs_ie, *oci_ie;
+ u8 wnmsleep_ie_len, oci_ie_len;
u16 wnmtfs_ie_len;
u8 *pos;
struct sta_info *sta;
@@ -87,14 +89,47 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
wnmtfs_ie = NULL;
}
+ oci_ie = NULL;
+ oci_ie_len = 0;
+#ifdef CONFIG_OCV
+ if (action_type == WNM_SLEEP_MODE_EXIT &&
+ wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(wnmtfs_ie);
+ os_free(oci_ie);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
- MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
+ MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+ oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Response action frame");
- return -1;
+ res = -1;
+ goto fail;
}
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
@@ -107,6 +142,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
/* add key data if MFP is enabled */
if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+ hapd->conf->wnm_sleep_mode_no_keys ||
action_type != WNM_SLEEP_MODE_EXIT) {
mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
} else {
@@ -116,11 +152,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
(int) gtk_elem_len);
#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
- if (res < 0) {
- os_free(wnmtfs_ie);
- os_free(mgmt);
- return -1;
- }
+ if (res < 0)
+ goto fail;
igtk_elem_len = res;
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
@@ -134,11 +167,18 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
pos += wnmsleep_ie_len;
- if (wnmtfs_ie)
+ if (wnmtfs_ie) {
os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+ pos += wnmtfs_ie_len;
+ }
+#ifdef CONFIG_OCV
+ /* copy OCV OCI here */
+ if (oci_ie_len > 0)
+ os_memcpy(pos, oci_ie, oci_ie_len);
+#endif /* CONFIG_OCV */
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
- igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
+ igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
/* In driver, response frame should be forced to sent when STA is in
* PS mode */
@@ -174,7 +214,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
wpa_set_wnmsleep(sta->wpa_sm, 0);
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
addr, NULL, NULL);
- if (!wpa_auth_uses_mfp(sta->wpa_sm))
+ if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+ hapd->conf->wnm_sleep_mode_no_keys)
wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
}
} else
@@ -182,7 +223,9 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#undef MAX_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN
+fail:
os_free(wnmtfs_ie);
+ os_free(oci_ie);
os_free(mgmt);
return res;
}
@@ -199,18 +242,44 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
u8 *tfsreq_ie_start = NULL;
u8 *tfsreq_ie_end = NULL;
u16 tfsreq_ie_len = 0;
+#ifdef CONFIG_OCV
+ struct sta_info *sta;
+ const u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
+#endif /* CONFIG_OCV */
+
+ if (!hapd->conf->wnm_sleep_mode) {
+ wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
+ MACSTR " since WNM-Sleep Mode is disabled",
+ MAC2STR(addr));
+ return;
+ }
+
+ if (len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore too short WNM-Sleep Mode Request from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
dialog_token = *pos++;
while (pos + 1 < frm + len) {
u8 ie_len = pos[1];
if (pos + 2 + ie_len > frm + len)
break;
- if (*pos == WLAN_EID_WNMSLEEP)
+ if (*pos == WLAN_EID_WNMSLEEP &&
+ ie_len >= (int) sizeof(*wnmsleep_ie) - 2)
wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_REQ) {
if (!tfsreq_ie_start)
tfsreq_ie_start = (u8 *) pos;
tfsreq_ie_end = (u8 *) pos;
+#ifdef CONFIG_OCV
+ } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
+ pos[2] == WLAN_EID_EXT_OCV_OCI) {
+ oci_ie = pos + 3;
+ oci_ie_len = ie_len - 1;
+#endif /* CONFIG_OCV */
} else
wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
*pos);
@@ -222,6 +291,27 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
return;
}
+#ifdef CONFIG_OCV
+ sta = ap_get_sta(hapd, addr);
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
+ sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
+ return;
+ }
+
+ if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
tfsreq_ie_start && tfsreq_ie_end &&
tfsreq_ie_end - tfsreq_ie_start >= 0) {
@@ -249,20 +339,14 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
const u8 *addr,
- u8 dialog_token,
- const char *url)
+ u8 dialog_token)
{
struct ieee80211_mgmt *mgmt;
- size_t url_len, len;
+ size_t len;
u8 *pos;
int res;
- if (url)
- url_len = os_strlen(url);
- else
- url_len = 0;
-
- mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0));
+ mgmt = os_zalloc(sizeof(*mgmt));
if (mgmt == NULL)
return -1;
os_memcpy(mgmt->da, addr, ETH_ALEN);
@@ -277,11 +361,6 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
mgmt->u.action.u.bss_tm_req.validity_interval = 1;
pos = mgmt->u.action.u.bss_tm_req.variable;
- if (url) {
- *pos++ += url_len;
- os_memcpy(pos, url, url_len);
- pos += url_len;
- }
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
@@ -305,6 +384,20 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
{
u8 dialog_token, reason;
const u8 *pos, *end;
+ int enabled = hapd->conf->bss_transition;
+
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled)
+ enabled = 1;
+#endif /* CONFIG_MBO */
+ if (!enabled) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore BSS Transition Management Query from "
+ MACSTR
+ " since BSS Transition Management is disabled",
+ MAC2STR(addr));
+ return;
+ }
if (len < 2) {
wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from "
@@ -324,7 +417,20 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
- ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL);
+ ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
+}
+
+
+void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+
+ if (sta->agreed_to_steer) {
+ wpa_printf(MSG_DEBUG, "%s: Reset steering flag for STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+ sta->agreed_to_steer = 0;
+ }
}
@@ -334,6 +440,21 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
{
u8 dialog_token, status_code, bss_termination_delay;
const u8 *pos, *end;
+ int enabled = hapd->conf->bss_transition;
+ struct sta_info *sta;
+
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled)
+ enabled = 1;
+#endif /* CONFIG_MBO */
+ if (!enabled) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore BSS Transition Management Response from "
+ MACSTR
+ " since BSS Transition Management is disabled",
+ MAC2STR(addr));
+ return;
+ }
if (len < 3) {
wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from "
@@ -352,11 +473,23 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
"bss_termination_delay=%u", MAC2STR(addr), dialog_token,
status_code, bss_termination_delay);
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for received BSS TM Response",
+ MAC2STR(addr));
+ return;
+ }
+
if (status_code == WNM_BSS_TM_ACCEPT) {
if (end - pos < ETH_ALEN) {
wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
return;
}
+ sta->agreed_to_steer = 1;
+ eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
+ eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
+ hapd, sta);
wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
MAC2STR(pos));
wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
@@ -366,6 +499,7 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
MAC2STR(pos));
pos += ETH_ALEN;
} else {
+ sta->agreed_to_steer = 0;
wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
" status_code=%u bss_termination_delay=%u",
MAC2STR(addr), status_code, bss_termination_delay);
@@ -376,6 +510,71 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
}
+static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *buf,
+ size_t len)
+{
+ u8 dialog_token, type;
+
+ if (len < 2)
+ return;
+ dialog_token = *buf++;
+ type = *buf++;
+ len -= 2;
+
+ wpa_printf(MSG_DEBUG,
+ "WNM: Received WNM Notification Request frame from "
+ MACSTR " (dialog_token=%u type=%u)",
+ MAC2STR(addr), dialog_token, type);
+ wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
+ buf, len);
+ if (type == WLAN_EID_VENDOR_SPECIFIC)
+ mbo_ap_wnm_notification_req(hapd, addr, buf, len);
+}
+
+
+static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *buf,
+ size_t len)
+{
+ u8 dialog_token;
+ char *hex;
+ size_t hex_len;
+
+ if (!hapd->conf->coloc_intf_reporting) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore unexpected Collocated Interference Report from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+
+ if (len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore too short Collocated Interference Report from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+ dialog_token = *buf++;
+ len--;
+
+ wpa_printf(MSG_DEBUG,
+ "WNM: Received Collocated Interference Report frame from "
+ MACSTR " (dialog_token=%u)",
+ MAC2STR(addr), dialog_token);
+ wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements",
+ buf, len);
+
+ hex_len = 2 * len + 1;
+ hex = os_malloc(hex_len);
+ if (!hex)
+ return;
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s",
+ MAC2STR(addr), dialog_token, hex);
+ os_free(hex);
+}
+
+
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -402,6 +601,14 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
case WNM_SLEEP_MODE_REQ:
ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen);
return 0;
+ case WNM_NOTIFICATION_REQ:
+ ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload,
+ plen);
+ return 0;
+ case WNM_COLLOCATED_INTERFERENCE_REPORT:
+ ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload,
+ plen);
+ return 0;
}
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
@@ -527,7 +734,8 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
u8 req_mode, int disassoc_timer, u8 valid_int,
const u8 *bss_term_dur, const char *url,
- const u8 *nei_rep, size_t nei_rep_len)
+ const u8 *nei_rep, size_t nei_rep_len,
+ const u8 *mbo_attrs, size_t mbo_len)
{
u8 *buf, *pos;
struct ieee80211_mgmt *mgmt;
@@ -536,7 +744,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x",
MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int);
- buf = os_zalloc(1000 + nei_rep_len);
+ buf = os_zalloc(1000 + nei_rep_len + mbo_len);
if (buf == NULL)
return -1;
mgmt = (struct ieee80211_mgmt *) buf;
@@ -579,6 +787,11 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
pos += nei_rep_len;
}
+ if (mbo_len > 0) {
+ pos += mbo_add_ie(pos, buf + sizeof(buf) - pos, mbo_attrs,
+ mbo_len);
+ }
+
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Failed to send BSS Transition Management Request frame");
@@ -594,3 +807,40 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
}
+
+
+int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
+ unsigned int auto_report, unsigned int timeout)
+{
+ u8 buf[100], *pos;
+ struct ieee80211_mgmt *mgmt;
+ u8 dialog_token = 1;
+
+ if (auto_report > 3 || timeout > 63)
+ return -1;
+ os_memset(buf, 0, sizeof(buf));
+ mgmt = (struct ieee80211_mgmt *) buf;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.coloc_intf_req.action =
+ WNM_COLLOCATED_INTERFERENCE_REQ;
+ mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token;
+ mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2);
+ pos = &mgmt->u.action.u.coloc_intf_req.req_info;
+ pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
+ MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
+ MAC2STR(sta->addr), dialog_token, auto_report, timeout);
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Failed to send Collocated Interference Request frame");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/ap/wnm_ap.h b/contrib/wpa/src/ap/wnm_ap.h
index 7789307..1806ba0 100644
--- a/contrib/wpa/src/ap/wnm_ap.h
+++ b/contrib/wpa/src/ap/wnm_ap.h
@@ -21,6 +21,10 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
u8 req_mode, int disassoc_timer, u8 valid_int,
const u8 *bss_term_dur, const char *url,
- const u8 *nei_rep, size_t nei_rep_len);
+ const u8 *nei_rep, size_t nei_rep_len,
+ const u8 *mbo_attrs, size_t mbo_len);
+void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx);
+int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
+ unsigned int auto_report, unsigned int timeout);
#endif /* WNM_AP_H */
diff --git a/contrib/wpa/src/ap/wpa_auth.c b/contrib/wpa/src/ap/wpa_auth.c
index 63f252f..f2e028c 100644
--- a/contrib/wpa/src/ap/wpa_auth.c
+++ b/contrib/wpa/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,12 +13,17 @@
#include "utils/state_machine.h"
#include "utils/bitfield.h"
#include "common/ieee802_11_defs.h"
+#include "common/ocv.h"
+#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
+#include "crypto/aes_siv.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/random.h"
#include "eapol_auth/eapol_auth_sm.h"
+#include "drivers/driver.h"
#include "ap_config.h"
#include "ieee802_11.h"
#include "wpa_auth.h"
@@ -33,8 +38,14 @@
static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
static int wpa_sm_step(struct wpa_state_machine *sm);
-static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
- size_t data_len);
+static int wpa_verify_key_mic(int akmp, size_t pmk_len, struct wpa_ptk *PTK,
+ u8 *data, size_t data_len);
+#ifdef CONFIG_FILS
+static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
+ u8 *buf, size_t buf_len, u16 *_key_data_len);
+static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
+ const struct wpabuf *hlp);
+#endif /* CONFIG_FILS */
static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
@@ -44,19 +55,20 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
- const u8 *pmk, struct wpa_ptk *ptk);
+ const u8 *pmk, unsigned int pmk_len,
+ struct wpa_ptk *ptk);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
-static const u32 dot11RSNAConfigGroupUpdateCount = 4;
-static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
static const u32 eapol_key_timeout_first = 100; /* ms */
static const u32 eapol_key_timeout_subseq = 1000; /* ms */
static const u32 eapol_key_timeout_first_group = 500; /* ms */
+static const u32 eapol_key_timeout_no_retrans = 4000; /* ms */
/* TODO: make these configurable */
static const int dot11RSNAConfigPMKLifetime = 43200;
@@ -67,8 +79,8 @@ static const int dot11RSNAConfigSATimeout = 60;
static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
- if (wpa_auth->cb.mic_failure_report)
- return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+ if (wpa_auth->cb->mic_failure_report)
+ return wpa_auth->cb->mic_failure_report(wpa_auth->cb_ctx, addr);
return 0;
}
@@ -76,8 +88,8 @@ static inline int wpa_auth_mic_failure_report(
static inline void wpa_auth_psk_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
- if (wpa_auth->cb.psk_failure_report)
- wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr);
+ if (wpa_auth->cb->psk_failure_report)
+ wpa_auth->cb->psk_failure_report(wpa_auth->cb_ctx, addr);
}
@@ -85,38 +97,39 @@ static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var,
int value)
{
- if (wpa_auth->cb.set_eapol)
- wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value);
+ if (wpa_auth->cb->set_eapol)
+ wpa_auth->cb->set_eapol(wpa_auth->cb_ctx, addr, var, value);
}
static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var)
{
- if (wpa_auth->cb.get_eapol == NULL)
+ if (wpa_auth->cb->get_eapol == NULL)
return -1;
- return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var);
+ return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
}
static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
const u8 *addr,
const u8 *p2p_dev_addr,
- const u8 *prev_psk)
+ const u8 *prev_psk, size_t *psk_len,
+ int *vlan_id)
{
- if (wpa_auth->cb.get_psk == NULL)
+ if (wpa_auth->cb->get_psk == NULL)
return NULL;
- return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, p2p_dev_addr,
- prev_psk);
+ return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
+ prev_psk, psk_len, vlan_id);
}
static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
const u8 *addr, u8 *msk, size_t *len)
{
- if (wpa_auth->cb.get_msk == NULL)
+ if (wpa_auth->cb->get_msk == NULL)
return -1;
- return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len);
+ return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
}
@@ -125,19 +138,19 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
enum wpa_alg alg, const u8 *addr, int idx,
u8 *key, size_t key_len)
{
- if (wpa_auth->cb.set_key == NULL)
+ if (wpa_auth->cb->set_key == NULL)
return -1;
- return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
+ key, key_len);
}
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
- if (wpa_auth->cb.get_seqnum == NULL)
+ if (wpa_auth->cb->get_seqnum == NULL)
return -1;
- return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+ return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
}
@@ -145,10 +158,10 @@ static inline int
wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *data, size_t data_len, int encrypt)
{
- if (wpa_auth->cb.send_eapol == NULL)
+ if (wpa_auth->cb->send_eapol == NULL)
return -1;
- return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len,
- encrypt);
+ return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
+ encrypt);
}
@@ -156,9 +169,9 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
const u8 *addr)
{
- if (wpa_auth->cb.start_ampe == NULL)
+ if (wpa_auth->cb->start_ampe == NULL)
return -1;
- return wpa_auth->cb.start_ampe(wpa_auth->cb.ctx, addr);
+ return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
}
#endif /* CONFIG_MESH */
@@ -167,9 +180,9 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb.for_each_sta == NULL)
+ if (wpa_auth->cb->for_each_sta == NULL)
return 0;
- return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx);
+ return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -177,18 +190,18 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb.for_each_auth == NULL)
+ if (wpa_auth->cb->for_each_auth == NULL)
return 0;
- return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx);
+ return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
}
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
- if (wpa_auth->cb.logger == NULL)
+ if (wpa_auth->cb->logger == NULL)
return;
- wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt);
+ wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
}
@@ -199,7 +212,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
int maxlen;
va_list ap;
- if (wpa_auth->cb.logger == NULL)
+ if (wpa_auth->cb->logger == NULL)
return;
maxlen = os_strlen(fmt) + 100;
@@ -218,30 +231,33 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
- const u8 *addr)
+ const u8 *addr, u16 reason)
{
- if (wpa_auth->cb.disconnect == NULL)
+ if (wpa_auth->cb->disconnect == NULL)
return;
- wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
- wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)",
+ MAC2STR(addr), reason);
+ wpa_auth->cb->disconnect(wpa_auth->cb_ctx, addr, reason);
}
-static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
+#ifdef CONFIG_OCV
+static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
+ struct wpa_channel_info *ci)
{
- int ret = 0;
-#ifdef CONFIG_IEEE80211R
- if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- ret = 1;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
- if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
- ret = 1;
-#endif /* CONFIG_IEEE80211W */
- if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
- ret = 1;
- return ret;
+ if (!wpa_auth->cb->channel_info)
+ return -1;
+ return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
+}
+#endif /* CONFIG_OCV */
+
+
+static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int vlan_id)
+{
+ if (!wpa_auth->cb->update_vlan)
+ return -1;
+ return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id);
}
@@ -304,6 +320,19 @@ static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
}
+void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm)
+{
+ if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) {
+ wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for "
+ MACSTR " (%d seconds)", MAC2STR(sm->addr),
+ sm->wpa_auth->conf.wpa_ptk_rekey);
+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0,
+ wpa_rekey_ptk, sm->wpa_auth, sm);
+ }
+}
+
+
static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
{
if (sm->pmksa == ctx)
@@ -339,6 +368,10 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
wpa_get_ntp_timestamp(buf + ETH_ALEN);
ptr = (unsigned long) group;
os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
+#ifdef TEST_FUZZ
+ os_memset(buf + ETH_ALEN, 0xab, 8);
+ os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr));
+#endif /* TEST_FUZZ */
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
return -1;
@@ -408,7 +441,8 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
*/
struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_auth_config *conf,
- struct wpa_auth_callbacks *cb)
+ const struct wpa_auth_callbacks *cb,
+ void *cb_ctx)
{
struct wpa_authenticator *wpa_auth;
@@ -417,7 +451,8 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
return NULL;
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
- os_memcpy(&wpa_auth->cb, cb, sizeof(*cb));
+ wpa_auth->cb = cb;
+ wpa_auth->cb_ctx = cb_ctx;
if (wpa_auth_gen_wpa_ie(wpa_auth)) {
wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
@@ -442,7 +477,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
return NULL;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
if (wpa_auth->ft_pmk_cache == NULL) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
@@ -452,7 +487,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
os_free(wpa_auth);
return NULL;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (wpa_auth->conf.wpa_gmk_rekey) {
eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
@@ -505,17 +540,13 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
-#ifdef CONFIG_PEERKEY
- while (wpa_auth->stsl_negotiations)
- wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
-#endif /* CONFIG_PEERKEY */
-
pmksa_cache_auth_deinit(wpa_auth->pmksa);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
wpa_auth->ft_pmk_cache = NULL;
-#endif /* CONFIG_IEEE80211R */
+ wpa_ft_deinit(wpa_auth);
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
bitfield_free(wpa_auth->ip_pool);
@@ -598,16 +629,28 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
return -1;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sm->ft_completed) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"FT authentication already completed - do not "
"start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+ sm->Pair = TRUE;
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_FILS
+ if (sm->fils_completed) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "FILS authentication already completed - do not start 4-way handshake");
+ /* Go to PTKINITDONE state to allow GTK rekeying */
+ sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+ sm->Pair = TRUE;
+ return 0;
+ }
+#endif /* CONFIG_FILS */
if (sm->started) {
os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
@@ -659,14 +702,17 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
os_free(sm->assoc_resp_ftie);
wpabuf_free(sm->ft_pending_req_ies);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
wpa_group_put(sm->wpa_auth, sm->group);
- os_free(sm);
+#ifdef CONFIG_DPP2
+ wpabuf_clear_free(sm->dpp_z);
+#endif /* CONFIG_DPP2 */
+ bin_clear_free(sm, sizeof(*sm));
}
@@ -679,15 +725,19 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"strict rekeying - force GTK rekey since STA "
"is leaving");
- eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
- eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
- NULL);
+ if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
+ sm->wpa_auth, NULL) == -1)
+ eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
+ NULL);
}
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+#ifdef CONFIG_IEEE80211R_AP
+ wpa_ft_sta_deinit(sm);
+#endif /* CONFIG_IEEE80211R_AP */
if (sm->in_step_loop) {
/* Must not free state machine while wpa_sm_step() is running.
* Freeing will be completed in the end of wpa_sm_step(). */
@@ -738,7 +788,7 @@ static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
struct wpa_eapol_ie_parse *kde)
@@ -785,7 +835,7 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
@@ -827,25 +877,44 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
struct wpa_ptk PTK;
int ok = 0;
const u8 *pmk = NULL;
+ size_t pmk_len;
+ int vlan_id = 0;
+ os_memset(&PTK, 0, sizeof(PTK));
for (;;) {
- if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
- sm->p2p_dev_addr, pmk);
+ sm->p2p_dev_addr, pmk, &pmk_len,
+ &vlan_id);
if (pmk == NULL)
break;
- } else
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
+ os_memcpy(sm->xxkey, pmk, pmk_len);
+ sm->xxkey_len = pmk_len;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+ } else {
pmk = sm->PMK;
+ pmk_len = sm->pmk_len;
+ }
- wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK);
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+ break;
- if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
- == 0) {
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
+ data, data_len) == 0) {
+ if (sm->PMK != pmk) {
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ }
ok = 1;
break;
}
- if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+ if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+ wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
}
@@ -858,6 +927,11 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
wpa_printf(MSG_DEBUG,
"WPA: Earlier SNonce resulted in matching MIC");
sm->alt_snonce_valid = 0;
+
+ if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+ wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
+ return -1;
+
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
@@ -872,39 +946,41 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- struct wpa_eapol_key_192 *key192;
u16 key_info, key_data_length;
- enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
- SMK_M1, SMK_M3, SMK_ERROR } msg;
+ enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST } msg;
char *msgtxt;
struct wpa_eapol_ie_parse kde;
- int ft;
- const u8 *eapol_key_ie, *key_data;
- size_t eapol_key_ie_len, keyhdrlen, mic_len;
+ const u8 *key_data;
+ size_t keyhdrlen, mic_len;
+ u8 *mic;
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
return;
+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
- mic_len = wpa_mic_len(sm->wpa_key_mgmt);
- keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+ keyhdrlen = sizeof(*key) + mic_len + 2;
- if (data_len < sizeof(*hdr) + keyhdrlen)
+ if (data_len < sizeof(*hdr) + keyhdrlen) {
+ wpa_printf(MSG_DEBUG, "WPA: Ignore too short EAPOL-Key frame");
return;
+ }
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
- key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ mic = (u8 *) (key + 1);
key_info = WPA_GET_BE16(key->key_info);
- if (mic_len == 24) {
- key_data = (const u8 *) (key192 + 1);
- key_data_length = WPA_GET_BE16(key192->key_data_length);
- } else {
- key_data = (const u8 *) (key + 1);
- key_data_length = WPA_GET_BE16(key->key_data_length);
- }
+ key_data = mic + mic_len + 2;
+ key_data_length = WPA_GET_BE16(mic + mic_len);
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
- " key_info=0x%x type=%u key_data_length=%u",
- MAC2STR(sm->addr), key_info, key->type, key_data_length);
+ " key_info=0x%x type=%u mic_len=%u key_data_length=%u",
+ MAC2STR(sm->addr), key_info, key->type,
+ (unsigned int) mic_len, key_data_length);
+ wpa_hexdump(MSG_MSGDUMP,
+ "WPA: EAPOL-Key header (ending before Key MIC)",
+ key, sizeof(*key));
+ wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
+ mic, mic_len);
if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
"key_data overflow (%d > %lu)",
@@ -945,25 +1021,20 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
* are set */
- if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) ==
- (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) {
- if (key_info & WPA_KEY_INFO_ERROR) {
- msg = SMK_ERROR;
- msgtxt = "SMK Error";
- } else {
- msg = SMK_M1;
- msgtxt = "SMK M1";
- }
- } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
- msg = SMK_M3;
- msgtxt = "SMK M3";
- } else if (key_info & WPA_KEY_INFO_REQUEST) {
+ if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+ wpa_printf(MSG_DEBUG, "WPA: Ignore SMK message");
+ return;
+ }
+
+ if (key_info & WPA_KEY_INFO_REQUEST) {
msg = REQUEST;
msgtxt = "Request";
} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
msg = GROUP_2;
msgtxt = "2/2 Group";
- } else if (key_data_length == 0) {
+ } else if (key_data_length == 0 ||
+ (mic_len == 0 && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
+ key_data_length == AES_BLOCK_SIZE)) {
msg = PAIRWISE_4;
msgtxt = "4/4 Pairwise";
} else {
@@ -971,15 +1042,13 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
msgtxt = "2/4 Pairwise";
}
- /* TODO: key_info type validation for PeerKey */
if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
msg == GROUP_2) {
u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (sm->pairwise == WPA_CIPHER_CCMP ||
sm->pairwise == WPA_CIPHER_GCMP) {
- if (wpa_use_aes_cmac(sm) &&
- sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
- !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
+ if (wpa_use_cmac(sm->wpa_key_mgmt) &&
+ !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -989,7 +1058,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
return;
}
- if (!wpa_use_aes_cmac(sm) &&
+ if (!wpa_use_cmac(sm->wpa_key_mgmt) &&
+ !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -999,7 +1069,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
}
}
- if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
+ if (wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
"did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
@@ -1087,6 +1157,15 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
}
continue_processing:
+#ifdef CONFIG_FILS
+ if (sm->wpa == WPA_VERSION_WPA2 && mic_len == 0 &&
+ !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "WPA: Encr Key Data bit not set even though AEAD cipher is supposed to be used - drop frame");
+ return;
+ }
+#endif /* CONFIG_FILS */
+
switch (msg) {
case PAIRWISE_2:
if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
@@ -1114,70 +1193,10 @@ continue_processing:
"collect more entropy for random number "
"generation");
random_mark_pool_ready();
- wpa_sta_disconnect(wpa_auth, sm->addr);
- return;
- }
- if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/4 with "
- "invalid Key Data contents");
- return;
- }
- if (kde.rsn_ie) {
- eapol_key_ie = kde.rsn_ie;
- eapol_key_ie_len = kde.rsn_ie_len;
- } else if (kde.osen) {
- eapol_key_ie = kde.osen;
- eapol_key_ie_len = kde.osen_len;
- } else {
- eapol_key_ie = kde.wpa_ie;
- eapol_key_ie_len = kde.wpa_ie_len;
- }
- ft = sm->wpa == WPA_VERSION_WPA2 &&
- wpa_key_mgmt_ft(sm->wpa_key_mgmt);
- if (sm->wpa_ie == NULL ||
- wpa_compare_rsn_ie(ft,
- sm->wpa_ie, sm->wpa_ie_len,
- eapol_key_ie, eapol_key_ie_len)) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "WPA IE from (Re)AssocReq did not "
- "match with msg 2/4");
- if (sm->wpa_ie) {
- wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
- sm->wpa_ie, sm->wpa_ie_len);
- }
- wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
- eapol_key_ie, eapol_key_ie_len);
- /* MLME-DEAUTHENTICATE.request */
- wpa_sta_disconnect(wpa_auth, sm->addr);
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
-#ifdef CONFIG_IEEE80211R
- if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
- wpa_sta_disconnect(wpa_auth, sm->addr);
- return;
- }
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_P2P
- if (kde.ip_addr_req && kde.ip_addr_req[0] &&
- wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
- int idx;
- wpa_printf(MSG_DEBUG, "P2P: IP address requested in "
- "EAPOL-Key exchange");
- idx = bitfield_get_first_zero(wpa_auth->ip_pool);
- if (idx >= 0) {
- u32 start = WPA_GET_BE32(wpa_auth->conf.
- ip_addr_start);
- bitfield_set(wpa_auth->ip_pool, idx);
- WPA_PUT_BE32(sm->ip_addr, start + idx);
- wpa_printf(MSG_DEBUG, "P2P: Assigned IP "
- "address %u.%u.%u.%u to " MACSTR,
- sm->ip_addr[0], sm->ip_addr[1],
- sm->ip_addr[2], sm->ip_addr[3],
- MAC2STR(sm->addr));
- }
- }
-#endif /* CONFIG_P2P */
break;
case PAIRWISE_4:
if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
@@ -1199,28 +1218,6 @@ continue_processing:
return;
}
break;
-#ifdef CONFIG_PEERKEY
- case SMK_M1:
- case SMK_M3:
- case SMK_ERROR:
- if (!wpa_auth->conf.peerkey) {
- wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but "
- "PeerKey use disabled - ignoring message");
- return;
- }
- if (!sm->PTK_valid) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg SMK in "
- "invalid state - dropped");
- return;
- }
- break;
-#else /* CONFIG_PEERKEY */
- case SMK_M1:
- case SMK_M3:
- case SMK_ERROR:
- return; /* STSL disabled - ignore SMK messages */
-#endif /* CONFIG_PEERKEY */
case REQUEST:
break;
}
@@ -1234,22 +1231,55 @@ continue_processing:
return;
}
- if (!(key_info & WPA_KEY_INFO_MIC)) {
+ if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
+ !(key_info & WPA_KEY_INFO_MIC)) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received invalid EAPOL-Key: Key MIC not set");
return;
}
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
+ (key_info & WPA_KEY_INFO_MIC)) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received invalid EAPOL-Key: Key MIC set");
+ return;
+ }
+#endif /* CONFIG_FILS */
+
sm->MICVerified = FALSE;
if (sm->PTK_valid && !sm->update_snonce) {
- if (wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
- data_len) &&
+ if (mic_len &&
+ wpa_verify_key_mic(sm->wpa_key_mgmt, sm->pmk_len, &sm->PTK,
+ data, data_len) &&
(msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
wpa_try_alt_snonce(sm, data, data_len))) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
return;
}
+#ifdef CONFIG_FILS
+ if (!mic_len &&
+ wpa_aead_decrypt(sm, &sm->PTK, data, data_len,
+ &key_data_length) < 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
+ return;
+ }
+#endif /* CONFIG_FILS */
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
sm->MICVerified = TRUE;
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
@@ -1272,12 +1302,7 @@ continue_processing:
* even though MAC address KDE is not normally encrypted,
* supplicant is allowed to encrypt it.
*/
- if (msg == SMK_ERROR) {
-#ifdef CONFIG_PEERKEY
- wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
-#endif /* CONFIG_PEERKEY */
- return;
- } else if (key_info & WPA_KEY_INFO_ERROR) {
+ if (key_info & WPA_KEY_INFO_ERROR) {
if (wpa_receive_error_report(
wpa_auth, sm,
!(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
@@ -1287,11 +1312,6 @@ continue_processing:
"received EAPOL-Key Request for new "
"4-Way Handshake");
wpa_request_new_ptk(sm);
-#ifdef CONFIG_PEERKEY
- } else if (msg == SMK_M1) {
- wpa_smk_m1(wpa_auth, sm, key, key_data,
- key_data_length);
-#endif /* CONFIG_PEERKEY */
} else if (key_data_length > 0 &&
wpa_parse_kde_ies(key_data, key_data_length,
&kde) == 0 &&
@@ -1330,18 +1350,10 @@ continue_processing:
wpa_replay_counter_mark_invalid(sm->key_replay, NULL);
}
-#ifdef CONFIG_PEERKEY
- if (msg == SMK_M3) {
- wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
- return;
- }
-#endif /* CONFIG_PEERKEY */
-
os_free(sm->last_rx_eapol_key);
- sm->last_rx_eapol_key = os_malloc(data_len);
+ sm->last_rx_eapol_key = os_memdup(data, data_len);
if (sm->last_rx_eapol_key == NULL)
return;
- os_memcpy(sm->last_rx_eapol_key, data, data_len);
sm->last_rx_eapol_key_len = data_len;
sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
@@ -1356,7 +1368,7 @@ continue_processing:
static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
const u8 *gnonce, u8 *gtk, size_t gtk_len)
{
- u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16];
+ u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + WPA_GTK_MAX_LEN];
u8 *pos;
int ret = 0;
@@ -1367,21 +1379,33 @@ static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
* is done only at the Authenticator and as such, does not need to be
* exactly same.
*/
+ os_memset(data, 0, sizeof(data));
os_memcpy(data, addr, ETH_ALEN);
os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
pos = data + ETH_ALEN + WPA_NONCE_LEN;
wpa_get_ntp_timestamp(pos);
+#ifdef TEST_FUZZ
+ os_memset(pos, 0xef, 8);
+#endif /* TEST_FUZZ */
pos += 8;
- if (random_get_bytes(pos, 16) < 0)
+ if (random_get_bytes(pos, gtk_len) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
- sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len);
-#else /* CONFIG_IEEE80211W */
- if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len)
- < 0)
+#ifdef CONFIG_SHA384
+ if (sha384_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+ gtk, gtk_len) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
+#else /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA256
+ if (sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+ gtk, gtk_len) < 0)
+ ret = -1;
+#else /* CONFIG_SHA256 */
+ if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+ gtk, gtk_len) < 0)
+ ret = -1;
+#endif /* CONFIG_SHA256 */
+#endif /* CONFIG_SHA384 */
return ret;
}
@@ -1407,26 +1431,24 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- struct wpa_eapol_key_192 *key192;
size_t len, mic_len, keyhdrlen;
int alg;
int key_data_len, pad_len = 0;
u8 *buf, *pos;
int version, pairwise;
int i;
- u8 *key_data;
+ u8 *key_mic, *key_data;
- mic_len = wpa_mic_len(sm->wpa_key_mgmt);
- keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+ keyhdrlen = sizeof(*key) + mic_len + 2;
len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
if (force_version)
version = force_version;
- else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->wpa_key_mgmt))
+ else if (wpa_use_akm_defined(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
- else if (wpa_use_aes_cmac(sm))
+ else if (wpa_use_cmac(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
else if (sm->pairwise != WPA_CIPHER_TKIP)
version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
@@ -1448,8 +1470,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
key_data_len = kde_len;
if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
+ wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
pad_len = key_data_len % 8;
if (pad_len)
@@ -1458,6 +1479,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
}
len += key_data_len;
+ if (!mic_len && encr)
+ len += AES_BLOCK_SIZE;
hdr = os_zalloc(len);
if (hdr == NULL)
@@ -1466,7 +1489,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
- key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ key_mic = (u8 *) (key + 1);
key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
key->type = sm->wpa == WPA_VERSION_WPA2 ?
@@ -1479,11 +1502,11 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
WPA_PUT_BE16(key->key_info, key_info);
alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
- WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
- if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+ if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
WPA_PUT_BE16(key->key_length, 0);
+ else
+ WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
- /* FIX: STSL: what to use as key_replay_counter? */
for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
os_memcpy(sm->key_replay[i].counter,
@@ -1505,10 +1528,31 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
if (kde && !encr) {
os_memcpy(key_data, kde, kde_len);
- if (mic_len == 24)
- WPA_PUT_BE16(key192->key_data_length, kde_len);
- else
- WPA_PUT_BE16(key->key_data_length, kde_len);
+ WPA_PUT_BE16(key_mic + mic_len, kde_len);
+#ifdef CONFIG_FILS
+ } else if (!mic_len && kde) {
+ const u8 *aad[1];
+ size_t aad_len[1];
+
+ WPA_PUT_BE16(key_mic, AES_BLOCK_SIZE + kde_len);
+ wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
+ kde, kde_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KEK",
+ sm->PTK.kek, sm->PTK.kek_len);
+ /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
+ * to Key Data (exclusive). */
+ aad[0] = (u8 *) hdr;
+ aad_len[0] = key_mic + 2 - (u8 *) hdr;
+ if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len, kde, kde_len,
+ 1, aad, aad_len, key_mic + 2) < 0) {
+ wpa_printf(MSG_DEBUG, "WPA: AES-SIV encryption failed");
+ return;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPA: Encrypted Key Data from SIV",
+ key_mic + 2, AES_BLOCK_SIZE + kde_len);
+#endif /* CONFIG_FILS */
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
if (buf == NULL) {
@@ -1525,24 +1569,24 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
buf, key_data_len);
if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
+ wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: Encrypt Key Data using AES-WRAP (KEK length %u)",
+ (unsigned int) sm->PTK.kek_len);
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
(key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
os_free(buf);
return;
}
- if (mic_len == 24)
- WPA_PUT_BE16(key192->key_data_length,
- key_data_len);
- else
- WPA_PUT_BE16(key->key_data_length,
- key_data_len);
+ WPA_PUT_BE16(key_mic + mic_len, key_data_len);
#ifndef CONFIG_NO_RC4
} else if (sm->PTK.kek_len == 16) {
u8 ek[32];
+
+ wpa_printf(MSG_DEBUG,
+ "WPA: Encrypt Key Data using RC4");
os_memcpy(key->key_iv,
sm->group->Counter + WPA_NONCE_LEN - 16, 16);
inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
@@ -1550,12 +1594,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
os_memcpy(key_data, buf, key_data_len);
rc4_skip(ek, 32, 256, key_data, key_data_len);
- if (mic_len == 24)
- WPA_PUT_BE16(key192->key_data_length,
- key_data_len);
- else
- WPA_PUT_BE16(key->key_data_length,
- key_data_len);
+ WPA_PUT_BE16(key_mic + mic_len, key_data_len);
#endif /* CONFIG_NO_RC4 */
} else {
os_free(hdr);
@@ -1566,9 +1605,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
}
if (key_info & WPA_KEY_INFO_MIC) {
- u8 *key_mic;
-
- if (!sm->PTK_valid) {
+ if (!sm->PTK_valid || !mic_len) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PTK not valid when sending EAPOL-Key "
"frame");
@@ -1576,10 +1613,12 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
return;
}
- key_mic = key192->key_mic; /* same offset for key and key192 */
- wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
- sm->wpa_key_mgmt, version,
- (u8 *) hdr, len, key_mic);
+ if (wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
+ sm->wpa_key_mgmt, version,
+ (u8 *) hdr, len, key_mic) < 0) {
+ os_free(hdr);
+ return;
+ }
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1608,7 +1647,7 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
{
int timeout_ms;
int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
- int ctr;
+ u32 ctr;
if (sm == NULL)
return;
@@ -1622,41 +1661,46 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
eapol_key_timeout_first_group;
else
timeout_ms = eapol_key_timeout_subseq;
+ if (wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ (!pairwise || (key_info & WPA_KEY_INFO_MIC)))
+ timeout_ms = eapol_key_timeout_no_retrans;
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
sm->pending_1_of_4_timeout = 1;
+#ifdef TEST_FUZZ
+ timeout_ms = 1;
+#endif /* TEST_FUZZ */
wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
- "counter %d)", timeout_ms, ctr);
+ "counter %u)", timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
wpa_send_eapol_timeout, wpa_auth, sm);
}
-static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
- size_t data_len)
+static int wpa_verify_key_mic(int akmp, size_t pmk_len, struct wpa_ptk *PTK,
+ u8 *data, size_t data_len)
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- struct wpa_eapol_key_192 *key192;
u16 key_info;
int ret = 0;
- u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
- size_t mic_len = wpa_mic_len(akmp);
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN], *mic_pos;
+ size_t mic_len = wpa_mic_len(akmp, pmk_len);
if (data_len < sizeof(*hdr) + sizeof(*key))
return -1;
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
- key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ mic_pos = (u8 *) (key + 1);
key_info = WPA_GET_BE16(key->key_info);
- os_memcpy(mic, key192->key_mic, mic_len);
- os_memset(key192->key_mic, 0, mic_len);
+ os_memcpy(mic, mic_pos, mic_len);
+ os_memset(mic_pos, 0, mic_len);
if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
key_info & WPA_KEY_INFO_TYPE_MASK,
- data, data_len, key192->key_mic) ||
- os_memcmp_const(mic, key192->key_mic, mic_len) != 0)
+ data, data_len, mic_pos) ||
+ os_memcmp_const(mic, mic_pos, mic_len) != 0)
ret = -1;
- os_memcpy(key192->key_mic, mic, mic_len);
+ os_memcpy(mic_pos, mic, mic_len);
return ret;
}
@@ -1665,7 +1709,10 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
{
sm->PTK_valid = FALSE;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
- wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, 0);
+ if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
+ 0))
+ wpa_printf(MSG_DEBUG,
+ "RSN: PTK removal from the driver failed");
sm->pairwise_set = FALSE;
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
}
@@ -1696,6 +1743,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
case WPA_DEAUTH:
case WPA_DISASSOC:
sm->DeauthenticationRequest = TRUE;
+#ifdef CONFIG_IEEE80211R_AP
+ os_memset(sm->PMK, 0, sizeof(sm->PMK));
+ sm->pmk_len = 0;
+ os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+ sm->xxkey_len = 0;
+ os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+ sm->pmk_r1_len = 0;
+#endif /* CONFIG_IEEE80211R_AP */
break;
case WPA_REAUTH:
case WPA_REAUTH_EAPOL:
@@ -1729,27 +1784,46 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
sm->ReAuthenticationRequest = TRUE;
break;
case WPA_ASSOC_FT:
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
"after association");
wpa_ft_install_ptk(sm);
/* Using FT protocol, not WPA auth state machine */
sm->ft_completed = 1;
+ wpa_auth_set_ptk_rekey_timer(sm);
+ return 0;
+#else /* CONFIG_IEEE80211R_AP */
+ break;
+#endif /* CONFIG_IEEE80211R_AP */
+ case WPA_ASSOC_FILS:
+#ifdef CONFIG_FILS
+ wpa_printf(MSG_DEBUG,
+ "FILS: TK configuration after association");
+ fils_set_tk(sm);
+ sm->fils_completed = 1;
return 0;
-#else /* CONFIG_IEEE80211R */
+#else /* CONFIG_FILS */
break;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
+ case WPA_DRV_STA_REMOVED:
+ sm->tk_already_set = FALSE;
+ return 0;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
sm->ft_completed = 0;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot && event == WPA_AUTH)
remove_ptk = 0;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
+ (event == WPA_AUTH || event == WPA_ASSOC))
+ remove_ptk = 0;
+#endif /* CONFIG_FILS */
if (remove_ptk) {
sm->PTK_valid = FALSE;
@@ -1794,7 +1868,9 @@ SM_STATE(WPA_PTK, INITIALIZE)
wpa_remove_ptk(sm);
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
sm->TimeoutCtr = 0;
- if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) {
wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
WPA_EAPOL_authorized, 0);
}
@@ -1803,9 +1879,14 @@ SM_STATE(WPA_PTK, INITIALIZE)
SM_STATE(WPA_PTK, DISCONNECT)
{
+ u16 reason = sm->disconnect_reason;
+
SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
sm->Disconnect = FALSE;
- wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ sm->disconnect_reason = 0;
+ if (!reason)
+ reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr, reason);
}
@@ -1914,25 +1995,54 @@ SM_STATE(WPA_PTK, INITPMK)
size_t len = 2 * PMK_LEN;
SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
sm->xxkey_len = 0;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (sm->pmksa) {
wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
- os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN);
+ os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
+ sm->pmk_len = sm->pmksa->pmk_len;
+#ifdef CONFIG_DPP
+ } else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No PMKSA cache entry for STA - reject connection");
+ sm->Disconnect = TRUE;
+ sm->disconnect_reason = WLAN_REASON_INVALID_PMKID;
+ return;
+#endif /* CONFIG_DPP */
} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
+ unsigned int pmk_len;
+
+ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt))
+ pmk_len = PMK_LEN_SUITE_B_192;
+ else
+ pmk_len = PMK_LEN;
wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
- "(len=%lu)", (unsigned long) len);
- os_memcpy(sm->PMK, msk, PMK_LEN);
-#ifdef CONFIG_IEEE80211R
+ "(MSK len=%lu PMK len=%u)", (unsigned long) len,
+ pmk_len);
+ if (len < pmk_len) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: MSK not long enough (%u) to create PMK (%u)",
+ (unsigned int) len, (unsigned int) pmk_len);
+ sm->Disconnect = TRUE;
+ return;
+ }
+ os_memcpy(sm->PMK, msk, pmk_len);
+ sm->pmk_len = pmk_len;
+#ifdef CONFIG_IEEE80211R_AP
if (len >= 2 * PMK_LEN) {
- os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
- sm->xxkey_len = PMK_LEN;
+ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
+ os_memcpy(sm->xxkey, msk, SHA384_MAC_LEN);
+ sm->xxkey_len = SHA384_MAC_LEN;
+ } else {
+ os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
+ sm->xxkey_len = PMK_LEN;
+ }
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
} else {
wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
- sm->wpa_auth->cb.get_msk);
+ sm->wpa_auth->cb->get_msk);
sm->Disconnect = TRUE;
return;
}
@@ -1954,15 +2064,30 @@ SM_STATE(WPA_PTK, INITPMK)
SM_STATE(WPA_PTK, INITPSK)
{
const u8 *psk;
+ size_t psk_len;
+
SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
- psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL);
+ psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
+ &psk_len, NULL);
if (psk) {
- os_memcpy(sm->PMK, psk, PMK_LEN);
-#ifdef CONFIG_IEEE80211R
+ os_memcpy(sm->PMK, psk, psk_len);
+ sm->pmk_len = psk_len;
+#ifdef CONFIG_IEEE80211R_AP
os_memcpy(sm->xxkey, psk, PMK_LEN);
sm->xxkey_len = PMK_LEN;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+ }
+#ifdef CONFIG_SAE
+ if (wpa_auth_uses_sae(sm) && sm->pmksa) {
+ wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache");
+ os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
+ sm->pmk_len = sm->pmksa->pmk_len;
+#ifdef CONFIG_IEEE80211R_AP
+ os_memcpy(sm->xxkey, sm->pmksa->pmk, sm->pmksa->pmk_len);
+ sm->xxkey_len = sm->pmksa->pmk_len;
+#endif /* CONFIG_IEEE80211R_AP */
}
+#endif /* CONFIG_SAE */
sm->req_replay_counter_used = 0;
}
@@ -1978,7 +2103,7 @@ SM_STATE(WPA_PTK, PTKSTART)
sm->alt_snonce_valid = FALSE;
sm->TimeoutCtr++;
- if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+ if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -1987,11 +2112,23 @@ SM_STATE(WPA_PTK, PTKSTART)
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 1/4 msg of 4-Way Handshake");
/*
- * TODO: Could add PMKID even with WPA2-PSK, but only if there is only
- * one possible PSK for this STA.
+ * For infrastructure BSS cases, it is better for the AP not to include
+ * the PMKID KDE in EAPOL-Key msg 1/4 since it could be used to initiate
+ * offline search for the passphrase/PSK without having to be able to
+ * capture a 4-way handshake from a STA that has access to the network.
+ *
+ * For IBSS cases, addition of PMKID KDE could be considered even with
+ * WPA2-PSK cases that use multiple PSKs, but only if there is a single
+ * possible PSK for this STA. However, this should not be done unless
+ * there is support for using that information on the supplicant side.
+ * The concern about exposing PMKID unnecessarily in infrastructure BSS
+ * cases would also apply here, but at least in the IBSS case, this
+ * would cover a potential real use case.
*/
if (sm->wpa == WPA_VERSION_WPA2 &&
- wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+ (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) ||
+ (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && sm->pmksa) ||
+ wpa_key_mgmt_sae(sm->wpa_key_mgmt)) &&
sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN) {
pmkid = buf;
pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
@@ -1999,19 +2136,65 @@ SM_STATE(WPA_PTK, PTKSTART)
pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
if (sm->pmksa) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID from PMKSA entry",
+ sm->pmksa->pmkid, PMKID_LEN);
os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
sm->pmksa->pmkid, PMKID_LEN);
} else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
/* No KCK available to derive PMKID */
+ wpa_printf(MSG_DEBUG,
+ "RSN: No KCK available to derive PMKID for message 1/4");
pmkid = NULL;
+#ifdef CONFIG_FILS
+ } else if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ if (sm->pmkid_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID from FILS/ERP",
+ sm->pmkid, PMKID_LEN);
+ os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+ sm->pmkid, PMKID_LEN);
+ } else {
+ /* No PMKID available */
+ wpa_printf(MSG_DEBUG,
+ "RSN: No FILS/ERP PMKID available for message 1/4");
+ pmkid = NULL;
+ }
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R_AP
+ } else if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ sm->ft_completed) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMKID in message 1/4 when using FT protocol");
+ pmkid = NULL;
+ pmkid_len = 0;
+#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_SAE
+ } else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
+ if (sm->pmkid_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID from SAE",
+ sm->pmkid, PMKID_LEN);
+ os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+ sm->pmkid, PMKID_LEN);
+ } else {
+ /* No PMKID available */
+ wpa_printf(MSG_DEBUG,
+ "RSN: No SAE PMKID available for message 1/4");
+ pmkid = NULL;
+ }
+#endif /* CONFIG_SAE */
} else {
/*
* Calculate PMKID since no PMKSA cache entry was
* available with pre-calculated PMKID.
*/
- rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
+ rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
- wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
+ sm->wpa_key_mgmt);
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID derived from PMK",
+ &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
}
}
wpa_send_eapol(sm->wpa_auth, sm,
@@ -2021,52 +2204,681 @@ SM_STATE(WPA_PTK, PTKSTART)
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
- const u8 *pmk, struct wpa_ptk *ptk)
+ const u8 *pmk, unsigned int pmk_len,
+ struct wpa_ptk *ptk)
{
-#ifdef CONFIG_IEEE80211R
- if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
-#endif /* CONFIG_IEEE80211R */
+ const u8 *z = NULL;
+ size_t z_len = 0;
+
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+ if (sm->ft_completed) {
+ u8 ptk_name[WPA_PMK_NAME_LEN];
+
+ return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
+ sm->SNonce, sm->ANonce,
+ sm->addr, sm->wpa_auth->addr,
+ sm->pmk_r1_name,
+ ptk, ptk_name,
+ sm->wpa_key_mgmt,
+ sm->pairwise);
+ }
+ return wpa_auth_derive_ptk_ft(sm, ptk);
+ }
+#endif /* CONFIG_IEEE80211R_AP */
- return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+ z = wpabuf_head(sm->dpp_z);
+ z_len = wpabuf_len(sm->dpp_z);
+ }
+#endif /* CONFIG_DPP2 */
+
+ return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, sm->wpa_key_mgmt, sm->pairwise);
+ ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
+}
+
+
+#ifdef CONFIG_FILS
+
+int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *snonce, const u8 *anonce,
+ const u8 *dhss, size_t dhss_len,
+ struct wpabuf *g_sta, struct wpabuf *g_ap)
+{
+ u8 ick[FILS_ICK_MAX_LEN];
+ size_t ick_len;
+ int res;
+ u8 fils_ft[FILS_FT_MAX_LEN];
+ size_t fils_ft_len = 0;
+
+ res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr,
+ snonce, anonce, dhss, dhss_len,
+ &sm->PTK, ick, &ick_len,
+ sm->wpa_key_mgmt, sm->pairwise,
+ fils_ft, &fils_ft_len);
+ if (res < 0)
+ return res;
+ sm->PTK_valid = TRUE;
+ sm->tk_already_set = FALSE;
+
+#ifdef CONFIG_IEEE80211R_AP
+ if (fils_ft_len) {
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_auth_config *conf = &wpa_auth->conf;
+ u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+ int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+ size_t pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
+
+ if (wpa_derive_pmk_r0(fils_ft, fils_ft_len,
+ conf->ssid, conf->ssid_len,
+ conf->mobility_domain,
+ conf->r0_key_holder,
+ conf->r0_key_holder_len,
+ sm->addr, pmk_r0, pmk_r0_name,
+ use_sha384) < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
+ pmk_r0, pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
+ pmk_r0_name, WPA_PMK_NAME_LEN);
+ wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
+ os_memset(fils_ft, 0, sizeof(fils_ft));
+
+ res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
+ sm->addr, sm->pmk_r1_name,
+ use_sha384);
+ os_memset(pmk_r0, 0, PMK_LEN_MAX);
+ if (res < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+ sm->pmk_r1_name_valid = 1;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+
+ res = fils_key_auth_sk(ick, ick_len, snonce, anonce,
+ sm->addr, sm->wpa_auth->addr,
+ g_sta ? wpabuf_head(g_sta) : NULL,
+ g_sta ? wpabuf_len(g_sta) : 0,
+ g_ap ? wpabuf_head(g_ap) : NULL,
+ g_ap ? wpabuf_len(g_ap) : 0,
+ sm->wpa_key_mgmt, sm->fils_key_auth_sta,
+ sm->fils_key_auth_ap,
+ &sm->fils_key_auth_len);
+ os_memset(ick, 0, sizeof(ick));
+
+ /* Store nonces for (Re)Association Request/Response frame processing */
+ os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
+ os_memcpy(sm->ANonce, anonce, FILS_NONCE_LEN);
+
+ return res;
+}
+
+
+static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
+ u8 *buf, size_t buf_len, u16 *_key_data_len)
+{
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ u8 *pos;
+ u16 key_data_len;
+ u8 *tmp;
+ const u8 *aad[1];
+ size_t aad_len[1];
+
+ hdr = (struct ieee802_1x_hdr *) buf;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ pos = (u8 *) (key + 1);
+ key_data_len = WPA_GET_BE16(pos);
+ if (key_data_len < AES_BLOCK_SIZE ||
+ key_data_len > buf_len - sizeof(*hdr) - sizeof(*key) - 2) {
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "No room for AES-SIV data in the frame");
+ return -1;
+ }
+ pos += 2; /* Pointing at the Encrypted Key Data field */
+
+ tmp = os_malloc(key_data_len);
+ if (!tmp)
+ return -1;
+
+ /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
+ * to Key Data (exclusive). */
+ aad[0] = buf;
+ aad_len[0] = pos - buf;
+ if (aes_siv_decrypt(ptk->kek, ptk->kek_len, pos, key_data_len,
+ 1, aad, aad_len, tmp) < 0) {
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "Invalid AES-SIV data in the frame");
+ bin_clear_free(tmp, key_data_len);
+ return -1;
+ }
+
+ /* AEAD decryption and validation completed successfully */
+ key_data_len -= AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Decrypted Key Data",
+ tmp, key_data_len);
+
+ /* Replace Key Data field with the decrypted version */
+ os_memcpy(pos, tmp, key_data_len);
+ pos -= 2; /* Key Data Length field */
+ WPA_PUT_BE16(pos, key_data_len);
+ bin_clear_free(tmp, key_data_len);
+ if (_key_data_len)
+ *_key_data_len = key_data_len;
+ return 0;
+}
+
+
+const u8 * wpa_fils_validate_fils_session(struct wpa_state_machine *sm,
+ const u8 *ies, size_t ies_len,
+ const u8 *fils_session)
+{
+ const u8 *ie, *end;
+ const u8 *session = NULL;
+
+ if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Not a FILS AKM - reject association");
+ return NULL;
+ }
+
+ /* Verify Session element */
+ ie = ies;
+ end = ((const u8 *) ie) + ies_len;
+ while (ie + 1 < end) {
+ if (ie + 2 + ie[1] > end)
+ break;
+ if (ie[0] == WLAN_EID_EXTENSION &&
+ ie[1] >= 1 + FILS_SESSION_LEN &&
+ ie[2] == WLAN_EID_EXT_FILS_SESSION) {
+ session = ie;
+ break;
+ }
+ ie += 2 + ie[1];
+ }
+
+ if (!session) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: %s: Could not find FILS Session element in Assoc Req - reject",
+ __func__);
+ return NULL;
+ }
+
+ if (!fils_session) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: %s: Could not find FILS Session element in STA entry - reject",
+ __func__);
+ return NULL;
+ }
+
+ if (os_memcmp(fils_session, session + 3, FILS_SESSION_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
+ fils_session, FILS_SESSION_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
+ session + 3, FILS_SESSION_LEN);
+ return NULL;
+ }
+ return session;
+}
+
+
+int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
+ size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to parse decrypted elements");
+ return -1;
+ }
+
+ if (!elems.fils_session) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
+ return -1;
+ }
+
+ if (!elems.fils_key_confirm) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
+ return -1;
+ }
+
+ if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unexpected Key-Auth length %d (expected %d)",
+ elems.fils_key_confirm_len,
+ (int) sm->fils_key_auth_len);
+ return -1;
+ }
+
+ if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_sta,
+ sm->fils_key_auth_len) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
+ elems.fils_key_confirm, elems.fils_key_confirm_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
+ sm->fils_key_auth_sta, sm->fils_key_auth_len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
+ const struct ieee80211_mgmt *mgmt, size_t frame_len,
+ u8 *pos, size_t left)
+{
+ u16 fc, stype;
+ const u8 *end, *ie_start, *ie, *session, *crypt;
+ const u8 *aad[5];
+ size_t aad_len[5];
+
+ if (!sm || !sm->PTK_valid) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No KEK to decrypt Assocication Request frame");
+ return -1;
+ }
+
+ if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Not a FILS AKM - reject association");
+ return -1;
+ }
+
+ end = ((const u8 *) mgmt) + frame_len;
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+ if (stype == WLAN_FC_STYPE_REASSOC_REQ)
+ ie_start = mgmt->u.reassoc_req.variable;
+ else
+ ie_start = mgmt->u.assoc_req.variable;
+ ie = ie_start;
+
+ /*
+ * Find FILS Session element which is the last unencrypted element in
+ * the frame.
+ */
+ session = wpa_fils_validate_fils_session(sm, ie, end - ie,
+ fils_session);
+ if (!session) {
+ wpa_printf(MSG_DEBUG, "FILS: Session validation failed");
+ return -1;
+ }
+
+ crypt = session + 2 + session[1];
+
+ if (end - crypt < AES_BLOCK_SIZE) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Too short frame to include AES-SIV data");
+ return -1;
+ }
+
+ /* AES-SIV AAD vectors */
+
+ /* The STA's MAC address */
+ aad[0] = mgmt->sa;
+ aad_len[0] = ETH_ALEN;
+ /* The AP's BSSID */
+ aad[1] = mgmt->da;
+ aad_len[1] = ETH_ALEN;
+ /* The STA's nonce */
+ aad[2] = sm->SNonce;
+ aad_len[2] = FILS_NONCE_LEN;
+ /* The AP's nonce */
+ aad[3] = sm->ANonce;
+ aad_len[3] = FILS_NONCE_LEN;
+ /*
+ * The (Re)Association Request frame from the Capability Information
+ * field to the FILS Session element (both inclusive).
+ */
+ aad[4] = (const u8 *) &mgmt->u.assoc_req.capab_info;
+ aad_len[4] = crypt - aad[4];
+
+ if (aes_siv_decrypt(sm->PTK.kek, sm->PTK.kek_len, crypt, end - crypt,
+ 5, aad, aad_len, pos + (crypt - ie_start)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Invalid AES-SIV data in the frame");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: Decrypted Association Request elements",
+ pos, left - AES_BLOCK_SIZE);
+
+ if (wpa_fils_validate_key_confirm(sm, pos, left - AES_BLOCK_SIZE) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Key Confirm validation failed");
+ return -1;
+ }
+
+ return left - AES_BLOCK_SIZE;
+}
+
+
+int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
+ size_t current_len, size_t max_len,
+ const struct wpabuf *hlp)
+{
+ u8 *end = buf + max_len;
+ u8 *pos = buf + current_len;
+ struct ieee80211_mgmt *mgmt;
+ struct wpabuf *plain;
+ const u8 *aad[5];
+ size_t aad_len[5];
+
+ if (!sm || !sm->PTK_valid)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG,
+ "FILS: Association Response frame before FILS processing",
+ buf, current_len);
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+
+ /* AES-SIV AAD vectors */
+
+ /* The AP's BSSID */
+ aad[0] = mgmt->sa;
+ aad_len[0] = ETH_ALEN;
+ /* The STA's MAC address */
+ aad[1] = mgmt->da;
+ aad_len[1] = ETH_ALEN;
+ /* The AP's nonce */
+ aad[2] = sm->ANonce;
+ aad_len[2] = FILS_NONCE_LEN;
+ /* The STA's nonce */
+ aad[3] = sm->SNonce;
+ aad_len[3] = FILS_NONCE_LEN;
+ /*
+ * The (Re)Association Response frame from the Capability Information
+ * field (the same offset in both Association and Reassociation
+ * Response frames) to the FILS Session element (both inclusive).
+ */
+ aad[4] = (const u8 *) &mgmt->u.assoc_resp.capab_info;
+ aad_len[4] = pos - aad[4];
+
+ /* The following elements will be encrypted with AES-SIV */
+ plain = fils_prepare_plainbuf(sm, hlp);
+ if (!plain) {
+ wpa_printf(MSG_DEBUG, "FILS: Plain buffer prep failed");
+ return -1;
+ }
+
+ if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Not enough room for FILS elements");
+ wpabuf_free(plain);
+ return -1;
+ }
+
+ wpa_hexdump_buf_key(MSG_DEBUG, "FILS: Association Response plaintext",
+ plain);
+
+ if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
+ wpabuf_head(plain), wpabuf_len(plain),
+ 5, aad, aad_len, pos) < 0) {
+ wpabuf_free(plain);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG,
+ "FILS: Encrypted Association Response elements",
+ pos, AES_BLOCK_SIZE + wpabuf_len(plain));
+ current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
+ wpabuf_free(plain);
+
+ sm->fils_completed = 1;
+
+ return current_len;
+}
+
+
+static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
+ const struct wpabuf *hlp)
+{
+ struct wpabuf *plain;
+ u8 *len, *tmp, *tmp2;
+ u8 hdr[2];
+ u8 *gtk, dummy_gtk[32];
+ size_t gtk_len;
+ struct wpa_group *gsm;
+
+ plain = wpabuf_alloc(1000);
+ if (!plain)
+ return NULL;
+
+ /* TODO: FILS Public Key */
+
+ /* FILS Key Confirmation */
+ wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(plain, 1 + sm->fils_key_auth_len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(plain, WLAN_EID_EXT_FILS_KEY_CONFIRM);
+ wpabuf_put_data(plain, sm->fils_key_auth_ap, sm->fils_key_auth_len);
+
+ /* FILS HLP Container */
+ if (hlp)
+ wpabuf_put_buf(plain, hlp);
+
+ /* TODO: FILS IP Address Assignment */
+
+ /* Key Delivery */
+ gsm = sm->group;
+ wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
+ len = wpabuf_put(plain, 1);
+ wpabuf_put_u8(plain, WLAN_EID_EXT_KEY_DELIVERY);
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN,
+ wpabuf_put(plain, WPA_KEY_RSC_LEN));
+ /* GTK KDE */
+ gtk = gsm->GTK[gsm->GN - 1];
+ gtk_len = gsm->GTK_len;
+ if (sm->wpa_auth->conf.disable_gtk ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
+ wpabuf_free(plain);
+ return NULL;
+ }
+ gtk = dummy_gtk;
+ }
+ hdr[0] = gsm->GN & 0x03;
+ hdr[1] = 0;
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = wpa_add_kde(tmp, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+ gtk, gtk_len);
+ wpabuf_put(plain, tmp2 - tmp);
+
+ /* IGTK KDE */
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = ieee80211w_kde_add(sm, tmp);
+ wpabuf_put(plain, tmp2 - tmp);
+
+ *len = (u8 *) wpabuf_put(plain, 0) - len - 1;
+
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "FILS: Failed to get channel info for OCI element");
+ wpabuf_free(plain);
+ return NULL;
+ }
+
+ pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0) {
+ wpabuf_free(plain);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ return plain;
+}
+
+
+int fils_set_tk(struct wpa_state_machine *sm)
+{
+ enum wpa_alg alg;
+ int klen;
+
+ if (!sm || !sm->PTK_valid) {
+ wpa_printf(MSG_DEBUG, "FILS: No valid PTK available to set TK");
+ return -1;
+ }
+ if (sm->tk_already_set) {
+ wpa_printf(MSG_DEBUG, "FILS: TK already set to the driver");
+ return -1;
+ }
+
+ alg = wpa_cipher_to_alg(sm->pairwise);
+ klen = wpa_cipher_key_len(sm->pairwise);
+
+ wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+ sm->PTK.tk, klen)) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
+ return -1;
+ }
+ sm->tk_already_set = TRUE;
+
+ return 0;
+}
+
+
+u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
+ const u8 *fils_session, struct wpabuf *hlp)
+{
+ struct wpabuf *plain;
+ u8 *pos = buf;
+
+ /* FILS Session */
+ *pos++ = WLAN_EID_EXTENSION; /* Element ID */
+ *pos++ = 1 + FILS_SESSION_LEN; /* Length */
+ *pos++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
+ os_memcpy(pos, fils_session, FILS_SESSION_LEN);
+ pos += FILS_SESSION_LEN;
+
+ plain = fils_prepare_plainbuf(sm, hlp);
+ if (!plain) {
+ wpa_printf(MSG_DEBUG, "FILS: Plain buffer prep failed");
+ return NULL;
+ }
+
+ os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
+ pos += wpabuf_len(plain);
+
+ wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
+ (unsigned int) wpabuf_len(plain));
+ wpabuf_free(plain);
+ sm->fils_completed = 1;
+ return pos;
+}
+
+#endif /* CONFIG_FILS */
+
+
+#ifdef CONFIG_OCV
+int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx)
+{
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+
+ if (!wpa_auth->cb->get_sta_tx_params)
+ return -1;
+ return wpa_auth->cb->get_sta_tx_params(wpa_auth->cb_ctx, sm->addr,
+ ap_max_chanwidth, ap_seg1_idx,
+ bandwidth, seg1_idx);
}
+#endif /* CONFIG_OCV */
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
struct wpa_ptk PTK;
int ok = 0, psk_found = 0;
const u8 *pmk = NULL;
+ size_t pmk_len;
+ int ft;
+ const u8 *eapol_key_ie, *key_data, *mic;
+ u16 key_data_length;
+ size_t mic_len, eapol_key_ie_len;
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ struct wpa_eapol_ie_parse kde;
+ int vlan_id = 0;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
sm->update_snonce = FALSE;
+ os_memset(&PTK, 0, sizeof(PTK));
+
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
/* WPA with IEEE 802.1X: use the derived PMK from EAP
* WPA-PSK: iterate through possible PSKs and select the one matching
* the packet */
for (;;) {
- if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
- sm->p2p_dev_addr, pmk);
+ sm->p2p_dev_addr, pmk, &pmk_len,
+ &vlan_id);
if (pmk == NULL)
break;
psk_found = 1;
- } else
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
+ os_memcpy(sm->xxkey, pmk, pmk_len);
+ sm->xxkey_len = pmk_len;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+ } else {
pmk = sm->PMK;
+ pmk_len = sm->pmk_len;
+ }
+
+ if ((!pmk || !pmk_len) && sm->pmksa) {
+ wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache");
+ pmk = sm->pmksa->pmk;
+ pmk_len = sm->pmksa->pmk_len;
+ }
- wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
+ if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+ break;
- if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
+ if (mic_len &&
+ wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
+ if (sm->PMK != pmk) {
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ }
+ ok = 1;
+ break;
+ }
+
+#ifdef CONFIG_FILS
+ if (!mic_len &&
+ wpa_aead_decrypt(sm, &PTK, sm->last_rx_eapol_key,
+ sm->last_rx_eapol_key_len, NULL) == 0) {
ok = 1;
break;
}
+#endif /* CONFIG_FILS */
- if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+ if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+ wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
}
@@ -2078,7 +2890,105 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
return;
}
-#ifdef CONFIG_IEEE80211R
+ /*
+ * Note: last_rx_eapol_key length fields have already been validated in
+ * wpa_receive().
+ */
+ hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ mic = (u8 *) (key + 1);
+ key_data = mic + mic_len + 2;
+ key_data_length = WPA_GET_BE16(mic + mic_len);
+ if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
+ sizeof(*key) - mic_len - 2)
+ return;
+
+ if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key msg 2/4 with invalid Key Data contents");
+ return;
+ }
+ if (kde.rsn_ie) {
+ eapol_key_ie = kde.rsn_ie;
+ eapol_key_ie_len = kde.rsn_ie_len;
+ } else if (kde.osen) {
+ eapol_key_ie = kde.osen;
+ eapol_key_ie_len = kde.osen_len;
+ } else {
+ eapol_key_ie = kde.wpa_ie;
+ eapol_key_ie_len = kde.wpa_ie_len;
+ }
+ ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
+ if (sm->wpa_ie == NULL ||
+ wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
+ eapol_key_ie, eapol_key_ie_len)) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "WPA IE from (Re)AssocReq did not match with msg 2/4");
+ if (sm->wpa_ie) {
+ wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
+ sm->wpa_ie, sm->wpa_ie_len);
+ }
+ wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
+ eapol_key_ie, eapol_key_ie_len);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(wpa_auth, &ci) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Failed to get channel info to validate received OCI in EAPOL-Key 2/4");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+#ifdef CONFIG_IEEE80211R_AP
+ if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_P2P
+ if (kde.ip_addr_req && kde.ip_addr_req[0] &&
+ wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
+ int idx;
+ wpa_printf(MSG_DEBUG,
+ "P2P: IP address requested in EAPOL-Key exchange");
+ idx = bitfield_get_first_zero(wpa_auth->ip_pool);
+ if (idx >= 0) {
+ u32 start = WPA_GET_BE32(wpa_auth->conf.ip_addr_start);
+ bitfield_set(wpa_auth->ip_pool, idx);
+ WPA_PUT_BE32(sm->ip_addr, start + idx);
+ wpa_printf(MSG_DEBUG,
+ "P2P: Assigned IP address %u.%u.%u.%u to "
+ MACSTR, sm->ip_addr[0], sm->ip_addr[1],
+ sm->ip_addr[2], sm->ip_addr[3],
+ MAC2STR(sm->addr));
+ }
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_IEEE80211R_AP
if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
/*
* Verify that PMKR1Name from EAPOL-Key message 2/4 matches
@@ -2097,7 +3007,14 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
return;
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+ if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+ wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
@@ -2107,6 +3024,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
* state machine data based on whatever PSK was selected here.
*/
os_memcpy(sm->PMK, pmk, PMK_LEN);
+ sm->pmk_len = PMK_LEN;
}
sm->MICVerified = TRUE;
@@ -2155,7 +3073,8 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
else
os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
- if (sm->wpa_auth->conf.disable_gtk) {
+ if (sm->wpa_auth->conf.disable_gtk ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
@@ -2186,6 +3105,36 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
#endif /* CONFIG_IEEE80211W */
+static int ocv_oci_len(struct wpa_state_machine *sm)
+{
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm))
+ return OCV_OCI_KDE_LEN;
+#endif /* CONFIG_OCV */
+ return 0;
+}
+
+static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
+{
+#ifdef CONFIG_OCV
+ struct wpa_channel_info ci;
+
+ if (!wpa_auth_uses_ocv(sm))
+ return 0;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element");
+ return -1;
+ }
+
+ return ocv_insert_oci_kde(&ci, argpos);
+#else /* CONFIG_OCV */
+ return 0;
+#endif /* CONFIG_OCV */
+}
+
+
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
@@ -2198,7 +3147,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
sm->TimeoutEvt = FALSE;
sm->TimeoutCtr++;
- if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+ if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ sm->TimeoutCtr > 1) {
+ /* Do not allow retransmission of EAPOL-Key msg 3/4 */
+ return;
+ }
+ if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -2228,7 +3182,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk) {
+ if (sm->wpa_auth->conf.disable_gtk ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -2263,15 +3218,15 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
}
}
- kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
kde_len += 300; /* FTIE + 2 * TIE */
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr) > 0)
kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
@@ -2283,18 +3238,23 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
pos = kde;
os_memcpy(pos, wpa_ie, wpa_ie_len);
pos += wpa_ie_len;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
- int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name);
+ int res;
+ size_t elen;
+
+ elen = pos - kde;
+ res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
wpa_printf(MSG_ERROR, "FT: Failed to insert "
"PMKR1Name into RSN IE in EAPOL-Key data");
os_free(kde);
return;
}
- pos += res;
+ pos -= wpa_ie_len;
+ pos += elen;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (gtk) {
u8 hdr[2];
hdr[0] = keyidx & 0x03;
@@ -2303,17 +3263,32 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde);
+ return;
+ }
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
struct wpa_auth_config *conf;
conf = &sm->wpa_auth->conf;
- res = wpa_write_ftie(conf, conf->r0_key_holder,
- conf->r0_key_holder_len,
- NULL, NULL, pos, kde + kde_len - pos,
- NULL, 0);
+ if (sm->assoc_resp_ftie &&
+ kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
+ os_memcpy(pos, sm->assoc_resp_ftie,
+ 2 + sm->assoc_resp_ftie[1]);
+ res = 2 + sm->assoc_resp_ftie[1];
+ } else {
+ int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
+ res = wpa_write_ftie(conf, use_sha384,
+ conf->r0_key_holder,
+ conf->r0_key_holder_len,
+ NULL, NULL, pos,
+ kde + kde_len - pos,
+ NULL, 0);
+ }
if (res < 0) {
wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
"into EAPOL-Key Key Data");
@@ -2333,10 +3308,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
- WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
+ WPA_PUT_LE32(pos, conf->r0_key_lifetime);
pos += 4;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr) > 0) {
u8 addr[3 * 4];
@@ -2349,7 +3324,9 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
#endif /* CONFIG_P2P */
wpa_send_eapol(sm->wpa_auth, sm,
- (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
+ (secure ? WPA_KEY_INFO_SECURE : 0) |
+ (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
+ WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
_rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
@@ -2366,20 +3343,18 @@ SM_STATE(WPA_PTK, PTKINITDONE)
int klen = wpa_cipher_key_len(sm->pairwise);
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
sm->PTK.tk, klen)) {
- wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = TRUE;
- if (sm->wpa_auth->conf.wpa_ptk_rekey) {
- eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
- eloop_register_timeout(sm->wpa_auth->conf.
- wpa_ptk_rekey, 0, wpa_rekey_ptk,
- sm->wpa_auth, sm);
- }
+ wpa_auth_set_ptk_rekey_timer(sm);
- if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) {
wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
WPA_EAPOL_authorized, 1);
}
@@ -2405,9 +3380,9 @@ SM_STATE(WPA_PTK, PTKINITDONE)
"pairwise key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
}
@@ -2451,15 +3426,22 @@ SM_STEP(WPA_PTK)
wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
WPA_EAPOL_keyRun) > 0)
SM_ENTER(WPA_PTK, INITPMK);
- else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)
+ else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE
/* FIX: && 802.1X::keyRun */)
SM_ENTER(WPA_PTK, INITPSK);
+ else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP)
+ SM_ENTER(WPA_PTK, INITPMK);
break;
case WPA_PTK_INITPMK:
if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
- WPA_EAPOL_keyAvailable) > 0)
+ WPA_EAPOL_keyAvailable) > 0) {
SM_ENTER(WPA_PTK, PTKSTART);
- else {
+#ifdef CONFIG_DPP
+ } else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->pmksa) {
+ SM_ENTER(WPA_PTK, PTKSTART);
+#endif /* CONFIG_DPP */
+ } else {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
"INITPMK - keyAvailable = false");
@@ -2468,9 +3450,13 @@ SM_STEP(WPA_PTK)
break;
case WPA_PTK_INITPSK:
if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
- NULL))
+ NULL, NULL, NULL)) {
+ SM_ENTER(WPA_PTK, PTKSTART);
+#ifdef CONFIG_SAE
+ } else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
SM_ENTER(WPA_PTK, PTKSTART);
- else {
+#endif /* CONFIG_SAE */
+ } else {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
"no PSK configured for the STA");
wpa_auth->dot11RSNA4WayHandshakeFailures++;
@@ -2482,11 +3468,12 @@ SM_STEP(WPA_PTK)
sm->EAPOLKeyPairwise)
SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
else if (sm->TimeoutCtr >
- (int) dot11RSNAConfigPairwiseUpdateCount) {
+ sm->wpa_auth->conf.wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKSTART: Retry limit %d reached",
- dot11RSNAConfigPairwiseUpdateCount);
+ wpa_auth_vlogger(
+ sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKSTART: Retry limit %u reached",
+ sm->wpa_auth->conf.wpa_pairwise_update_count);
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKSTART);
@@ -2510,12 +3497,14 @@ SM_STEP(WPA_PTK)
sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
- (int) dot11RSNAConfigPairwiseUpdateCount) {
+ sm->wpa_auth->conf.wpa_pairwise_update_count ||
+ (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ sm->TimeoutCtr > 1)) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKINITNEGOTIATING: Retry limit %d "
- "reached",
- dot11RSNAConfigPairwiseUpdateCount);
+ wpa_auth_vlogger(
+ sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKINITNEGOTIATING: Retry limit %u reached",
+ sm->wpa_auth->conf.wpa_pairwise_update_count);
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -2550,7 +3539,12 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
sm->GTimeoutCtr++;
- if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
+ if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ sm->GTimeoutCtr > 1) {
+ /* Do not allow retransmission of EAPOL-Key group msg 1/2 */
+ return;
+ }
+ if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -2567,7 +3561,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
"sending 1/2 msg of Group Key Handshake");
gtk = gsm->GTK[gsm->GN - 1];
- if (sm->wpa_auth->conf.disable_gtk) {
+ if (sm->wpa_auth->conf.disable_gtk ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -2578,7 +3573,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
}
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
- ieee80211w_kde_len(sm);
+ ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
if (kde_buf == NULL)
return;
@@ -2589,6 +3584,10 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde_buf);
+ return;
+ }
kde_len = pos - kde;
} else {
kde = gtk;
@@ -2596,10 +3595,12 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
}
wpa_send_eapol(sm->wpa_auth, sm,
- WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_SECURE |
+ (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
+ WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK |
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
- rsc, gsm->GNonce, kde, kde_len, gsm->GN, 1);
+ rsc, NULL, kde, kde_len, gsm->GN, 1);
os_free(kde_buf);
}
@@ -2607,8 +3608,67 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
{
+#ifdef CONFIG_OCV
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ const u8 *key_data, *mic;
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ struct wpa_eapol_ie_parse kde;
+ size_t mic_len;
+ u16 key_data_length;
+#endif /* CONFIG_OCV */
+
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
sm->EAPOLKeyReceived = FALSE;
+
+#ifdef CONFIG_OCV
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+
+ /*
+ * Note: last_rx_eapol_key length fields have already been validated in
+ * wpa_receive().
+ */
+ hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ mic = (u8 *) (key + 1);
+ key_data = mic + mic_len + 2;
+ key_data_length = WPA_GET_BE16(mic + mic_len);
+ if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
+ sizeof(*key) - mic_len - 2)
+ return;
+
+ if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key group msg 2/2 with invalid Key Data contents");
+ return;
+ }
+
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(wpa_auth, &ci) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
@@ -2628,6 +3688,10 @@ SM_STATE(WPA_PTK_GROUP, KEYERROR)
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
sm->Disconnect = TRUE;
+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "group key handshake failed (%s) after %u tries",
+ sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
+ sm->wpa_auth->conf.wpa_group_update_count);
}
@@ -2647,7 +3711,9 @@ SM_STEP(WPA_PTK_GROUP)
!sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
else if (sm->GTimeoutCtr >
- (int) dot11RSNAConfigGroupUpdateCount)
+ sm->wpa_auth->conf.wpa_group_update_count ||
+ (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ sm->GTimeoutCtr > 1))
SM_ENTER(WPA_PTK_GROUP, KEYERROR);
else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
@@ -2750,7 +3816,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
}
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
/* update GTK when exiting WNM-Sleep Mode */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
{
@@ -2829,7 +3895,7 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
return pos - start;
}
#endif /* CONFIG_IEEE80211W */
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
@@ -3107,8 +4173,8 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
RSN_VERSION,
!!wpa_auth->conf.wpa_strict_rekey,
- dot11RSNAConfigGroupUpdateCount,
- dot11RSNAConfigPairwiseUpdateCount,
+ wpa_auth->conf.wpa_group_update_count,
+ wpa_auth->conf.wpa_pairwise_update_count,
wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
@@ -3211,6 +4277,15 @@ int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
}
+const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
+{
+ if (!sm)
+ return NULL;
+ *len = sm->pmk_len;
+ return sm->PMK;
+}
+
+
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{
if (sm == NULL)
@@ -3235,6 +4310,14 @@ int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
}
+int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm)
+{
+ if (!sm || !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+ return 0;
+ return sm->tk_already_set;
+}
+
+
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
struct rsn_pmksa_cache_entry *entry)
{
@@ -3269,13 +4352,21 @@ const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+ unsigned int pmk_len,
int session_timeout, struct eapol_state_machine *eapol)
{
if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
- if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
+ if (pmk_len > PMK_LEN_SUITE_B_192)
+ pmk_len = PMK_LEN_SUITE_B_192;
+ } else if (pmk_len > PMK_LEN) {
+ pmk_len = PMK_LEN;
+ }
+
+ if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_auth->addr, sm->addr, session_timeout,
eapol, sm->wpa_key_mgmt))
@@ -3293,7 +4384,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
if (wpa_auth == NULL)
return -1;
- if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len,
+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
NULL, 0,
wpa_auth->addr,
sta_addr, session_timeout, eapol,
@@ -3305,12 +4396,12 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
- const u8 *pmk)
+ const u8 *pmk, const u8 *pmkid)
{
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
- if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN,
+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
NULL, 0,
wpa_auth->addr, addr, 0, NULL,
WPA_KEY_MGMT_SAE))
@@ -3320,6 +4411,29 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
}
+void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid)
+{
+ os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
+ sm->pmkid_set = 1;
+}
+
+
+int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ int session_timeout, int akmp)
+{
+ if (wpa_auth->conf.disable_pmksa_caching)
+ return -1;
+
+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
+ NULL, 0, wpa_auth->addr, addr, session_timeout,
+ NULL, akmp))
+ return 0;
+
+ return -1;
+}
+
+
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr)
{
@@ -3336,6 +4450,99 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
}
+int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
+ size_t len)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return 0;
+ return pmksa_cache_auth_list(wpa_auth->pmksa, buf, len);
+}
+
+
+void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
+{
+ if (wpa_auth && wpa_auth->pmksa)
+ pmksa_cache_auth_flush(wpa_auth->pmksa);
+}
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ char *buf, size_t len)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return 0;
+
+ return pmksa_cache_auth_list_mesh(wpa_auth->pmksa, addr, buf, len);
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
+ const u8 *pmkid, int expiration)
+{
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ entry = pmksa_cache_auth_create_entry(pmk, PMK_LEN, pmkid, NULL, 0, aa,
+ spa, 0, NULL, WPA_KEY_MGMT_SAE);
+ if (!entry)
+ return NULL;
+
+ os_get_reltime(&now);
+ entry->expiration = now.sec + expiration;
+ return entry;
+}
+
+
+int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ int ret;
+
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return -1;
+
+ ret = pmksa_cache_auth_add_entry(wpa_auth->pmksa, entry);
+ if (ret < 0)
+ wpa_printf(MSG_DEBUG,
+ "RSN: Failed to store external PMKSA cache for "
+ MACSTR, MAC2STR(entry->spa));
+
+ return ret;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 *pmkid)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return NULL;
+ return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, pmkid);
+}
+
+
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+ struct wpa_state_machine *sm,
+ struct wpa_authenticator *wpa_auth,
+ u8 *pmkid, u8 *pmk)
+{
+ if (!sm)
+ return;
+
+ sm->pmksa = pmksa;
+ os_memcpy(pmk, pmksa->pmk, PMK_LEN);
+ os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN);
+ os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN);
+}
+
+
/*
* Remove and free the group from wpa_authenticator. This is triggered by a
* callback to make sure nobody is currently iterating the group list while it
@@ -3414,6 +4621,98 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
}
+/*
+ * Enforce that the group state machine for the VLAN is running, increase
+ * reference counter as interface is up. References might have been increased
+ * even if a negative value is returned.
+ * Returns: -1 on error (group missing, group already failed); otherwise, 0
+ */
+int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
+{
+ struct wpa_group *group;
+
+ if (wpa_auth == NULL)
+ return 0;
+
+ group = wpa_auth->group;
+ while (group) {
+ if (group->vlan_id == vlan_id)
+ break;
+ group = group->next;
+ }
+
+ if (group == NULL) {
+ group = wpa_auth_add_group(wpa_auth, vlan_id);
+ if (group == NULL)
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "WPA: Ensure group state machine running for VLAN ID %d",
+ vlan_id);
+
+ wpa_group_get(wpa_auth, group);
+ group->num_setup_iface++;
+
+ if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+ return -1;
+
+ return 0;
+}
+
+
+/*
+ * Decrease reference counter, expected to be zero afterwards.
+ * returns: -1 on error (group not found, group in fail state)
+ * -2 if wpa_group is still referenced
+ * 0 else
+ */
+int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
+{
+ struct wpa_group *group;
+ int ret = 0;
+
+ if (wpa_auth == NULL)
+ return 0;
+
+ group = wpa_auth->group;
+ while (group) {
+ if (group->vlan_id == vlan_id)
+ break;
+ group = group->next;
+ }
+
+ if (group == NULL)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "WPA: Try stopping group state machine for VLAN ID %d",
+ vlan_id);
+
+ if (group->num_setup_iface <= 0) {
+ wpa_printf(MSG_ERROR,
+ "WPA: wpa_auth_release_group called more often than wpa_auth_ensure_group for VLAN ID %d, skipping.",
+ vlan_id);
+ return -1;
+ }
+ group->num_setup_iface--;
+
+ if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+ ret = -1;
+
+ if (group->references > 1) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: Cannot stop group state machine for VLAN ID %d as references are still hold",
+ vlan_id);
+ ret = -2;
+ }
+
+ wpa_group_put(wpa_auth, group);
+
+ return ret;
+}
+
+
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
{
struct wpa_group *group;
@@ -3478,6 +4777,14 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
(timeout_ms % 1000) * 1000,
wpa_send_eapol_timeout, wpa_auth, sm);
}
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->eapol_status_cb) {
+ sm->eapol_status_cb(sm->eapol_status_cb_ctx1,
+ sm->eapol_status_cb_ctx2);
+ sm->eapol_status_cb = NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -3524,3 +4831,379 @@ void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth)
for (group = wpa_auth->group; group; group = group->next)
wpa_group_config_group_keys(wpa_auth, group);
}
+
+
+#ifdef CONFIG_FILS
+
+struct wpa_auth_fils_iter_data {
+ struct wpa_authenticator *auth;
+ const u8 *cache_id;
+ struct rsn_pmksa_cache_entry *pmksa;
+ const u8 *spa;
+ const u8 *pmkid;
+};
+
+
+static int wpa_auth_fils_iter(struct wpa_authenticator *a, void *ctx)
+{
+ struct wpa_auth_fils_iter_data *data = ctx;
+
+ if (a == data->auth || !a->conf.fils_cache_id_set ||
+ os_memcmp(a->conf.fils_cache_id, data->cache_id,
+ FILS_CACHE_ID_LEN) != 0)
+ return 0;
+ data->pmksa = pmksa_cache_auth_get(a->pmksa, data->spa, data->pmkid);
+ return data->pmksa != NULL;
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, const u8 *pmkid)
+{
+ struct wpa_auth_fils_iter_data idata;
+
+ if (!wpa_auth->conf.fils_cache_id_set)
+ return NULL;
+ idata.auth = wpa_auth;
+ idata.cache_id = wpa_auth->conf.fils_cache_id;
+ idata.pmksa = NULL;
+ idata.spa = sta_addr;
+ idata.pmkid = pmkid;
+ wpa_auth_for_each_auth(wpa_auth, wpa_auth_fils_iter, &idata);
+ return idata.pmksa;
+}
+
+
+#ifdef CONFIG_IEEE80211R_AP
+int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
+ u8 *buf, size_t len)
+{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
+
+ return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
+ conf->r0_key_holder_len,
+ NULL, NULL, buf, len, NULL, 0);
+}
+#endif /* CONFIG_IEEE80211R_AP */
+
+
+void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
+ u8 *fils_anonce, u8 *fils_snonce,
+ u8 *fils_kek, size_t *fils_kek_len)
+{
+ os_memcpy(fils_anonce, sm->ANonce, WPA_NONCE_LEN);
+ os_memcpy(fils_snonce, sm->SNonce, WPA_NONCE_LEN);
+ os_memcpy(fils_kek, sm->PTK.kek, WPA_KEK_MAX_LEN);
+ *fils_kek_len = sm->PTK.kek_len;
+}
+
+
+void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid)
+{
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
+ sm->pmkid_set = 1;
+}
+
+#endif /* CONFIG_FILS */
+
+
+void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
+{
+ if (sm)
+ sm->auth_alg = auth_alg;
+}
+
+
+#ifdef CONFIG_DPP2
+void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
+{
+ if (sm) {
+ wpabuf_clear_free(sm->dpp_z);
+ sm->dpp_z = z ? wpabuf_dup(z) : NULL;
+ }
+}
+#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+
+int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
+ void (*cb)(void *ctx1, void *ctx2),
+ void *ctx1, void *ctx2)
+{
+ const u8 *anonce = sm->ANonce;
+ u8 anonce_buf[WPA_NONCE_LEN];
+
+ if (change_anonce) {
+ if (random_get_bytes(anonce_buf, WPA_NONCE_LEN))
+ return -1;
+ anonce = anonce_buf;
+ }
+
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "sending 1/4 msg of 4-Way Handshake (TESTING)");
+ wpa_send_eapol(sm->wpa_auth, sm,
+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
+ anonce, NULL, 0, 0, 0);
+ return 0;
+}
+
+
+int wpa_auth_resend_m3(struct wpa_state_machine *sm,
+ void (*cb)(void *ctx1, void *ctx2),
+ void *ctx1, void *ctx2)
+{
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+#ifdef CONFIG_IEEE80211W
+ u8 *opos;
+#endif /* CONFIG_IEEE80211W */
+ size_t gtk_len, kde_len;
+ struct wpa_group *gsm = sm->group;
+ u8 *wpa_ie;
+ int wpa_ie_len, secure, keyidx, encr = 0;
+
+ /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
+ GTK[GN], IGTK, [FTIE], [TIE * 2])
+ */
+
+ /* Use 0 RSC */
+ os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+ /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
+ wpa_ie = sm->wpa_auth->wpa_ie;
+ wpa_ie_len = sm->wpa_auth->wpa_ie_len;
+ if (sm->wpa == WPA_VERSION_WPA &&
+ (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+ wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+ /* WPA-only STA, remove RSN IE and possible MDIE */
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ wpa_ie_len = wpa_ie[1] + 2;
+ }
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "sending 3/4 msg of 4-Way Handshake (TESTING)");
+ if (sm->wpa == WPA_VERSION_WPA2) {
+ /* WPA2 send GTK in the 4-way handshake */
+ secure = 1;
+ gtk = gsm->GTK[gsm->GN - 1];
+ gtk_len = gsm->GTK_len;
+ keyidx = gsm->GN;
+ _rsc = rsc;
+ encr = 1;
+ } else {
+ /* WPA does not include GTK in msg 3/4 */
+ secure = 0;
+ gtk = NULL;
+ gtk_len = 0;
+ keyidx = 0;
+ _rsc = NULL;
+ if (sm->rx_eapol_key_secure) {
+ /*
+ * It looks like Windows 7 supplicant tries to use
+ * Secure bit in msg 2/4 after having reported Michael
+ * MIC failure and it then rejects the 4-way handshake
+ * if msg 3/4 does not set Secure bit. Work around this
+ * by setting the Secure bit here even in the case of
+ * WPA if the supplicant used it first.
+ */
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "STA used Secure bit in WPA msg 2/4 - "
+ "set Secure for 3/4 as workaround");
+ secure = 1;
+ }
+ }
+
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+ if (gtk)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+ kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
+ kde_len += 300; /* FTIE + 2 * TIE */
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+ kde = os_malloc(kde_len);
+ if (kde == NULL)
+ return -1;
+
+ pos = kde;
+ os_memcpy(pos, wpa_ie, wpa_ie_len);
+ pos += wpa_ie_len;
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+ int res;
+ size_t elen;
+
+ elen = pos - kde;
+ res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FT: Failed to insert "
+ "PMKR1Name into RSN IE in EAPOL-Key data");
+ os_free(kde);
+ return -1;
+ }
+ pos -= wpa_ie_len;
+ pos += elen;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+ if (gtk) {
+ u8 hdr[2];
+ hdr[0] = keyidx & 0x03;
+ hdr[1] = 0;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+ gtk, gtk_len);
+ }
+#ifdef CONFIG_IEEE80211W
+ opos = pos;
+ pos = ieee80211w_kde_add(sm, pos);
+ if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
+ /* skip KDE header and keyid */
+ opos += 2 + RSN_SELECTOR_LEN + 2;
+ os_memset(opos, 0, 6); /* clear PN */
+ }
+#endif /* CONFIG_IEEE80211W */
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde);
+ return -1;
+ }
+
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+ int res;
+ struct wpa_auth_config *conf;
+
+ conf = &sm->wpa_auth->conf;
+ if (sm->assoc_resp_ftie &&
+ kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
+ os_memcpy(pos, sm->assoc_resp_ftie,
+ 2 + sm->assoc_resp_ftie[1]);
+ res = 2 + sm->assoc_resp_ftie[1];
+ } else {
+ int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
+ res = wpa_write_ftie(conf, use_sha384,
+ conf->r0_key_holder,
+ conf->r0_key_holder_len,
+ NULL, NULL, pos,
+ kde + kde_len - pos,
+ NULL, 0);
+ }
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
+ "into EAPOL-Key Key Data");
+ os_free(kde);
+ return -1;
+ }
+ pos += res;
+
+ /* TIE[ReassociationDeadline] (TU) */
+ *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+ *pos++ = 5;
+ *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
+ WPA_PUT_LE32(pos, conf->reassociation_deadline);
+ pos += 4;
+
+ /* TIE[KeyLifetime] (seconds) */
+ *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+ *pos++ = 5;
+ *pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
+ WPA_PUT_LE32(pos, conf->r0_key_lifetime);
+ pos += 4;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+
+ wpa_send_eapol(sm->wpa_auth, sm,
+ (secure ? WPA_KEY_INFO_SECURE : 0) |
+ (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
+ WPA_KEY_INFO_MIC : 0) |
+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
+ WPA_KEY_INFO_KEY_TYPE,
+ _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ os_free(kde);
+ return 0;
+}
+
+
+int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
+ void (*cb)(void *ctx1, void *ctx2),
+ void *ctx1, void *ctx2)
+{
+ u8 rsc[WPA_KEY_RSC_LEN];
+ struct wpa_group *gsm = sm->group;
+ const u8 *kde;
+ u8 *kde_buf = NULL, *pos, hdr[2];
+#ifdef CONFIG_IEEE80211W
+ u8 *opos;
+#endif /* CONFIG_IEEE80211W */
+ size_t kde_len;
+ u8 *gtk;
+
+ /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
+ os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+ /* Use 0 RSC */
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "sending 1/2 msg of Group Key Handshake (TESTING)");
+
+ gtk = gsm->GTK[gsm->GN - 1];
+ if (sm->wpa == WPA_VERSION_WPA2) {
+ kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
+ ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+ kde_buf = os_malloc(kde_len);
+ if (kde_buf == NULL)
+ return -1;
+
+ kde = pos = kde_buf;
+ hdr[0] = gsm->GN & 0x03;
+ hdr[1] = 0;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+ gtk, gsm->GTK_len);
+#ifdef CONFIG_IEEE80211W
+ opos = pos;
+ pos = ieee80211w_kde_add(sm, pos);
+ if (pos - opos >=
+ 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
+ /* skip KDE header and keyid */
+ opos += 2 + RSN_SELECTOR_LEN + 2;
+ os_memset(opos, 0, 6); /* clear PN */
+ }
+#endif /* CONFIG_IEEE80211W */
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde_buf);
+ return -1;
+ }
+ kde_len = pos - kde;
+ } else {
+ kde = gtk;
+ kde_len = gsm->GTK_len;
+ }
+
+ sm->eapol_status_cb = cb;
+ sm->eapol_status_cb_ctx1 = ctx1;
+ sm->eapol_status_cb_ctx2 = ctx2;
+
+ wpa_send_eapol(sm->wpa_auth, sm,
+ WPA_KEY_INFO_SECURE |
+ (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
+ WPA_KEY_INFO_MIC : 0) |
+ WPA_KEY_INFO_ACK |
+ (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
+ rsc, NULL, kde, kde_len, gsm->GN, 1);
+
+ os_free(kde_buf);
+ return 0;
+}
+
+
+int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth)
+{
+ if (!wpa_auth)
+ return -1;
+ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+ return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/contrib/wpa/src/ap/wpa_auth.h b/contrib/wpa/src/ap/wpa_auth.h
index 1b1442f..df1e17a 100644
--- a/contrib/wpa/src/ap/wpa_auth.h
+++ b/contrib/wpa/src/ap/wpa_auth.h
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,8 @@
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
+struct vlan_description;
+
#define MAX_OWN_IE_OVERRIDE 256
#ifdef _MSC_VER
@@ -37,65 +39,100 @@ struct ft_rrb_frame {
#define FT_PACKET_REQUEST 0
#define FT_PACKET_RESPONSE 1
-/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
-#define FT_PACKET_R0KH_R1KH_PULL 200
-#define FT_PACKET_R0KH_R1KH_RESP 201
-#define FT_PACKET_R0KH_R1KH_PUSH 202
-#define FT_R0KH_R1KH_PULL_DATA_LEN 44
-#define FT_R0KH_R1KH_RESP_DATA_LEN 76
-#define FT_R0KH_R1KH_PUSH_DATA_LEN 88
-#define FT_R0KH_R1KH_PULL_NONCE_LEN 16
+/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r. These
+ * use OUI Extended EtherType as the encapsulating format. */
+#define FT_PACKET_R0KH_R1KH_PULL 0x01
+#define FT_PACKET_R0KH_R1KH_RESP 0x02
+#define FT_PACKET_R0KH_R1KH_PUSH 0x03
+#define FT_PACKET_R0KH_R1KH_SEQ_REQ 0x04
+#define FT_PACKET_R0KH_R1KH_SEQ_RESP 0x05
+
+/* packet layout
+ * IEEE 802 extended OUI ethertype frame header
+ * u16 authlen (little endian)
+ * multiple of struct ft_rrb_tlv (authenticated only, length = authlen)
+ * multiple of struct ft_rrb_tlv (AES-SIV encrypted, AES-SIV needs an extra
+ * blocksize length)
+ *
+ * AES-SIV AAD;
+ * source MAC address (6)
+ * authenticated-only TLVs (authlen)
+ * subtype (1; FT_PACKET_*)
+ */
-struct ft_r0kh_r1kh_pull_frame {
- u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
- u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
- le16 data_length; /* little endian length of data (44) */
- u8 ap_address[ETH_ALEN];
+#define FT_RRB_NONCE_LEN 16
- u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
- u8 pmk_r0_name[WPA_PMK_NAME_LEN];
- u8 r1kh_id[FT_R1KH_ID_LEN];
- u8 s1kh_id[ETH_ALEN];
- u8 pad[4]; /* 8-octet boundary for AES key wrap */
- u8 key_wrap_extra[8];
-} STRUCT_PACKED;
+#define FT_RRB_LAST_EMPTY 0 /* placeholder or padding */
-struct ft_r0kh_r1kh_resp_frame {
- u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
- u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
- le16 data_length; /* little endian length of data (76) */
- u8 ap_address[ETH_ALEN];
+#define FT_RRB_SEQ 1 /* struct ft_rrb_seq */
+#define FT_RRB_NONCE 2 /* size FT_RRB_NONCE_LEN */
+#define FT_RRB_TIMESTAMP 3 /* le32 unix seconds */
- u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; /* copied from pull */
- u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
- u8 s1kh_id[ETH_ALEN]; /* copied from pull */
- u8 pmk_r1[PMK_LEN];
- u8 pmk_r1_name[WPA_PMK_NAME_LEN];
- le16 pairwise;
- u8 pad[2]; /* 8-octet boundary for AES key wrap */
- u8 key_wrap_extra[8];
-} STRUCT_PACKED;
+#define FT_RRB_R0KH_ID 4 /* FT_R0KH_ID_MAX_LEN */
+#define FT_RRB_R1KH_ID 5 /* FT_R1KH_ID_LEN */
+#define FT_RRB_S1KH_ID 6 /* ETH_ALEN */
-struct ft_r0kh_r1kh_push_frame {
- u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
- u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
- le16 data_length; /* little endian length of data (88) */
- u8 ap_address[ETH_ALEN];
+#define FT_RRB_PMK_R0_NAME 7 /* WPA_PMK_NAME_LEN */
+#define FT_RRB_PMK_R0 8 /* PMK_LEN */
+#define FT_RRB_PMK_R1_NAME 9 /* WPA_PMK_NAME_LEN */
+#define FT_RRB_PMK_R1 10 /* PMK_LEN */
+
+#define FT_RRB_PAIRWISE 11 /* le16 */
+#define FT_RRB_EXPIRES_IN 12 /* le16 seconds */
+
+#define FT_RRB_VLAN_UNTAGGED 13 /* le16 */
+#define FT_RRB_VLAN_TAGGED 14 /* n times le16 */
+
+#define FT_RRB_IDENTITY 15
+#define FT_RRB_RADIUS_CUI 16
+#define FT_RRB_SESSION_TIMEOUT 17 /* le32 seconds */
+
+struct ft_rrb_tlv {
+ le16 type;
+ le16 len;
+ /* followed by data of length len */
+} STRUCT_PACKED;
- /* Encrypted with AES key-wrap */
- u8 timestamp[4]; /* current time in seconds since unix epoch, little
- * endian */
- u8 r1kh_id[FT_R1KH_ID_LEN];
- u8 s1kh_id[ETH_ALEN];
- u8 pmk_r0_name[WPA_PMK_NAME_LEN];
- u8 pmk_r1[PMK_LEN];
- u8 pmk_r1_name[WPA_PMK_NAME_LEN];
- le16 pairwise;
- u8 pad[6]; /* 8-octet boundary for AES key wrap */
- u8 key_wrap_extra[8];
+struct ft_rrb_seq {
+ le32 dom;
+ le32 seq;
+ le32 ts;
} STRUCT_PACKED;
+/* session TLVs:
+ * required: PMK_R1, PMK_R1_NAME, PAIRWISE
+ * optional: VLAN_UNTAGGED, VLAN_TAGGED, EXPIRES_IN, IDENTITY, RADIUS_CUI,
+ * SESSION_TIMEOUT
+ *
+ * pull frame TLVs:
+ * auth:
+ * required: SEQ, NONCE, R0KH_ID, R1KH_ID
+ * encrypted:
+ * required: PMK_R0_NAME, S1KH_ID
+ *
+ * response frame TLVs:
+ * auth:
+ * required: SEQ, NONCE, R0KH_ID, R1KH_ID
+ * encrypted:
+ * required: S1KH_ID
+ * optional: session TLVs
+ *
+ * push frame TLVs:
+ * auth:
+ * required: SEQ, R0KH_ID, R1KH_ID
+ * encrypted:
+ * required: S1KH_ID, PMK_R0_NAME, session TLVs
+ *
+ * sequence number request frame TLVs:
+ * auth:
+ * required: R0KH_ID, R1KH_ID, NONCE
+ *
+ * sequence number response frame TLVs:
+ * auth:
+ * required: SEQ, NONCE, R0KH_ID, R1KH_ID
+ */
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
@@ -107,6 +144,8 @@ struct wpa_authenticator;
struct wpa_state_machine;
struct rsn_pmksa_cache_entry;
struct eapol_state_machine;
+struct ft_remote_seq;
+struct wpa_channel_info;
struct ft_remote_r0kh {
@@ -114,7 +153,8 @@ struct ft_remote_r0kh {
u8 addr[ETH_ALEN];
u8 id[FT_R0KH_ID_MAX_LEN];
size_t id_len;
- u8 key[16];
+ u8 key[32];
+ struct ft_remote_seq *seq;
};
@@ -122,7 +162,8 @@ struct ft_remote_r1kh {
struct ft_remote_r1kh *next;
u8 addr[ETH_ALEN];
u8 id[FT_R1KH_ID_LEN];
- u8 key[16];
+ u8 key[32];
+ struct ft_remote_seq *seq;
};
@@ -135,10 +176,12 @@ struct wpa_auth_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ u32 wpa_group_update_count;
+ u32 wpa_pairwise_update_count;
+ int wpa_disable_eapol_key_retries;
int rsn_pairwise;
int rsn_preauth;
int eapol_version;
- int peerkey;
int wmm_enabled;
int wmm_uapsd;
int disable_pmksa_caching;
@@ -147,21 +190,31 @@ struct wpa_auth_config {
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
+ int sae_require_mfp;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_OCV
+ int ocv; /* Operating Channel Validation */
+#endif /* CONFIG_OCV */
+#ifdef CONFIG_IEEE80211R_AP
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
size_t r0_key_holder_len;
u8 r1_key_holder[FT_R1KH_ID_LEN];
- u32 r0_key_lifetime;
+ u32 r0_key_lifetime; /* PMK-R0 lifetime seconds */
+ int rkh_pos_timeout;
+ int rkh_neg_timeout;
+ int rkh_pull_timeout; /* ms */
+ int rkh_pull_retries;
+ int r1_max_key_lifetime;
u32 reassociation_deadline;
- struct ft_remote_r0kh *r0kh_list;
- struct ft_remote_r1kh *r1kh_list;
+ struct ft_remote_r0kh **r0kh_list;
+ struct ft_remote_r1kh **r1kh_list;
int pmk_r1_push;
int ft_over_ds;
-#endif /* CONFIG_IEEE80211R */
+ int ft_psk_generate_local;
+#endif /* CONFIG_IEEE80211R_AP */
int disable_gtk;
int ap_mlme;
#ifdef CONFIG_TESTING_OPTIONS
@@ -175,6 +228,10 @@ struct wpa_auth_config {
u8 ip_addr_start[4];
u8 ip_addr_end[4];
#endif /* CONFIG_P2P */
+#ifdef CONFIG_FILS
+ unsigned int fils_cache_id_set:1;
+ u8 fils_cache_id[FILS_CACHE_ID_LEN];
+#endif /* CONFIG_FILS */
};
typedef enum {
@@ -188,7 +245,6 @@ typedef enum {
} wpa_eapol_variable;
struct wpa_auth_callbacks {
- void *ctx;
void (*logger)(void *ctx, const u8 *addr, logger_level level,
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
@@ -198,7 +254,8 @@ struct wpa_auth_callbacks {
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr,
- const u8 *prev_psk);
+ const u8 *prev_psk, size_t *psk_len,
+ int *vlan_id);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key, size_t key_len);
@@ -211,13 +268,34 @@ struct wpa_auth_callbacks {
void *ctx), void *cb_ctx);
int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
size_t data_len);
-#ifdef CONFIG_IEEE80211R
+ int (*send_oui)(void *ctx, const u8 *dst, u8 oui_suffix, const u8 *data,
+ size_t data_len);
+ int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
+ int (*update_vlan)(void *ctx, const u8 *addr, int vlan_id);
+ int (*get_sta_tx_params)(void *ctx, const u8 *addr,
+ int ap_max_chanwidth, int ap_seg1_idx,
+ int *bandwidth, int *seg1_idx);
+#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+ int (*set_vlan)(void *ctx, const u8 *sta_addr,
+ struct vlan_description *vlan);
+ int (*get_vlan)(void *ctx, const u8 *sta_addr,
+ struct vlan_description *vlan);
+ int (*set_identity)(void *ctx, const u8 *sta_addr,
+ const u8 *identity, size_t identity_len);
+ size_t (*get_identity)(void *ctx, const u8 *sta_addr, const u8 **buf);
+ int (*set_radius_cui)(void *ctx, const u8 *sta_addr,
+ const u8 *radius_cui, size_t radius_cui_len);
+ size_t (*get_radius_cui)(void *ctx, const u8 *sta_addr, const u8 **buf);
+ void (*set_session_timeout)(void *ctx, const u8 *sta_addr,
+ int session_timeout);
+ int (*get_session_timeout)(void *ctx, const u8 *sta_addr);
+
int (*send_ft_action)(void *ctx, const u8 *dst,
const u8 *data, size_t data_len);
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
size_t tspec_ielen);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_MESH
int (*start_ampe)(void *ctx, const u8 *sta_addr);
#endif /* CONFIG_MESH */
@@ -225,7 +303,8 @@ struct wpa_auth_callbacks {
struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_auth_config *conf,
- struct wpa_auth_callbacks *cb);
+ const struct wpa_auth_callbacks *cb,
+ void *cb_ctx);
int wpa_init_keys(struct wpa_authenticator *wpa_auth);
void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
@@ -235,17 +314,20 @@ enum {
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
- WPA_INVALID_MDIE, WPA_INVALID_PROTO
+ WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID
};
-
+
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
+ struct wpa_state_machine *sm, int freq,
const u8 *wpa_ie, size_t wpa_ie_len,
- const u8 *mdie, size_t mdie_len);
+ const u8 *mdie, size_t mdie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
+void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv);
+int wpa_auth_uses_ocv(struct wpa_state_machine *sm);
struct wpa_state_machine *
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *p2p_dev_addr);
@@ -258,7 +340,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
u8 *data, size_t data_len);
enum wpa_event {
WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
- WPA_REAUTH_EAPOL, WPA_ASSOC_FT
+ WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_ASSOC_FILS, WPA_DRV_STA_REMOVED
};
void wpa_remove_ptk(struct wpa_state_machine *sm);
int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
@@ -269,9 +351,11 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
+const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len);
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
+int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm);
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
struct rsn_pmksa_cache_entry *entry);
struct rsn_pmksa_cache_entry *
@@ -280,20 +364,45 @@ void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
size_t *len);
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+ unsigned int pmk_len,
int session_timeout, struct eapol_state_machine *eapol);
int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
const u8 *pmk, size_t len, const u8 *sta_addr,
int session_timeout,
struct eapol_state_machine *eapol);
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
- const u8 *pmk);
+ const u8 *pmk, const u8 *pmkid);
+void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
+int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ int session_timeout, int akmp);
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr);
+int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
+ size_t len);
+void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
+int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ char *buf, size_t len);
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
+ const u8 *pmkid, int expiration);
+int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
+ struct rsn_pmksa_cache_entry *entry);
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 *pmkid);
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, const u8 *pmkid);
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+ struct wpa_state_machine *sm,
+ struct wpa_authenticator *wpa_auth,
+ u8 *pmkid, u8 *pmk);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
const u8 *req_ies, size_t req_ies_len);
@@ -308,8 +417,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
const u8 *data, size_t data_len);
+void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
+ const u8 *dst_addr, u8 oui_suffix, const u8 *data,
+ size_t data_len);
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
-#endif /* CONFIG_IEEE80211R */
+void wpa_ft_deinit(struct wpa_authenticator *wpa_auth);
+void wpa_ft_sta_deinit(struct wpa_state_machine *sm);
+#endif /* CONFIG_IEEE80211R_AP */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
@@ -326,4 +440,54 @@ int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
struct radius_das_attrs *attr);
void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
+int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id);
+int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id);
+int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *snonce, const u8 *anonce,
+ const u8 *dhss, size_t dhss_len,
+ struct wpabuf *g_sta, struct wpabuf *g_ap);
+int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
+ const struct ieee80211_mgmt *mgmt, size_t frame_len,
+ u8 *pos, size_t left);
+int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
+ size_t current_len, size_t max_len,
+ const struct wpabuf *hlp);
+int fils_set_tk(struct wpa_state_machine *sm);
+u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *eid,
+ const u8 *fils_session,
+ struct wpabuf *fils_hlp_resp);
+const u8 * wpa_fils_validate_fils_session(struct wpa_state_machine *sm,
+ const u8 *ies, size_t ies_len,
+ const u8 *fils_session);
+int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
+ size_t ies_len);
+
+int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx);
+
+int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
+ u8 *buf, size_t len);
+void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
+ u8 *fils_anonce, u8 *fils_snonce,
+ u8 *fils_kek, size_t *fils_kek_len);
+void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid);
+u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
+ u8 *pos, size_t max_len,
+ const u8 *req_ies, size_t req_ies_len);
+void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
+void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
+
+int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
+ void (*cb)(void *ctx1, void *ctx2),
+ void *ctx1, void *ctx2);
+int wpa_auth_resend_m3(struct wpa_state_machine *sm,
+ void (*cb)(void *ctx1, void *ctx2),
+ void *ctx1, void *ctx2);
+int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
+ void (*cb)(void *ctx1, void *ctx2),
+ void *ctx1, void *ctx2);
+int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
+void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
+
#endif /* WPA_AUTH_H */
diff --git a/contrib/wpa/src/ap/wpa_auth_ft.c b/contrib/wpa/src/ap/wpa_auth_ft.c
index f8f5dbe..ac16199 100644
--- a/contrib/wpa/src/ap/wpa_auth_ft.c
+++ b/contrib/wpa/src/ap/wpa_auth_ft.c
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,7 +13,12 @@
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "drivers/driver.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
#include "crypto/aes_wrap.h"
+#include "crypto/sha384.h"
#include "crypto/random.h"
#include "ap_config.h"
#include "ieee802_11.h"
@@ -22,41 +27,735 @@
#include "wpa_auth_i.h"
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
+
+const unsigned int ftRRBseqTimeout = 10;
+const unsigned int ftRRBmaxQueueLen = 100;
+
static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
const u8 *current_ap, const u8 *sta_addr,
u16 status, const u8 *resp_ies,
size_t resp_ies_len);
+static void ft_finish_pull(struct wpa_state_machine *sm);
+static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx);
+static void wpa_ft_rrb_seq_timeout(void *eloop_ctx, void *timeout_ctx);
+
+struct tlv_list {
+ u16 type;
+ size_t len;
+ const u8 *data;
+};
+
+
+/**
+ * wpa_ft_rrb_decrypt - Decrypt FT RRB message
+ * @key: AES-SIV key for AEAD
+ * @key_len: Length of key in octets
+ * @enc: Pointer to encrypted TLVs
+ * @enc_len: Length of encrypted TLVs in octets
+ * @auth: Pointer to authenticated TLVs
+ * @auth_len: Length of authenticated TLVs in octets
+ * @src_addr: MAC address of the frame sender
+ * @type: Vendor-specific subtype of the RRB frame (FT_PACKET_*)
+ * @plain: Pointer to return the pointer to the allocated plaintext buffer;
+ * needs to be freed by the caller if not NULL;
+ * will only be returned on success
+ * @plain_len: Pointer to return the length of the allocated plaintext buffer
+ * in octets
+ * Returns: 0 on success, -1 on error
+ */
+static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, const size_t auth_len,
+ const u8 *src_addr, u8 type,
+ u8 **plain, size_t *plain_size)
+{
+ const u8 *ad[3] = { src_addr, auth, &type };
+ size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
+
+ wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
+ MAC2STR(src_addr), type);
+ wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypt using key", key, key_len);
+ wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs", enc, enc_len);
+ wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
+
+ if (!key) { /* skip decryption */
+ *plain = os_memdup(enc, enc_len);
+ if (enc_len > 0 && !*plain)
+ goto err;
+
+ *plain_size = enc_len;
+
+ return 0;
+ }
+
+ *plain = NULL;
+
+ /* SIV overhead */
+ if (enc_len < AES_BLOCK_SIZE)
+ goto err;
+
+ *plain = os_zalloc(enc_len - AES_BLOCK_SIZE);
+ if (!*plain)
+ goto err;
+
+ if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
+ *plain) < 0) {
+ if (enc_len < AES_BLOCK_SIZE + 2)
+ goto err;
+
+ /* Try to work around Ethernet devices that add extra
+ * two octet padding even if the frame is longer than
+ * the minimum Ethernet frame. */
+ enc_len -= 2;
+ if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
+ *plain) < 0)
+ goto err;
+ }
+
+ *plain_size = enc_len - AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypted TLVs",
+ *plain, *plain_size);
+ return 0;
+err:
+ os_free(*plain);
+ *plain = NULL;
+ *plain_size = 0;
+
+ wpa_printf(MSG_ERROR, "FT(RRB): Failed to decrypt");
+
+ return -1;
+}
+
+
+/* get first tlv record in packet matching type
+ * @data (decrypted) packet
+ * @return 0 on success else -1
+ */
+static int wpa_ft_rrb_get_tlv(const u8 *plain, size_t plain_len,
+ u16 type, size_t *tlv_len, const u8 **tlv_data)
+{
+ const struct ft_rrb_tlv *f;
+ size_t left;
+ le16 type16;
+ size_t len;
+
+ left = plain_len;
+ type16 = host_to_le16(type);
+
+ while (left >= sizeof(*f)) {
+ f = (const struct ft_rrb_tlv *) plain;
+
+ left -= sizeof(*f);
+ plain += sizeof(*f);
+ len = le_to_host16(f->len);
+
+ if (left < len) {
+ wpa_printf(MSG_DEBUG, "FT: RRB message truncated");
+ break;
+ }
+
+ if (f->type == type16) {
+ *tlv_len = len;
+ *tlv_data = plain;
+ return 0;
+ }
+
+ left -= len;
+ plain += len;
+ }
+
+ return -1;
+}
+
+
+static void wpa_ft_rrb_dump(const u8 *plain, const size_t plain_len)
+{
+ const struct ft_rrb_tlv *f;
+ size_t left;
+ size_t len;
+
+ left = plain_len;
+
+ wpa_printf(MSG_DEBUG, "FT: RRB dump message");
+ while (left >= sizeof(*f)) {
+ f = (const struct ft_rrb_tlv *) plain;
+
+ left -= sizeof(*f);
+ plain += sizeof(*f);
+ len = le_to_host16(f->len);
+
+ wpa_printf(MSG_DEBUG, "FT: RRB TLV type = %d, len = %zu",
+ le_to_host16(f->type), len);
+
+ if (left < len) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB message truncated: left %zu bytes, need %zu",
+ left, len);
+ break;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FT: RRB TLV data", plain, len);
+
+ left -= len;
+ plain += len;
+ }
+
+ if (left > 0)
+ wpa_hexdump(MSG_DEBUG, "FT: RRB TLV padding", plain, left);
+
+ wpa_printf(MSG_DEBUG, "FT: RRB dump message end");
+}
+
+
+static int cmp_int(const void *a, const void *b)
+{
+ int x, y;
+
+ x = *((int *) a);
+ y = *((int *) b);
+ return x - y;
+}
+
+
+static int wpa_ft_rrb_get_tlv_vlan(const u8 *plain, const size_t plain_len,
+ struct vlan_description *vlan)
+{
+ struct ft_rrb_tlv *f;
+ size_t left;
+ size_t len;
+ int taggedidx;
+ int vlan_id;
+ int type;
+
+ left = plain_len;
+ taggedidx = 0;
+ os_memset(vlan, 0, sizeof(*vlan));
+
+ while (left >= sizeof(*f)) {
+ f = (struct ft_rrb_tlv *) plain;
+
+ left -= sizeof(*f);
+ plain += sizeof(*f);
+
+ len = le_to_host16(f->len);
+ type = le_to_host16(f->type);
+
+ if (left < len) {
+ wpa_printf(MSG_DEBUG, "FT: RRB message truncated");
+ return -1;
+ }
+
+ if (type != FT_RRB_VLAN_UNTAGGED && type != FT_RRB_VLAN_TAGGED)
+ goto skip;
+
+ if (type == FT_RRB_VLAN_UNTAGGED && len != sizeof(le16)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB VLAN_UNTAGGED invalid length");
+ return -1;
+ }
+
+ if (type == FT_RRB_VLAN_TAGGED && len % sizeof(le16) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB VLAN_TAGGED invalid length");
+ return -1;
+ }
+
+ while (len >= sizeof(le16)) {
+ vlan_id = WPA_GET_LE16(plain);
+ plain += sizeof(le16);
+ left -= sizeof(le16);
+ len -= sizeof(le16);
+
+ if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB VLAN ID invalid %d",
+ vlan_id);
+ continue;
+ }
+
+ if (type == FT_RRB_VLAN_UNTAGGED)
+ vlan->untagged = vlan_id;
+
+ if (type == FT_RRB_VLAN_TAGGED &&
+ taggedidx < MAX_NUM_TAGGED_VLAN) {
+ vlan->tagged[taggedidx] = vlan_id;
+ taggedidx++;
+ } else if (type == FT_RRB_VLAN_TAGGED) {
+ wpa_printf(MSG_DEBUG, "FT: RRB too many VLANs");
+ }
+ }
+
+ skip:
+ left -= len;
+ plain += len;
+ }
+
+ if (taggedidx)
+ qsort(vlan->tagged, taggedidx, sizeof(int), cmp_int);
+
+ vlan->notempty = vlan->untagged || vlan->tagged[0];
+
+ return 0;
+}
+
+
+static size_t wpa_ft_tlv_len(const struct tlv_list *tlvs)
+{
+ size_t tlv_len = 0;
+ int i;
+
+ if (!tlvs)
+ return 0;
+
+ for (i = 0; tlvs[i].type != FT_RRB_LAST_EMPTY; i++) {
+ tlv_len += sizeof(struct ft_rrb_tlv);
+ tlv_len += tlvs[i].len;
+ }
+
+ return tlv_len;
+}
+
+
+static size_t wpa_ft_tlv_lin(const struct tlv_list *tlvs, u8 *start,
+ u8 *endpos)
+{
+ int i;
+ size_t tlv_len;
+ struct ft_rrb_tlv *hdr;
+ u8 *pos;
+
+ if (!tlvs)
+ return 0;
+
+ tlv_len = 0;
+ pos = start;
+ for (i = 0; tlvs[i].type != FT_RRB_LAST_EMPTY; i++) {
+ if (tlv_len + sizeof(*hdr) > (size_t) (endpos - start))
+ return tlv_len;
+ tlv_len += sizeof(*hdr);
+ hdr = (struct ft_rrb_tlv *) pos;
+ hdr->type = host_to_le16(tlvs[i].type);
+ hdr->len = host_to_le16(tlvs[i].len);
+ pos = start + tlv_len;
+
+ if (tlv_len + tlvs[i].len > (size_t) (endpos - start))
+ return tlv_len;
+ if (tlvs[i].len == 0)
+ continue;
+ tlv_len += tlvs[i].len;
+ os_memcpy(pos, tlvs[i].data, tlvs[i].len);
+ pos = start + tlv_len;
+ }
+
+ return tlv_len;
+}
+
+
+static size_t wpa_ft_vlan_len(const struct vlan_description *vlan)
+{
+ size_t tlv_len = 0;
+ int i;
+
+ if (!vlan || !vlan->notempty)
+ return 0;
+
+ if (vlan->untagged) {
+ tlv_len += sizeof(struct ft_rrb_tlv);
+ tlv_len += sizeof(le16);
+ }
+ if (vlan->tagged[0])
+ tlv_len += sizeof(struct ft_rrb_tlv);
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && vlan->tagged[i]; i++)
+ tlv_len += sizeof(le16);
+
+ return tlv_len;
+}
+
+
+static size_t wpa_ft_vlan_lin(const struct vlan_description *vlan,
+ u8 *start, u8 *endpos)
+{
+ size_t tlv_len;
+ int i, len;
+ struct ft_rrb_tlv *hdr;
+ u8 *pos = start;
+
+ if (!vlan || !vlan->notempty)
+ return 0;
+
+ tlv_len = 0;
+ if (vlan->untagged) {
+ tlv_len += sizeof(*hdr);
+ if (start + tlv_len > endpos)
+ return tlv_len;
+ hdr = (struct ft_rrb_tlv *) pos;
+ hdr->type = host_to_le16(FT_RRB_VLAN_UNTAGGED);
+ hdr->len = host_to_le16(sizeof(le16));
+ pos = start + tlv_len;
+
+ tlv_len += sizeof(le16);
+ if (start + tlv_len > endpos)
+ return tlv_len;
+ WPA_PUT_LE16(pos, vlan->untagged);
+ pos = start + tlv_len;
+ }
+
+ if (!vlan->tagged[0])
+ return tlv_len;
+
+ tlv_len += sizeof(*hdr);
+ if (start + tlv_len > endpos)
+ return tlv_len;
+ hdr = (struct ft_rrb_tlv *) pos;
+ hdr->type = host_to_le16(FT_RRB_VLAN_TAGGED);
+ len = 0; /* len is computed below */
+ pos = start + tlv_len;
+
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && vlan->tagged[i]; i++) {
+ tlv_len += sizeof(le16);
+ if (start + tlv_len > endpos)
+ break;
+ len += sizeof(le16);
+ WPA_PUT_LE16(pos, vlan->tagged[i]);
+ pos = start + tlv_len;
+ }
+
+ hdr->len = host_to_le16(len);
+
+ return tlv_len;
+}
+
+
+static int wpa_ft_rrb_lin(const struct tlv_list *tlvs1,
+ const struct tlv_list *tlvs2,
+ const struct vlan_description *vlan,
+ u8 **plain, size_t *plain_len)
+{
+ u8 *pos, *endpos;
+ size_t tlv_len;
+
+ tlv_len = wpa_ft_tlv_len(tlvs1);
+ tlv_len += wpa_ft_tlv_len(tlvs2);
+ tlv_len += wpa_ft_vlan_len(vlan);
+
+ *plain_len = tlv_len;
+ *plain = os_zalloc(tlv_len);
+ if (!*plain) {
+ wpa_printf(MSG_ERROR, "FT: Failed to allocate plaintext");
+ goto err;
+ }
+
+ pos = *plain;
+ endpos = *plain + tlv_len;
+ pos += wpa_ft_tlv_lin(tlvs1, pos, endpos);
+ pos += wpa_ft_tlv_lin(tlvs2, pos, endpos);
+ pos += wpa_ft_vlan_lin(vlan, pos, endpos);
+
+ /* sanity check */
+ if (pos != endpos) {
+ wpa_printf(MSG_ERROR, "FT: Length error building RRB");
+ goto err;
+ }
+ return 0;
+
+err:
+ os_free(*plain);
+ *plain = NULL;
+ *plain_len = 0;
+ return -1;
+}
+
+
+static int wpa_ft_rrb_encrypt(const u8 *key, const size_t key_len,
+ const u8 *plain, const size_t plain_len,
+ const u8 *auth, const size_t auth_len,
+ const u8 *src_addr, u8 type, u8 *enc)
+{
+ const u8 *ad[3] = { src_addr, auth, &type };
+ size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
+
+ wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
+ MAC2STR(src_addr), type);
+ wpa_hexdump_key(MSG_DEBUG, "FT(RRB): plaintext message",
+ plain, plain_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT(RRB): encrypt using key", key, key_len);
+ wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
+
+ if (!key) {
+ /* encryption not needed, return plaintext as packet */
+ os_memcpy(enc, plain, plain_len);
+ } else if (aes_siv_encrypt(key, key_len, plain, plain_len,
+ 3, ad, ad_len, enc) < 0) {
+ wpa_printf(MSG_ERROR, "FT: Failed to encrypt RRB-OUI message");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs",
+ enc, plain_len + AES_BLOCK_SIZE);
+
+ return 0;
+}
+
+
+/**
+ * wpa_ft_rrb_build - Build and encrypt an FT RRB message
+ * @key: AES-SIV key for AEAD
+ * @key_len: Length of key in octets
+ * @tlvs_enc0: First set of to-be-encrypted TLVs
+ * @tlvs_enc1: Second set of to-be-encrypted TLVs
+ * @tlvs_auth: Set of to-be-authenticated TLVs
+ * @src_addr: MAC address of the frame sender
+ * @type: Vendor-specific subtype of the RRB frame (FT_PACKET_*)
+ * @packet Pointer to return the pointer to the allocated packet buffer;
+ * needs to be freed by the caller if not null;
+ * will only be returned on success
+ * @packet_len: Pointer to return the length of the allocated buffer in octets
+ * Returns: 0 on success, -1 on error
+ */
+static int wpa_ft_rrb_build(const u8 *key, const size_t key_len,
+ const struct tlv_list *tlvs_enc0,
+ const struct tlv_list *tlvs_enc1,
+ const struct tlv_list *tlvs_auth,
+ const struct vlan_description *vlan,
+ const u8 *src_addr, u8 type,
+ u8 **packet, size_t *packet_len)
+{
+ u8 *plain = NULL, *auth = NULL, *pos, *tmp;
+ size_t plain_len = 0, auth_len = 0;
+ int ret = -1;
+ size_t pad_len = 0;
+
+ *packet = NULL;
+ if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0)
+ goto out;
+
+ if (wpa_ft_rrb_lin(tlvs_auth, NULL, NULL, &auth, &auth_len) < 0)
+ goto out;
+
+ *packet_len = sizeof(u16) + auth_len + plain_len;
+ if (key)
+ *packet_len += AES_BLOCK_SIZE;
+#define RRB_MIN_MSG_LEN 64
+ if (*packet_len < RRB_MIN_MSG_LEN) {
+ pad_len = RRB_MIN_MSG_LEN - *packet_len;
+ if (pad_len < sizeof(struct ft_rrb_tlv))
+ pad_len = sizeof(struct ft_rrb_tlv);
+ wpa_printf(MSG_DEBUG,
+ "FT: Pad message to minimum Ethernet frame length (%d --> %d)",
+ (int) *packet_len, (int) (*packet_len + pad_len));
+ *packet_len += pad_len;
+ tmp = os_realloc(auth, auth_len + pad_len);
+ if (!tmp)
+ goto out;
+ auth = tmp;
+ pos = auth + auth_len;
+ WPA_PUT_LE16(pos, FT_RRB_LAST_EMPTY);
+ pos += 2;
+ WPA_PUT_LE16(pos, pad_len - sizeof(struct ft_rrb_tlv));
+ pos += 2;
+ os_memset(pos, 0, pad_len - sizeof(struct ft_rrb_tlv));
+ auth_len += pad_len;
+
+ }
+ *packet = os_zalloc(*packet_len);
+ if (!*packet)
+ goto out;
+
+ pos = *packet;
+ WPA_PUT_LE16(pos, auth_len);
+ pos += 2;
+ os_memcpy(pos, auth, auth_len);
+ pos += auth_len;
+ if (wpa_ft_rrb_encrypt(key, key_len, plain, plain_len, auth,
+ auth_len, src_addr, type, pos) < 0)
+ goto out;
+ wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", *packet, *packet_len);
+
+ ret = 0;
+
+out:
+ bin_clear_free(plain, plain_len);
+ os_free(auth);
+
+ if (ret) {
+ wpa_printf(MSG_ERROR, "FT: Failed to build RRB-OUI message");
+ os_free(*packet);
+ *packet = NULL;
+ *packet_len = 0;
+ }
+
+ return ret;
+}
+
+
+#define RRB_GET_SRC(srcfield, type, field, txt, checklength) do { \
+ if (wpa_ft_rrb_get_tlv(srcfield, srcfield##_len, type, \
+ &f_##field##_len, &f_##field) < 0 || \
+ (checklength > 0 && ((size_t) checklength) != f_##field##_len)) { \
+ wpa_printf(MSG_INFO, "FT: Missing required " #field \
+ " in %s from " MACSTR, txt, MAC2STR(src_addr)); \
+ wpa_ft_rrb_dump(srcfield, srcfield##_len); \
+ goto out; \
+ } \
+} while (0)
+
+#define RRB_GET(type, field, txt, checklength) \
+ RRB_GET_SRC(plain, type, field, txt, checklength)
+#define RRB_GET_AUTH(type, field, txt, checklength) \
+ RRB_GET_SRC(auth, type, field, txt, checklength)
+
+#define RRB_GET_OPTIONAL_SRC(srcfield, type, field, txt, checklength) do { \
+ if (wpa_ft_rrb_get_tlv(srcfield, srcfield##_len, type, \
+ &f_##field##_len, &f_##field) < 0 || \
+ (checklength > 0 && ((size_t) checklength) != f_##field##_len)) { \
+ wpa_printf(MSG_DEBUG, "FT: Missing optional " #field \
+ " in %s from " MACSTR, txt, MAC2STR(src_addr)); \
+ f_##field##_len = 0; \
+ f_##field = NULL; \
+ } \
+} while (0)
+
+#define RRB_GET_OPTIONAL(type, field, txt, checklength) \
+ RRB_GET_OPTIONAL_SRC(plain, type, field, txt, checklength)
+#define RRB_GET_OPTIONAL_AUTH(type, field, txt, checklength) \
+ RRB_GET_OPTIONAL_SRC(auth, type, field, txt, checklength)
static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
const u8 *data, size_t data_len)
{
- if (wpa_auth->cb.send_ether == NULL)
+ if (wpa_auth->cb->send_ether == NULL)
return -1;
wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
- return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
- data, data_len);
+ return wpa_auth->cb->send_ether(wpa_auth->cb_ctx, dst, ETH_P_RRB,
+ data, data_len);
+}
+
+
+static int wpa_ft_rrb_oui_send(struct wpa_authenticator *wpa_auth,
+ const u8 *dst, u8 oui_suffix,
+ const u8 *data, size_t data_len)
+{
+ if (!wpa_auth->cb->send_oui)
+ return -1;
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR " (len=%u)",
+ oui_suffix, MAC2STR(dst), (unsigned int) data_len);
+ return wpa_auth->cb->send_oui(wpa_auth->cb_ctx, dst, oui_suffix, data,
+ data_len);
}
static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
const u8 *dst, const u8 *data, size_t data_len)
{
- if (wpa_auth->cb.send_ft_action == NULL)
+ if (wpa_auth->cb->send_ft_action == NULL)
return -1;
- return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst,
- data, data_len);
+ return wpa_auth->cb->send_ft_action(wpa_auth->cb_ctx, dst,
+ data, data_len);
+}
+
+
+static const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, const u8 *p2p_dev_addr,
+ const u8 *prev_psk)
+{
+ if (wpa_auth->cb->get_psk == NULL)
+ return NULL;
+ return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
+ prev_psk, NULL, NULL);
}
static struct wpa_state_machine *
wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
{
- if (wpa_auth->cb.add_sta == NULL)
+ if (wpa_auth->cb->add_sta == NULL)
return NULL;
- return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr);
+ return wpa_auth->cb->add_sta(wpa_auth->cb_ctx, sta_addr);
+}
+
+
+static int wpa_ft_set_vlan(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, struct vlan_description *vlan)
+{
+ if (!wpa_auth->cb->set_vlan)
+ return -1;
+ return wpa_auth->cb->set_vlan(wpa_auth->cb_ctx, sta_addr, vlan);
+}
+
+
+static int wpa_ft_get_vlan(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, struct vlan_description *vlan)
+{
+ if (!wpa_auth->cb->get_vlan)
+ return -1;
+ return wpa_auth->cb->get_vlan(wpa_auth->cb_ctx, sta_addr, vlan);
+}
+
+
+static int
+wpa_ft_set_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 *identity, size_t identity_len)
+{
+ if (!wpa_auth->cb->set_identity)
+ return -1;
+ return wpa_auth->cb->set_identity(wpa_auth->cb_ctx, sta_addr, identity,
+ identity_len);
+}
+
+
+static size_t
+wpa_ft_get_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 **buf)
+{
+ *buf = NULL;
+ if (!wpa_auth->cb->get_identity)
+ return 0;
+ return wpa_auth->cb->get_identity(wpa_auth->cb_ctx, sta_addr, buf);
+}
+
+
+static int
+wpa_ft_set_radius_cui(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 *radius_cui, size_t radius_cui_len)
+{
+ if (!wpa_auth->cb->set_radius_cui)
+ return -1;
+ return wpa_auth->cb->set_radius_cui(wpa_auth->cb_ctx, sta_addr,
+ radius_cui, radius_cui_len);
+}
+
+
+static size_t
+wpa_ft_get_radius_cui(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 **buf)
+{
+ *buf = NULL;
+ if (!wpa_auth->cb->get_radius_cui)
+ return 0;
+ return wpa_auth->cb->get_radius_cui(wpa_auth->cb_ctx, sta_addr, buf);
+}
+
+
+static void
+wpa_ft_set_session_timeout(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, int session_timeout)
+{
+ if (!wpa_auth->cb->set_session_timeout)
+ return;
+ wpa_auth->cb->set_session_timeout(wpa_auth->cb_ctx, sta_addr,
+ session_timeout);
+}
+
+
+static int
+wpa_ft_get_session_timeout(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr)
+{
+ if (!wpa_auth->cb->get_session_timeout)
+ return 0;
+ return wpa_auth->cb->get_session_timeout(wpa_auth->cb_ctx, sta_addr);
}
@@ -64,13 +763,24 @@ static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr,
u8 *tspec_ie, size_t tspec_ielen)
{
- if (wpa_auth->cb.add_tspec == NULL) {
+ if (wpa_auth->cb->add_tspec == NULL) {
wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
return -1;
}
- return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
- tspec_ielen);
+ return wpa_auth->cb->add_tspec(wpa_auth->cb_ctx, sta_addr, tspec_ie,
+ tspec_ielen);
+}
+
+
+#ifdef CONFIG_OCV
+static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
+ struct wpa_channel_info *ci)
+{
+ if (!wpa_auth->cb->channel_info)
+ return -1;
+ return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
}
+#endif /* CONFIG_OCV */
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
@@ -93,30 +803,44 @@ int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
}
-int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
- size_t r0kh_id_len,
+int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
+ const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len)
{
u8 *pos = buf, *ielen;
- struct rsn_ftie *hdr;
+ size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
+ sizeof(struct rsn_ftie);
- if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
+ if (len < 2 + hdrlen + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
subelem_len)
return -1;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ielen = pos++;
- hdr = (struct rsn_ftie *) pos;
- os_memset(hdr, 0, sizeof(*hdr));
- pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
- if (anonce)
- os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
- if (snonce)
- os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *hdr = (struct rsn_ftie_sha384 *) pos;
+
+ os_memset(hdr, 0, sizeof(*hdr));
+ pos += sizeof(*hdr);
+ WPA_PUT_LE16(hdr->mic_control, 0);
+ if (anonce)
+ os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+ if (snonce)
+ os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+ } else {
+ struct rsn_ftie *hdr = (struct rsn_ftie *) pos;
+
+ os_memset(hdr, 0, sizeof(*hdr));
+ pos += sizeof(*hdr);
+ WPA_PUT_LE16(hdr->mic_control, 0);
+ if (anonce)
+ os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+ if (snonce)
+ os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+ }
/* Optional Parameters */
*pos++ = FTIE_SUBELEM_R1KH_ID;
@@ -142,35 +866,434 @@ int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
}
+/* A packet to be handled after seq response */
+struct ft_remote_item {
+ struct dl_list list;
+
+ u8 nonce[FT_RRB_NONCE_LEN];
+ struct os_reltime nonce_ts;
+
+ u8 src_addr[ETH_ALEN];
+ u8 *enc;
+ size_t enc_len;
+ u8 *auth;
+ size_t auth_len;
+ int (*cb)(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ int no_defer);
+};
+
+
+static void wpa_ft_rrb_seq_free(struct ft_remote_item *item)
+{
+ eloop_cancel_timeout(wpa_ft_rrb_seq_timeout, ELOOP_ALL_CTX, item);
+ dl_list_del(&item->list);
+ bin_clear_free(item->enc, item->enc_len);
+ os_free(item->auth);
+ os_free(item);
+}
+
+
+static void wpa_ft_rrb_seq_flush(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_seq *rkh_seq, int cb)
+{
+ struct ft_remote_item *item, *n;
+
+ dl_list_for_each_safe(item, n, &rkh_seq->rx.queue,
+ struct ft_remote_item, list) {
+ if (cb && item->cb)
+ item->cb(wpa_auth, item->src_addr, item->enc,
+ item->enc_len, item->auth, item->auth_len, 1);
+ wpa_ft_rrb_seq_free(item);
+ }
+}
+
+
+static void wpa_ft_rrb_seq_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ft_remote_item *item = timeout_ctx;
+
+ wpa_ft_rrb_seq_free(item);
+}
+
+
+static int
+wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_seq *rkh_seq, const u8 *src_addr,
+ const u8 *f_r0kh_id, size_t f_r0kh_id_len,
+ const u8 *f_r1kh_id, const u8 *key, size_t key_len,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ int (*cb)(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ int no_defer))
+{
+ struct ft_remote_item *item = NULL;
+ u8 *packet = NULL;
+ size_t packet_len;
+ struct tlv_list seq_req_auth[] = {
+ { .type = FT_RRB_NONCE, .len = FT_RRB_NONCE_LEN,
+ .data = NULL /* to be filled: item->nonce */ },
+ { .type = FT_RRB_R0KH_ID, .len = f_r0kh_id_len,
+ .data = f_r0kh_id },
+ { .type = FT_RRB_R1KH_ID, .len = FT_R1KH_ID_LEN,
+ .data = f_r1kh_id },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ if (dl_list_len(&rkh_seq->rx.queue) >= ftRRBmaxQueueLen) {
+ wpa_printf(MSG_DEBUG, "FT: Sequence number queue too long");
+ goto err;
+ }
+
+ wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
+ MAC2STR(src_addr));
+ item = os_zalloc(sizeof(*item));
+ if (!item)
+ goto err;
+
+ os_memcpy(item->src_addr, src_addr, ETH_ALEN);
+ item->cb = cb;
+
+ if (random_get_bytes(item->nonce, FT_RRB_NONCE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Seq num nonce: out of random bytes");
+ goto err;
+ }
+
+ if (os_get_reltime(&item->nonce_ts) < 0)
+ goto err;
+
+ if (enc && enc_len > 0) {
+ item->enc = os_memdup(enc, enc_len);
+ item->enc_len = enc_len;
+ if (!item->enc)
+ goto err;
+ }
+
+ if (auth && auth_len > 0) {
+ item->auth = os_memdup(auth, auth_len);
+ item->auth_len = auth_len;
+ if (!item->auth)
+ goto err;
+ }
+
+ eloop_register_timeout(ftRRBseqTimeout, 0, wpa_ft_rrb_seq_timeout,
+ wpa_auth, item);
+
+ seq_req_auth[0].data = item->nonce;
+
+ if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_req_auth, NULL,
+ wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_REQ,
+ &packet, &packet_len) < 0) {
+ item = NULL; /* some other seq resp might still accept this */
+ goto err;
+ }
+
+ dl_list_add(&rkh_seq->rx.queue, &item->list);
+
+ wpa_ft_rrb_oui_send(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_REQ,
+ packet, packet_len);
+
+ os_free(packet);
+
+ return 0;
+err:
+ wpa_printf(MSG_DEBUG, "FT: Failed to send sequence number request");
+ if (item) {
+ os_free(item->auth);
+ bin_clear_free(item->enc, item->enc_len);
+ os_free(item);
+ }
+
+ return -1;
+}
+
+
+#define FT_RRB_SEQ_OK 0
+#define FT_RRB_SEQ_DROP 1
+#define FT_RRB_SEQ_DEFER 2
+
+static int
+wpa_ft_rrb_seq_chk(struct ft_remote_seq *rkh_seq, const u8 *src_addr,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ const char *msgtype, int no_defer)
+{
+ const u8 *f_seq;
+ size_t f_seq_len;
+ const struct ft_rrb_seq *msg_both;
+ u32 msg_seq, msg_off, rkh_off;
+ struct os_reltime now;
+ unsigned int i;
+
+ RRB_GET_AUTH(FT_RRB_SEQ, seq, msgtype, sizeof(*msg_both));
+ wpa_hexdump(MSG_DEBUG, "FT: sequence number", f_seq, f_seq_len);
+ msg_both = (const struct ft_rrb_seq *) f_seq;
+
+ if (rkh_seq->rx.num_last == 0) {
+ /* first packet from remote */
+ goto defer;
+ }
+
+ if (le_to_host32(msg_both->dom) != rkh_seq->rx.dom) {
+ /* remote might have rebooted */
+ goto defer;
+ }
+
+ if (os_get_reltime(&now) == 0) {
+ u32 msg_ts_now_remote, msg_ts_off;
+ struct os_reltime now_remote;
+
+ os_reltime_sub(&now, &rkh_seq->rx.time_offset, &now_remote);
+ msg_ts_now_remote = now_remote.sec;
+ msg_ts_off = le_to_host32(msg_both->ts) -
+ (msg_ts_now_remote - ftRRBseqTimeout);
+ if (msg_ts_off > 2 * ftRRBseqTimeout)
+ goto defer;
+ }
+
+ msg_seq = le_to_host32(msg_both->seq);
+ rkh_off = rkh_seq->rx.last[rkh_seq->rx.offsetidx];
+ msg_off = msg_seq - rkh_off;
+ if (msg_off > 0xC0000000)
+ goto out; /* too old message, drop it */
+
+ if (msg_off <= 0x40000000) {
+ for (i = 0; i < rkh_seq->rx.num_last; i++) {
+ if (rkh_seq->rx.last[i] == msg_seq)
+ goto out; /* duplicate message, drop it */
+ }
+
+ return FT_RRB_SEQ_OK;
+ }
+
+defer:
+ if (no_defer)
+ goto out;
+
+ wpa_printf(MSG_DEBUG, "FT: Possibly invalid sequence number in %s from "
+ MACSTR, msgtype, MAC2STR(src_addr));
+
+ return FT_RRB_SEQ_DEFER;
+out:
+ wpa_printf(MSG_DEBUG, "FT: Invalid sequence number in %s from " MACSTR,
+ msgtype, MAC2STR(src_addr));
+
+ return FT_RRB_SEQ_DROP;
+}
+
+
+static void
+wpa_ft_rrb_seq_accept(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_seq *rkh_seq, const u8 *src_addr,
+ const u8 *auth, size_t auth_len,
+ const char *msgtype)
+{
+ const u8 *f_seq;
+ size_t f_seq_len;
+ const struct ft_rrb_seq *msg_both;
+ u32 msg_seq, msg_off, min_off, rkh_off;
+ int minidx = 0;
+ unsigned int i;
+
+ RRB_GET_AUTH(FT_RRB_SEQ, seq, msgtype, sizeof(*msg_both));
+ msg_both = (const struct ft_rrb_seq *) f_seq;
+
+ msg_seq = le_to_host32(msg_both->seq);
+
+ if (rkh_seq->rx.num_last < FT_REMOTE_SEQ_BACKLOG) {
+ rkh_seq->rx.last[rkh_seq->rx.num_last] = msg_seq;
+ rkh_seq->rx.num_last++;
+ return;
+ }
+
+ rkh_off = rkh_seq->rx.last[rkh_seq->rx.offsetidx];
+ for (i = 0; i < rkh_seq->rx.num_last; i++) {
+ msg_off = rkh_seq->rx.last[i] - rkh_off;
+ min_off = rkh_seq->rx.last[minidx] - rkh_off;
+ if (msg_off < min_off && i != rkh_seq->rx.offsetidx)
+ minidx = i;
+ }
+ rkh_seq->rx.last[rkh_seq->rx.offsetidx] = msg_seq;
+ rkh_seq->rx.offsetidx = minidx;
+
+ return;
+out:
+ /* RRB_GET_AUTH should never fail here as
+ * wpa_ft_rrb_seq_chk() verified FT_RRB_SEQ presence. */
+ wpa_printf(MSG_ERROR, "FT: %s() failed", __func__);
+}
+
+
+static int wpa_ft_new_seq(struct ft_remote_seq *rkh_seq,
+ struct ft_rrb_seq *f_seq)
+{
+ struct os_reltime now;
+
+ if (os_get_reltime(&now) < 0)
+ return -1;
+
+ if (!rkh_seq->tx.dom) {
+ if (random_get_bytes((u8 *) &rkh_seq->tx.seq,
+ sizeof(rkh_seq->tx.seq))) {
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to get random data for sequence number initialization");
+ rkh_seq->tx.seq = now.usec;
+ }
+ if (random_get_bytes((u8 *) &rkh_seq->tx.dom,
+ sizeof(rkh_seq->tx.dom))) {
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to get random data for sequence number initialization");
+ rkh_seq->tx.dom = now.usec;
+ }
+ rkh_seq->tx.dom |= 1;
+ }
+
+ f_seq->dom = host_to_le32(rkh_seq->tx.dom);
+ f_seq->seq = host_to_le32(rkh_seq->tx.seq);
+ f_seq->ts = host_to_le32(now.sec);
+
+ rkh_seq->tx.seq++;
+
+ return 0;
+}
+
+
struct wpa_ft_pmk_r0_sa {
- struct wpa_ft_pmk_r0_sa *next;
- u8 pmk_r0[PMK_LEN];
+ struct dl_list list;
+ u8 pmk_r0[PMK_LEN_MAX];
+ size_t pmk_r0_len;
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 spa[ETH_ALEN];
int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
- /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+ struct vlan_description *vlan;
+ os_time_t expiration; /* 0 for no expiration */
+ u8 *identity;
+ size_t identity_len;
+ u8 *radius_cui;
+ size_t radius_cui_len;
+ os_time_t session_timeout; /* 0 for no expiration */
+ /* TODO: radius_class, EAP type */
int pmk_r1_pushed;
};
struct wpa_ft_pmk_r1_sa {
- struct wpa_ft_pmk_r1_sa *next;
- u8 pmk_r1[PMK_LEN];
+ struct dl_list list;
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 spa[ETH_ALEN];
int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
- /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+ struct vlan_description *vlan;
+ u8 *identity;
+ size_t identity_len;
+ u8 *radius_cui;
+ size_t radius_cui_len;
+ os_time_t session_timeout; /* 0 for no expiration */
+ /* TODO: radius_class, EAP type */
};
struct wpa_ft_pmk_cache {
- struct wpa_ft_pmk_r0_sa *pmk_r0;
- struct wpa_ft_pmk_r1_sa *pmk_r1;
+ struct dl_list pmk_r0; /* struct wpa_ft_pmk_r0_sa */
+ struct dl_list pmk_r1; /* struct wpa_ft_pmk_r1_sa */
};
+
+static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx);
+static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx);
+
+
+static void wpa_ft_free_pmk_r0(struct wpa_ft_pmk_r0_sa *r0)
+{
+ if (!r0)
+ return;
+
+ dl_list_del(&r0->list);
+ eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
+
+ os_memset(r0->pmk_r0, 0, PMK_LEN_MAX);
+ os_free(r0->vlan);
+ os_free(r0->identity);
+ os_free(r0->radius_cui);
+ os_free(r0);
+}
+
+
+static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_ft_pmk_r0_sa *r0 = eloop_ctx;
+ struct os_reltime now;
+ int expires_in;
+ int session_timeout;
+
+ os_get_reltime(&now);
+
+ if (!r0)
+ return;
+
+ expires_in = r0->expiration - now.sec;
+ session_timeout = r0->session_timeout - now.sec;
+ /* conditions to remove from cache:
+ * a) r0->expiration is set and hit
+ * -or-
+ * b) r0->session_timeout is set and hit
+ */
+ if ((!r0->expiration || expires_in > 0) &&
+ (!r0->session_timeout || session_timeout > 0)) {
+ wpa_printf(MSG_ERROR,
+ "FT: %s() called for non-expired entry %p",
+ __func__, r0);
+ eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
+ if (r0->expiration && expires_in > 0)
+ eloop_register_timeout(expires_in + 1, 0,
+ wpa_ft_expire_pmk_r0, r0, NULL);
+ if (r0->session_timeout && session_timeout > 0)
+ eloop_register_timeout(session_timeout + 1, 0,
+ wpa_ft_expire_pmk_r0, r0, NULL);
+ return;
+ }
+
+ wpa_ft_free_pmk_r0(r0);
+}
+
+
+static void wpa_ft_free_pmk_r1(struct wpa_ft_pmk_r1_sa *r1)
+{
+ if (!r1)
+ return;
+
+ dl_list_del(&r1->list);
+ eloop_cancel_timeout(wpa_ft_expire_pmk_r1, r1, NULL);
+
+ os_memset(r1->pmk_r1, 0, PMK_LEN_MAX);
+ os_free(r1->vlan);
+ os_free(r1->identity);
+ os_free(r1->radius_cui);
+ os_free(r1);
+}
+
+
+static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_ft_pmk_r1_sa *r1 = eloop_ctx;
+
+ wpa_ft_free_pmk_r1(r1);
+}
+
+
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
{
struct wpa_ft_pmk_cache *cache;
cache = os_zalloc(sizeof(*cache));
+ if (cache) {
+ dl_list_init(&cache->pmk_r0);
+ dl_list_init(&cache->pmk_r1);
+ }
return cache;
}
@@ -181,21 +1304,13 @@ void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
struct wpa_ft_pmk_r0_sa *r0, *r0prev;
struct wpa_ft_pmk_r1_sa *r1, *r1prev;
- r0 = cache->pmk_r0;
- while (r0) {
- r0prev = r0;
- r0 = r0->next;
- os_memset(r0prev->pmk_r0, 0, PMK_LEN);
- os_free(r0prev);
- }
+ dl_list_for_each_safe(r0, r0prev, &cache->pmk_r0,
+ struct wpa_ft_pmk_r0_sa, list)
+ wpa_ft_free_pmk_r0(r0);
- r1 = cache->pmk_r1;
- while (r1) {
- r1prev = r1;
- r1 = r1->next;
- os_memset(r1prev->pmk_r1, 0, PMK_LEN);
- os_free(r1prev);
- }
+ dl_list_for_each_safe(r1, r1prev, &cache->pmk_r1,
+ struct wpa_ft_pmk_r1_sa, list)
+ wpa_ft_free_pmk_r1(r1);
os_free(cache);
}
@@ -203,24 +1318,63 @@ void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
const u8 *spa, const u8 *pmk_r0,
- const u8 *pmk_r0_name, int pairwise)
+ size_t pmk_r0_len,
+ const u8 *pmk_r0_name, int pairwise,
+ const struct vlan_description *vlan,
+ int expires_in, int session_timeout,
+ const u8 *identity, size_t identity_len,
+ const u8 *radius_cui, size_t radius_cui_len)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r0_sa *r0;
+ struct os_reltime now;
- /* TODO: add expiration and limit on number of entries in cache */
+ /* TODO: add limit on number of entries in cache */
+ os_get_reltime(&now);
r0 = os_zalloc(sizeof(*r0));
if (r0 == NULL)
return -1;
- os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
+ os_memcpy(r0->pmk_r0, pmk_r0, pmk_r0_len);
+ r0->pmk_r0_len = pmk_r0_len;
os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
os_memcpy(r0->spa, spa, ETH_ALEN);
r0->pairwise = pairwise;
+ if (expires_in > 0)
+ r0->expiration = now.sec + expires_in;
+ if (vlan && vlan->notempty) {
+ r0->vlan = os_zalloc(sizeof(*vlan));
+ if (!r0->vlan) {
+ bin_clear_free(r0, sizeof(*r0));
+ return -1;
+ }
+ *r0->vlan = *vlan;
+ }
+ if (identity) {
+ r0->identity = os_malloc(identity_len);
+ if (r0->identity) {
+ os_memcpy(r0->identity, identity, identity_len);
+ r0->identity_len = identity_len;
+ }
+ }
+ if (radius_cui) {
+ r0->radius_cui = os_malloc(radius_cui_len);
+ if (r0->radius_cui) {
+ os_memcpy(r0->radius_cui, radius_cui, radius_cui_len);
+ r0->radius_cui_len = radius_cui_len;
+ }
+ }
+ if (session_timeout > 0)
+ r0->session_timeout = now.sec + session_timeout;
- r0->next = cache->pmk_r0;
- cache->pmk_r0 = r0;
+ dl_list_add(&cache->pmk_r0, &r0->list);
+ if (expires_in > 0)
+ eloop_register_timeout(expires_in + 1, 0, wpa_ft_expire_pmk_r0,
+ r0, NULL);
+ if (session_timeout > 0)
+ eloop_register_timeout(session_timeout + 1, 0,
+ wpa_ft_expire_pmk_r0, r0, NULL);
return 0;
}
@@ -228,49 +1382,89 @@ static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
const u8 *spa, const u8 *pmk_r0_name,
- u8 *pmk_r0, int *pairwise)
+ const struct wpa_ft_pmk_r0_sa **r0_out)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r0_sa *r0;
+ struct os_reltime now;
- r0 = cache->pmk_r0;
- while (r0) {
+ os_get_reltime(&now);
+ dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
WPA_PMK_NAME_LEN) == 0) {
- os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
- if (pairwise)
- *pairwise = r0->pairwise;
+ *r0_out = r0;
return 0;
}
-
- r0 = r0->next;
}
+ *r0_out = NULL;
return -1;
}
static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
const u8 *spa, const u8 *pmk_r1,
- const u8 *pmk_r1_name, int pairwise)
+ size_t pmk_r1_len,
+ const u8 *pmk_r1_name, int pairwise,
+ const struct vlan_description *vlan,
+ int expires_in, int session_timeout,
+ const u8 *identity, size_t identity_len,
+ const u8 *radius_cui, size_t radius_cui_len)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+ int max_expires_in = wpa_auth->conf.r1_max_key_lifetime;
struct wpa_ft_pmk_r1_sa *r1;
+ struct os_reltime now;
- /* TODO: add expiration and limit on number of entries in cache */
+ /* TODO: limit on number of entries in cache */
+ os_get_reltime(&now);
+
+ if (max_expires_in && (max_expires_in < expires_in || expires_in == 0))
+ expires_in = max_expires_in;
r1 = os_zalloc(sizeof(*r1));
if (r1 == NULL)
return -1;
- os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
+ os_memcpy(r1->pmk_r1, pmk_r1, pmk_r1_len);
+ r1->pmk_r1_len = pmk_r1_len;
os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
os_memcpy(r1->spa, spa, ETH_ALEN);
r1->pairwise = pairwise;
+ if (vlan && vlan->notempty) {
+ r1->vlan = os_zalloc(sizeof(*vlan));
+ if (!r1->vlan) {
+ bin_clear_free(r1, sizeof(*r1));
+ return -1;
+ }
+ *r1->vlan = *vlan;
+ }
+ if (identity) {
+ r1->identity = os_malloc(identity_len);
+ if (r1->identity) {
+ os_memcpy(r1->identity, identity, identity_len);
+ r1->identity_len = identity_len;
+ }
+ }
+ if (radius_cui) {
+ r1->radius_cui = os_malloc(radius_cui_len);
+ if (r1->radius_cui) {
+ os_memcpy(r1->radius_cui, radius_cui, radius_cui_len);
+ r1->radius_cui_len = radius_cui_len;
+ }
+ }
+ if (session_timeout > 0)
+ r1->session_timeout = now.sec + session_timeout;
+
+ dl_list_add(&cache->pmk_r1, &r1->list);
- r1->next = cache->pmk_r1;
- cache->pmk_r1 = r1;
+ if (expires_in > 0)
+ eloop_register_timeout(expires_in + 1, 0, wpa_ft_expire_pmk_r1,
+ r1, NULL);
+ if (session_timeout > 0)
+ eloop_register_timeout(session_timeout + 1, 0,
+ wpa_ft_expire_pmk_r1, r1, NULL);
return 0;
}
@@ -278,94 +1472,615 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
const u8 *spa, const u8 *pmk_r1_name,
- u8 *pmk_r1, int *pairwise)
+ u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui, size_t *radius_cui_len,
+ int *session_timeout)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r1_sa *r1;
+ struct os_reltime now;
- r1 = cache->pmk_r1;
- while (r1) {
+ os_get_reltime(&now);
+
+ dl_list_for_each(r1, &cache->pmk_r1, struct wpa_ft_pmk_r1_sa, list) {
if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
WPA_PMK_NAME_LEN) == 0) {
- os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
+ os_memcpy(pmk_r1, r1->pmk_r1, r1->pmk_r1_len);
+ *pmk_r1_len = r1->pmk_r1_len;
if (pairwise)
*pairwise = r1->pairwise;
+ if (vlan && r1->vlan)
+ *vlan = *r1->vlan;
+ if (vlan && !r1->vlan)
+ os_memset(vlan, 0, sizeof(*vlan));
+ if (identity && identity_len) {
+ *identity = r1->identity;
+ *identity_len = r1->identity_len;
+ }
+ if (radius_cui && radius_cui_len) {
+ *radius_cui = r1->radius_cui;
+ *radius_cui_len = r1->radius_cui_len;
+ }
+ if (session_timeout && r1->session_timeout > now.sec)
+ *session_timeout = r1->session_timeout -
+ now.sec;
+ else if (session_timeout && r1->session_timeout)
+ *session_timeout = 1;
+ else if (session_timeout)
+ *session_timeout = 0;
return 0;
}
-
- r1 = r1->next;
}
return -1;
}
-static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
- const u8 *ies, size_t ies_len,
- const u8 *pmk_r0_name)
+static int wpa_ft_rrb_init_r0kh_seq(struct ft_remote_r0kh *r0kh)
+{
+ if (r0kh->seq)
+ return 0;
+
+ r0kh->seq = os_zalloc(sizeof(*r0kh->seq));
+ if (!r0kh->seq) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to allocate r0kh->seq");
+ return -1;
+ }
+
+ dl_list_init(&r0kh->seq->rx.queue);
+
+ return 0;
+}
+
+
+static void wpa_ft_rrb_lookup_r0kh(struct wpa_authenticator *wpa_auth,
+ const u8 *f_r0kh_id, size_t f_r0kh_id_len,
+ struct ft_remote_r0kh **r0kh_out,
+ struct ft_remote_r0kh **r0kh_wildcard)
{
struct ft_remote_r0kh *r0kh;
- struct ft_r0kh_r1kh_pull_frame frame, f;
- r0kh = sm->wpa_auth->conf.r0kh_list;
- while (r0kh) {
- if (r0kh->id_len == sm->r0kh_id_len &&
- os_memcmp_const(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) ==
- 0)
+ *r0kh_wildcard = NULL;
+ *r0kh_out = NULL;
+
+ if (wpa_auth->conf.r0kh_list)
+ r0kh = *wpa_auth->conf.r0kh_list;
+ else
+ r0kh = NULL;
+ for (; r0kh; r0kh = r0kh->next) {
+ if (r0kh->id_len == 1 && r0kh->id[0] == '*')
+ *r0kh_wildcard = r0kh;
+ if (f_r0kh_id && r0kh->id_len == f_r0kh_id_len &&
+ os_memcmp_const(f_r0kh_id, r0kh->id, f_r0kh_id_len) == 0)
+ *r0kh_out = r0kh;
+ }
+
+ if (!*r0kh_out && !*r0kh_wildcard)
+ wpa_printf(MSG_DEBUG, "FT: No matching R0KH found");
+
+ if (*r0kh_out && wpa_ft_rrb_init_r0kh_seq(*r0kh_out) < 0)
+ *r0kh_out = NULL;
+}
+
+
+static int wpa_ft_rrb_init_r1kh_seq(struct ft_remote_r1kh *r1kh)
+{
+ if (r1kh->seq)
+ return 0;
+
+ r1kh->seq = os_zalloc(sizeof(*r1kh->seq));
+ if (!r1kh->seq) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to allocate r1kh->seq");
+ return -1;
+ }
+
+ dl_list_init(&r1kh->seq->rx.queue);
+
+ return 0;
+}
+
+
+static void wpa_ft_rrb_lookup_r1kh(struct wpa_authenticator *wpa_auth,
+ const u8 *f_r1kh_id,
+ struct ft_remote_r1kh **r1kh_out,
+ struct ft_remote_r1kh **r1kh_wildcard)
+{
+ struct ft_remote_r1kh *r1kh;
+
+ *r1kh_wildcard = NULL;
+ *r1kh_out = NULL;
+
+ if (wpa_auth->conf.r1kh_list)
+ r1kh = *wpa_auth->conf.r1kh_list;
+ else
+ r1kh = NULL;
+ for (; r1kh; r1kh = r1kh->next) {
+ if (is_zero_ether_addr(r1kh->addr) &&
+ is_zero_ether_addr(r1kh->id))
+ *r1kh_wildcard = r1kh;
+ if (f_r1kh_id &&
+ os_memcmp_const(r1kh->id, f_r1kh_id, FT_R1KH_ID_LEN) == 0)
+ *r1kh_out = r1kh;
+ }
+
+ if (!*r1kh_out && !*r1kh_wildcard)
+ wpa_printf(MSG_DEBUG, "FT: No matching R1KH found");
+
+ if (*r1kh_out && wpa_ft_rrb_init_r1kh_seq(*r1kh_out) < 0)
+ *r1kh_out = NULL;
+}
+
+
+static int wpa_ft_rrb_check_r0kh(struct wpa_authenticator *wpa_auth,
+ const u8 *f_r0kh_id, size_t f_r0kh_id_len)
+{
+ if (f_r0kh_id_len != wpa_auth->conf.r0_key_holder_len ||
+ os_memcmp_const(f_r0kh_id, wpa_auth->conf.r0_key_holder,
+ f_r0kh_id_len) != 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int wpa_ft_rrb_check_r1kh(struct wpa_authenticator *wpa_auth,
+ const u8 *f_r1kh_id)
+{
+ if (os_memcmp_const(f_r1kh_id, wpa_auth->conf.r1_key_holder,
+ FT_R1KH_ID_LEN) != 0)
+ return -1;
+
+ return 0;
+}
+
+
+static void wpa_ft_rrb_del_r0kh(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_authenticator *wpa_auth = eloop_ctx;
+ struct ft_remote_r0kh *r0kh, *prev = NULL;
+
+ if (!wpa_auth->conf.r0kh_list)
+ return;
+
+ for (r0kh = *wpa_auth->conf.r0kh_list; r0kh; r0kh = r0kh->next) {
+ if (r0kh == timeout_ctx)
break;
- r0kh = r0kh->next;
+ prev = r0kh;
+ }
+ if (!r0kh)
+ return;
+ if (prev)
+ prev->next = r0kh->next;
+ else
+ *wpa_auth->conf.r0kh_list = r0kh->next;
+ if (r0kh->seq)
+ wpa_ft_rrb_seq_flush(wpa_auth, r0kh->seq, 0);
+ os_free(r0kh->seq);
+ os_free(r0kh);
+}
+
+
+static void wpa_ft_rrb_r0kh_replenish(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_r0kh *r0kh, int timeout)
+{
+ if (timeout > 0)
+ eloop_replenish_timeout(timeout, 0, wpa_ft_rrb_del_r0kh,
+ wpa_auth, r0kh);
+}
+
+
+static void wpa_ft_rrb_r0kh_timeout(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_r0kh *r0kh, int timeout)
+{
+ eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth, r0kh);
+
+ if (timeout > 0)
+ eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh,
+ wpa_auth, r0kh);
+}
+
+
+static struct ft_remote_r0kh *
+wpa_ft_rrb_add_r0kh(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_r0kh *r0kh_wildcard,
+ const u8 *src_addr, const u8 *r0kh_id, size_t id_len,
+ int timeout)
+{
+ struct ft_remote_r0kh *r0kh;
+
+ if (!wpa_auth->conf.r0kh_list)
+ return NULL;
+
+ r0kh = os_zalloc(sizeof(*r0kh));
+ if (!r0kh)
+ return NULL;
+
+ if (src_addr)
+ os_memcpy(r0kh->addr, src_addr, sizeof(r0kh->addr));
+
+ if (id_len > FT_R0KH_ID_MAX_LEN)
+ id_len = FT_R0KH_ID_MAX_LEN;
+ os_memcpy(r0kh->id, r0kh_id, id_len);
+ r0kh->id_len = id_len;
+
+ os_memcpy(r0kh->key, r0kh_wildcard->key, sizeof(r0kh->key));
+
+ r0kh->next = *wpa_auth->conf.r0kh_list;
+ *wpa_auth->conf.r0kh_list = r0kh;
+
+ if (timeout > 0)
+ eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh,
+ wpa_auth, r0kh);
+
+ if (wpa_ft_rrb_init_r0kh_seq(r0kh) < 0)
+ return NULL;
+
+ return r0kh;
+}
+
+
+static void wpa_ft_rrb_del_r1kh(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_authenticator *wpa_auth = eloop_ctx;
+ struct ft_remote_r1kh *r1kh, *prev = NULL;
+
+ if (!wpa_auth->conf.r1kh_list)
+ return;
+
+ for (r1kh = *wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) {
+ if (r1kh == timeout_ctx)
+ break;
+ prev = r1kh;
+ }
+ if (!r1kh)
+ return;
+ if (prev)
+ prev->next = r1kh->next;
+ else
+ *wpa_auth->conf.r1kh_list = r1kh->next;
+ if (r1kh->seq)
+ wpa_ft_rrb_seq_flush(wpa_auth, r1kh->seq, 0);
+ os_free(r1kh->seq);
+ os_free(r1kh);
+}
+
+
+static void wpa_ft_rrb_r1kh_replenish(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_r1kh *r1kh, int timeout)
+{
+ if (timeout > 0)
+ eloop_replenish_timeout(timeout, 0, wpa_ft_rrb_del_r1kh,
+ wpa_auth, r1kh);
+}
+
+
+static struct ft_remote_r1kh *
+wpa_ft_rrb_add_r1kh(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_r1kh *r1kh_wildcard,
+ const u8 *src_addr, const u8 *r1kh_id, int timeout)
+{
+ struct ft_remote_r1kh *r1kh;
+
+ if (!wpa_auth->conf.r1kh_list)
+ return NULL;
+
+ r1kh = os_zalloc(sizeof(*r1kh));
+ if (!r1kh)
+ return NULL;
+
+ os_memcpy(r1kh->addr, src_addr, sizeof(r1kh->addr));
+ os_memcpy(r1kh->id, r1kh_id, sizeof(r1kh->id));
+ os_memcpy(r1kh->key, r1kh_wildcard->key, sizeof(r1kh->key));
+ r1kh->next = *wpa_auth->conf.r1kh_list;
+ *wpa_auth->conf.r1kh_list = r1kh;
+
+ if (timeout > 0)
+ eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r1kh,
+ wpa_auth, r1kh);
+
+ if (wpa_ft_rrb_init_r1kh_seq(r1kh) < 0)
+ return NULL;
+
+ return r1kh;
+}
+
+
+void wpa_ft_sta_deinit(struct wpa_state_machine *sm)
+{
+ eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL);
+}
+
+
+static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
+{
+ struct ft_remote_r0kh *r0kh;
+ struct ft_remote_r1kh *r1kh;
+
+ eloop_cancel_timeout(wpa_ft_rrb_seq_timeout, wpa_auth, ELOOP_ALL_CTX);
+
+ if (wpa_auth->conf.r0kh_list)
+ r0kh = *wpa_auth->conf.r0kh_list;
+ else
+ r0kh = NULL;
+ for (; r0kh; r0kh = r0kh->next) {
+ if (!r0kh->seq)
+ continue;
+ wpa_ft_rrb_seq_flush(wpa_auth, r0kh->seq, 0);
+ os_free(r0kh->seq);
+ r0kh->seq = NULL;
+ }
+
+ if (wpa_auth->conf.r1kh_list)
+ r1kh = *wpa_auth->conf.r1kh_list;
+ else
+ r1kh = NULL;
+ for (; r1kh; r1kh = r1kh->next) {
+ if (!r1kh->seq)
+ continue;
+ wpa_ft_rrb_seq_flush(wpa_auth, r1kh->seq, 0);
+ os_free(r1kh->seq);
+ r1kh->seq = NULL;
+ }
+}
+
+
+static void wpa_ft_deinit_rkh_tmp(struct wpa_authenticator *wpa_auth)
+{
+ struct ft_remote_r0kh *r0kh, *r0kh_next, *r0kh_prev = NULL;
+ struct ft_remote_r1kh *r1kh, *r1kh_next, *r1kh_prev = NULL;
+
+ if (wpa_auth->conf.r0kh_list)
+ r0kh = *wpa_auth->conf.r0kh_list;
+ else
+ r0kh = NULL;
+ while (r0kh) {
+ r0kh_next = r0kh->next;
+ if (eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth,
+ r0kh) > 0) {
+ if (r0kh_prev)
+ r0kh_prev->next = r0kh_next;
+ else
+ *wpa_auth->conf.r0kh_list = r0kh_next;
+ os_free(r0kh);
+ } else {
+ r0kh_prev = r0kh;
+ }
+ r0kh = r0kh_next;
+ }
+
+ if (wpa_auth->conf.r1kh_list)
+ r1kh = *wpa_auth->conf.r1kh_list;
+ else
+ r1kh = NULL;
+ while (r1kh) {
+ r1kh_next = r1kh->next;
+ if (eloop_cancel_timeout(wpa_ft_rrb_del_r1kh, wpa_auth,
+ r1kh) > 0) {
+ if (r1kh_prev)
+ r1kh_prev->next = r1kh_next;
+ else
+ *wpa_auth->conf.r1kh_list = r1kh_next;
+ os_free(r1kh);
+ } else {
+ r1kh_prev = r1kh;
+ }
+ r1kh = r1kh_next;
+ }
+}
+
+
+void wpa_ft_deinit(struct wpa_authenticator *wpa_auth)
+{
+ wpa_ft_deinit_seq(wpa_auth);
+ wpa_ft_deinit_rkh_tmp(wpa_auth);
+}
+
+
+static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth,
+ const u8 *f_r0kh_id, size_t f_r0kh_id_len)
+{
+ struct ft_remote_r0kh *r0kh, *r0kh_wildcard;
+
+ if (!wpa_auth->conf.rkh_neg_timeout)
+ return;
+
+ wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len,
+ &r0kh, &r0kh_wildcard);
+
+ if (!r0kh_wildcard) {
+ /* r0kh removed after neg_timeout and might need re-adding */
+ return;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID",
+ f_r0kh_id, f_r0kh_id_len);
+
+ if (r0kh) {
+ wpa_ft_rrb_r0kh_timeout(wpa_auth, r0kh,
+ wpa_auth->conf.rkh_neg_timeout);
+ os_memset(r0kh->addr, 0, ETH_ALEN);
+ } else
+ wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, NULL, f_r0kh_id,
+ f_r0kh_id_len,
+ wpa_auth->conf.rkh_neg_timeout);
+}
+
+
+static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_state_machine *sm = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "FT: Timeout pending pull request for " MACSTR,
+ MAC2STR(sm->addr));
+ if (sm->ft_pending_pull_left_retries <= 0)
+ wpa_ft_block_r0kh(sm->wpa_auth, sm->r0kh_id, sm->r0kh_id_len);
+
+ /* cancel multiple timeouts */
+ eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL);
+ ft_finish_pull(sm);
+}
+
+
+static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
+ const u8 *ies, size_t ies_len,
+ const u8 *pmk_r0_name)
+{
+ struct ft_remote_r0kh *r0kh, *r0kh_wildcard;
+ u8 *packet = NULL;
+ const u8 *key, *f_r1kh_id = sm->wpa_auth->conf.r1_key_holder;
+ size_t packet_len, key_len;
+ struct ft_rrb_seq f_seq;
+ int tsecs, tusecs, first;
+ struct wpabuf *ft_pending_req_ies;
+ int r0kh_timeout;
+ struct tlv_list req_enc[] = {
+ { .type = FT_RRB_PMK_R0_NAME, .len = WPA_PMK_NAME_LEN,
+ .data = pmk_r0_name },
+ { .type = FT_RRB_S1KH_ID, .len = ETH_ALEN,
+ .data = sm->addr },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+ struct tlv_list req_auth[] = {
+ { .type = FT_RRB_NONCE, .len = FT_RRB_NONCE_LEN,
+ .data = sm->ft_pending_pull_nonce },
+ { .type = FT_RRB_SEQ, .len = sizeof(f_seq),
+ .data = (u8 *) &f_seq },
+ { .type = FT_RRB_R0KH_ID, .len = sm->r0kh_id_len,
+ .data = sm->r0kh_id },
+ { .type = FT_RRB_R1KH_ID, .len = FT_R1KH_ID_LEN,
+ .data = f_r1kh_id },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ if (sm->ft_pending_pull_left_retries <= 0)
+ return -1;
+ first = sm->ft_pending_pull_left_retries ==
+ sm->wpa_auth->conf.rkh_pull_retries;
+ sm->ft_pending_pull_left_retries--;
+
+ wpa_ft_rrb_lookup_r0kh(sm->wpa_auth, sm->r0kh_id, sm->r0kh_id_len,
+ &r0kh, &r0kh_wildcard);
+
+ /* Keep r0kh sufficiently long in the list for seq num check */
+ r0kh_timeout = sm->wpa_auth->conf.rkh_pull_timeout / 1000 +
+ 1 + ftRRBseqTimeout;
+ if (r0kh) {
+ wpa_ft_rrb_r0kh_replenish(sm->wpa_auth, r0kh, r0kh_timeout);
+ } else if (r0kh_wildcard) {
+ wpa_printf(MSG_DEBUG, "FT: Using wildcard R0KH-ID");
+ /* r0kh->addr: updated by SEQ_RESP and wpa_ft_expire_pull */
+ r0kh = wpa_ft_rrb_add_r0kh(sm->wpa_auth, r0kh_wildcard,
+ r0kh_wildcard->addr,
+ sm->r0kh_id, sm->r0kh_id_len,
+ r0kh_timeout);
}
if (r0kh == NULL) {
wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
sm->r0kh_id, sm->r0kh_id_len);
return -1;
}
+ if (is_zero_ether_addr(r0kh->addr)) {
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted",
+ sm->r0kh_id, sm->r0kh_id_len);
+ return -1;
+ }
+ if (os_memcmp(r0kh->addr, sm->wpa_auth->addr, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: R0KH-ID points to self - no matching key available");
+ return -1;
+ }
+
+ key = r0kh->key;
+ key_len = sizeof(r0kh->key);
wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
"address " MACSTR, MAC2STR(r0kh->addr));
- os_memset(&frame, 0, sizeof(frame));
- frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
- frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
- frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
- os_memcpy(frame.ap_address, sm->wpa_auth->addr, ETH_ALEN);
+ if (r0kh->seq->rx.num_last == 0) {
+ /* A sequence request will be sent out anyway when pull
+ * response is received. Send it out now to avoid one RTT. */
+ wpa_ft_rrb_seq_req(sm->wpa_auth, r0kh->seq, r0kh->addr,
+ r0kh->id, r0kh->id_len, f_r1kh_id, key,
+ key_len, NULL, 0, NULL, 0, NULL);
+ }
- /* aes_wrap() does not support inplace encryption, so use a temporary
- * buffer for the data. */
- if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) {
+ if (first &&
+ random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
"nonce");
return -1;
}
- os_memcpy(sm->ft_pending_pull_nonce, f.nonce,
- FT_R0KH_R1KH_PULL_NONCE_LEN);
- os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
- os_memcpy(f.r1kh_id, sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
- os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN);
- os_memset(f.pad, 0, sizeof(f.pad));
- if (aes_wrap(r0kh->key, sizeof(r0kh->key),
- (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
- f.nonce, frame.nonce) < 0)
+ if (wpa_ft_new_seq(r0kh->seq, &f_seq) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to get seq num");
return -1;
+ }
+ if (wpa_ft_rrb_build(key, key_len, req_enc, NULL, req_auth, NULL,
+ sm->wpa_auth->addr, FT_PACKET_R0KH_R1KH_PULL,
+ &packet, &packet_len) < 0)
+ return -1;
+
+ ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len);
wpabuf_free(sm->ft_pending_req_ies);
- sm->ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len);
- if (sm->ft_pending_req_ies == NULL)
+ sm->ft_pending_req_ies = ft_pending_req_ies;
+ if (!sm->ft_pending_req_ies) {
+ os_free(packet);
return -1;
+ }
+
+ tsecs = sm->wpa_auth->conf.rkh_pull_timeout / 1000;
+ tusecs = (sm->wpa_auth->conf.rkh_pull_timeout % 1000) * 1000;
+ eloop_register_timeout(tsecs, tusecs, wpa_ft_expire_pull, sm, NULL);
- wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
+ wpa_ft_rrb_oui_send(sm->wpa_auth, r0kh->addr, FT_PACKET_R0KH_R1KH_PULL,
+ packet, packet_len);
+
+ os_free(packet);
return 0;
}
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk)
+int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm,
+ const u8 *pmk_r0, const u8 *pmk_r0_name)
{
- u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
- u8 pmk_r1[PMK_LEN];
+ int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
+ struct vlan_description vlan;
+ const u8 *identity, *radius_cui;
+ size_t identity_len, radius_cui_len;
+ int session_timeout;
+ size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
+ SHA384_MAC_LEN : PMK_LEN;
+
+ if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
+ MAC2STR(sm->addr));
+ return -1;
+ }
+
+ identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
+ radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr,
+ &radius_cui);
+ session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
+
+ return wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
+ pmk_r0_name, sm->pairwise, &vlan, expires_in,
+ session_timeout, identity, identity_len,
+ radius_cui, radius_cui_len);
+}
+
+
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
+{
+ u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+ size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
+ SHA384_MAC_LEN : PMK_LEN;
+ size_t pmk_r1_len = pmk_r0_len;
+ u8 pmk_r1[PMK_LEN_MAX];
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
@@ -373,6 +2088,12 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
const u8 *ssid = sm->wpa_auth->conf.ssid;
size_t ssid_len = sm->wpa_auth->conf.ssid_len;
+ int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
+ int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
+ struct vlan_description vlan;
+ const u8 *identity, *radius_cui;
+ size_t identity_len, radius_cui_len;
+ int session_timeout;
if (sm->xxkey_len == 0) {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
@@ -380,23 +2101,45 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
return -1;
}
- wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
- r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
- wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
- sm->pairwise);
+ if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
+ MAC2STR(sm->addr));
+ return -1;
+ }
- wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
- pmk_r1, sm->pmk_r1_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
+ identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
+ radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr,
+ &radius_cui);
+ session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
+
+ if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+ r0kh, r0kh_len, sm->addr,
+ pmk_r0, pmk_r0_name,
+ wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
+ if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
+ wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
+ pmk_r0_name,
+ sm->pairwise, &vlan, expires_in,
+ session_timeout, identity, identity_len,
+ radius_cui, radius_cui_len);
+
+ if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
+ pmk_r1, sm->pmk_r1_name) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
WPA_PMK_NAME_LEN);
- wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
- sm->pairwise);
-
- return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, sm->pmk_r1_name,
+ if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
+ wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
+ sm->pmk_r1_name, sm->pairwise, &vlan,
+ expires_in, session_timeout, identity,
+ identity_len, radius_cui, radius_cui_len);
+
+ return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
+ sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
}
@@ -404,9 +2147,9 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
- if (wpa_auth->cb.get_seqnum == NULL)
+ if (wpa_auth->cb->get_seqnum == NULL)
return -1;
- return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+ return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
}
@@ -418,6 +2161,16 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
const u8 *key;
size_t key_len;
u8 keybuf[32];
+ const u8 *kek;
+ size_t kek_len;
+
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kek = sm->PTK.kek2;
+ kek_len = sm->PTK.kek2_len;
+ } else {
+ kek = sm->PTK.kek;
+ kek_len = sm->PTK.kek_len;
+ }
key_len = gsm->GTK_len;
if (key_len > sizeof(keybuf))
@@ -456,8 +2209,10 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
subelem[4] = gsm->GTK_len;
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
- if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
- subelem + 13)) {
+ if (aes_wrap(kek, kek_len, key_len / 8, key, subelem + 13)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: GTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
os_free(subelem);
return NULL;
}
@@ -473,10 +2228,23 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
u8 *subelem, *pos;
struct wpa_group *gsm = sm->group;
size_t subelem_len;
+ const u8 *kek;
+ size_t kek_len;
+ size_t igtk_len;
+
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kek = sm->PTK.kek2;
+ kek_len = sm->PTK.kek2_len;
+ } else {
+ kek = sm->PTK.kek;
+ kek_len = sm->PTK.kek_len;
+ }
+
+ igtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
* Key[16+8] */
- subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
+ subelem_len = 1 + 1 + 2 + 6 + 1 + igtk_len + 8;
subelem = os_zalloc(subelem_len);
if (subelem == NULL)
return NULL;
@@ -488,9 +2256,12 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
pos += 2;
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
- *pos++ = WPA_IGTK_LEN;
- if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, WPA_IGTK_LEN / 8,
+ *pos++ = igtk_len;
+ if (aes_wrap(kek, kek_len, igtk_len / 8,
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: IGTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
os_free(subelem);
return NULL;
}
@@ -637,17 +2408,21 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
const u8 *req_ies, size_t req_ies_len)
{
u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
+ u8 *fte_mic, *elem_count;
size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
int res;
struct wpa_auth_config *conf;
- struct rsn_ftie *_ftie;
struct wpa_ft_ies parse;
u8 *ric_start;
u8 *anonce, *snonce;
+ const u8 *kck;
+ size_t kck_len;
+ int use_sha384;
if (sm == NULL)
return pos;
+ use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
conf = &sm->wpa_auth->conf;
if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
@@ -655,14 +2430,28 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
end = pos + max_len;
- if (auth_alg == WLAN_AUTH_FT) {
+ if (auth_alg == WLAN_AUTH_FT ||
+ ((auth_alg == WLAN_AUTH_FILS_SK ||
+ auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ auth_alg == WLAN_AUTH_FILS_PK) &&
+ (sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384)))) {
+ if (!sm->pmk_r1_name_valid) {
+ wpa_printf(MSG_ERROR,
+ "FT: PMKR1Name is not valid for Assoc Resp RSNE");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name for Assoc Resp RSNE",
+ sm->pmk_r1_name, WPA_PMK_NAME_LEN);
/*
* RSN (only present if this is a Reassociation Response and
- * part of a fast BSS transition)
+ * part of a fast BSS transition; or if this is a
+ * (Re)Association Response frame during an FT initial mobility
+ * domain association using FILS)
*/
res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
if (res < 0)
- return pos;
+ return NULL;
rsnie = pos;
rsnie_len = res;
pos += res;
@@ -671,7 +2460,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
/* Mobility Domain Information */
res = wpa_write_mdie(conf, pos, end - pos);
if (res < 0)
- return pos;
+ return NULL;
mdie = pos;
mdie_len = res;
pos += res;
@@ -679,6 +2468,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
/* Fast BSS Transition Information */
if (auth_alg == WLAN_AUTH_FT) {
subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
+ if (!subelem) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add GTK subelement");
+ return NULL;
+ }
r0kh_id = sm->r0kh_id;
r0kh_id_len = sm->r0kh_id_len;
anonce = sm->ANonce;
@@ -690,14 +2484,16 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
u8 *nbuf;
igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
if (igtk == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add IGTK subelement");
os_free(subelem);
- return pos;
+ return NULL;
}
nbuf = os_realloc(subelem, subelem_len + igtk_len);
if (nbuf == NULL) {
os_free(subelem);
os_free(igtk);
- return pos;
+ return NULL;
}
subelem = nbuf;
os_memcpy(subelem + subelem_len, igtk, igtk_len);
@@ -705,50 +2501,101 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
os_free(igtk);
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ u8 *nbuf, *ocipos;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element");
+ os_free(subelem);
+ return NULL;
+ }
+
+ subelem_len += 2 + OCV_OCI_LEN;
+ nbuf = os_realloc(subelem, subelem_len);
+ if (!nbuf) {
+ os_free(subelem);
+ return NULL;
+ }
+ subelem = nbuf;
+
+ ocipos = subelem + subelem_len - 2 - OCV_OCI_LEN;
+ *ocipos++ = FTIE_SUBELEM_OCI;
+ *ocipos++ = OCV_OCI_LEN;
+ if (ocv_insert_oci(&ci, &ocipos) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
} else {
r0kh_id = conf->r0_key_holder;
r0kh_id_len = conf->r0_key_holder_len;
anonce = NULL;
snonce = NULL;
}
- res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
- end - pos, subelem, subelem_len);
+ res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
+ anonce, snonce, pos, end - pos,
+ subelem, subelem_len);
os_free(subelem);
if (res < 0)
- return pos;
+ return NULL;
ftie = pos;
ftie_len = res;
pos += res;
- os_free(sm->assoc_resp_ftie);
- sm->assoc_resp_ftie = os_malloc(ftie_len);
- if (sm->assoc_resp_ftie)
- os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *_ftie =
+ (struct rsn_ftie_sha384 *) (ftie + 2);
- _ftie = (struct rsn_ftie *) (ftie + 2);
+ fte_mic = _ftie->mic;
+ elem_count = &_ftie->mic_control[1];
+ } else {
+ struct rsn_ftie *_ftie = (struct rsn_ftie *) (ftie + 2);
+
+ fte_mic = _ftie->mic;
+ elem_count = &_ftie->mic_control[1];
+ }
if (auth_alg == WLAN_AUTH_FT)
- _ftie->mic_control[1] = 3; /* Information element count */
+ *elem_count = 3; /* Information element count */
ric_start = pos;
- if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
+ if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, use_sha384) == 0
+ && parse.ric) {
pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
parse.ric_len);
if (auth_alg == WLAN_AUTH_FT)
- _ftie->mic_control[1] +=
+ *elem_count +=
ieee802_11_ie_count(ric_start,
pos - ric_start);
}
if (ric_start == pos)
ric_start = NULL;
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kck = sm->PTK.kck2;
+ kck_len = sm->PTK.kck2_len;
+ } else {
+ kck = sm->PTK.kck;
+ kck_len = sm->PTK.kck_len;
+ }
if (auth_alg == WLAN_AUTH_FT &&
- wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
- sm->wpa_auth->addr, 6,
+ wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 6,
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
- _ftie->mic) < 0)
+ fte_mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+ return NULL;
+ }
+
+ os_free(sm->assoc_resp_ftie);
+ sm->assoc_resp_ftie = os_malloc(ftie_len);
+ if (!sm->assoc_resp_ftie)
+ return NULL;
+ os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
return pos;
}
@@ -759,10 +2606,10 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
enum wpa_alg alg, const u8 *addr, int idx,
u8 *key, size_t key_len)
{
- if (wpa_auth->cb.set_key == NULL)
+ if (wpa_auth->cb->set_key == NULL)
return -1;
- return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
+ key, key_len);
}
@@ -804,20 +2651,221 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
}
+/* Derive PMK-R1 from PSK, check all available PSK */
+static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm,
+ const u8 *req_pmk_r1_name,
+ u8 *out_pmk_r1, int *out_pairwise,
+ struct vlan_description *out_vlan,
+ const u8 **out_identity, size_t *out_identity_len,
+ const u8 **out_radius_cui,
+ size_t *out_radius_cui_len,
+ int *out_session_timeout)
+{
+ const u8 *pmk = NULL;
+ u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ const u8 *mdid = wpa_auth->conf.mobility_domain;
+ const u8 *r0kh = sm->r0kh_id;
+ size_t r0kh_len = sm->r0kh_id_len;
+ const u8 *r1kh = wpa_auth->conf.r1_key_holder;
+ const u8 *ssid = wpa_auth->conf.ssid;
+ size_t ssid_len = wpa_auth->conf.ssid_len;
+ int pairwise;
+
+ pairwise = sm->pairwise;
+
+ for (;;) {
+ pmk = wpa_ft_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
+ pmk);
+ if (pmk == NULL)
+ break;
+
+ if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
+ r0kh_len, sm->addr,
+ pmk_r0, pmk_r0_name, 0) < 0 ||
+ wpa_derive_pmk_r1(pmk_r0, PMK_LEN, pmk_r0_name, r1kh,
+ sm->addr, pmk_r1, pmk_r1_name) < 0 ||
+ os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
+ WPA_PMK_NAME_LEN) != 0)
+ continue;
+
+ /* We found a PSK that matches the requested pmk_r1_name */
+ wpa_printf(MSG_DEBUG,
+ "FT: Found PSK to generate PMK-R1 locally");
+ os_memcpy(out_pmk_r1, pmk_r1, PMK_LEN);
+ if (out_pairwise)
+ *out_pairwise = pairwise;
+ os_memcpy(sm->PMK, pmk, PMK_LEN);
+ sm->pmk_len = PMK_LEN;
+ if (out_vlan &&
+ wpa_ft_get_vlan(sm->wpa_auth, sm->addr, out_vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: vlan not available for STA "
+ MACSTR, MAC2STR(sm->addr));
+ return -1;
+ }
+
+ if (out_identity && out_identity_len) {
+ *out_identity_len = wpa_ft_get_identity(
+ sm->wpa_auth, sm->addr, out_identity);
+ }
+
+ if (out_radius_cui && out_radius_cui_len) {
+ *out_radius_cui_len = wpa_ft_get_radius_cui(
+ sm->wpa_auth, sm->addr, out_radius_cui);
+ }
+
+ if (out_session_timeout) {
+ *out_session_timeout = wpa_ft_get_session_timeout(
+ sm->wpa_auth, sm->addr);
+ }
+
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "FT: Did not find PSK to generate PMK-R1 locally");
+ return -1;
+}
+
+
+/* Detect the configuration the station asked for.
+ * Required to detect FT-PSK and pairwise cipher.
+ */
+static int wpa_ft_set_key_mgmt(struct wpa_state_machine *sm,
+ struct wpa_ft_ies *parse)
+{
+ int key_mgmt, ciphers;
+
+ if (sm->wpa_key_mgmt)
+ return 0;
+
+ key_mgmt = parse->key_mgmt & sm->wpa_auth->conf.wpa_key_mgmt;
+ if (!key_mgmt) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid key mgmt (0x%x) from "
+ MACSTR, parse->key_mgmt, MAC2STR(sm->addr));
+ return -1;
+ }
+ if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+#ifdef CONFIG_SHA384
+ else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
+ else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
+#ifdef CONFIG_FILS
+ else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+ else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
+#endif /* CONFIG_FILS */
+ ciphers = parse->pairwise_cipher & sm->wpa_auth->conf.rsn_pairwise;
+ if (!ciphers) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid pairwise cipher (0x%x) from "
+ MACSTR,
+ parse->pairwise_cipher, MAC2STR(sm->addr));
+ return -1;
+ }
+ sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
+
+ return 0;
+}
+
+
+static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ const u8 *r0kh_id, size_t r0kh_id_len,
+ const u8 *req_pmk_r0_name,
+ const u8 *req_pmk_r1_name,
+ u8 *out_pmk_r1, int *out_pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui,
+ size_t *radius_cui_len,
+ int *out_session_timeout)
+{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
+ const struct wpa_ft_pmk_r0_sa *r0;
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ int expires_in = 0;
+ int session_timeout = 0;
+ struct os_reltime now;
+
+ if (conf->r0_key_holder_len != r0kh_id_len ||
+ os_memcmp(conf->r0_key_holder, r0kh_id, conf->r0_key_holder_len) !=
+ 0)
+ return -1; /* not our R0KH-ID */
+
+ wpa_printf(MSG_DEBUG, "FT: STA R0KH-ID matching local configuration");
+ if (wpa_ft_fetch_pmk_r0(sm->wpa_auth, sm->addr, req_pmk_r0_name, &r0) <
+ 0)
+ return -1; /* no matching PMKR0Name in local cache */
+
+ wpa_printf(MSG_DEBUG, "FT: Requested PMKR0Name found in local cache");
+
+ if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_len, r0->pmk_r0_name,
+ conf->r1_key_holder,
+ sm->addr, out_pmk_r1, pmk_r1_name) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, r0->pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ os_get_reltime(&now);
+ if (r0->expiration)
+ expires_in = r0->expiration - now.sec;
+
+ if (r0->session_timeout)
+ session_timeout = r0->session_timeout - now.sec;
+
+ wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, r0->pmk_r0_len,
+ pmk_r1_name,
+ sm->pairwise, r0->vlan, expires_in, session_timeout,
+ r0->identity, r0->identity_len,
+ r0->radius_cui, r0->radius_cui_len);
+
+ *out_pairwise = sm->pairwise;
+ if (vlan) {
+ if (r0->vlan)
+ *vlan = *r0->vlan;
+ else
+ os_memset(vlan, 0, sizeof(*vlan));
+ }
+
+ if (identity && identity_len) {
+ *identity = r0->identity;
+ *identity_len = r0->identity_len;
+ }
+
+ if (radius_cui && radius_cui_len) {
+ *radius_cui = r0->radius_cui;
+ *radius_cui_len = r0->radius_cui_len;
+ }
+
+ *out_session_timeout = session_timeout;
+
+ return 0;
+}
+
+
static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
const u8 *ies, size_t ies_len,
u8 **resp_ies, size_t *resp_ies_len)
{
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
- u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN_MAX], pmk_r1_name[WPA_PMK_NAME_LEN];
u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
size_t buflen;
int ret;
u8 *pos, *end;
- int pairwise;
+ int pairwise, session_timeout = 0;
+ struct vlan_description vlan;
+ const u8 *identity, *radius_cui;
+ size_t identity_len = 0, radius_cui_len = 0;
+ int use_sha384;
+ size_t pmk_r1_len;
*resp_ies = NULL;
*resp_ies_len = 0;
@@ -828,10 +2876,12 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
ies, ies_len);
- if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+ use_sha384 = wpa_key_mgmt_sha384(parse.key_mgmt);
+ pmk_r1_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
mdie = (struct rsn_mdie *) parse.mdie;
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
@@ -842,13 +2892,27 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
return WLAN_STATUS_INVALID_MDIE;
}
- ftie = (struct rsn_ftie *) parse.ftie;
- if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
- wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
- return WLAN_STATUS_INVALID_FTIE;
- }
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *ftie;
- os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+ ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+ }
if (parse.r0kh_id == NULL) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
@@ -865,28 +2929,62 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
return WLAN_STATUS_INVALID_PMKID;
}
+ if (wpa_ft_set_key_mgmt(sm, &parse) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
parse.rsn_pmkid, WPA_PMK_NAME_LEN);
- wpa_derive_pmk_r1_name(parse.rsn_pmkid,
- sm->wpa_auth->conf.r1_key_holder, sm->addr,
- pmk_r1_name);
+ if (wpa_derive_pmk_r1_name(parse.rsn_pmkid,
+ sm->wpa_auth->conf.r1_key_holder, sm->addr,
+ pmk_r1_name, use_sha384) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
pmk_r1_name, WPA_PMK_NAME_LEN);
- if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
- &pairwise) < 0) {
+ if (conf->ft_psk_generate_local &&
+ wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
+ if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise,
+ &vlan, &identity, &identity_len,
+ &radius_cui, &radius_cui_len,
+ &session_timeout) < 0)
+ return WLAN_STATUS_INVALID_PMKID;
+ wpa_printf(MSG_DEBUG,
+ "FT: Generated PMK-R1 for FT-PSK locally");
+ } else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name,
+ pmk_r1, &pmk_r1_len, &pairwise, &vlan,
+ &identity, &identity_len, &radius_cui,
+ &radius_cui_len, &session_timeout) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMK-R1 available in local cache for the requested PMKR1Name");
+ if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm,
+ parse.r0kh_id, parse.r0kh_id_len,
+ parse.rsn_pmkid,
+ pmk_r1_name, pmk_r1, &pairwise,
+ &vlan, &identity, &identity_len,
+ &radius_cui, &radius_cui_len,
+ &session_timeout) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Generated PMK-R1 based on local PMK-R0");
+ goto pmk_r1_derived;
+ }
+
if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
- wpa_printf(MSG_DEBUG, "FT: Did not have matching "
- "PMK-R1 and unknown R0KH-ID");
+ wpa_printf(MSG_DEBUG,
+ "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH");
return WLAN_STATUS_INVALID_PMKID;
}
return -1; /* Status pending */
+ } else {
+ wpa_printf(MSG_DEBUG, "FT: Found PMKR1Name from local cache");
}
- wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
+pmk_r1_derived:
+ wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len);
sm->pmk_r1_name_valid = 1;
os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+ os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len);
+ sm->pmk_r1_len = pmk_r1_len;
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -899,8 +2997,8 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
- if (wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, pmk_r1_name,
+ if (wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
+ sm->addr, sm->wpa_auth->addr, pmk_r1_name,
&sm->PTK, ptk_name, sm->wpa_key_mgmt,
pairwise) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -910,44 +3008,51 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
sm->tk_already_set = FALSE;
wpa_ft_install_ptk(sm);
+ if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ if (wpa_ft_set_identity(sm->wpa_auth, sm->addr,
+ identity, identity_len) < 0 ||
+ wpa_ft_set_radius_cui(sm->wpa_auth, sm->addr,
+ radius_cui, radius_cui_len) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to configure identity/CUI");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ wpa_ft_set_session_timeout(sm->wpa_auth, sm->addr, session_timeout);
+
buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
2 + FT_R1KH_ID_LEN + 200;
*resp_ies = os_zalloc(buflen);
- if (*resp_ies == NULL) {
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (*resp_ies == NULL)
+ goto fail;
pos = *resp_ies;
end = *resp_ies + buflen;
ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
ret = wpa_write_mdie(conf, pos, end - pos);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
- ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
+ ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
*resp_ies_len = pos - *resp_ies;
return WLAN_STATUS_SUCCESS;
+fail:
+ os_free(*resp_ies);
+ *resp_ies = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
@@ -975,6 +3080,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
sm->ft_pending_cb = cb;
sm->ft_pending_cb_ctx = ctx;
sm->ft_pending_auth_transaction = auth_transaction;
+ sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries;
res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
&resp_ies_len);
if (res < 0) {
@@ -998,17 +3104,23 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
{
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
size_t mic_len = 16;
unsigned int count;
+ const u8 *kck;
+ size_t kck_len;
+ int use_sha384;
+ const u8 *anonce, *snonce, *fte_mic;
+ u8 fte_elem_count;
if (sm == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
- if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
@@ -1039,34 +3151,56 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_MDIE;
}
- ftie = (struct rsn_ftie *) parse.ftie;
- if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
- wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
- return WLAN_STATUS_INVALID_FTIE;
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *ftie;
+
+ ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ fte_elem_count = ftie->mic_control[1];
+ fte_mic = ftie->mic;
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ fte_elem_count = ftie->mic_control[1];
+ fte_mic = ftie->mic;
}
- if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
- ftie->snonce, WPA_NONCE_LEN);
+ snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->SNonce, WPA_NONCE_LEN);
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
- if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
- ftie->anonce, WPA_NONCE_LEN);
+ anonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
sm->ANonce, WPA_NONCE_LEN);
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (parse.r0kh_id == NULL) {
wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
@@ -1078,12 +3212,12 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
parse.r0kh_id, parse.r0kh_id_len);
wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
sm->r0kh_id, sm->r0kh_id_len);
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (parse.r1kh_id == NULL) {
wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
@@ -1094,7 +3228,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (parse.rsn_pmkid == NULL ||
@@ -1102,21 +3236,27 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
{
wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
"RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
- return -1;
+ return WLAN_STATUS_INVALID_PMKID;
}
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
- if (ftie->mic_control[1] != count) {
+ if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
- ftie->mic_control[1], count);
- return -1;
+ fte_elem_count, count);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
- sm->wpa_auth->addr, 5,
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kck = sm->PTK.kck2;
+ kck_len = sm->PTK.kck2_len;
+ } else {
+ kck = sm->PTK.kck;
+ kck_len = sm->PTK.kck_len;
+ }
+ if (wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 5,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -1126,12 +3266,12 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (os_memcmp_const(mic, ftie->mic, mic_len) != 0) {
+ if (os_memcmp_const(mic, fte_mic, mic_len) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC",
- ftie->mic, mic_len);
+ fte_mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
parse.mdie - 2, parse.mdie_len + 2);
@@ -1142,6 +3282,32 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_FTIE;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in (Re)Assoc Request");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ }
+#endif /* CONFIG_OCV */
+
return WLAN_STATUS_SUCCESS;
}
@@ -1199,6 +3365,11 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
+ if (!sm->wpa_auth->conf.ft_over_ds) {
+ wpa_printf(MSG_DEBUG, "FT: Over-DS option disabled - reject");
+ return -1;
+ }
+
/* RRB - Forward action frame to the target AP */
frame = os_malloc(sizeof(*frame) + len);
if (frame == NULL)
@@ -1251,6 +3422,7 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb;
sm->ft_pending_cb_ctx = sm;
os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN);
+ sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries;
res = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
&resp_ies_len);
if (res < 0) {
@@ -1316,112 +3488,431 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
}
+static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
+ const struct tlv_list *tlvs,
+ const struct wpa_ft_pmk_r0_sa *pmk_r0,
+ const u8 *r1kh_id, const u8 *s1kh_id,
+ const struct tlv_list *tlv_auth,
+ const u8 *src_addr, u8 type,
+ u8 **packet, size_t *packet_len)
+{
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len = pmk_r0->pmk_r0_len;
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 f_pairwise[sizeof(le16)];
+ u8 f_expires_in[sizeof(le16)];
+ u8 f_session_timeout[sizeof(le32)];
+ int expires_in;
+ int session_timeout;
+ struct os_reltime now;
+ int ret;
+ struct tlv_list sess_tlv[] = {
+ { .type = FT_RRB_PMK_R1, .len = pmk_r1_len,
+ .data = pmk_r1 },
+ { .type = FT_RRB_PMK_R1_NAME, .len = sizeof(pmk_r1_name),
+ .data = pmk_r1_name },
+ { .type = FT_RRB_PAIRWISE, .len = sizeof(f_pairwise),
+ .data = f_pairwise },
+ { .type = FT_RRB_EXPIRES_IN, .len = sizeof(f_expires_in),
+ .data = f_expires_in },
+ { .type = FT_RRB_IDENTITY, .len = pmk_r0->identity_len,
+ .data = pmk_r0->identity },
+ { .type = FT_RRB_RADIUS_CUI, .len = pmk_r0->radius_cui_len,
+ .data = pmk_r0->radius_cui },
+ { .type = FT_RRB_SESSION_TIMEOUT,
+ .len = sizeof(f_session_timeout),
+ .data = f_session_timeout },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
+ pmk_r0->pmk_r0_name, r1kh_id,
+ s1kh_id, pmk_r1, pmk_r1_name) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 (for peer AP)",
+ pmk_r1, pmk_r1_len);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name (for peer AP)",
+ pmk_r1_name, WPA_PMK_NAME_LEN);
+ WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
+
+ os_get_reltime(&now);
+ if (pmk_r0->expiration > now.sec)
+ expires_in = pmk_r0->expiration - now.sec;
+ else if (pmk_r0->expiration)
+ expires_in = 1;
+ else
+ expires_in = 0;
+ WPA_PUT_LE16(f_expires_in, expires_in);
+
+ if (pmk_r0->session_timeout > now.sec)
+ session_timeout = pmk_r0->session_timeout - now.sec;
+ else if (pmk_r0->session_timeout)
+ session_timeout = 1;
+ else
+ session_timeout = 0;
+ WPA_PUT_LE32(f_session_timeout, session_timeout);
+
+ ret = wpa_ft_rrb_build(key, key_len, tlvs, sess_tlv, tlv_auth,
+ pmk_r0->vlan, src_addr, type,
+ packet, packet_len);
+
+ os_memset(pmk_r1, 0, sizeof(pmk_r1));
+
+ return ret;
+}
+
+
static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
- const u8 *data, size_t data_len)
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ int no_defer)
{
- struct ft_r0kh_r1kh_pull_frame f;
- const u8 *crypt;
- u8 *plain;
- struct ft_remote_r1kh *r1kh;
- struct ft_r0kh_r1kh_resp_frame resp, r;
- u8 pmk_r0[PMK_LEN];
- int pairwise;
+ const char *msgtype = "pull request";
+ u8 *plain = NULL, *packet = NULL;
+ size_t plain_len = 0, packet_len = 0;
+ struct ft_remote_r1kh *r1kh, *r1kh_wildcard;
+ const u8 *key;
+ size_t key_len;
+ int seq_ret;
+ const u8 *f_nonce, *f_r0kh_id, *f_r1kh_id, *f_s1kh_id, *f_pmk_r0_name;
+ size_t f_nonce_len, f_r0kh_id_len, f_r1kh_id_len, f_s1kh_id_len;
+ size_t f_pmk_r0_name_len;
+ const struct wpa_ft_pmk_r0_sa *r0;
+ int ret;
+ struct tlv_list resp[2];
+ struct tlv_list resp_auth[5];
+ struct ft_rrb_seq f_seq;
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
- if (data_len < sizeof(f))
- return -1;
+ RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1);
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", f_r0kh_id, f_r0kh_id_len);
- r1kh = wpa_auth->conf.r1kh_list;
- while (r1kh) {
- if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
- break;
- r1kh = r1kh->next;
+ if (wpa_ft_rrb_check_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len)) {
+ wpa_printf(MSG_DEBUG, "FT: R0KH-ID mismatch");
+ goto out;
}
- if (r1kh == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
- "PMK-R1 pull source address " MACSTR,
- MAC2STR(src_addr));
- return -1;
+
+ RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, msgtype, FT_R1KH_ID_LEN);
+ wpa_printf(MSG_DEBUG, "FT: R1KH-ID=" MACSTR, MAC2STR(f_r1kh_id));
+
+ wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh, &r1kh_wildcard);
+ if (r1kh) {
+ key = r1kh->key;
+ key_len = sizeof(r1kh->key);
+ } else if (r1kh_wildcard) {
+ wpa_printf(MSG_DEBUG, "FT: Using wildcard R1KH-ID");
+ key = r1kh_wildcard->key;
+ key_len = sizeof(r1kh_wildcard->key);
+ } else {
+ goto out;
}
- crypt = data + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
- os_memset(&f, 0, sizeof(f));
- plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
- /* aes_unwrap() does not support inplace decryption, so use a temporary
- * buffer for the data. */
- if (aes_unwrap(r1kh->key, sizeof(r1kh->key),
- (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
- crypt, plain) < 0) {
- wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
- "request from " MACSTR, MAC2STR(src_addr));
- return -1;
+ RRB_GET_AUTH(FT_RRB_NONCE, nonce, "pull request", FT_RRB_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: nonce", f_nonce, f_nonce_len);
+
+ seq_ret = FT_RRB_SEQ_DROP;
+ if (r1kh)
+ seq_ret = wpa_ft_rrb_seq_chk(r1kh->seq, src_addr, enc, enc_len,
+ auth, auth_len, msgtype, no_defer);
+ if (!no_defer && r1kh_wildcard &&
+ (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) {
+ /* wildcard: r1kh-id unknown or changed addr -> do a seq req */
+ seq_ret = FT_RRB_SEQ_DEFER;
}
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
- f.nonce, sizeof(f.nonce));
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
- f.pmk_r0_name, WPA_PMK_NAME_LEN);
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
- MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
-
- os_memset(&resp, 0, sizeof(resp));
- resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
- resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
- resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
- os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
-
- /* aes_wrap() does not support inplace encryption, so use a temporary
- * buffer for the data. */
- os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
- os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
- os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
- if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
- &pairwise) < 0) {
- wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
- "PMK-R1 pull");
- return -1;
+ if (seq_ret == FT_RRB_SEQ_DROP)
+ goto out;
+
+ if (wpa_ft_rrb_decrypt(key, key_len, enc, enc_len, auth, auth_len,
+ src_addr, FT_PACKET_R0KH_R1KH_PULL,
+ &plain, &plain_len) < 0)
+ goto out;
+
+ if (!r1kh)
+ r1kh = wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard, src_addr,
+ f_r1kh_id,
+ wpa_auth->conf.rkh_pos_timeout);
+ if (!r1kh)
+ goto out;
+
+ if (seq_ret == FT_RRB_SEQ_DEFER) {
+ wpa_ft_rrb_seq_req(wpa_auth, r1kh->seq, src_addr, f_r0kh_id,
+ f_r0kh_id_len, f_r1kh_id, key, key_len,
+ enc, enc_len, auth, auth_len,
+ &wpa_ft_rrb_rx_pull);
+ goto out;
}
- wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
- r.pmk_r1, r.pmk_r1_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
- WPA_PMK_NAME_LEN);
- r.pairwise = host_to_le16(pairwise);
- os_memset(r.pad, 0, sizeof(r.pad));
+ wpa_ft_rrb_seq_accept(wpa_auth, r1kh->seq, src_addr, auth, auth_len,
+ msgtype);
+ wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh,
+ wpa_auth->conf.rkh_pos_timeout);
- if (aes_wrap(r1kh->key, sizeof(r1kh->key),
- (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
- r.nonce, resp.nonce) < 0) {
- os_memset(pmk_r0, 0, PMK_LEN);
- return -1;
+ RRB_GET(FT_RRB_PMK_R0_NAME, pmk_r0_name, msgtype, WPA_PMK_NAME_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", f_pmk_r0_name,
+ f_pmk_r0_name_len);
+
+ RRB_GET(FT_RRB_S1KH_ID, s1kh_id, msgtype, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "FT: S1KH-ID=" MACSTR, MAC2STR(f_s1kh_id));
+
+ if (wpa_ft_new_seq(r1kh->seq, &f_seq) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to get seq num");
+ goto out;
+ }
+
+ resp[0].type = FT_RRB_S1KH_ID;
+ resp[0].len = f_s1kh_id_len;
+ resp[0].data = f_s1kh_id;
+ resp[1].type = FT_RRB_LAST_EMPTY;
+ resp[1].len = 0;
+ resp[1].data = NULL;
+
+ resp_auth[0].type = FT_RRB_NONCE;
+ resp_auth[0].len = f_nonce_len;
+ resp_auth[0].data = f_nonce;
+ resp_auth[1].type = FT_RRB_SEQ;
+ resp_auth[1].len = sizeof(f_seq);
+ resp_auth[1].data = (u8 *) &f_seq;
+ resp_auth[2].type = FT_RRB_R0KH_ID;
+ resp_auth[2].len = f_r0kh_id_len;
+ resp_auth[2].data = f_r0kh_id;
+ resp_auth[3].type = FT_RRB_R1KH_ID;
+ resp_auth[3].len = f_r1kh_id_len;
+ resp_auth[3].data = f_r1kh_id;
+ resp_auth[4].type = FT_RRB_LAST_EMPTY;
+ resp_auth[4].len = 0;
+ resp_auth[4].data = NULL;
+
+ if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: No matching PMK-R0-Name found");
+ ret = wpa_ft_rrb_build(key, key_len, resp, NULL, resp_auth,
+ NULL, wpa_auth->addr,
+ FT_PACKET_R0KH_R1KH_RESP,
+ &packet, &packet_len);
+ } else {
+ ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id,
+ f_s1kh_id, resp_auth, wpa_auth->addr,
+ FT_PACKET_R0KH_R1KH_RESP,
+ &packet, &packet_len);
}
- os_memset(pmk_r0, 0, PMK_LEN);
+ if (!ret)
+ wpa_ft_rrb_oui_send(wpa_auth, src_addr,
+ FT_PACKET_R0KH_R1KH_RESP, packet,
+ packet_len);
- wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
+out:
+ os_free(plain);
+ os_free(packet);
return 0;
}
-static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
+/* @returns 0 on success
+ * -1 on error
+ * -2 if FR_RRB_PAIRWISE is missing
+ */
+static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr, u8 type,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ const char *msgtype, u8 *s1kh_id_out,
+ int (*cb)(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ int no_defer))
+{
+ u8 *plain = NULL;
+ size_t plain_len = 0;
+ struct ft_remote_r0kh *r0kh, *r0kh_wildcard;
+ const u8 *key;
+ size_t key_len;
+ int seq_ret;
+ const u8 *f_r1kh_id, *f_s1kh_id, *f_r0kh_id;
+ const u8 *f_pmk_r1_name, *f_pairwise, *f_pmk_r1;
+ const u8 *f_expires_in;
+ size_t f_r1kh_id_len, f_s1kh_id_len, f_r0kh_id_len;
+ const u8 *f_identity, *f_radius_cui;
+ const u8 *f_session_timeout;
+ size_t f_pmk_r1_name_len, f_pairwise_len, f_pmk_r1_len;
+ size_t f_expires_in_len;
+ size_t f_identity_len, f_radius_cui_len;
+ size_t f_session_timeout_len;
+ int pairwise;
+ int ret = -1;
+ int expires_in;
+ int session_timeout;
+ struct vlan_description vlan;
+ size_t pmk_r1_len;
+
+ RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1);
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", f_r0kh_id, f_r0kh_id_len);
+
+ RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, msgtype, FT_R1KH_ID_LEN);
+ wpa_printf(MSG_DEBUG, "FT: R1KH-ID=" MACSTR, MAC2STR(f_r1kh_id));
+
+ if (wpa_ft_rrb_check_r1kh(wpa_auth, f_r1kh_id)) {
+ wpa_printf(MSG_DEBUG, "FT: R1KH-ID mismatch");
+ goto out;
+ }
+
+ wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, &r0kh,
+ &r0kh_wildcard);
+ if (r0kh) {
+ key = r0kh->key;
+ key_len = sizeof(r0kh->key);
+ } else if (r0kh_wildcard) {
+ wpa_printf(MSG_DEBUG, "FT: Using wildcard R0KH-ID");
+ key = r0kh_wildcard->key;
+ key_len = sizeof(r0kh_wildcard->key);
+ } else {
+ goto out;
+ }
+
+ seq_ret = FT_RRB_SEQ_DROP;
+ if (r0kh) {
+ seq_ret = wpa_ft_rrb_seq_chk(r0kh->seq, src_addr, enc, enc_len,
+ auth, auth_len, msgtype,
+ cb ? 0 : 1);
+ }
+ if (cb && r0kh_wildcard &&
+ (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) {
+ /* wildcard: r0kh-id unknown or changed addr -> do a seq req */
+ seq_ret = FT_RRB_SEQ_DEFER;
+ }
+
+ if (seq_ret == FT_RRB_SEQ_DROP)
+ goto out;
+
+ if (wpa_ft_rrb_decrypt(key, key_len, enc, enc_len, auth, auth_len,
+ src_addr, type, &plain, &plain_len) < 0)
+ goto out;
+
+ if (!r0kh)
+ r0kh = wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, src_addr,
+ f_r0kh_id, f_r0kh_id_len,
+ wpa_auth->conf.rkh_pos_timeout);
+ if (!r0kh)
+ goto out;
+
+ if (seq_ret == FT_RRB_SEQ_DEFER) {
+ wpa_ft_rrb_seq_req(wpa_auth, r0kh->seq, src_addr, f_r0kh_id,
+ f_r0kh_id_len, f_r1kh_id, key, key_len,
+ enc, enc_len, auth, auth_len, cb);
+ goto out;
+ }
+
+ wpa_ft_rrb_seq_accept(wpa_auth, r0kh->seq, src_addr, auth, auth_len,
+ msgtype);
+ wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh,
+ wpa_auth->conf.rkh_pos_timeout);
+
+ RRB_GET(FT_RRB_S1KH_ID, s1kh_id, msgtype, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "FT: S1KH-ID=" MACSTR, MAC2STR(f_s1kh_id));
+
+ if (s1kh_id_out)
+ os_memcpy(s1kh_id_out, f_s1kh_id, ETH_ALEN);
+
+ ret = -2;
+ RRB_GET(FT_RRB_PAIRWISE, pairwise, msgtype, sizeof(le16));
+ wpa_hexdump(MSG_DEBUG, "FT: pairwise", f_pairwise, f_pairwise_len);
+
+ ret = -1;
+ RRB_GET(FT_RRB_PMK_R1_NAME, pmk_r1_name, msgtype, WPA_PMK_NAME_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
+ f_pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ pmk_r1_len = PMK_LEN;
+ if (wpa_ft_rrb_get_tlv(plain, plain_len, FT_RRB_PMK_R1, &f_pmk_r1_len,
+ &f_pmk_r1) == 0 &&
+ (f_pmk_r1_len == PMK_LEN || f_pmk_r1_len == SHA384_MAC_LEN))
+ pmk_r1_len = f_pmk_r1_len;
+ RRB_GET(FT_RRB_PMK_R1, pmk_r1, msgtype, pmk_r1_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f_pmk_r1, pmk_r1_len);
+
+ pairwise = WPA_GET_LE16(f_pairwise);
+
+ RRB_GET_OPTIONAL(FT_RRB_EXPIRES_IN, expires_in, msgtype,
+ sizeof(le16));
+ if (f_expires_in)
+ expires_in = WPA_GET_LE16(f_expires_in);
+ else
+ expires_in = 0;
+
+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 %s - expires_in=%d", msgtype,
+ expires_in);
+
+ if (wpa_ft_rrb_get_tlv_vlan(plain, plain_len, &vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Cannot parse vlan");
+ wpa_ft_rrb_dump(plain, plain_len);
+ goto out;
+ }
+
+ wpa_printf(MSG_DEBUG, "FT: vlan %d%s",
+ le_to_host16(vlan.untagged), vlan.tagged[0] ? "+" : "");
+
+ RRB_GET_OPTIONAL(FT_RRB_IDENTITY, identity, msgtype, -1);
+ if (f_identity)
+ wpa_hexdump_ascii(MSG_DEBUG, "FT: Identity", f_identity,
+ f_identity_len);
+
+ RRB_GET_OPTIONAL(FT_RRB_RADIUS_CUI, radius_cui, msgtype, -1);
+ if (f_radius_cui)
+ wpa_hexdump_ascii(MSG_DEBUG, "FT: CUI", f_radius_cui,
+ f_radius_cui_len);
+
+ RRB_GET_OPTIONAL(FT_RRB_SESSION_TIMEOUT, session_timeout, msgtype,
+ sizeof(le32));
+ if (f_session_timeout)
+ session_timeout = WPA_GET_LE32(f_session_timeout);
+ else
+ session_timeout = 0;
+ wpa_printf(MSG_DEBUG, "FT: session_timeout %d", session_timeout);
+
+ if (wpa_ft_store_pmk_r1(wpa_auth, f_s1kh_id, f_pmk_r1, pmk_r1_len,
+ f_pmk_r1_name,
+ pairwise, &vlan, expires_in, session_timeout,
+ f_identity, f_identity_len, f_radius_cui,
+ f_radius_cui_len) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ if (plain) {
+ os_memset(plain, 0, plain_len);
+ os_free(plain);
+ }
+
+ return ret;
+
+}
+
+
+static void ft_finish_pull(struct wpa_state_machine *sm)
{
- struct wpa_state_machine *sm = eloop_ctx;
int res;
u8 *resp_ies;
size_t resp_ies_len;
u16 status;
+ if (!sm->ft_pending_cb || !sm->ft_pending_req_ies)
+ return;
+
res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies),
wpabuf_len(sm->ft_pending_req_ies),
&resp_ies, &resp_ies_len);
+ if (res < 0) {
+ /* this loop is broken by ft_pending_pull_left_retries */
+ wpa_printf(MSG_DEBUG,
+ "FT: Callback postponed until response is available");
+ return;
+ }
wpabuf_free(sm->ft_pending_req_ies);
sm->ft_pending_req_ies = NULL;
- if (res < 0)
- res = WLAN_STATUS_UNSPECIFIED_FAILURE;
status = res;
wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR
" - status %u", MAC2STR(sm->addr), status);
@@ -1433,171 +3924,383 @@ static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
}
-static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx)
+struct ft_get_sta_ctx {
+ const u8 *nonce;
+ const u8 *s1kh_id;
+ struct wpa_state_machine *sm;
+};
+
+
+static int ft_get_sta_cb(struct wpa_state_machine *sm, void *ctx)
{
- struct ft_r0kh_r1kh_resp_frame *frame = ctx;
+ struct ft_get_sta_ctx *info = ctx;
- if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
- return 0;
- if (os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
- FT_R0KH_R1KH_PULL_NONCE_LEN) != 0)
- return 0;
- if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
+ if ((info->s1kh_id &&
+ os_memcmp(info->s1kh_id, sm->addr, ETH_ALEN) != 0) ||
+ os_memcmp(info->nonce, sm->ft_pending_pull_nonce,
+ FT_RRB_NONCE_LEN) != 0 ||
+ sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
return 0;
- wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
- MACSTR " - process from timeout", MAC2STR(sm->addr));
- eloop_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL);
+ info->sm = sm;
+
return 1;
}
static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
- const u8 *data, size_t data_len)
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ int no_defer)
{
- struct ft_r0kh_r1kh_resp_frame f;
- const u8 *crypt;
- u8 *plain;
- struct ft_remote_r0kh *r0kh;
- int pairwise, res;
+ const char *msgtype = "pull response";
+ int nak, ret = -1;
+ struct ft_get_sta_ctx ctx;
+ u8 s1kh_id[ETH_ALEN];
+ const u8 *f_nonce;
+ size_t f_nonce_len;
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
- if (data_len < sizeof(f))
- return -1;
+ RRB_GET_AUTH(FT_RRB_NONCE, nonce, msgtype, FT_RRB_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: nonce", f_nonce, f_nonce_len);
- r0kh = wpa_auth->conf.r0kh_list;
- while (r0kh) {
- if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
- break;
- r0kh = r0kh->next;
- }
- if (r0kh == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
- "PMK-R0 pull response source address " MACSTR,
- MAC2STR(src_addr));
+ os_memset(&ctx, 0, sizeof(ctx));
+ ctx.nonce = f_nonce;
+ if (!wpa_auth_for_each_sta(wpa_auth, ft_get_sta_cb, &ctx)) {
+ /* nonce not found */
+ wpa_printf(MSG_DEBUG, "FT: Invalid nonce");
return -1;
}
- crypt = data + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
- os_memset(&f, 0, sizeof(f));
- plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
- /* aes_unwrap() does not support inplace decryption, so use a temporary
- * buffer for the data. */
- if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
- (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
- crypt, plain) < 0) {
- wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
- "response from " MACSTR, MAC2STR(src_addr));
- return -1;
+ ret = wpa_ft_rrb_rx_r1(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_RESP,
+ enc, enc_len, auth, auth_len, msgtype, s1kh_id,
+ no_defer ? NULL : &wpa_ft_rrb_rx_resp);
+ if (ret == -2) {
+ ret = 0;
+ nak = 1;
+ } else {
+ nak = 0;
}
-
- if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
- FT_R1KH_ID_LEN) != 0) {
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
- "matching R1KH-ID");
+ if (ret < 0)
return -1;
- }
-
- pairwise = le_to_host16(f.pairwise);
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
- f.nonce, sizeof(f.nonce));
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
- MACSTR " pairwise=0x%x",
- MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
- f.pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
- f.pmk_r1_name, WPA_PMK_NAME_LEN);
- res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
- pairwise);
- wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
- wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f);
- os_memset(f.pmk_r1, 0, PMK_LEN);
+ ctx.s1kh_id = s1kh_id;
+ if (wpa_auth_for_each_sta(wpa_auth, ft_get_sta_cb, &ctx)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Response to a pending pull request for " MACSTR,
+ MAC2STR(ctx.sm->addr));
+ eloop_cancel_timeout(wpa_ft_expire_pull, ctx.sm, NULL);
+ if (nak)
+ ctx.sm->ft_pending_pull_left_retries = 0;
+ ft_finish_pull(ctx.sm);
+ }
- return res ? 0 : -1;
+out:
+ return ret;
}
static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
- const u8 *data, size_t data_len)
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len, int no_defer)
{
- struct ft_r0kh_r1kh_push_frame f;
- const u8 *crypt;
- u8 *plain;
- struct ft_remote_r0kh *r0kh;
- struct os_time now;
- os_time_t tsend;
- int pairwise;
+ const char *msgtype = "push";
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
- if (data_len < sizeof(f))
+ if (wpa_ft_rrb_rx_r1(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_PUSH,
+ enc, enc_len, auth, auth_len, msgtype, NULL,
+ no_defer ? NULL : wpa_ft_rrb_rx_push) < 0)
return -1;
- r0kh = wpa_auth->conf.r0kh_list;
- while (r0kh) {
- if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
- break;
- r0kh = r0kh->next;
+ return 0;
+}
+
+
+static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr, int type,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ struct ft_remote_seq **rkh_seq,
+ u8 **key, size_t *key_len,
+ struct ft_remote_r0kh **r0kh_out,
+ struct ft_remote_r1kh **r1kh_out,
+ struct ft_remote_r0kh **r0kh_wildcard_out,
+ struct ft_remote_r1kh **r1kh_wildcard_out)
+{
+ struct ft_remote_r0kh *r0kh = NULL;
+ struct ft_remote_r1kh *r1kh = NULL;
+ const u8 *f_r0kh_id, *f_r1kh_id;
+ size_t f_r0kh_id_len, f_r1kh_id_len;
+ int to_r0kh, to_r1kh;
+ u8 *plain = NULL;
+ size_t plain_len = 0;
+ struct ft_remote_r0kh *r0kh_wildcard;
+ struct ft_remote_r1kh *r1kh_wildcard;
+
+ RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, "seq", -1);
+ RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, "seq", FT_R1KH_ID_LEN);
+
+ to_r0kh = !wpa_ft_rrb_check_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len);
+ to_r1kh = !wpa_ft_rrb_check_r1kh(wpa_auth, f_r1kh_id);
+
+ if (to_r0kh && to_r1kh) {
+ wpa_printf(MSG_DEBUG, "FT: seq - local R0KH-ID and R1KH-ID");
+ goto out;
}
- if (r0kh == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
- "PMK-R0 push source address " MACSTR,
- MAC2STR(src_addr));
- return -1;
+
+ if (!to_r0kh && !to_r1kh) {
+ wpa_printf(MSG_DEBUG, "FT: seq - remote R0KH-ID and R1KH-ID");
+ goto out;
}
- crypt = data + offsetof(struct ft_r0kh_r1kh_push_frame, timestamp);
- os_memset(&f, 0, sizeof(f));
- plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
- timestamp);
- /* aes_unwrap() does not support inplace decryption, so use a temporary
- * buffer for the data. */
- if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
- (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
- crypt, plain) < 0) {
- wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
- MACSTR, MAC2STR(src_addr));
- return -1;
+ if (!to_r0kh) {
+ wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len,
+ &r0kh, &r0kh_wildcard);
+ if (!r0kh_wildcard &&
+ (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) {
+ wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
+ f_r0kh_id, f_r0kh_id_len);
+ goto out;
+ }
+ if (r0kh) {
+ *key = r0kh->key;
+ *key_len = sizeof(r0kh->key);
+ } else {
+ *key = r0kh_wildcard->key;
+ *key_len = sizeof(r0kh_wildcard->key);
+ }
}
- os_get_time(&now);
- tsend = WPA_GET_LE32(f.timestamp);
- if ((now.sec > tsend && now.sec - tsend > 60) ||
- (now.sec < tsend && tsend - now.sec > 60)) {
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
- "timestamp: sender time %d own time %d\n",
- (int) tsend, (int) now.sec);
- return -1;
+ if (!to_r1kh) {
+ wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh,
+ &r1kh_wildcard);
+ if (!r1kh_wildcard &&
+ (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) {
+ wpa_hexdump(MSG_DEBUG, "FT: Did not find R1KH-ID",
+ f_r1kh_id, FT_R1KH_ID_LEN);
+ goto out;
+ }
+ if (r1kh) {
+ *key = r1kh->key;
+ *key_len = sizeof(r1kh->key);
+ } else {
+ *key = r1kh_wildcard->key;
+ *key_len = sizeof(r1kh_wildcard->key);
+ }
}
- if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
- FT_R1KH_ID_LEN) != 0) {
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
- "R1KH-ID (received " MACSTR " own " MACSTR ")",
- MAC2STR(f.r1kh_id),
- MAC2STR(wpa_auth->conf.r1_key_holder));
- return -1;
+ if (wpa_ft_rrb_decrypt(*key, *key_len, enc, enc_len, auth, auth_len,
+ src_addr, type, &plain, &plain_len) < 0)
+ goto out;
+
+ os_free(plain);
+
+ if (!to_r0kh) {
+ if (!r0kh)
+ r0kh = wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard,
+ src_addr, f_r0kh_id,
+ f_r0kh_id_len,
+ ftRRBseqTimeout);
+ if (!r0kh)
+ goto out;
+
+ wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh, ftRRBseqTimeout);
+ *rkh_seq = r0kh->seq;
+ if (r0kh_out)
+ *r0kh_out = r0kh;
+ if (r0kh_wildcard_out)
+ *r0kh_wildcard_out = r0kh_wildcard;
+ }
+
+ if (!to_r1kh) {
+ if (!r1kh)
+ r1kh = wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard,
+ src_addr, f_r1kh_id,
+ ftRRBseqTimeout);
+ if (!r1kh)
+ goto out;
+
+ wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh, ftRRBseqTimeout);
+ *rkh_seq = r1kh->seq;
+ if (r1kh_out)
+ *r1kh_out = r1kh;
+ if (r1kh_wildcard_out)
+ *r1kh_wildcard_out = r1kh_wildcard;
}
- pairwise = le_to_host16(f.pairwise);
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
- MACSTR " pairwise=0x%x",
- MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
- f.pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
- f.pmk_r1_name, WPA_PMK_NAME_LEN);
+ return 0;
+out:
+ return -1;
+}
+
- wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
- pairwise);
- os_memset(f.pmk_r1, 0, PMK_LEN);
+static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ int no_defer)
+{
+ int ret = -1;
+ struct ft_rrb_seq f_seq;
+ const u8 *f_nonce, *f_r0kh_id, *f_r1kh_id;
+ size_t f_nonce_len, f_r0kh_id_len, f_r1kh_id_len;
+ struct ft_remote_seq *rkh_seq = NULL;
+ u8 *packet = NULL, *key = NULL;
+ size_t packet_len = 0, key_len = 0;
+ struct tlv_list seq_resp_auth[5];
+
+ wpa_printf(MSG_DEBUG, "FT: Received sequence number request");
+
+ if (wpa_ft_rrb_rx_seq(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_REQ,
+ enc, enc_len, auth, auth_len, &rkh_seq, &key,
+ &key_len, NULL, NULL, NULL, NULL) < 0)
+ goto out;
+
+ RRB_GET_AUTH(FT_RRB_NONCE, nonce, "seq request", FT_RRB_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: seq request - nonce", f_nonce, f_nonce_len);
+
+ RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, "seq", -1);
+ RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, "seq", FT_R1KH_ID_LEN);
+
+ if (wpa_ft_new_seq(rkh_seq, &f_seq) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to get seq num");
+ goto out;
+ }
+
+ seq_resp_auth[0].type = FT_RRB_NONCE;
+ seq_resp_auth[0].len = f_nonce_len;
+ seq_resp_auth[0].data = f_nonce;
+ seq_resp_auth[1].type = FT_RRB_SEQ;
+ seq_resp_auth[1].len = sizeof(f_seq);
+ seq_resp_auth[1].data = (u8 *) &f_seq;
+ seq_resp_auth[2].type = FT_RRB_R0KH_ID;
+ seq_resp_auth[2].len = f_r0kh_id_len;
+ seq_resp_auth[2].data = f_r0kh_id;
+ seq_resp_auth[3].type = FT_RRB_R1KH_ID;
+ seq_resp_auth[3].len = FT_R1KH_ID_LEN;
+ seq_resp_auth[3].data = f_r1kh_id;
+ seq_resp_auth[4].type = FT_RRB_LAST_EMPTY;
+ seq_resp_auth[4].len = 0;
+ seq_resp_auth[4].data = NULL;
+
+ if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_resp_auth, NULL,
+ wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_RESP,
+ &packet, &packet_len) < 0)
+ goto out;
+
+ wpa_ft_rrb_oui_send(wpa_auth, src_addr,
+ FT_PACKET_R0KH_R1KH_SEQ_RESP, packet,
+ packet_len);
+
+out:
+ os_free(packet);
+
+ return ret;
+}
+
+
+static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ int no_defer)
+{
+ u8 *key = NULL;
+ size_t key_len = 0;
+ struct ft_remote_r0kh *r0kh = NULL, *r0kh_wildcard = NULL;
+ struct ft_remote_r1kh *r1kh = NULL, *r1kh_wildcard = NULL;
+ const u8 *f_nonce, *f_seq;
+ size_t f_nonce_len, f_seq_len;
+ struct ft_remote_seq *rkh_seq = NULL;
+ struct ft_remote_item *item;
+ struct os_reltime now, now_remote;
+ int seq_ret, found;
+ const struct ft_rrb_seq *msg_both;
+ u32 msg_dom, msg_seq;
+
+ wpa_printf(MSG_DEBUG, "FT: Received sequence number response");
+
+ if (wpa_ft_rrb_rx_seq(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_RESP,
+ enc, enc_len, auth, auth_len, &rkh_seq, &key,
+ &key_len, &r0kh, &r1kh, &r0kh_wildcard,
+ &r1kh_wildcard) < 0)
+ goto out;
+
+ RRB_GET_AUTH(FT_RRB_NONCE, nonce, "seq response", FT_RRB_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: seq response - nonce", f_nonce,
+ f_nonce_len);
+
+ found = 0;
+ dl_list_for_each(item, &rkh_seq->rx.queue, struct ft_remote_item,
+ list) {
+ if (os_memcmp_const(f_nonce, item->nonce,
+ FT_RRB_NONCE_LEN) != 0 ||
+ os_get_reltime(&now) < 0 ||
+ os_reltime_expired(&now, &item->nonce_ts, ftRRBseqTimeout))
+ continue;
+
+ found = 1;
+ break;
+ }
+ if (!found) {
+ wpa_printf(MSG_DEBUG, "FT: seq response - bad nonce");
+ goto out;
+ }
+
+ if (r0kh) {
+ wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh,
+ wpa_auth->conf.rkh_pos_timeout);
+ if (r0kh_wildcard)
+ os_memcpy(r0kh->addr, src_addr, ETH_ALEN);
+ }
+
+ if (r1kh) {
+ wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh,
+ wpa_auth->conf.rkh_pos_timeout);
+ if (r1kh_wildcard)
+ os_memcpy(r1kh->addr, src_addr, ETH_ALEN);
+ }
+
+ seq_ret = wpa_ft_rrb_seq_chk(rkh_seq, src_addr, enc, enc_len, auth,
+ auth_len, "seq response", 1);
+ if (seq_ret == FT_RRB_SEQ_OK) {
+ wpa_printf(MSG_DEBUG, "FT: seq response - valid seq number");
+ wpa_ft_rrb_seq_accept(wpa_auth, rkh_seq, src_addr, auth,
+ auth_len, "seq response");
+ } else {
+ wpa_printf(MSG_DEBUG, "FT: seq response - reset seq number");
+
+ RRB_GET_AUTH(FT_RRB_SEQ, seq, "seq response",
+ sizeof(*msg_both));
+ msg_both = (const struct ft_rrb_seq *) f_seq;
+
+ msg_dom = le_to_host32(msg_both->dom);
+ msg_seq = le_to_host32(msg_both->seq);
+ now_remote.sec = le_to_host32(msg_both->ts);
+ now_remote.usec = 0;
+
+ rkh_seq->rx.num_last = 2;
+ rkh_seq->rx.dom = msg_dom;
+ rkh_seq->rx.offsetidx = 0;
+ /* Accept some older, possibly cached packets as well */
+ rkh_seq->rx.last[0] = msg_seq - FT_REMOTE_SEQ_BACKLOG -
+ dl_list_len(&rkh_seq->rx.queue);
+ rkh_seq->rx.last[1] = msg_seq;
+
+ /* local time - offset = remote time
+ * <=> local time - remote time = offset */
+ os_reltime_sub(&now, &now_remote, &rkh_seq->rx.time_offset);
+ }
+
+ wpa_ft_rrb_seq_flush(wpa_auth, rkh_seq, 1);
return 0;
+out:
+ return -1;
}
@@ -1642,13 +4345,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1;
}
- if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
- return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
- if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
- return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
- if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
- return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
-
wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
if (alen < 1 + 1 + 2 * ETH_ALEN) {
@@ -1726,65 +4422,140 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
}
-static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
- struct wpa_ft_pmk_r0_sa *pmk_r0,
- struct ft_remote_r1kh *r1kh,
- const u8 *s1kh_id, int pairwise)
-{
- struct ft_r0kh_r1kh_push_frame frame, f;
- struct os_time now;
- const u8 *plain;
- u8 *crypt;
-
- os_memset(&frame, 0, sizeof(frame));
- frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
- frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
- frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
- os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
-
- /* aes_wrap() does not support inplace encryption, so use a temporary
- * buffer for the data. */
- os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
- os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
- os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
- wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
- s1kh_id, f.pmk_r1, f.pmk_r1_name);
- wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
- WPA_PMK_NAME_LEN);
- os_get_time(&now);
- WPA_PUT_LE32(f.timestamp, now.sec);
- f.pairwise = host_to_le16(pairwise);
- os_memset(f.pad, 0, sizeof(f.pad));
- plain = ((const u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
- timestamp);
- crypt = ((u8 *) &frame) + offsetof(struct ft_r0kh_r1kh_push_frame,
- timestamp);
- if (aes_wrap(r1kh->key, sizeof(r1kh->key),
- (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
- plain, crypt) < 0)
+void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
+ const u8 *dst_addr, u8 oui_suffix, const u8 *data,
+ size_t data_len)
+{
+ const u8 *auth, *enc;
+ size_t alen, elen;
+ int no_defer = 0;
+
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
+ MACSTR, MAC2STR(src_addr));
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
+ wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
+
+ if (is_multicast_ether_addr(src_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB-OUI received frame from multicast address "
+ MACSTR, MAC2STR(src_addr));
+ return;
+ }
+
+ if (is_multicast_ether_addr(dst_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB-OUI received frame from remote AP " MACSTR
+ " to multicast address " MACSTR,
+ MAC2STR(src_addr), MAC2STR(dst_addr));
+ no_defer = 1;
+ }
+
+ if (data_len < sizeof(u16)) {
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
return;
+ }
+
+ alen = WPA_GET_LE16(data);
+ if (data_len < sizeof(u16) + alen) {
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
+ return;
+ }
+
+ auth = data + sizeof(u16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Authenticated payload", auth, alen);
+ enc = data + sizeof(u16) + alen;
+ elen = data_len - sizeof(u16) - alen;
+ wpa_hexdump(MSG_MSGDUMP, "FT: Encrypted payload", enc, elen);
+
+ switch (oui_suffix) {
+ case FT_PACKET_R0KH_R1KH_PULL:
+ wpa_ft_rrb_rx_pull(wpa_auth, src_addr, enc, elen, auth, alen,
+ no_defer);
+ break;
+ case FT_PACKET_R0KH_R1KH_RESP:
+ wpa_ft_rrb_rx_resp(wpa_auth, src_addr, enc, elen, auth, alen,
+ no_defer);
+ break;
+ case FT_PACKET_R0KH_R1KH_PUSH:
+ wpa_ft_rrb_rx_push(wpa_auth, src_addr, enc, elen, auth, alen,
+ no_defer);
+ break;
+ case FT_PACKET_R0KH_R1KH_SEQ_REQ:
+ wpa_ft_rrb_rx_seq_req(wpa_auth, src_addr, enc, elen, auth, alen,
+ no_defer);
+ break;
+ case FT_PACKET_R0KH_R1KH_SEQ_RESP:
+ wpa_ft_rrb_rx_seq_resp(wpa_auth, src_addr, enc, elen, auth,
+ alen, no_defer);
+ break;
+ }
+}
- wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
+
+static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
+ struct wpa_ft_pmk_r0_sa *pmk_r0,
+ struct ft_remote_r1kh *r1kh,
+ const u8 *s1kh_id)
+{
+ u8 *packet;
+ size_t packet_len;
+ struct ft_rrb_seq f_seq;
+ struct tlv_list push[] = {
+ { .type = FT_RRB_S1KH_ID, .len = ETH_ALEN,
+ .data = s1kh_id },
+ { .type = FT_RRB_PMK_R0_NAME, .len = WPA_PMK_NAME_LEN,
+ .data = pmk_r0->pmk_r0_name },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+ struct tlv_list push_auth[] = {
+ { .type = FT_RRB_SEQ, .len = sizeof(f_seq),
+ .data = (u8 *) &f_seq },
+ { .type = FT_RRB_R0KH_ID,
+ .len = wpa_auth->conf.r0_key_holder_len,
+ .data = wpa_auth->conf.r0_key_holder },
+ { .type = FT_RRB_R1KH_ID, .len = FT_R1KH_ID_LEN,
+ .data = r1kh->id },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ if (wpa_ft_new_seq(r1kh->seq, &f_seq) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to get seq num");
+ return -1;
+ }
+
+ if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
+ r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
+ FT_PACKET_R0KH_R1KH_PUSH,
+ &packet, &packet_len) < 0)
+ return -1;
+
+ wpa_ft_rrb_oui_send(wpa_auth, r1kh->addr, FT_PACKET_R0KH_R1KH_PUSH,
+ packet, packet_len);
+
+ os_free(packet);
+ return 0;
}
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
{
- struct wpa_ft_pmk_r0_sa *r0;
+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+ struct wpa_ft_pmk_r0_sa *r0, *r0found = NULL;
struct ft_remote_r1kh *r1kh;
if (!wpa_auth->conf.pmk_r1_push)
return;
+ if (!wpa_auth->conf.r1kh_list)
+ return;
- r0 = wpa_auth->ft_pmk_cache->pmk_r0;
- while (r0) {
- if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
+ dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
+ if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0) {
+ r0found = r0;
break;
- r0 = r0->next;
+ }
}
+ r0 = r0found;
if (r0 == NULL || r0->pmk_r1_pushed)
return;
r0->pmk_r1_pushed = 1;
@@ -1792,11 +4563,14 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
"for STA " MACSTR, MAC2STR(addr));
- r1kh = wpa_auth->conf.r1kh_list;
- while (r1kh) {
- wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
- r1kh = r1kh->next;
+ for (r1kh = *wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) {
+ if (is_zero_ether_addr(r1kh->addr) ||
+ is_zero_ether_addr(r1kh->id))
+ continue;
+ if (wpa_ft_rrb_init_r1kh_seq(r1kh) < 0)
+ continue;
+ wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr);
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
diff --git a/contrib/wpa/src/ap/wpa_auth_glue.c b/contrib/wpa/src/ap/wpa_auth_glue.c
index f98cc50..45172c6 100644
--- a/contrib/wpa/src/ap/wpa_auth_glue.c
+++ b/contrib/wpa/src/ap/wpa_auth_glue.c
@@ -9,13 +9,17 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "common/wpa_ctrl.h"
+#include "crypto/sha1.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
#include "l2_packet/l2_packet.h"
+#include "eth_p_oui.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "preauth_auth.h"
@@ -23,6 +27,8 @@
#include "tkip_countermeasures.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
+#include "ieee802_11.h"
+#include "pmksa_cache_auth.h"
#include "wpa_auth.h"
#include "wpa_auth_glue.h"
@@ -40,19 +46,26 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
+ wconf->wpa_group_update_count = conf->wpa_group_update_count;
+ wconf->wpa_disable_eapol_key_retries =
+ conf->wpa_disable_eapol_key_retries;
+ wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
- wconf->peerkey = conf->peerkey;
wconf->wmm_enabled = conf->wmm_enabled;
wconf->wmm_uapsd = conf->wmm_uapsd;
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
+#ifdef CONFIG_OCV
+ wconf->ocv = conf->ocv;
+#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
+ wconf->sae_require_mfp = conf->sae_require_mfp;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wconf->ssid_len = conf->ssid.ssid_len;
if (wconf->ssid_len > SSID_MAX_LEN)
wconf->ssid_len = SSID_MAX_LEN;
@@ -67,12 +80,18 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
}
os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
wconf->r0_key_lifetime = conf->r0_key_lifetime;
+ wconf->r1_max_key_lifetime = conf->r1_max_key_lifetime;
wconf->reassociation_deadline = conf->reassociation_deadline;
- wconf->r0kh_list = conf->r0kh_list;
- wconf->r1kh_list = conf->r1kh_list;
+ wconf->rkh_pos_timeout = conf->rkh_pos_timeout;
+ wconf->rkh_neg_timeout = conf->rkh_neg_timeout;
+ wconf->rkh_pull_timeout = conf->rkh_pull_timeout;
+ wconf->rkh_pull_retries = conf->rkh_pull_retries;
+ wconf->r0kh_list = &conf->r0kh_list;
+ wconf->r1kh_list = &conf->r1kh_list;
wconf->pmk_r1_push = conf->pmk_r1_push;
wconf->ft_over_ds = conf->ft_over_ds;
-#endif /* CONFIG_IEEE80211R */
+ wconf->ft_psk_generate_local = conf->ft_psk_generate_local;
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_HS20
wconf->disable_gtk = conf->disable_dgaf;
if (conf->osen) {
@@ -106,6 +125,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4);
os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_FILS
+ wconf->fils_cache_id_set = conf->fils_cache_id_set;
+ os_memcpy(wconf->fils_cache_id, conf->fils_cache_id,
+ FILS_CACHE_ID_LEN);
+#endif /* CONFIG_FILS */
}
@@ -222,21 +246,52 @@ static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
const u8 *p2p_dev_addr,
- const u8 *prev_psk)
+ const u8 *prev_psk, size_t *psk_len,
+ int *vlan_id)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
const u8 *psk;
+ if (vlan_id)
+ *vlan_id = 0;
+ if (psk_len)
+ *psk_len = PMK_LEN;
+
#ifdef CONFIG_SAE
if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
if (!sta->sae || prev_psk)
return NULL;
return sta->sae->pmk;
}
+ if (sta && wpa_auth_uses_sae(sta->wpa_sm)) {
+ wpa_printf(MSG_DEBUG,
+ "No PSK for STA trying to use SAE with PMKSA caching");
+ return NULL;
+ }
#endif /* CONFIG_SAE */
- psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk);
+#ifdef CONFIG_OWE
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
+ sta && sta->owe_pmk) {
+ if (psk_len)
+ *psk_len = sta->owe_pmk_len;
+ return sta->owe_pmk;
+ }
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta) {
+ struct rsn_pmksa_cache_entry *sa;
+
+ sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+ if (sa && sa->akmp == WPA_KEY_MGMT_OWE) {
+ if (psk_len)
+ *psk_len = sa->pmk_len;
+ return sa->pmk;
+ }
+ }
+#endif /* CONFIG_OWE */
+
+ psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk,
+ vlan_id);
/*
* This is about to iterate over all psks, prev_psk gives the last
* returned psk which should not be returned again.
@@ -244,8 +299,18 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
*/
if (sta && sta->psk && !psk) {
struct hostapd_sta_wpa_psk_short *pos;
+
+ if (vlan_id)
+ *vlan_id = 0;
psk = sta->psk->psk;
for (pos = sta->psk; pos; pos = pos->next) {
+ if (pos->is_passphrase) {
+ pbkdf2_sha1(pos->passphrase,
+ hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len, 4096,
+ pos->psk, PMK_LEN);
+ pos->is_passphrase = 0;
+ }
if (pos->psk == prev_psk) {
psk = pos->next ? pos->next->psk : NULL;
break;
@@ -299,6 +364,37 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (addr && !is_broadcast_ether_addr(addr)) {
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta) {
+ sta->last_tk_alg = alg;
+ sta->last_tk_key_idx = idx;
+ if (key)
+ os_memcpy(sta->last_tk, key, key_len);
+ sta->last_tk_len = key_len;
+ }
+#ifdef CONFIG_IEEE80211W
+ } else if (alg == WPA_ALG_IGTK ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256) {
+ hapd->last_igtk_alg = alg;
+ hapd->last_igtk_key_idx = idx;
+ if (key)
+ os_memcpy(hapd->last_igtk, key, key_len);
+ hapd->last_igtk_len = key_len;
+#endif /* CONFIG_IEEE80211W */
+ } else {
+ hapd->last_gtk_alg = alg;
+ hapd->last_gtk_key_idx = idx;
+ if (key)
+ os_memcpy(hapd->last_gtk, key, key_len);
+ hapd->last_gtk_len = key_len;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
key, key_len);
}
@@ -393,7 +489,32 @@ static int hostapd_wpa_auth_for_each_auth(
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
+
+struct wpa_ft_rrb_rx_later_data {
+ struct dl_list list;
+ u8 addr[ETH_ALEN];
+ size_t data_len;
+ /* followed by data_len octets of data */
+};
+
+static void hostapd_wpa_ft_rrb_rx_later(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct wpa_ft_rrb_rx_later_data *data, *n;
+
+ dl_list_for_each_safe(data, n, &hapd->l2_queue,
+ struct wpa_ft_rrb_rx_later_data, list) {
+ if (hapd->wpa_auth) {
+ wpa_ft_rrb_rx(hapd->wpa_auth, data->addr,
+ (const u8 *) (data + 1),
+ data->data_len);
+ }
+ dl_list_del(&data->list);
+ os_free(data);
+ }
+}
+
struct wpa_auth_ft_iface_iter_data {
struct hostapd_data *src_hapd;
@@ -406,31 +527,54 @@ struct wpa_auth_ft_iface_iter_data {
static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
{
struct wpa_auth_ft_iface_iter_data *idata = ctx;
+ struct wpa_ft_rrb_rx_later_data *data;
struct hostapd_data *hapd;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
- if (hapd == idata->src_hapd)
+ if (hapd == idata->src_hapd ||
+ !hapd->wpa_auth ||
+ os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0)
continue;
- if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) {
- wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to "
- "locally managed BSS " MACSTR "@%s -> "
- MACSTR "@%s",
- MAC2STR(idata->src_hapd->own_addr),
- idata->src_hapd->conf->iface,
- MAC2STR(hapd->own_addr), hapd->conf->iface);
- wpa_ft_rrb_rx(hapd->wpa_auth,
- idata->src_hapd->own_addr,
- idata->data, idata->data_len);
+
+ wpa_printf(MSG_DEBUG,
+ "FT: Send RRB data directly to locally managed BSS "
+ MACSTR "@%s -> " MACSTR "@%s",
+ MAC2STR(idata->src_hapd->own_addr),
+ idata->src_hapd->conf->iface,
+ MAC2STR(hapd->own_addr), hapd->conf->iface);
+
+ /* Defer wpa_ft_rrb_rx() until next eloop step as this is
+ * when it would be triggered when reading from a socket.
+ * This avoids
+ * hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv,
+ * that is calling hapd0:recv handler from within
+ * hapd0:send directly.
+ */
+ data = os_zalloc(sizeof(*data) + idata->data_len);
+ if (!data)
return 1;
- }
+
+ os_memcpy(data->addr, idata->src_hapd->own_addr, ETH_ALEN);
+ os_memcpy(data + 1, idata->data, idata->data_len);
+ data->data_len = idata->data_len;
+
+ dl_list_add(&hapd->l2_queue, &data->list);
+
+ if (!eloop_is_timeout_registered(hostapd_wpa_ft_rrb_rx_later,
+ hapd, NULL))
+ eloop_register_timeout(0, 0,
+ hostapd_wpa_ft_rrb_rx_later,
+ hapd, NULL);
+
+ return 1;
}
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
@@ -455,7 +599,7 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
}
#endif /* CONFIG_TESTING_OPTIONS */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (proto == ETH_P_RRB && hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
int res;
@@ -470,7 +614,7 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
if (res == 1)
return data_len;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (hapd->driver && hapd->driver->send_ether)
return hapd->driver->send_ether(hapd->drv_priv, dst,
@@ -493,7 +637,225 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_ETH_P_OUI
+static struct eth_p_oui_ctx * hostapd_wpa_get_oui(struct hostapd_data *hapd,
+ u8 oui_suffix)
+{
+ switch (oui_suffix) {
+#ifdef CONFIG_IEEE80211R_AP
+ case FT_PACKET_R0KH_R1KH_PULL:
+ return hapd->oui_pull;
+ case FT_PACKET_R0KH_R1KH_RESP:
+ return hapd->oui_resp;
+ case FT_PACKET_R0KH_R1KH_PUSH:
+ return hapd->oui_push;
+ case FT_PACKET_R0KH_R1KH_SEQ_REQ:
+ return hapd->oui_sreq;
+ case FT_PACKET_R0KH_R1KH_SEQ_RESP:
+ return hapd->oui_sresp;
+#endif /* CONFIG_IEEE80211R_AP */
+ default:
+ return NULL;
+ }
+}
+#endif /* CONFIG_ETH_P_OUI */
+
+
+#ifdef CONFIG_IEEE80211R_AP
+
+struct oui_deliver_later_data {
+ struct dl_list list;
+ u8 src_addr[ETH_ALEN];
+ u8 dst_addr[ETH_ALEN];
+ size_t data_len;
+ u8 oui_suffix;
+ /* followed by data_len octets of data */
+};
+
+static void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct oui_deliver_later_data *data, *n;
+ struct eth_p_oui_ctx *oui_ctx;
+
+ dl_list_for_each_safe(data, n, &hapd->l2_oui_queue,
+ struct oui_deliver_later_data, list) {
+ oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix);
+ if (hapd->wpa_auth && oui_ctx) {
+ eth_p_oui_deliver(oui_ctx, data->src_addr,
+ data->dst_addr,
+ (const u8 *) (data + 1),
+ data->data_len);
+ }
+ dl_list_del(&data->list);
+ os_free(data);
+ }
+}
+
+
+struct wpa_auth_oui_iface_iter_data {
+ struct hostapd_data *src_hapd;
+ const u8 *dst_addr;
+ const u8 *data;
+ size_t data_len;
+ u8 oui_suffix;
+};
+
+static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
+{
+ struct wpa_auth_oui_iface_iter_data *idata = ctx;
+ struct oui_deliver_later_data *data;
+ struct hostapd_data *hapd;
+ size_t j;
+
+ for (j = 0; j < iface->num_bss; j++) {
+ hapd = iface->bss[j];
+ if (hapd == idata->src_hapd)
+ continue;
+ if (!is_multicast_ether_addr(idata->dst_addr) &&
+ os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
+ continue;
+
+ /* defer eth_p_oui_deliver until next eloop step as this is
+ * when it would be triggerd from reading from sock
+ * This avoids
+ * hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv,
+ * that is calling hapd0:recv handler from within
+ * hapd0:send directly.
+ */
+ data = os_zalloc(sizeof(*data) + idata->data_len);
+ if (!data)
+ return 1;
+
+ os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN);
+ os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN);
+ os_memcpy(data + 1, idata->data, idata->data_len);
+ data->data_len = idata->data_len;
+ data->oui_suffix = idata->oui_suffix;
+
+ dl_list_add(&hapd->l2_oui_queue, &data->list);
+
+ if (!eloop_is_timeout_registered(hostapd_oui_deliver_later,
+ hapd, NULL))
+ eloop_register_timeout(0, 0,
+ hostapd_oui_deliver_later,
+ hapd, NULL);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_IEEE80211R_AP */
+
+
+static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix,
+ const u8 *data, size_t data_len)
+{
+#ifdef CONFIG_ETH_P_OUI
+ struct hostapd_data *hapd = ctx;
+ struct eth_p_oui_ctx *oui_ctx;
+
+#ifdef CONFIG_IEEE80211R_AP
+ if (hapd->iface->interfaces &&
+ hapd->iface->interfaces->for_each_interface) {
+ struct wpa_auth_oui_iface_iter_data idata;
+ int res;
+
+ idata.src_hapd = hapd;
+ idata.dst_addr = dst;
+ idata.data = data;
+ idata.data_len = data_len;
+ idata.oui_suffix = oui_suffix;
+ res = hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, hostapd_wpa_auth_oui_iter,
+ &idata);
+ if (res == 1)
+ return data_len;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+
+ oui_ctx = hostapd_wpa_get_oui(hapd, oui_suffix);
+ if (!oui_ctx)
+ return -1;
+
+ return eth_p_oui_send(oui_ctx, hapd->own_addr, dst, data, data_len);
+#else /* CONFIG_ETH_P_OUI */
+ return -1;
+#endif /* CONFIG_ETH_P_OUI */
+}
+
+
+static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci)
+{
+ struct hostapd_data *hapd = ctx;
+
+ return hostapd_drv_channel_info(hapd, ci);
+}
+
+
+static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
+{
+#ifndef CONFIG_NO_VLAN
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ struct vlan_description vlan_desc;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = 1;
+ vlan_desc.untagged = vlan_id;
+ if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file",
+ vlan_id);
+ return -1;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to assign VLAN ID %d from wpa_psk_file to "
+ MACSTR, vlan_id, MAC2STR(sta->addr));
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO,
+ "Assigned VLAN ID %d from wpa_psk_file to " MACSTR,
+ vlan_id, MAC2STR(sta->addr));
+ if ((sta->flags & WLAN_STA_ASSOC) &&
+ ap_sta_bind_vlan(hapd, sta) < 0)
+ return -1;
+#endif /* CONFIG_NO_VLAN */
+
+ return 0;
+}
+
+
+#ifdef CONFIG_OCV
+static int hostapd_get_sta_tx_params(void *ctx, const u8 *addr,
+ int ap_max_chanwidth, int ap_seg1_idx,
+ int *bandwidth, int *seg1_idx)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ hostapd_wpa_auth_logger(hapd, addr, LOGGER_INFO,
+ "Failed to get STA info to validate received OCI");
+ return -1;
+ }
+
+ return get_tx_parameters(sta, ap_max_chanwidth, ap_seg1_idx, bandwidth,
+ seg1_idx);
+}
+#endif /* CONFIG_OCV */
+
+
+#ifdef CONFIG_IEEE80211R_AP
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
const u8 *data, size_t data_len)
@@ -531,12 +893,18 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR
+ " based on WPA authenticator callback",
+ MAC2STR(sta_addr));
if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
+ if (hapd->driver && hapd->driver->add_sta_node)
+ sta->added_unassoc = 1;
+ sta->ft_over_ds = 1;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
return sta->wpa_sm;
@@ -553,6 +921,244 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
}
+static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
+ struct vlan_description *vlan)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta || !sta->wpa_sm)
+ return -1;
+
+ if (vlan->notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, vlan)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from FT",
+ vlan->untagged, vlan->tagged[0] ? "+" : "");
+ return -1;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, vlan) < 0)
+ return -1;
+ /* Configure wpa_group for GTK but ignore error due to driver not
+ * knowing this STA. */
+ ap_sta_bind_vlan(hapd, sta);
+
+ if (sta->vlan_id)
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+
+ return 0;
+}
+
+
+static int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr,
+ struct vlan_description *vlan)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ if (sta->vlan_desc)
+ *vlan = *sta->vlan_desc;
+ else
+ os_memset(vlan, 0, sizeof(*vlan));
+
+ return 0;
+}
+
+
+static int
+hostapd_wpa_auth_set_identity(void *ctx, const u8 *sta_addr,
+ const u8 *identity, size_t identity_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ os_free(sta->identity);
+ sta->identity = NULL;
+
+ if (sta->eapol_sm) {
+ os_free(sta->eapol_sm->identity);
+ sta->eapol_sm->identity = NULL;
+ sta->eapol_sm->identity_len = 0;
+ }
+
+ if (!identity_len)
+ return 0;
+
+ /* sta->identity is NULL terminated */
+ sta->identity = os_zalloc(identity_len + 1);
+ if (!sta->identity)
+ return -1;
+ os_memcpy(sta->identity, identity, identity_len);
+
+ if (sta->eapol_sm) {
+ sta->eapol_sm->identity = os_zalloc(identity_len);
+ if (!sta->eapol_sm->identity)
+ return -1;
+ os_memcpy(sta->eapol_sm->identity, identity, identity_len);
+ sta->eapol_sm->identity_len = identity_len;
+ }
+
+ return 0;
+}
+
+
+static size_t
+hostapd_wpa_auth_get_identity(void *ctx, const u8 *sta_addr, const u8 **buf)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ size_t len;
+ char *identity;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return 0;
+
+ *buf = ieee802_1x_get_identity(sta->eapol_sm, &len);
+ if (*buf && len)
+ return len;
+
+ if (!sta->identity) {
+ *buf = NULL;
+ return 0;
+ }
+
+ identity = sta->identity;
+ len = os_strlen(identity);
+ *buf = (u8 *) identity;
+
+ return len;
+}
+
+
+static int
+hostapd_wpa_auth_set_radius_cui(void *ctx, const u8 *sta_addr,
+ const u8 *radius_cui, size_t radius_cui_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ os_free(sta->radius_cui);
+ sta->radius_cui = NULL;
+
+ if (sta->eapol_sm) {
+ wpabuf_free(sta->eapol_sm->radius_cui);
+ sta->eapol_sm->radius_cui = NULL;
+ }
+
+ if (!radius_cui)
+ return 0;
+
+ /* sta->radius_cui is NULL terminated */
+ sta->radius_cui = os_zalloc(radius_cui_len + 1);
+ if (!sta->radius_cui)
+ return -1;
+ os_memcpy(sta->radius_cui, radius_cui, radius_cui_len);
+
+ if (sta->eapol_sm) {
+ sta->eapol_sm->radius_cui = wpabuf_alloc_copy(radius_cui,
+ radius_cui_len);
+ if (!sta->eapol_sm->radius_cui)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static size_t
+hostapd_wpa_auth_get_radius_cui(void *ctx, const u8 *sta_addr, const u8 **buf)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ struct wpabuf *b;
+ size_t len;
+ char *radius_cui;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return 0;
+
+ b = ieee802_1x_get_radius_cui(sta->eapol_sm);
+ if (b) {
+ len = wpabuf_len(b);
+ *buf = wpabuf_head(b);
+ return len;
+ }
+
+ if (!sta->radius_cui) {
+ *buf = NULL;
+ return 0;
+ }
+
+ radius_cui = sta->radius_cui;
+ len = os_strlen(radius_cui);
+ *buf = (u8 *) radius_cui;
+
+ return len;
+}
+
+
+static void hostapd_wpa_auth_set_session_timeout(void *ctx, const u8 *sta_addr,
+ int session_timeout)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return;
+
+ if (session_timeout) {
+ os_get_reltime(&sta->session_timeout);
+ sta->session_timeout.sec += session_timeout;
+ sta->session_timeout_set = 1;
+ ap_sta_session_timeout(hapd, sta, session_timeout);
+ } else {
+ sta->session_timeout_set = 0;
+ ap_sta_no_session_timeout(hapd, sta);
+ }
+}
+
+
+static int hostapd_wpa_auth_get_session_timeout(void *ctx, const u8 *sta_addr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ struct os_reltime now, remaining;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta || !sta->session_timeout_set)
+ return 0;
+
+ os_get_reltime(&now);
+ if (os_reltime_before(&sta->session_timeout, &now)) {
+ /* already expired, return >0 as timeout was set */
+ return 1;
+ }
+
+ os_reltime_sub(&sta->session_timeout, &now, &remaining);
+
+ return (remaining.sec > 0) ? remaining.sec : 1;
+}
+
+
static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -563,11 +1169,30 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
ethhdr = (struct l2_ethhdr *) buf;
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
+ if (!is_multicast_ether_addr(ethhdr->h_dest) &&
+ os_memcmp(hapd->own_addr, ethhdr->h_dest, ETH_ALEN) != 0)
+ return;
wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
len - sizeof(*ethhdr));
}
+static void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr,
+ const u8 *dst_addr, u8 oui_suffix,
+ const u8 *buf, size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+
+ wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
+ MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr));
+ if (!is_multicast_ether_addr(dst_addr) &&
+ os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0)
+ return;
+ wpa_ft_rrb_oui_rx(hapd->wpa_auth, src_addr, dst_addr, oui_suffix, buf,
+ len);
+}
+
+
static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
u8 *tspec_ie, size_t tspec_ielen)
{
@@ -575,13 +1200,99 @@ static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
}
-#endif /* CONFIG_IEEE80211R */
+
+
+static int hostapd_wpa_register_ft_oui(struct hostapd_data *hapd,
+ const char *ft_iface)
+{
+ hapd->oui_pull = eth_p_oui_register(hapd, ft_iface,
+ FT_PACKET_R0KH_R1KH_PULL,
+ hostapd_rrb_oui_receive, hapd);
+ if (!hapd->oui_pull)
+ return -1;
+
+ hapd->oui_resp = eth_p_oui_register(hapd, ft_iface,
+ FT_PACKET_R0KH_R1KH_RESP,
+ hostapd_rrb_oui_receive, hapd);
+ if (!hapd->oui_resp)
+ return -1;
+
+ hapd->oui_push = eth_p_oui_register(hapd, ft_iface,
+ FT_PACKET_R0KH_R1KH_PUSH,
+ hostapd_rrb_oui_receive, hapd);
+ if (!hapd->oui_push)
+ return -1;
+
+ hapd->oui_sreq = eth_p_oui_register(hapd, ft_iface,
+ FT_PACKET_R0KH_R1KH_SEQ_REQ,
+ hostapd_rrb_oui_receive, hapd);
+ if (!hapd->oui_sreq)
+ return -1;
+
+ hapd->oui_sresp = eth_p_oui_register(hapd, ft_iface,
+ FT_PACKET_R0KH_R1KH_SEQ_RESP,
+ hostapd_rrb_oui_receive, hapd);
+ if (!hapd->oui_sresp)
+ return -1;
+
+ return 0;
+}
+
+
+static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd)
+{
+ eth_p_oui_unregister(hapd->oui_pull);
+ hapd->oui_pull = NULL;
+ eth_p_oui_unregister(hapd->oui_resp);
+ hapd->oui_resp = NULL;
+ eth_p_oui_unregister(hapd->oui_push);
+ hapd->oui_push = NULL;
+ eth_p_oui_unregister(hapd->oui_sreq);
+ hapd->oui_sreq = NULL;
+ eth_p_oui_unregister(hapd->oui_sresp);
+ hapd->oui_sresp = NULL;
+}
+#endif /* CONFIG_IEEE80211R_AP */
int hostapd_setup_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config _conf;
- struct wpa_auth_callbacks cb;
+ static const struct wpa_auth_callbacks cb = {
+ .logger = hostapd_wpa_auth_logger,
+ .disconnect = hostapd_wpa_auth_disconnect,
+ .mic_failure_report = hostapd_wpa_auth_mic_failure_report,
+ .psk_failure_report = hostapd_wpa_auth_psk_failure_report,
+ .set_eapol = hostapd_wpa_auth_set_eapol,
+ .get_eapol = hostapd_wpa_auth_get_eapol,
+ .get_psk = hostapd_wpa_auth_get_psk,
+ .get_msk = hostapd_wpa_auth_get_msk,
+ .set_key = hostapd_wpa_auth_set_key,
+ .get_seqnum = hostapd_wpa_auth_get_seqnum,
+ .send_eapol = hostapd_wpa_auth_send_eapol,
+ .for_each_sta = hostapd_wpa_auth_for_each_sta,
+ .for_each_auth = hostapd_wpa_auth_for_each_auth,
+ .send_ether = hostapd_wpa_auth_send_ether,
+ .send_oui = hostapd_wpa_auth_send_oui,
+ .channel_info = hostapd_channel_info,
+ .update_vlan = hostapd_wpa_auth_update_vlan,
+#ifdef CONFIG_OCV
+ .get_sta_tx_params = hostapd_get_sta_tx_params,
+#endif /* CONFIG_OCV */
+#ifdef CONFIG_IEEE80211R_AP
+ .send_ft_action = hostapd_wpa_auth_send_ft_action,
+ .add_sta = hostapd_wpa_auth_add_sta,
+ .add_tspec = hostapd_wpa_auth_add_tspec,
+ .set_vlan = hostapd_wpa_auth_set_vlan,
+ .get_vlan = hostapd_wpa_auth_get_vlan,
+ .set_identity = hostapd_wpa_auth_set_identity,
+ .get_identity = hostapd_wpa_auth_get_identity,
+ .set_radius_cui = hostapd_wpa_auth_set_radius_cui,
+ .get_radius_cui = hostapd_wpa_auth_get_radius_cui,
+ .set_session_timeout = hostapd_wpa_auth_set_session_timeout,
+ .get_session_timeout = hostapd_wpa_auth_get_session_timeout,
+#endif /* CONFIG_IEEE80211R_AP */
+ };
const u8 *wpa_ie;
size_t wpa_ie_len;
@@ -590,28 +1301,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1;
- os_memset(&cb, 0, sizeof(cb));
- cb.ctx = hapd;
- cb.logger = hostapd_wpa_auth_logger;
- cb.disconnect = hostapd_wpa_auth_disconnect;
- cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
- cb.psk_failure_report = hostapd_wpa_auth_psk_failure_report;
- cb.set_eapol = hostapd_wpa_auth_set_eapol;
- cb.get_eapol = hostapd_wpa_auth_get_eapol;
- cb.get_psk = hostapd_wpa_auth_get_psk;
- cb.get_msk = hostapd_wpa_auth_get_msk;
- cb.set_key = hostapd_wpa_auth_set_key;
- cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
- cb.send_eapol = hostapd_wpa_auth_send_eapol;
- cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
- cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
- cb.send_ether = hostapd_wpa_auth_send_ether;
-#ifdef CONFIG_IEEE80211R
- cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
- cb.add_sta = hostapd_wpa_auth_add_sta;
- cb.add_tspec = hostapd_wpa_auth_add_tspec;
-#endif /* CONFIG_IEEE80211R */
- hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
+ hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
return -1;
@@ -636,12 +1326,14 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
return -1;
}
-#ifdef CONFIG_IEEE80211R
- if (!hostapd_drv_none(hapd) && hapd->conf->ft_over_ds &&
+#ifdef CONFIG_IEEE80211R_AP
+ if (!hostapd_drv_none(hapd) &&
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
- hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
- hapd->conf->bridge :
- hapd->conf->iface, NULL, ETH_P_RRB,
+ const char *ft_iface;
+
+ ft_iface = hapd->conf->bridge[0] ? hapd->conf->bridge :
+ hapd->conf->iface;
+ hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
hostapd_rrb_receive, hapd, 1);
if (hapd->l2 == NULL &&
(hapd->driver == NULL ||
@@ -650,8 +1342,14 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
"interface");
return -1;
}
+
+ if (hostapd_wpa_register_ft_oui(hapd, ft_iface)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to open ETH_P_OUI interface");
+ return -1;
+ }
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
return 0;
@@ -674,13 +1372,14 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
wpa_deinit(hapd->wpa_auth);
hapd->wpa_auth = NULL;
- if (hostapd_set_privacy(hapd, 0)) {
+ if (hapd->drv_priv && hostapd_set_privacy(hapd, 0)) {
wpa_printf(MSG_DEBUG, "Could not disable "
"PrivacyInvoked for interface %s",
hapd->conf->iface);
}
- if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
+ if (hapd->drv_priv &&
+ hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
wpa_printf(MSG_DEBUG, "Could not remove generic "
"information element from interface %s",
hapd->conf->iface);
@@ -688,8 +1387,13 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
}
ieee802_1x_deinit(hapd);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
+ eloop_cancel_timeout(hostapd_wpa_ft_rrb_rx_later, hapd, ELOOP_ALL_CTX);
+ hostapd_wpa_ft_rrb_rx_later(hapd, NULL); /* flush without delivering */
+ eloop_cancel_timeout(hostapd_oui_deliver_later, hapd, ELOOP_ALL_CTX);
+ hostapd_oui_deliver_later(hapd, NULL); /* flush without delivering */
l2_packet_deinit(hapd->l2);
hapd->l2 = NULL;
-#endif /* CONFIG_IEEE80211R */
+ hostapd_wpa_unregister_ft_oui(hapd);
+#endif /* CONFIG_IEEE80211R_AP */
}
diff --git a/contrib/wpa/src/ap/wpa_auth_i.h b/contrib/wpa/src/ap/wpa_auth_i.h
index 234d84c..4babd0c 100644
--- a/contrib/wpa/src/ap/wpa_auth_i.h
+++ b/contrib/wpa/src/ap/wpa_auth_i.h
@@ -9,24 +9,20 @@
#ifndef WPA_AUTH_I_H
#define WPA_AUTH_I_H
+#include "utils/list.h"
+
/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
#define RSNA_MAX_EAPOL_RETRIES 4
struct wpa_group;
-struct wpa_stsl_negotiation {
- struct wpa_stsl_negotiation *next;
- u8 initiator[ETH_ALEN];
- u8 peer[ETH_ALEN];
-};
-
-
struct wpa_state_machine {
struct wpa_authenticator *wpa_auth;
struct wpa_group *group;
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
+ u16 auth_alg;
enum {
WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
@@ -48,8 +44,9 @@ struct wpa_state_machine {
Boolean AuthenticationRequest;
Boolean ReAuthenticationRequest;
Boolean Disconnect;
- int TimeoutCtr;
- int GTimeoutCtr;
+ u16 disconnect_reason; /* specific reason code to use with Disconnect */
+ u32 TimeoutCtr;
+ u32 GTimeoutCtr;
Boolean TimeoutEvt;
Boolean EAPOLKeyReceived;
Boolean EAPOLKeyPairwise;
@@ -60,7 +57,9 @@ struct wpa_state_machine {
u8 SNonce[WPA_NONCE_LEN];
u8 alt_SNonce[WPA_NONCE_LEN];
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
- u8 PMK[PMK_LEN];
+ u8 PMK[PMK_LEN_MAX];
+ unsigned int pmk_len;
+ u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
struct wpa_ptk PTK;
Boolean PTK_valid;
Boolean pairwise_set;
@@ -88,11 +87,15 @@ struct wpa_state_machine {
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
unsigned int alt_snonce_valid:1;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
+ unsigned int pmkid_set:1;
+#ifdef CONFIG_OCV
+ unsigned int ocv_enabled:1;
+#endif /* CONFIG_OCV */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
@@ -112,9 +115,12 @@ struct wpa_state_machine {
u32 dot11RSNAStatsTKIPLocalMICFailures;
u32 dot11RSNAStatsTKIPRemoteMICFailures;
-#ifdef CONFIG_IEEE80211R
- u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+#ifdef CONFIG_IEEE80211R_AP
+ u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
+ * first 384 bits of MSK */
size_t xxkey_len;
+ u8 pmk_r1[PMK_LEN_MAX];
+ unsigned int pmk_r1_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
* Request */
u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
@@ -128,16 +134,34 @@ struct wpa_state_machine {
const u8 *ies, size_t ies_len);
void *ft_pending_cb_ctx;
struct wpabuf *ft_pending_req_ies;
- u8 ft_pending_pull_nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
+ u8 ft_pending_pull_nonce[FT_RRB_NONCE_LEN];
u8 ft_pending_auth_transaction;
u8 ft_pending_current_ap[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R */
+ int ft_pending_pull_left_retries;
+#endif /* CONFIG_IEEE80211R_AP */
int pending_1_of_4_timeout;
#ifdef CONFIG_P2P
u8 ip_addr[4];
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_FILS
+ u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
+ u8 fils_key_auth_ap[FILS_MAX_KEY_AUTH_LEN];
+ size_t fils_key_auth_len;
+ unsigned int fils_completed:1;
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_DPP2
+ struct wpabuf *dpp_z;
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ void (*eapol_status_cb)(void *ctx1, void *ctx2);
+ void *eapol_status_cb_ctx1;
+ void *eapol_status_cb_ctx2;
+#endif /* CONFIG_TESTING_OPTIONS */
};
@@ -172,6 +196,7 @@ struct wpa_group {
#endif /* CONFIG_IEEE80211W */
/* Number of references except those in struct wpa_group->next */
unsigned int references;
+ unsigned int num_setup_iface;
};
@@ -192,10 +217,9 @@ struct wpa_authenticator {
unsigned int dot11RSNATKIPCounterMeasuresInvoked;
unsigned int dot11RSNA4WayHandshakeFailures;
- struct wpa_stsl_negotiation *stsl_negotiations;
-
struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
+ const struct wpa_auth_callbacks *cb;
+ void *cb_ctx;
u8 *wpa_ie;
size_t wpa_ie_len;
@@ -211,6 +235,38 @@ struct wpa_authenticator {
};
+#ifdef CONFIG_IEEE80211R_AP
+
+#define FT_REMOTE_SEQ_BACKLOG 16
+struct ft_remote_seq_rx {
+ u32 dom;
+ struct os_reltime time_offset; /* local time - offset = remote time */
+
+ /* accepted sequence numbers: (offset ... offset + 0x40000000]
+ * (except those in last)
+ * dropped sequence numbers: (offset - 0x40000000 ... offset]
+ * all others trigger SEQ_REQ message (except first message)
+ */
+ u32 last[FT_REMOTE_SEQ_BACKLOG];
+ unsigned int num_last;
+ u32 offsetidx;
+
+ struct dl_list queue; /* send nonces + rrb msgs awaiting seq resp */
+};
+
+struct ft_remote_seq_tx {
+ u32 dom; /* non zero if initialized */
+ u32 seq;
+};
+
+struct ft_remote_seq {
+ struct ft_remote_seq_rx rx;
+ struct ft_remote_seq_tx tx;
+};
+
+#endif /* CONFIG_IEEE80211R_AP */
+
+
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
@@ -229,32 +285,19 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx);
-#ifdef CONFIG_PEERKEY
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
- struct wpa_stsl_negotiation *neg);
-void wpa_smk_error(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
- const u8 *key_data, size_t key_data_len);
-void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key,
- const u8 *key_data, size_t key_data_len);
-void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key,
- const u8 *key_data, size_t key_data_len);
-#endif /* CONFIG_PEERKEY */
-
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
-int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
- size_t r0kh_id_len,
+int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
+ const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len);
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk);
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
-#endif /* CONFIG_IEEE80211R */
+int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
+ const u8 *pmk_r0_name);
+#endif /* CONFIG_IEEE80211R_AP */
#endif /* WPA_AUTH_I_H */
diff --git a/contrib/wpa/src/ap/wpa_auth_ie.c b/contrib/wpa/src/ap/wpa_auth_ie.c
index eafb828..8580a5a 100644
--- a/contrib/wpa/src/ap/wpa_auth_ie.c
+++ b/contrib/wpa/src/ap/wpa_auth_ie.c
@@ -1,6 +1,6 @@
/*
* hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -164,18 +164,25 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
pos += RSN_SELECTOR_LEN;
num_suites++;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+#ifdef CONFIG_SHA384
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_SHA384 */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
@@ -210,6 +217,51 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+#ifdef CONFIG_FILS
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#ifdef CONFIG_IEEE80211R_AP
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OSEN) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_HS20 */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -230,8 +282,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
capab = 0;
if (conf->rsn_preauth)
capab |= WPA_CAPABILITY_PREAUTH;
- if (conf->peerkey)
- capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
if (conf->wmm_enabled) {
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
@@ -243,15 +293,19 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing)
- capab |= BIT(8) | BIT(14) | BIT(15);
+ capab |= BIT(8) | BIT(15);
#endif /* CONFIG_RSN_TESTING */
WPA_PUT_LE16(pos, capab);
pos += 2;
if (pmkid) {
- if (pos + 2 + PMKID_LEN > buf + len)
+ if (2 + PMKID_LEN > buf + len - pos)
return -1;
/* PMKID Count */
WPA_PUT_LE16(pos, 1);
@@ -263,7 +317,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
- if (pos + 2 + 4 > buf + len)
+ if (2 + 4 > buf + len - pos)
return -1;
if (pmkid == NULL) {
/* PMKID Count */
@@ -364,6 +418,10 @@ static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
eid += 2;
@@ -407,7 +465,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
return res;
pos += res;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
res = wpa_write_mdie(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
@@ -415,7 +473,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
return res;
pos += res;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
res = wpa_write_wpa_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos);
@@ -472,9 +530,10 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
+ struct wpa_state_machine *sm, int freq,
const u8 *wpa_ie, size_t wpa_ie_len,
- const u8 *mdie, size_t mdie_len)
+ const u8 *mdie, size_t mdie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
{
struct wpa_ie_data data;
int ciphers, key_mgmt, res, version;
@@ -501,6 +560,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
if (version == WPA_PROTO_RSN) {
res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
+ if (!data.has_pairwise)
+ data.pairwise_cipher = wpa_default_rsn_cipher(freq);
+ if (!data.has_group)
+ data.group_cipher = wpa_default_rsn_cipher(freq);
+
+ if (wpa_key_mgmt_ft(data.key_mgmt) && !mdie &&
+ !wpa_key_mgmt_only_ft(data.key_mgmt)) {
+ /* Workaround for some HP and Epson printers that seem
+ * to incorrectly copy the FT-PSK + WPA-PSK AKMs from AP
+ * advertised RSNE to Association Request frame. */
+ wpa_printf(MSG_DEBUG,
+ "RSN: FT set in RSNE AKM but MDE is missing from "
+ MACSTR
+ " - ignore FT AKM(s) because there's also a non-FT AKM",
+ MAC2STR(sm->addr));
+ data.key_mgmt &= ~WPA_KEY_MGMT_FT;
+ }
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
@@ -509,12 +585,28 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_FILS
+#ifdef CONFIG_IEEE80211R_AP
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
+ selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
+ selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
+#endif /* CONFIG_IEEE80211R_AP */
+ else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
+ selector = RSN_AUTH_KEY_MGMT_FILS_SHA384;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
+ selector = RSN_AUTH_KEY_MGMT_FILS_SHA256;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R_AP
+#ifdef CONFIG_SHA384
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ selector = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
+#endif /* CONFIG_SHA384 */
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
@@ -531,6 +623,18 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+#ifdef CONFIG_OWE
+ else if (data.key_mgmt & WPA_KEY_MGMT_OWE)
+ selector = RSN_AUTH_KEY_MGMT_OWE;
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ else if (data.key_mgmt & WPA_KEY_MGMT_DPP)
+ selector = RSN_AUTH_KEY_MGMT_DPP;
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ else if (data.key_mgmt & WPA_KEY_MGMT_OSEN)
+ selector = RSN_AUTH_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
@@ -591,12 +695,28 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_FILS
+#ifdef CONFIG_IEEE80211R_AP
+ else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+#endif /* CONFIG_IEEE80211R_AP */
+ else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
+ else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R_AP
+#ifdef CONFIG_SHA384
+ else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -611,6 +731,18 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_SAE */
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+#ifdef CONFIG_OWE
+ else if (key_mgmt & WPA_KEY_MGMT_OWE)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_OWE;
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ else if (key_mgmt & WPA_KEY_MGMT_DPP)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_DPP;
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ else if (key_mgmt & WPA_KEY_MGMT_OSEN)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
else
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
@@ -634,12 +766,6 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
- if (ciphers & WPA_CIPHER_TKIP) {
- wpa_printf(MSG_DEBUG, "Management frame protection "
- "cannot use TKIP");
- return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
- }
-
if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
{
wpa_printf(MSG_DEBUG, "Unsupported management group "
@@ -648,14 +774,42 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
}
+#ifdef CONFIG_SAE
+ if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_OPTIONAL &&
+ wpa_auth->conf.sae_require_mfp &&
+ wpa_key_mgmt_sae(sm->wpa_key_mgmt) &&
+ !(data.capabilities & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection required with SAE, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_OCV
+ if ((data.capabilities & WPA_CAPABILITY_OCVC) &&
+ !(data.capabilities & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection required with OCV, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+ wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
+ (data.capabilities & WPA_CAPABILITY_OCVC));
+#endif /* CONFIG_OCV */
+
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
!(data.capabilities & WPA_CAPABILITY_MFPC))
sm->mgmt_frame_prot = 0;
else
sm->mgmt_frame_prot = 1;
+
+ if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection cannot use TKIP");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
@@ -668,8 +822,31 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
"MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
return WPA_INVALID_MDIE;
}
+ } else if (mdie != NULL) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Trying to use non-FT AKM suite, but MDIE included");
+ return WPA_INVALID_AKMP;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_OWE
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && !owe_dh) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: No Diffie-Hellman Parameter element");
+ return WPA_INVALID_AKMP;
+ }
+#ifdef CONFIG_DPP
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) {
+ /* Diffie-Hellman Parameter element can be used with DPP as
+ * well, so allow this to proceed. */
+ } else
+#endif /* CONFIG_DPP */
+ if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM");
+ return WPA_INVALID_AKMP;
+ }
+#endif /* CONFIG_OWE */
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
if (sm->pairwise < 0)
@@ -681,6 +858,21 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
else
sm->wpa = WPA_VERSION_WPA;
+#if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS)
+ if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&
+ (sm->auth_alg == WLAN_AUTH_FILS_SK ||
+ sm->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sm->auth_alg == WLAN_AUTH_FILS_PK) &&
+ (data.num_pmkid != 1 || !data.pmkid || !sm->pmk_r1_name_valid ||
+ os_memcmp_const(data.pmkid, sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN) != 0)) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "No PMKR1Name match for FILS+FT");
+ return WPA_INVALID_PMKID;
+ }
+#endif /* CONFIG_IEEE80211R_AP && CONFIG_FILS */
+
sm->pmksa = NULL;
for (i = 0; i < data.num_pmkid; i++) {
wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
@@ -712,14 +904,34 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
}
if (sm->pmksa && pmkid) {
+ struct vlan_description *vlan;
+
+ vlan = sm->pmksa->vlan_desc;
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "PMKID found from PMKSA cache "
- "eap_type=%d vlan_id=%d",
+ "PMKID found from PMKSA cache eap_type=%d vlan=%d%s",
sm->pmksa->eap_type_authsrv,
- sm->pmksa->vlan_id);
+ vlan ? vlan->untagged : 0,
+ (vlan && vlan->tagged[0]) ? "+" : "");
os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
}
+#ifdef CONFIG_SAE
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
+ !sm->pmksa) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "No PMKSA cache entry found for SAE");
+ return WPA_INVALID_PMKID;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_DPP
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && !sm->pmksa) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "No PMKSA cache entry found for DPP");
+ return WPA_INVALID_PMKID;
+ }
+#endif /* CONFIG_DPP */
+
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(wpa_ie_len);
@@ -791,7 +1003,7 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
- if (pos + 1 + RSN_SELECTOR_LEN < end &&
+ if (1 + RSN_SELECTOR_LEN < end - pos &&
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
@@ -812,36 +1024,6 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
-#ifdef CONFIG_PEERKEY
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
- ie->smk = pos + 2 + RSN_SELECTOR_LEN;
- ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
- ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
- ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
- ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
- ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
- ie->error = pos + 2 + RSN_SELECTOR_LEN;
- ie->error_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-#endif /* CONFIG_PEERKEY */
-
#ifdef CONFIG_IEEE80211W
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
@@ -870,6 +1052,15 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
@@ -887,13 +1078,13 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
int ret = 0;
os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+ for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
if (pos[0] == 0xdd &&
((pos == buf + len - 1) || pos[1] == 0)) {
/* Ignore padding */
break;
}
- if (pos + 2 + pos[1] > end) {
+ if (2 + pos[1] > end - pos) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
"underflow (ie=%d len=%d pos=%d)",
pos[0], pos[1], (int) (pos - buf));
@@ -905,14 +1096,14 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
if (*pos == WLAN_EID_RSN) {
ie->rsn_ie = pos;
ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
ie->mdie = pos;
ie->mdie_len = pos[1] + 2;
} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
ie->ftie = pos;
ie->ftie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
@@ -935,3 +1126,53 @@ int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
{
return sm ? sm->mgmt_frame_prot : 0;
}
+
+
+#ifdef CONFIG_OCV
+
+void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv)
+{
+ if (sm)
+ sm->ocv_enabled = ocv;
+}
+
+
+int wpa_auth_uses_ocv(struct wpa_state_machine *sm)
+{
+ return sm ? sm->ocv_enabled : 0;
+}
+
+#endif /* CONFIG_OCV */
+
+
+#ifdef CONFIG_OWE
+u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
+ u8 *pos, size_t max_len,
+ const u8 *req_ies, size_t req_ies_len)
+{
+ int res;
+ struct wpa_auth_config *conf;
+
+ if (!sm)
+ return pos;
+ conf = &sm->wpa_auth->conf;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->own_ie_override_len) {
+ if (max_len < conf->own_ie_override_len)
+ return NULL;
+ wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
+ conf->own_ie_override, conf->own_ie_override_len);
+ os_memcpy(pos, conf->own_ie_override,
+ conf->own_ie_override_len);
+ return pos + conf->own_ie_override_len;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ res = wpa_write_rsn_ie(conf, pos, max_len,
+ sm->pmksa ? sm->pmksa->pmkid : NULL);
+ if (res < 0)
+ return pos;
+ return pos + res;
+}
+#endif /* CONFIG_OWE */
diff --git a/contrib/wpa/src/ap/wpa_auth_ie.h b/contrib/wpa/src/ap/wpa_auth_ie.h
index d2067ba..a38b206 100644
--- a/contrib/wpa/src/ap/wpa_auth_ie.h
+++ b/contrib/wpa/src/ap/wpa_auth_ie.h
@@ -19,30 +19,24 @@ struct wpa_eapol_ie_parse {
size_t gtk_len;
const u8 *mac_addr;
size_t mac_addr_len;
-#ifdef CONFIG_PEERKEY
- const u8 *smk;
- size_t smk_len;
- const u8 *nonce;
- size_t nonce_len;
- const u8 *lifetime;
- size_t lifetime_len;
- const u8 *error;
- size_t error_len;
-#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
const u8 *igtk;
size_t igtk_len;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
const u8 *mdie;
size_t mdie_len;
const u8 *ftie;
size_t ftie_len;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
const u8 *osen;
size_t osen_len;
diff --git a/contrib/wpa/src/ap/wps_hostapd.c b/contrib/wpa/src/ap/wps_hostapd.c
index cde31e6..6161cdb 100644
--- a/contrib/wpa/src/ap/wps_hostapd.c
+++ b/contrib/wpa/src/ap/wps_hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / WPS integration
- * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -269,12 +269,6 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
}
-static int str_starts(const char *str, const char *start)
-{
- return os_strncmp(str, start, os_strlen(start)) == 0;
-}
-
-
static void wps_reload_config(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
@@ -360,6 +354,18 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
bss->wpa_pairwise,
bss->rsn_pairwise);
+ if (hapd->conf->wps_cred_add_sae &&
+ (cred->auth_type & WPS_AUTH_WPA2PSK) &&
+ cred->key_len != 2 * PMK_LEN) {
+ bss->wpa_key_mgmt |= WPA_KEY_MGMT_SAE;
+#ifdef CONFIG_IEEE80211W
+ if (bss->ieee80211w == NO_MGMT_FRAME_PROTECTION)
+ bss->ieee80211w =
+ MGMT_FRAME_PROTECTION_OPTIONAL;
+ bss->sae_require_mfp = 1;
+#endif /* CONFIG_IEEE80211W */
+ }
+
if (cred->key_len >= 8 && cred->key_len < 64) {
os_free(bss->ssid.wpa_passphrase);
bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
@@ -407,6 +413,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
char buf[1024];
int multi_bss;
int wpa;
+ int pmf_changed = 0;
if (hapd->wps == NULL)
return 0;
@@ -445,6 +452,8 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
hapd->wps->ssid_len = cred->ssid_len;
hapd->wps->encr_types = cred->encr_type;
+ hapd->wps->encr_types_rsn = cred->encr_type;
+ hapd->wps->encr_types_wpa = cred->encr_type;
hapd->wps->auth_types = cred->auth_type;
hapd->wps->ap_encr_type = cred->encr_type;
hapd->wps->ap_auth_type = cred->auth_type;
@@ -524,6 +533,10 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
if (wpa) {
char *prefix;
+#ifdef CONFIG_IEEE80211W
+ int sae = 0;
+#endif /* CONFIG_IEEE80211W */
+
fprintf(nconf, "wpa=%d\n", wpa);
fprintf(nconf, "wpa_key_mgmt=");
@@ -532,10 +545,30 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
fprintf(nconf, "WPA-EAP");
prefix = " ";
}
- if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+ if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
fprintf(nconf, "%sWPA-PSK", prefix);
+ prefix = " ";
+ }
+ if (hapd->conf->wps_cred_add_sae &&
+ (cred->auth_type & WPS_AUTH_WPA2PSK) &&
+ cred->key_len != 2 * PMK_LEN) {
+ fprintf(nconf, "%sSAE", prefix);
+#ifdef CONFIG_IEEE80211W
+ sae = 1;
+#endif /* CONFIG_IEEE80211W */
+ }
fprintf(nconf, "\n");
+#ifdef CONFIG_IEEE80211W
+ if (sae && hapd->conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+ fprintf(nconf, "ieee80211w=%d\n",
+ MGMT_FRAME_PROTECTION_OPTIONAL);
+ pmf_changed = 1;
+ }
+ if (sae)
+ fprintf(nconf, "sae_require_mfp=1\n");
+#endif /* CONFIG_IEEE80211W */
+
fprintf(nconf, "wpa_pairwise=");
prefix = "";
if (cred->encr_type & WPS_ENCR_AES) {
@@ -589,6 +622,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") ||
str_starts(buf, "wps_state=") ||
+ (pmf_changed && str_starts(buf, "ieee80211w=")) ||
str_starts(buf, "wpa=") ||
str_starts(buf, "wpa_psk=") ||
str_starts(buf, "wpa_pairwise=") ||
@@ -872,7 +906,8 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
hapd->wps_probe_resp_ie = NULL;
if (deinit_only) {
- hostapd_reset_ap_wps_ie(hapd);
+ if (hapd->drv_priv)
+ hostapd_reset_ap_wps_ie(hapd);
return;
}
@@ -978,6 +1013,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
{
struct wps_context *wps;
struct wps_registrar_config cfg;
+ u8 *multi_ap_netw_key = NULL;
if (conf->wps_state == 0) {
hostapd_wps_clear_ies(hapd, 0);
@@ -1067,10 +1103,16 @@ int hostapd_init_wps(struct hostapd_data *hapd,
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
wps->auth_types |= WPS_AUTH_WPA2;
- if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))
+ if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP_256)) {
wps->encr_types |= WPS_ENCR_AES;
- if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
+ wps->encr_types_rsn |= WPS_ENCR_AES;
+ }
+ if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
wps->encr_types |= WPS_ENCR_TKIP;
+ wps->encr_types_rsn |= WPS_ENCR_TKIP;
+ }
}
if (conf->wpa & WPA_PROTO_WPA) {
@@ -1079,10 +1121,14 @@ int hostapd_init_wps(struct hostapd_data *hapd,
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
wps->auth_types |= WPS_AUTH_WPA;
- if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
wps->encr_types |= WPS_ENCR_AES;
- if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ wps->encr_types_wpa |= WPS_ENCR_AES;
+ }
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
wps->encr_types |= WPS_ENCR_TKIP;
+ wps->encr_types_wpa |= WPS_ENCR_TKIP;
+ }
}
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
@@ -1122,6 +1168,33 @@ int hostapd_init_wps(struct hostapd_data *hapd,
/* Override parameters to enable security by default */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+ wps->encr_types_rsn = WPS_ENCR_AES | WPS_ENCR_TKIP;
+ wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
+ }
+
+ if ((hapd->conf->multi_ap & FRONTHAUL_BSS) &&
+ hapd->conf->multi_ap_backhaul_ssid.ssid_len) {
+ cfg.multi_ap_backhaul_ssid_len =
+ hapd->conf->multi_ap_backhaul_ssid.ssid_len;
+ cfg.multi_ap_backhaul_ssid =
+ hapd->conf->multi_ap_backhaul_ssid.ssid;
+
+ if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
+ cfg.multi_ap_backhaul_network_key = (const u8 *)
+ conf->multi_ap_backhaul_ssid.wpa_passphrase;
+ cfg.multi_ap_backhaul_network_key_len =
+ os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+ } else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
+ multi_ap_netw_key = os_malloc(2 * PMK_LEN + 1);
+ if (!multi_ap_netw_key)
+ goto fail;
+ wpa_snprintf_hex((char *) multi_ap_netw_key,
+ 2 * PMK_LEN + 1,
+ conf->multi_ap_backhaul_ssid.wpa_psk->psk,
+ PMK_LEN);
+ cfg.multi_ap_backhaul_network_key = multi_ap_netw_key;
+ cfg.multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
+ }
}
wps->ap_settings = conf->ap_settings;
@@ -1165,10 +1238,12 @@ int hostapd_init_wps(struct hostapd_data *hapd,
hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
hapd->wps = wps;
+ bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
return 0;
fail:
+ bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
hostapd_free_wps(wps);
return -1;
}
@@ -1614,7 +1689,8 @@ const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
unsigned int pin;
struct wps_ap_pin_data data;
- pin = wps_generate_pin();
+ if (wps_generate_pin(&pin) < 0)
+ return NULL;
os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
data.timeout = timeout;
hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
diff --git a/contrib/wpa/src/common/cli.c b/contrib/wpa/src/common/cli.c
new file mode 100644
index 0000000..b583d1c
--- /dev/null
+++ b/contrib/wpa/src/common/cli.c
@@ -0,0 +1,267 @@
+/*
+ * Common hostapd/wpa_supplicant command line interface functions
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "common/cli.h"
+
+
+const char *const cli_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n";
+
+const char *const cli_full_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"\n"
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are\n"
+"met:\n"
+"\n"
+"1. Redistributions of source code must retain the above copyright\n"
+" notice, this list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright\n"
+" notice, this list of conditions and the following disclaimer in the\n"
+" documentation and/or other materials provided with the distribution.\n"
+"\n"
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
+" names of its contributors may be used to endorse or promote products\n"
+" derived from this software without specific prior written permission.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+"\n";
+
+
+void cli_txt_list_free(struct cli_txt_entry *e)
+{
+ dl_list_del(&e->list);
+ os_free(e->txt);
+ os_free(e);
+}
+
+
+void cli_txt_list_flush(struct dl_list *list)
+{
+ struct cli_txt_entry *e;
+
+ while ((e = dl_list_first(list, struct cli_txt_entry, list)))
+ cli_txt_list_free(e);
+}
+
+
+struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
+ const char *txt)
+{
+ struct cli_txt_entry *e;
+
+ dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+ if (os_strcmp(e->txt, txt) == 0)
+ return e;
+ }
+ return NULL;
+}
+
+
+void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
+{
+ struct cli_txt_entry *e;
+
+ e = cli_txt_list_get(txt_list, txt);
+ if (e)
+ cli_txt_list_free(e);
+}
+
+
+void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
+{
+ u8 addr[ETH_ALEN];
+ char buf[18];
+
+ if (hwaddr_aton(txt, addr) < 0)
+ return;
+ os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ cli_txt_list_del(txt_list, buf);
+}
+
+
+void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+ int separator)
+{
+ const char *end;
+ char *buf;
+
+ end = os_strchr(txt, separator);
+ if (end == NULL)
+ end = txt + os_strlen(txt);
+ buf = dup_binstr(txt, end - txt);
+ if (buf == NULL)
+ return;
+ cli_txt_list_del(txt_list, buf);
+ os_free(buf);
+}
+
+
+int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
+{
+ struct cli_txt_entry *e;
+
+ e = cli_txt_list_get(txt_list, txt);
+ if (e)
+ return 0;
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return -1;
+ e->txt = os_strdup(txt);
+ if (e->txt == NULL) {
+ os_free(e);
+ return -1;
+ }
+ dl_list_add(txt_list, &e->list);
+ return 0;
+}
+
+
+int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
+{
+ u8 addr[ETH_ALEN];
+ char buf[18];
+
+ if (hwaddr_aton(txt, addr) < 0)
+ return -1;
+ os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ return cli_txt_list_add(txt_list, buf);
+}
+
+
+int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+ int separator)
+{
+ const char *end;
+ char *buf;
+ int ret;
+
+ end = os_strchr(txt, separator);
+ if (end == NULL)
+ end = txt + os_strlen(txt);
+ buf = dup_binstr(txt, end - txt);
+ if (buf == NULL)
+ return -1;
+ ret = cli_txt_list_add(txt_list, buf);
+ os_free(buf);
+ return ret;
+}
+
+
+char ** cli_txt_list_array(struct dl_list *txt_list)
+{
+ unsigned int i, count = dl_list_len(txt_list);
+ char **res;
+ struct cli_txt_entry *e;
+
+ res = os_calloc(count + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+
+ i = 0;
+ dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+ res[i] = os_strdup(e->txt);
+ if (res[i] == NULL)
+ break;
+ i++;
+ }
+
+ return res;
+}
+
+
+int get_cmd_arg_num(const char *str, int pos)
+{
+ int arg = 0, i;
+
+ for (i = 0; i <= pos; i++) {
+ if (str[i] != ' ') {
+ arg++;
+ while (i <= pos && str[i] != ' ')
+ i++;
+ }
+ }
+
+ if (arg > 0)
+ arg--;
+ return arg;
+}
+
+
+int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, char *argv[])
+{
+ int i, res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos, "%s", cmd);
+ if (os_snprintf_error(end - pos, res))
+ goto fail;
+ pos += res;
+
+ for (i = 0; i < argc; i++) {
+ res = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (os_snprintf_error(end - pos, res))
+ goto fail;
+ pos += res;
+ }
+
+ buf[buflen - 1] = '\0';
+ return 0;
+
+fail:
+ printf("Too long command\n");
+ return -1;
+}
+
+
+int tokenize_cmd(char *cmd, char *argv[])
+{
+ char *pos;
+ int argc = 0;
+
+ pos = cmd;
+ for (;;) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos == '\0')
+ break;
+ argv[argc] = pos;
+ argc++;
+ if (argc == max_args)
+ break;
+ if (*pos == '"') {
+ char *pos2 = os_strrchr(pos, '"');
+ if (pos2)
+ pos = pos2 + 1;
+ }
+ while (*pos != '\0' && *pos != ' ')
+ pos++;
+ if (*pos == ' ')
+ *pos++ = '\0';
+ }
+
+ return argc;
+}
diff --git a/contrib/wpa/src/common/cli.h b/contrib/wpa/src/common/cli.h
new file mode 100644
index 0000000..41ef329
--- /dev/null
+++ b/contrib/wpa/src/common/cli.h
@@ -0,0 +1,47 @@
+/*
+ * Common hostapd/wpa_supplicant command line interface functionality
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CLI_H
+#define CLI_H
+
+#include "utils/list.h"
+
+extern const char *const cli_license;
+extern const char *const cli_full_license;
+
+struct cli_txt_entry {
+ struct dl_list list;
+ char *txt;
+};
+
+void cli_txt_list_free(struct cli_txt_entry *e);
+void cli_txt_list_flush(struct dl_list *list);
+
+struct cli_txt_entry *
+cli_txt_list_get(struct dl_list *txt_list, const char *txt);
+
+void cli_txt_list_del(struct dl_list *txt_list, const char *txt);
+void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt);
+void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+ int separator);
+
+int cli_txt_list_add(struct dl_list *txt_list, const char *txt);
+int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt);
+int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+ int separator);
+
+char ** cli_txt_list_array(struct dl_list *txt_list);
+
+int get_cmd_arg_num(const char *str, int pos);
+int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+ char *argv[]);
+
+#define max_args 10
+int tokenize_cmd(char *cmd, char *argv[]);
+
+#endif /* CLI_H */
diff --git a/contrib/wpa/src/common/common_module_tests.c b/contrib/wpa/src/common/common_module_tests.c
index d69448b..30c52476 100644
--- a/contrib/wpa/src/common/common_module_tests.c
+++ b/contrib/wpa/src/common/common_module_tests.c
@@ -1,6 +1,6 @@
/*
* common module tests
- * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2014-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,10 +9,13 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
+#include "crypto/crypto.h"
#include "ieee802_11_common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
#include "wpa_common.h"
+#include "sae.h"
struct ieee802_11_parse_test_data {
@@ -52,12 +55,38 @@ static const struct ieee802_11_parse_test_data parse_tests[] = {
18, ParseOK, 9 },
{ (u8 *) "\x8b\x00", 2, ParseOK, 1 },
{ (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
+ { (u8 *) "\xed\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xef\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xef\x01\x11", 3, ParseOK, 1 },
+ { (u8 *) "\xf0\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xf1\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xf1\x02\x11\x22", 4, ParseOK, 1 },
+ { (u8 *) "\xf2\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xff\x00", 2, ParseUnknown, 1 },
+ { (u8 *) "\xff\x01\x00", 3, ParseUnknown, 1 },
+ { (u8 *) "\xff\x01\x01", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x02\x01\x00", 4, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x02", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x04\x02\x11\x22\x33", 6, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x04", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x05", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x0d\x05\x11\x22\x33\x44\x55\x55\x11\x22\x33\x44\x55\x55",
+ 15, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x06", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x02\x06\x00", 4, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x07", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x09\x07\x11\x22\x33\x44\x55\x66\x77\x88", 11,
+ ParseOK, 1 },
+ { (u8 *) "\xff\x01\x0c", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x02\x0c\x00", 4, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x0d", 3, ParseOK, 1 },
{ NULL, 0, ParseOK, 0 }
};
static int ieee802_11_parse_tests(void)
{
int i, ret = 0;
+ struct wpabuf *buf;
wpa_printf(MSG_INFO, "ieee802_11_parse tests");
@@ -83,6 +112,35 @@ static int ieee802_11_parse_tests(void)
ret = -1;
}
+ buf = ieee802_11_vendor_ie_concat((const u8 *) "\xdd\x05\x11\x22\x33\x44\x01\xdd\x05\x11\x22\x33\x44\x02\x00\x01",
+ 16, 0x11223344);
+ do {
+ const u8 *pos;
+
+ if (!buf) {
+ wpa_printf(MSG_ERROR,
+ "ieee802_11_vendor_ie_concat test 2 failed");
+ ret = -1;
+ break;
+ }
+
+ if (wpabuf_len(buf) != 2) {
+ wpa_printf(MSG_ERROR,
+ "ieee802_11_vendor_ie_concat test 3 failed");
+ ret = -1;
+ break;
+ }
+
+ pos = wpabuf_head(buf);
+ if (pos[0] != 0x01 || pos[1] != 0x02) {
+ wpa_printf(MSG_ERROR,
+ "ieee802_11_vendor_ie_concat test 3 failed");
+ ret = -1;
+ break;
+ }
+ } while (0);
+ wpabuf_free(buf);
+
return ret;
}
@@ -192,6 +250,179 @@ static int gas_tests(void)
}
+static int sae_tests(void)
+{
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+ int ret = -1;
+ /* IEEE P802.11-REVmd/D2.1, Annex J.10 */
+ const u8 addr1[ETH_ALEN] = { 0x82, 0x7b, 0x91, 0x9d, 0xd4, 0xb9 };
+ const u8 addr2[ETH_ALEN] = { 0x1e, 0xec, 0x49, 0xea, 0x64, 0x88 };
+ const char *pw = "mekmitasdigoat";
+ const char *pwid = "psk4internet";
+ const u8 local_rand[] = {
+ 0xa9, 0x06, 0xf6, 0x1e, 0x4d, 0x3a, 0x5d, 0x4e,
+ 0xb2, 0x96, 0x5f, 0xf3, 0x4c, 0xf9, 0x17, 0xdd,
+ 0x04, 0x44, 0x45, 0xc8, 0x78, 0xc1, 0x7c, 0xa5,
+ 0xd5, 0xb9, 0x37, 0x86, 0xda, 0x9f, 0x83, 0xcf
+ };
+ const u8 local_mask[] = {
+ 0x42, 0x34, 0xb4, 0xfb, 0x17, 0xaa, 0x43, 0x5c,
+ 0x52, 0xfb, 0xfd, 0xeb, 0xe6, 0x40, 0x39, 0xb4,
+ 0x34, 0x78, 0x20, 0x0e, 0x54, 0xff, 0x7b, 0x6e,
+ 0x07, 0xb6, 0x9c, 0xad, 0x74, 0x15, 0x3c, 0x15
+ };
+ const u8 local_commit[] = {
+ 0x13, 0x00, 0xeb, 0x3b, 0xab, 0x19, 0x64, 0xe4,
+ 0xa0, 0xab, 0x05, 0x92, 0x5d, 0xdf, 0x33, 0x39,
+ 0x51, 0x91, 0x38, 0xbc, 0x65, 0xd6, 0xcd, 0xc0,
+ 0xf8, 0x13, 0xdd, 0x6f, 0xd4, 0x34, 0x4e, 0xb4,
+ 0xbf, 0xe4, 0x4b, 0x5c, 0x21, 0x59, 0x76, 0x58,
+ 0xf4, 0xe3, 0xed, 0xdf, 0xb4, 0xb9, 0x9f, 0x25,
+ 0xb4, 0xd6, 0x54, 0x0f, 0x32, 0xff, 0x1f, 0xd5,
+ 0xc5, 0x30, 0xc6, 0x0a, 0x79, 0x44, 0x48, 0x61,
+ 0x0b, 0xc6, 0xde, 0x3d, 0x92, 0xbd, 0xbb, 0xd4,
+ 0x7d, 0x93, 0x59, 0x80, 0xca, 0x6c, 0xf8, 0x98,
+ 0x8a, 0xb6, 0x63, 0x0b, 0xe6, 0x76, 0x4c, 0x88,
+ 0x5c, 0xeb, 0x97, 0x93, 0x97, 0x0f, 0x69, 0x52,
+ 0x17, 0xee, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b,
+ 0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
+ 0x74
+ };
+ const u8 peer_commit[] = {
+ 0x13, 0x00, 0x55, 0x64, 0xf0, 0x45, 0xb2, 0xea,
+ 0x1e, 0x56, 0x6c, 0xf1, 0xdd, 0x74, 0x1f, 0x70,
+ 0xd9, 0xbe, 0x35, 0xd2, 0xdf, 0x5b, 0x9a, 0x55,
+ 0x02, 0x94, 0x6e, 0xe0, 0x3c, 0xf8, 0xda, 0xe2,
+ 0x7e, 0x1e, 0x05, 0xb8, 0x43, 0x0e, 0xb7, 0xa9,
+ 0x9e, 0x24, 0x87, 0x7c, 0xe6, 0x9b, 0xaf, 0x3d,
+ 0xc5, 0x80, 0xe3, 0x09, 0x63, 0x3d, 0x6b, 0x38,
+ 0x5f, 0x83, 0xee, 0x1c, 0x3e, 0xc3, 0x59, 0x1f,
+ 0x1a, 0x53, 0x93, 0xc0, 0x6e, 0x80, 0x5d, 0xdc,
+ 0xeb, 0x2f, 0xde, 0x50, 0x93, 0x0d, 0xd7, 0xcf,
+ 0xeb, 0xb9, 0x87, 0xc6, 0xff, 0x96, 0x66, 0xaf,
+ 0x16, 0x4e, 0xb5, 0x18, 0x4d, 0x8e, 0x66, 0x62,
+ 0xed, 0x6a, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b,
+ 0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
+ 0x74
+ };
+ const u8 kck[] = {
+ 0x59, 0x9d, 0x6f, 0x1e, 0x27, 0x54, 0x8b, 0xe8,
+ 0x49, 0x9d, 0xce, 0xed, 0x2f, 0xec, 0xcf, 0x94,
+ 0x81, 0x8c, 0xe1, 0xc7, 0x9f, 0x1b, 0x4e, 0xb3,
+ 0xd6, 0xa5, 0x32, 0x28, 0xa0, 0x9b, 0xf3, 0xed
+ };
+ const u8 pmk[] = {
+ 0x7a, 0xea, 0xd8, 0x6f, 0xba, 0x4c, 0x32, 0x21,
+ 0xfc, 0x43, 0x7f, 0x5f, 0x14, 0xd7, 0x0d, 0x85,
+ 0x4e, 0xa5, 0xd5, 0xaa, 0xc1, 0x69, 0x01, 0x16,
+ 0x79, 0x30, 0x81, 0xed, 0xa4, 0xd5, 0x57, 0xc5
+ };
+ const u8 pmkid[] = {
+ 0x40, 0xa0, 0x9b, 0x60, 0x17, 0xce, 0xbf, 0x00,
+ 0x72, 0x84, 0x3b, 0x53, 0x52, 0xaa, 0x2b, 0x4f
+ };
+ const u8 local_confirm[] = {
+ 0x01, 0x00, 0x12, 0xd9, 0xd5, 0xc7, 0x8c, 0x50,
+ 0x05, 0x26, 0xd3, 0x6c, 0x41, 0xdb, 0xc5, 0x6a,
+ 0xed, 0xf2, 0x91, 0x4c, 0xed, 0xdd, 0xd7, 0xca,
+ 0xd4, 0xa5, 0x8c, 0x48, 0xf8, 0x3d, 0xbd, 0xe9,
+ 0xfc, 0x77
+ };
+ const u8 peer_confirm[] = {
+ 0x01, 0x00, 0x02, 0x87, 0x1c, 0xf9, 0x06, 0x89,
+ 0x8b, 0x80, 0x60, 0xec, 0x18, 0x41, 0x43, 0xbe,
+ 0x77, 0xb8, 0xc0, 0x8a, 0x80, 0x19, 0xb1, 0x3e,
+ 0xb6, 0xd0, 0xae, 0xf0, 0xd8, 0x38, 0x3d, 0xfa,
+ 0xc2, 0xfd
+ };
+ struct wpabuf *buf = NULL;
+ struct crypto_bignum *mask = NULL;
+
+ os_memset(&sae, 0, sizeof(sae));
+ buf = wpabuf_alloc(1000);
+ if (!buf ||
+ sae_set_group(&sae, 19) < 0 ||
+ sae_prepare_commit(addr1, addr2, (const u8 *) pw, os_strlen(pw),
+ pwid, &sae) < 0)
+ goto fail;
+
+ /* Override local values based on SAE test vector */
+ crypto_bignum_deinit(sae.tmp->sae_rand, 1);
+ sae.tmp->sae_rand = crypto_bignum_init_set(local_rand,
+ sizeof(local_rand));
+ mask = crypto_bignum_init_set(local_mask, sizeof(local_mask));
+ if (!sae.tmp->sae_rand || !mask)
+ goto fail;
+
+ if (crypto_bignum_add(sae.tmp->sae_rand, mask,
+ sae.tmp->own_commit_scalar) < 0 ||
+ crypto_bignum_mod(sae.tmp->own_commit_scalar, sae.tmp->order,
+ sae.tmp->own_commit_scalar) < 0 ||
+ crypto_ec_point_mul(sae.tmp->ec, sae.tmp->pwe_ecc, mask,
+ sae.tmp->own_commit_element_ecc) < 0 ||
+ crypto_ec_point_invert(sae.tmp->ec,
+ sae.tmp->own_commit_element_ecc) < 0)
+ goto fail;
+
+ /* Check that output matches the test vector */
+ sae_write_commit(&sae, buf, NULL, pwid);
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
+
+ if (wpabuf_len(buf) != sizeof(local_commit) ||
+ os_memcmp(wpabuf_head(buf), local_commit,
+ sizeof(local_commit)) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in local commit");
+ goto fail;
+ }
+
+ if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
+ NULL) != 0 ||
+ sae_process_commit(&sae) < 0)
+ goto fail;
+
+ if (os_memcmp(kck, sae.tmp->kck, SAE_KCK_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in KCK");
+ goto fail;
+ }
+
+ if (os_memcmp(pmk, sae.pmk, SAE_PMK_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in PMK");
+ goto fail;
+ }
+
+ if (os_memcmp(pmkid, sae.pmkid, SAE_PMKID_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in PMKID");
+ goto fail;
+ }
+
+ buf->used = 0;
+ sae.send_confirm = 1;
+ sae_write_confirm(&sae, buf);
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: Confirm message", buf);
+
+ if (wpabuf_len(buf) != sizeof(local_confirm) ||
+ os_memcmp(wpabuf_head(buf), local_confirm,
+ sizeof(local_confirm)) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in local confirm");
+ goto fail;
+ }
+
+ if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ sae_clear_data(&sae);
+ wpabuf_free(buf);
+ crypto_bignum_deinit(mask, 1);
+ return ret;
+#else /* CONFIG_SAE */
+ return 0;
+#endif /* CONFIG_SAE */
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -200,6 +431,7 @@ int common_module_tests(void)
if (ieee802_11_parse_tests() < 0 ||
gas_tests() < 0 ||
+ sae_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/contrib/wpa/src/common/ctrl_iface_common.c b/contrib/wpa/src/common/ctrl_iface_common.c
new file mode 100644
index 0000000..e26407d
--- /dev/null
+++ b/contrib/wpa/src/common/ctrl_iface_common.c
@@ -0,0 +1,209 @@
+/*
+ * Common hostapd/wpa_supplicant ctrl iface code.
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <netdb.h>
+#include <sys/un.h>
+
+#include "utils/common.h"
+#include "ctrl_iface_common.h"
+
+static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
+ struct sockaddr_storage *b, socklen_t b_len)
+{
+ if (a->ss_family != b->ss_family)
+ return 1;
+
+ switch (a->ss_family) {
+#ifdef CONFIG_CTRL_IFACE_UDP
+ case AF_INET:
+ {
+ struct sockaddr_in *in_a, *in_b;
+
+ in_a = (struct sockaddr_in *) a;
+ in_b = (struct sockaddr_in *) b;
+
+ if (in_a->sin_port != in_b->sin_port)
+ return 1;
+ if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
+ return 1;
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *in6_a, *in6_b;
+
+ in6_a = (struct sockaddr_in6 *) a;
+ in6_b = (struct sockaddr_in6 *) b;
+
+ if (in6_a->sin6_port != in6_b->sin6_port)
+ return 1;
+ if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
+ sizeof(in6_a->sin6_addr)) != 0)
+ return 1;
+ break;
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ case AF_UNIX:
+ {
+ struct sockaddr_un *u_a, *u_b;
+
+ u_a = (struct sockaddr_un *) a;
+ u_b = (struct sockaddr_un *) b;
+
+ if (a_len != b_len ||
+ os_memcmp(u_a->sun_path, u_b->sun_path,
+ a_len - offsetof(struct sockaddr_un, sun_path))
+ != 0)
+ return 1;
+ break;
+ }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
+ socklen_t socklen)
+{
+ switch (sock->ss_family) {
+#ifdef CONFIG_CTRL_IFACE_UDP
+ case AF_INET:
+ case AF_INET6:
+ {
+ char host[NI_MAXHOST] = { 0 };
+ char service[NI_MAXSERV] = { 0 };
+
+ getnameinfo((struct sockaddr *) sock, socklen,
+ host, sizeof(host),
+ service, sizeof(service),
+ NI_NUMERICHOST);
+
+ wpa_printf(level, "%s %s:%s", msg, host, service);
+ break;
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ case AF_UNIX:
+ {
+ char addr_txt[200];
+
+ printf_encode(addr_txt, sizeof(addr_txt),
+ (u8 *) ((struct sockaddr_un *) sock)->sun_path,
+ socklen - offsetof(struct sockaddr_un, sun_path));
+ wpa_printf(level, "%s %s", msg, addr_txt);
+ break;
+ }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+ default:
+ wpa_printf(level, "%s", msg);
+ break;
+ }
+}
+
+
+static int ctrl_set_events(struct wpa_ctrl_dst *dst, const char *input)
+{
+ const char *value;
+ int val;
+
+ if (!input)
+ return 0;
+
+ value = os_strchr(input, '=');
+ if (!value)
+ return -1;
+ value++;
+ val = atoi(value);
+ if (val < 0 || val > 1)
+ return -1;
+
+ if (str_starts(input, "probe_rx_events=")) {
+ if (val)
+ dst->events |= WPA_EVENT_RX_PROBE_REQUEST;
+ else
+ dst->events &= ~WPA_EVENT_RX_PROBE_REQUEST;
+ }
+
+ return 0;
+}
+
+
+int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen, const char *input)
+{
+ struct wpa_ctrl_dst *dst;
+
+ /* Update event registration if already attached */
+ dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+ if (!sockaddr_compare(from, fromlen,
+ &dst->addr, dst->addrlen))
+ return ctrl_set_events(dst, input);
+ }
+
+ /* New attachment */
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ os_memcpy(&dst->addr, from, fromlen);
+ dst->addrlen = fromlen;
+ dst->debug_level = MSG_INFO;
+ ctrl_set_events(dst, input);
+ dl_list_add(ctrl_dst, &dst->list);
+
+ sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
+ return 0;
+}
+
+
+int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+ if (!sockaddr_compare(from, fromlen,
+ &dst->addr, dst->addrlen)) {
+ sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
+ from, fromlen);
+ dl_list_del(&dst->list);
+ os_free(dst);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen, const char *level)
+{
+ struct wpa_ctrl_dst *dst;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+ dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+ if (!sockaddr_compare(from, fromlen,
+ &dst->addr, dst->addrlen)) {
+ sockaddr_print(MSG_DEBUG,
+ "CTRL_IFACE changed monitor level",
+ from, fromlen);
+ dst->debug_level = atoi(level);
+ return 0;
+ }
+ }
+
+ return -1;
+}
diff --git a/contrib/wpa/src/common/ctrl_iface_common.h b/contrib/wpa/src/common/ctrl_iface_common.h
new file mode 100644
index 0000000..85e258e
--- /dev/null
+++ b/contrib/wpa/src/common/ctrl_iface_common.h
@@ -0,0 +1,42 @@
+/*
+ * Common hostapd/wpa_supplicant ctrl iface code.
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef CONTROL_IFACE_COMMON_H
+#define CONTROL_IFACE_COMMON_H
+
+#include "utils/list.h"
+
+/* Events enable bits (wpa_ctrl_dst::events) */
+#define WPA_EVENT_RX_PROBE_REQUEST BIT(0)
+
+/**
+ * struct wpa_ctrl_dst - Data structure of control interface monitors
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant.
+ */
+struct wpa_ctrl_dst {
+ struct dl_list list;
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int debug_level;
+ int errors;
+ u32 events; /* WPA_EVENT_* bitmap */
+};
+
+void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
+ socklen_t socklen);
+
+int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen, const char *input);
+int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen);
+int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen, const char *level);
+
+#endif /* CONTROL_IFACE_COMMON_H */
diff --git a/contrib/wpa/src/common/defs.h b/contrib/wpa/src/common/defs.h
index 6aea375..4faf1c8 100644
--- a/contrib/wpa/src/common/defs.h
+++ b/contrib/wpa/src/common/defs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Common definitions
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -51,16 +51,35 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_KEY_MGMT_OSEN BIT(15)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
+#define WPA_KEY_MGMT_FILS_SHA256 BIT(18)
+#define WPA_KEY_MGMT_FILS_SHA384 BIT(19)
+#define WPA_KEY_MGMT_FT_FILS_SHA256 BIT(20)
+#define WPA_KEY_MGMT_FT_FILS_SHA384 BIT(21)
+#define WPA_KEY_MGMT_OWE BIT(22)
+#define WPA_KEY_MGMT_DPP BIT(23)
+#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
+
+#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
+ WPA_KEY_MGMT_FT_IEEE8021X | \
+ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | \
+ WPA_KEY_MGMT_FT_SAE | \
+ WPA_KEY_MGMT_FT_FILS_SHA256 | \
+ WPA_KEY_MGMT_FT_FILS_SHA384)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
- WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
+ WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -74,9 +93,19 @@ static inline int wpa_key_mgmt_wpa_psk(int akm)
static inline int wpa_key_mgmt_ft(int akm)
{
- return !!(akm & (WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_FT_SAE));
+ return !!(akm & WPA_KEY_MGMT_FT);
+}
+
+static inline int wpa_key_mgmt_only_ft(int akm)
+{
+ int ft = wpa_key_mgmt_ft(akm);
+ akm &= ~WPA_KEY_MGMT_FT;
+ return ft && !akm;
+}
+
+static inline int wpa_key_mgmt_ft_psk(int akm)
+{
+ return !!(akm & WPA_KEY_MGMT_FT_PSK);
}
static inline int wpa_key_mgmt_sae(int akm)
@@ -85,17 +114,32 @@ static inline int wpa_key_mgmt_sae(int akm)
WPA_KEY_MGMT_FT_SAE));
}
+static inline int wpa_key_mgmt_fils(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384));
+}
+
static inline int wpa_key_mgmt_sha256(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_FT_SAE |
WPA_KEY_MGMT_OSEN |
- WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA256));
}
static inline int wpa_key_mgmt_sha384(int akm)
{
- return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
+ return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
+ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
+ WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA384));
}
static inline int wpa_key_mgmt_suite_b(int akm)
@@ -108,7 +152,10 @@ static inline int wpa_key_mgmt_wpa(int akm)
{
return wpa_key_mgmt_wpa_ieee8021x(akm) ||
wpa_key_mgmt_wpa_psk(akm) ||
- wpa_key_mgmt_sae(akm);
+ wpa_key_mgmt_fils(akm) ||
+ wpa_key_mgmt_sae(akm) ||
+ akm == WPA_KEY_MGMT_OWE ||
+ akm == WPA_KEY_MGMT_DPP;
}
static inline int wpa_key_mgmt_wpa_any(int akm)
@@ -132,7 +179,13 @@ static inline int wpa_key_mgmt_cckm(int akm)
#define WPA_AUTH_ALG_LEAP BIT(2)
#define WPA_AUTH_ALG_FT BIT(3)
#define WPA_AUTH_ALG_SAE BIT(4)
+#define WPA_AUTH_ALG_FILS BIT(5)
+#define WPA_AUTH_ALG_FILS_SK_PFS BIT(6)
+static inline int wpa_auth_alg_fils(int alg)
+{
+ return !!(alg & (WPA_AUTH_ALG_FILS | WPA_AUTH_ALG_FILS_SK_PFS));
+}
enum wpa_alg {
WPA_ALG_NONE,
@@ -312,6 +365,7 @@ enum wpa_ctrl_req_type {
WPA_CTRL_REQ_EAP_PASSPHRASE,
WPA_CTRL_REQ_SIM,
WPA_CTRL_REQ_PSK_PASSPHRASE,
+ WPA_CTRL_REQ_EXT_CERT_CHECK,
NUM_WPA_CTRL_REQS
};
@@ -319,13 +373,13 @@ enum wpa_ctrl_req_type {
#define EAP_MAX_METHODS 8
enum mesh_plink_state {
- PLINK_LISTEN = 1,
- PLINK_OPEN_SENT,
- PLINK_OPEN_RCVD,
+ PLINK_IDLE = 1,
+ PLINK_OPN_SNT,
+ PLINK_OPN_RCVD,
PLINK_CNF_RCVD,
PLINK_ESTAB,
PLINK_HOLDING,
- PLINK_BLOCKED,
+ PLINK_BLOCKED, /* not defined in the IEEE 802.11 standard */
};
enum set_band {
@@ -334,4 +388,35 @@ enum set_band {
WPA_SETBAND_2G
};
+enum wpa_radio_work_band {
+ BAND_2_4_GHZ = BIT(0),
+ BAND_5_GHZ = BIT(1),
+ BAND_60_GHZ = BIT(2),
+};
+
+enum beacon_rate_type {
+ BEACON_RATE_LEGACY,
+ BEACON_RATE_HT,
+ BEACON_RATE_VHT
+};
+
+enum eap_proxy_sim_state {
+ SIM_STATE_ERROR,
+};
+
+#define OCE_STA BIT(0)
+#define OCE_STA_CFON BIT(1)
+#define OCE_AP BIT(2)
+
+/* enum chan_width - Channel width definitions */
+enum chan_width {
+ CHAN_WIDTH_20_NOHT,
+ CHAN_WIDTH_20,
+ CHAN_WIDTH_40,
+ CHAN_WIDTH_80,
+ CHAN_WIDTH_80P80,
+ CHAN_WIDTH_160,
+ CHAN_WIDTH_UNKNOWN
+};
+
#endif /* DEFS_H */
diff --git a/contrib/wpa/src/common/dhcp.h b/contrib/wpa/src/common/dhcp.h
new file mode 100644
index 0000000..d28445e
--- /dev/null
+++ b/contrib/wpa/src/common/dhcp.h
@@ -0,0 +1,279 @@
+/*
+ * DHCP definitions
+ * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DHCP_H
+#define DHCP_H
+
+/*
+ * Translate Linux to FreeBSD
+ */
+#define iphdr ip
+#define ihl ip_hl
+#define verson ip_v
+#define tos ip_tos
+#define tot_len ip_len
+#define id ip_id
+#define frag_off ip_off
+#define ttl ip_ttl
+#define protocol ip_p
+#define check ip_sum
+#define saddr ip_src
+#define daddr ip_dst
+
+#include <netinet/ip.h>
+#if __FAVOR_BSD
+#include <netinet/udp.h>
+#else
+#define __FAVOR_BSD 1
+#include <netinet/udp.h>
+#undef __FAVOR_BSD
+#endif
+
+#define DHCP_SERVER_PORT 67
+#define DHCP_CLIENT_PORT 68
+
+struct dhcp_data {
+ u8 op;
+ u8 htype;
+ u8 hlen;
+ u8 hops;
+ be32 xid;
+ be16 secs;
+ be16 flags;
+ be32 client_ip;
+ be32 your_ip;
+ be32 server_ip;
+ be32 relay_ip;
+ u8 hw_addr[16];
+ u8 serv_name[64];
+ u8 boot_file[128];
+} STRUCT_PACKED;
+
+struct bootp_pkt {
+ struct iphdr iph;
+ struct udphdr udph;
+ u8 op;
+ u8 htype;
+ u8 hlen;
+ u8 hops;
+ be32 xid;
+ be16 secs;
+ be16 flags;
+ be32 client_ip;
+ be32 your_ip;
+ be32 server_ip;
+ be32 relay_ip;
+ u8 hw_addr[16];
+ u8 serv_name[64];
+ u8 boot_file[128];
+ u8 exten[312];
+} STRUCT_PACKED;
+
+#define DHCP_MAGIC 0x63825363
+
+/*
+ * IANA DHCP/BOOTP registry
+ * http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
+*/
+enum dhcp_options {
+ DHCP_OPT_PAD = 0,
+ DHCP_OPT_SUBNET_MASK = 1,
+ DHCP_OPT_TIME_OFFSET = 2,
+ DHCP_OPT_ROUTER = 3,
+ DHCP_OPT_TIME_SERVER = 4,
+ DHCP_OPT_NAME_SERVER = 5,
+ DHCP_OPT_DOMAIN_NAME_SERVER = 6,
+ DHCP_OPT_LOG_SERVER = 7,
+ DHCP_OPT_QUOTES_SERVER = 8,
+ DHCP_OPT_LPR_SERVER = 9,
+ DHCP_OPT_IMPRESS_SERVER = 10,
+ DHCP_OPT_RLP_SERVER = 11,
+ DHCP_OPT_HOSTNAME = 12,
+ DHCP_OPT_BOOT_FILE_SIZE = 13,
+ DHCP_OPT_MERIT_DUMP_FILE = 14,
+ DHCP_OPT_DOMAIN_NAME = 15,
+ DHCP_OPT_SWAP_SERVER = 16,
+ DHCP_OPT_ROOT_PATH = 17,
+ DHCP_OPT_EXTENSION_PATH = 18,
+ DHCP_OPT_FORWARD = 19,
+ DHCP_OPT_SRC_RTE = 20,
+ DHCP_OPT_POLICY_FILTER = 21,
+ DHCP_OPT_MAX_DG_ASSEMBLY = 22,
+ DHCP_OPT_DEFAULT_IP_TTL = 23,
+ DHCP_OPT_MTU_TIMEOUT = 24,
+ DHCP_OPT_MTU_PLATEAU = 25,
+ DHCP_OPT_MTU_INTERFACE = 26,
+ DHCP_OPT_ALL_SUBNETS_LOCAL = 27,
+ DHCP_OPT_BROADCAST_ADDRESS = 28,
+ DHCP_OPT_MASK_DISCOVERY = 29,
+ DHCP_OPT_MASK_SUPPLIER = 30,
+ DHCP_OPT_ROUTER_DISCOVERY = 31,
+ DHCP_OPT_ROUTER_SOLICITATION_ADDRESS = 32,
+ DHCP_OPT_STATIC_ROUTE = 33,
+ DHCP_OPT_TRAILERS = 34,
+ DHCP_OPT_ARP_TIMEOUT = 35,
+ DHCP_OPT_ETHERNET = 36,
+ DHCP_OPT_TCP_DEFAULT_TTL = 37,
+ DHCP_OPT_TCP_KEEPALIVE_INTERVAL = 38,
+ DHCP_OPT_TCP_KEEPALIVE_GARBAGE = 39,
+ DHCP_OPT_NIS_DOMAIN = 40,
+ DHCP_OPT_NIS_SERVERS = 41,
+ DHCP_OPT_NTP_SERVERS = 42,
+ DHCP_OPT_VENDOR_SPECIFIC = 43,
+ DHCP_OPT_NETBIOS_NAME_SERVER = 44,
+ DHCP_OPT_NETBIOS_DISTRIBUTION_SERVER = 45,
+ DHCP_OPT_NETBIOS_NODE_TYPE = 46,
+ DHCP_OPT_NETBIOS_SCOPE = 47,
+ DHCP_OPT_FONT_SERVER = 48,
+ DHCP_OPT_DISPLAY_MANAGER = 49,
+ DHCP_OPT_REQUESTED_IP_ADDRESS = 50,
+ DHCP_OPT_IP_ADDRESS_LEASE_TIME = 51,
+ DHCP_OPT_OVERLOAD = 52,
+ DHCP_OPT_MSG_TYPE = 53,
+ DHCP_OPT_SERVER_ID = 54,
+ DHCP_OPT_PARAMETER_REQ_LIST = 55,
+ DHCP_OPT_MESSAGE = 56,
+ DHCP_OPT_MAX_MESSAGE_SIZE = 57,
+ DHCP_OPT_RENEWAL_TIME = 58,
+ DHCP_OPT_REBINDING_TIME = 59,
+ DHCP_OPT_VENDOR_CLASS_ID = 60,
+ DHCP_OPT_CLIENT_ID = 61,
+ DHCP_OPT_NETWARE_IP_DOMAIN = 62,
+ DHCP_OPT_NETWARE_IP_OPTION = 63,
+ DHCP_OPT_NIS_V3_DOMAIN = 64,
+ DHCP_OPT_NIS_V3_SERVERS = 65,
+ DHCP_OPT_TFTP_SERVER_NAME = 66,
+ DHCP_OPT_BOOT_FILE_NAME = 67,
+ DHCP_OPT_HOME_AGENT_ADDRESSES = 68,
+ DHCP_OPT_SMTP_SERVER = 69,
+ DHCP_OPT_POP3_SERVER = 70,
+ DHCP_OPT_NNTP_SERVER = 71,
+ DHCP_OPT_WWW_SERVER = 72,
+ DHCP_OPT_FINGER_SERVER = 73,
+ DHCP_OPT_IRC_SERVER = 74,
+ DHCP_OPT_STREETTALK_SERVER = 75,
+ DHCP_OPT_STDA_SERVER = 76,
+ DHCP_OPT_USER_CLASS = 77,
+ DHCP_OPT_DIRECTORY_AGENT = 78,
+ DHCP_OPT_SERVICE_SCOPE = 79,
+ DHCP_OPT_RAPID_COMMIT = 80,
+ DHCP_OPT_CLIENT_FQDN = 81,
+ DHCP_OPT_RELAY_AGENT_INFO = 82,
+ DHCP_OPT_ISNS = 83,
+ DHCP_OPT_NDS_SERVERS = 85,
+ DHCP_OPT_NDS_TREE_NAME = 86,
+ DHCP_OPT_NDS_CONTEXT = 87,
+ DHCP_OPT_BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 88,
+ DHCP_OPT_BCMCS_CONTROLLER_IPV4_ADDRESS = 89,
+ DHCP_OPT_AUTHENTICATION = 90,
+ DHCP_OPT_CLIENT_LAST_TRANSACTION_TIME = 91,
+ DHCP_OPT_ASSOCIATED_IP = 92,
+ DHCP_OPT_CLIENT_SYSYEM = 93,
+ DHCP_OPT_CLIENT_NDI = 94,
+ DHCP_OPT_LDAP = 95,
+ DHCP_OPT_UUID_GUID = 97,
+ DHCP_OPT_USER_AUTH = 98,
+ DHCP_OPT_GEOCONF_CIVIC = 99,
+ DHCP_OPT_PCODE = 100,
+ DHCP_OPT_TCODE = 101,
+ DHCP_OPT_NETINFO_ADDRESS = 112,
+ DHCP_OPT_NETINFO_TAG = 113,
+ DHCP_OPT_URL = 114,
+ DHCP_OPT_AUTO_CONFIG = 116,
+ DHCP_OPT_NAME_SERVICE_SEARCH = 117,
+ DHCP_OPT_SUBNET_SELECTION = 118,
+ DHCP_OPT_DOMAIN_SEARCH = 119,
+ DHCP_OPT_SIP_SERVERS_DCP = 120,
+ DHCP_OPT_CLASSLESS_STATIC_ROUTE = 121,
+ DHCP_OPT_CCC = 122,
+ DHCP_OPT_GEOCONF = 123,
+ DHCP_OPT_V_I_VENDOR_CLASS = 124,
+ DHCP_OPT_V_I_VENDOR_SPECIFIC_INFO = 125,
+ DHCP_OPT_PANA_AGENT = 136,
+ DHCP_OPT_V4_LOST = 137,
+ DHCP_OPT_CAPWAP_AC_V4 = 138,
+ DHCP_OPT_IPV4_ADDRESS_MOS = 139,
+ DHCP_OPT_IPV4_FQDN_MOS = 140,
+ DHCP_OPT_SIP_UA_CONF = 141,
+ DHCP_OPT_IPV4_ADDRESS_ANDSF = 142,
+ DHCP_OPT_GEOLOC = 144,
+ DHCP_OPT_FORCERENEW_NONCE_CAPABLE = 145,
+ DHCP_OPT_RDNSS_SELECTION = 146,
+ DHCP_OPT_TFTP_SERVER_ADDRESS = 150,
+ DHCP_OPT_STATUS_CODE = 151,
+ DHCP_OPT_BASE_TIME = 152,
+ DHCP_OPT_START_TIME_OF_STATE = 153,
+ DHCP_OPT_QUERY_START_TIME = 154,
+ DHCP_OPT_QUERY_END_TIME = 155,
+ DHCP_OPT_STATE = 156,
+ DHCP_OPT_DATA_SOURCE = 157,
+ DHCP_OPT_V4_PCP_SERVER = 158,
+ DHCP_OPT_V4_PORTPARAMS = 159,
+ DHCP_OPT_CAPTIVE_PORTAL = 160,
+ DHCP_OPT_CONF_FILE = 209,
+ DHCP_OPT_PATH_PREFIX = 210,
+ DHCP_OPT_REBOOT_TIME = 211,
+ DHCP_OPT_6RD = 212,
+ DHCP_OPT_V4_ACCESS_DOMAIN = 213,
+ DHCP_OPT_SUBNET_ALLOCATION = 220,
+ DHCP_OPT_VSS = 221,
+ DHCP_OPT_END = 255
+};
+
+enum dhcp_message_types {
+ DHCPDISCOVER = 1,
+ DHCPOFFER = 2,
+ DHCPREQUEST = 3,
+ DHCPDECLINE = 4,
+ DHCPACK = 5,
+ DHCPNAK = 6,
+ DHCPRELEASE = 7,
+ DHCPINFORM = 8,
+ DHCPFORCERENEW = 9,
+ DHCPLEASEQUERY = 10,
+ DHCPLEASEUNASSIGNED = 11,
+ DHCPLEASEUNKNOWN = 12,
+ DHCPLEASEACTIVE = 13,
+ DHCPBULKLEASEQUERY = 14,
+ DHCPLEASEQUERYDONE = 15,
+ DHCPACTIVELEASEQUERY = 16,
+ DHCPLEASEQUERYSTATUS = 17,
+ DHCPTLS = 18,
+};
+
+enum dhcp_relay_agent_suboptions {
+ DHCP_RELAY_OPT_AGENT_CIRCUIT_ID = 1,
+ DHCP_RELAY_OPT_AGENT_REMOTE_ID = 2,
+ DHCP_RELAY_OPT_DOCSIS_DEVICE_CLASS = 4,
+ DHCP_RELAY_OPT_LINK_SELECTION = 5,
+ DHCP_RELAY_OPT_SUBSCRIBE_ID = 6,
+ DHCP_RELAY_OPT_RADIUS_ATTRIBUTES = 7,
+ DHCP_RELAY_OPT_AUTHENTICATION = 8,
+ DHCP_RELAY_OPT_VEDOR_SPECIFIC = 9,
+ DHCP_RELAY_OPT_RELAY_AGENT_FLAGS = 10,
+ DHCP_RELAY_OPT_SERVER_ID_OVERRIDE = 11,
+ DHCP_RELAY_OPT_RELAY_AGENT_ID = 12,
+ DHCP_RELAY_OPT_ACCESS_TECHNOLOGY_TYPE = 13,
+ DHCP_RELAY_OPT_ACCESS_NETWORK_NAME = 14,
+ DHCP_RELAY_OPT_ACCESS_POINT_NAME = 15,
+ DHCP_RELAY_OPT_ACCESS_POINT_BSSID = 16,
+ DHCP_RELAY_OPT_OPERATOR_ID = 17,
+ DHCP_RELAY_OPT_OPERATOR_REALM = 18,
+ DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION = 151,
+ DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION_CONTROL = 152,
+};
+
+enum access_technology_types {
+ ACCESS_TECHNOLOGY_VIRTUAL = 1,
+ ACCESS_TECHNOLOGY_PPP = 2,
+ ACCESS_TECHNOLOGY_ETHERNET = 3,
+ ACCESS_TECHNOLOGY_WLAN = 4,
+ ACCESS_TECHNOLOGY_WIMAX = 5,
+};
+
+#endif /* DHCP_H */
diff --git a/contrib/wpa/src/common/dpp.c b/contrib/wpa/src/common/dpp.c
new file mode 100644
index 0000000..49de476
--- /dev/null
+++ b/contrib/wpa/src/common/dpp.c
@@ -0,0 +1,8721 @@
+/*
+ * DPP functionality shared between hostapd and wpa_supplicant
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+
+#include "utils/common.h"
+#include "utils/base64.h"
+#include "utils/json.h"
+#include "common/ieee802_11_common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "common/gas.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
+#include "drivers/driver.h"
+#include "dpp.h"
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
+u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+u8 dpp_pkex_ephemeral_key_override[600];
+size_t dpp_pkex_ephemeral_key_override_len = 0;
+u8 dpp_protocol_key_override[600];
+size_t dpp_protocol_key_override_len = 0;
+u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
+size_t dpp_nonce_override_len = 0;
+
+static int dpp_test_gen_invalid_key(struct wpabuf *msg,
+ const struct dpp_curve_params *curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+/* Compatibility wrappers for older versions. */
+
+static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+ sig->r = r;
+ sig->s = s;
+ return 1;
+}
+
+
+static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
+ const BIGNUM **ps)
+{
+ if (pr)
+ *pr = sig->r;
+ if (ps)
+ *ps = sig->s;
+}
+
+#endif
+
+
+struct dpp_global {
+ struct dl_list bootstrap; /* struct dpp_bootstrap_info */
+ struct dl_list configurator; /* struct dpp_configurator */
+};
+
+static const struct dpp_curve_params dpp_curves[] = {
+ /* The mandatory to support and the default NIST P-256 curve needs to
+ * be the first entry on this list. */
+ { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
+ { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
+ { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
+ { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
+ { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
+ { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
+ { NULL, 0, 0, 0, 0, NULL, 0, NULL }
+};
+
+
+/* Role-specific elements for PKEX */
+
+/* NIST P-256 */
+static const u8 pkex_init_x_p256[32] = {
+ 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
+ 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
+ 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
+ 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
+ };
+static const u8 pkex_init_y_p256[32] = {
+ 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
+ 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
+ 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
+ 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
+ };
+static const u8 pkex_resp_x_p256[32] = {
+ 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
+ 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
+ 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
+ 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
+};
+static const u8 pkex_resp_y_p256[32] = {
+ 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
+ 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
+ 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
+ 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
+};
+
+/* NIST P-384 */
+static const u8 pkex_init_x_p384[48] = {
+ 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
+ 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
+ 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
+ 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
+ 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
+ 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
+};
+static const u8 pkex_init_y_p384[48] = {
+ 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
+ 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
+ 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
+ 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
+ 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
+ 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
+};
+static const u8 pkex_resp_x_p384[48] = {
+ 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
+ 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
+ 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
+ 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
+ 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
+ 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
+};
+static const u8 pkex_resp_y_p384[48] = {
+ 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
+ 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
+ 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
+ 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
+ 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
+ 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
+};
+
+/* NIST P-521 */
+static const u8 pkex_init_x_p521[66] = {
+ 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
+ 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
+ 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
+ 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
+ 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
+ 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
+ 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
+ 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
+ 0x97, 0x76
+};
+static const u8 pkex_init_y_p521[66] = {
+ 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
+ 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
+ 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
+ 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
+ 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
+ 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
+ 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
+ 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
+ 0x03, 0xa8
+};
+static const u8 pkex_resp_x_p521[66] = {
+ 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
+ 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
+ 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
+ 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
+ 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
+ 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
+ 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
+ 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
+ 0x84, 0xb4
+};
+static const u8 pkex_resp_y_p521[66] = {
+ 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
+ 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
+ 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
+ 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
+ 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
+ 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
+ 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
+ 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
+ 0xce, 0xe1
+};
+
+/* Brainpool P-256r1 */
+static const u8 pkex_init_x_bp_p256r1[32] = {
+ 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
+ 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
+ 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
+ 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
+};
+static const u8 pkex_init_y_bp_p256r1[32] = {
+ 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
+ 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
+ 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
+ 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
+};
+static const u8 pkex_resp_x_bp_p256r1[32] = {
+ 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
+ 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
+ 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
+ 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
+};
+static const u8 pkex_resp_y_bp_p256r1[32] = {
+ 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
+ 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
+ 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
+ 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
+};
+
+/* Brainpool P-384r1 */
+static const u8 pkex_init_x_bp_p384r1[48] = {
+ 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
+ 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
+ 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
+ 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
+ 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
+ 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
+};
+static const u8 pkex_init_y_bp_p384r1[48] = {
+ 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
+ 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
+ 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
+ 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
+ 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
+ 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
+};
+static const u8 pkex_resp_x_bp_p384r1[48] = {
+ 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
+ 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
+ 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
+ 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
+ 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
+ 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
+};
+static const u8 pkex_resp_y_bp_p384r1[48] = {
+ 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
+ 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
+ 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
+ 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
+ 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
+ 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
+};
+
+/* Brainpool P-512r1 */
+static const u8 pkex_init_x_bp_p512r1[64] = {
+ 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
+ 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
+ 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
+ 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
+ 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
+ 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
+ 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
+ 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
+};
+static const u8 pkex_init_y_bp_p512r1[64] = {
+ 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
+ 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
+ 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
+ 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
+ 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
+ 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
+ 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
+ 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
+};
+static const u8 pkex_resp_x_bp_p512r1[64] = {
+ 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
+ 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
+ 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
+ 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
+ 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
+ 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
+ 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
+ 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
+};
+static const u8 pkex_resp_y_bp_p512r1[64] = {
+ 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
+ 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
+ 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
+ 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
+ 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
+ 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
+ 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
+ 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
+};
+
+
+static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
+ const EC_POINT *point)
+{
+ BIGNUM *x, *y;
+ BN_CTX *ctx;
+ char *x_str = NULL, *y_str = NULL;
+
+ if (!wpa_debug_show_keys)
+ return;
+
+ ctx = BN_CTX_new();
+ x = BN_new();
+ y = BN_new();
+ if (!ctx || !x || !y ||
+ EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
+ goto fail;
+
+ x_str = BN_bn2hex(x);
+ y_str = BN_bn2hex(y);
+ if (!x_str || !y_str)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
+
+fail:
+ OPENSSL_free(x_str);
+ OPENSSL_free(y_str);
+ BN_free(x);
+ BN_free(y);
+ BN_CTX_free(ctx);
+}
+
+
+static int dpp_hash_vector(const struct dpp_curve_params *curve,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ if (curve->hash_len == 32)
+ return sha256_vector(num_elem, addr, len, mac);
+ if (curve->hash_len == 48)
+ return sha384_vector(num_elem, addr, len, mac);
+ if (curve->hash_len == 64)
+ return sha512_vector(num_elem, addr, len, mac);
+ return -1;
+}
+
+
+static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
+ const char *label, u8 *out, size_t outlen)
+{
+ if (hash_len == 32)
+ return hmac_sha256_kdf(secret, secret_len, NULL,
+ (const u8 *) label, os_strlen(label),
+ out, outlen);
+ if (hash_len == 48)
+ return hmac_sha384_kdf(secret, secret_len, NULL,
+ (const u8 *) label, os_strlen(label),
+ out, outlen);
+ if (hash_len == 64)
+ return hmac_sha512_kdf(secret, secret_len, NULL,
+ (const u8 *) label, os_strlen(label),
+ out, outlen);
+ return -1;
+}
+
+
+static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac)
+{
+ if (hash_len == 32)
+ return hmac_sha256_vector(key, key_len, num_elem, addr, len,
+ mac);
+ if (hash_len == 48)
+ return hmac_sha384_vector(key, key_len, num_elem, addr, len,
+ mac);
+ if (hash_len == 64)
+ return hmac_sha512_vector(key, key_len, num_elem, addr, len,
+ mac);
+ return -1;
+}
+
+
+static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
+ const u8 *data, size_t data_len, u8 *mac)
+{
+ if (hash_len == 32)
+ return hmac_sha256(key, key_len, data, data_len, mac);
+ if (hash_len == 48)
+ return hmac_sha384(key, key_len, data, data_len, mac);
+ if (hash_len == 64)
+ return hmac_sha512(key, key_len, data, data_len, mac);
+ return -1;
+}
+
+
+static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
+{
+ int num_bytes, offset;
+
+ num_bytes = BN_num_bytes(bn);
+ if ((size_t) num_bytes > len)
+ return -1;
+ offset = len - num_bytes;
+ os_memset(pos, 0, offset);
+ BN_bn2bin(bn, pos + offset);
+ return 0;
+}
+
+
+static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
+{
+ int len, res;
+ EC_KEY *eckey;
+ struct wpabuf *buf;
+ unsigned char *pos;
+
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
+ if (!eckey)
+ return NULL;
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
+ len = i2o_ECPublicKey(eckey, NULL);
+ if (len <= 0) {
+ wpa_printf(MSG_ERROR,
+ "DDP: Failed to determine public key encoding length");
+ EC_KEY_free(eckey);
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(len);
+ if (!buf) {
+ EC_KEY_free(eckey);
+ return NULL;
+ }
+
+ pos = wpabuf_put(buf, len);
+ res = i2o_ECPublicKey(eckey, &pos);
+ EC_KEY_free(eckey);
+ if (res != len) {
+ wpa_printf(MSG_ERROR,
+ "DDP: Failed to encode public key (res=%d/%d)",
+ res, len);
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ if (!prefix) {
+ /* Remove 0x04 prefix to match DPP definition */
+ pos = wpabuf_mhead(buf);
+ os_memmove(pos, pos + 1, len - 1);
+ buf->used--;
+ }
+
+ return buf;
+}
+
+
+static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
+ const u8 *buf_x, const u8 *buf_y,
+ size_t len)
+{
+ EC_KEY *eckey = NULL;
+ BN_CTX *ctx;
+ EC_POINT *point = NULL;
+ BIGNUM *x = NULL, *y = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ ctx = BN_CTX_new();
+ if (!ctx) {
+ wpa_printf(MSG_ERROR, "DPP: Out of memory");
+ return NULL;
+ }
+
+ point = EC_POINT_new(group);
+ x = BN_bin2bn(buf_x, len, NULL);
+ y = BN_bin2bn(buf_y, len, NULL);
+ if (!point || !x || !y) {
+ wpa_printf(MSG_ERROR, "DPP: Out of memory");
+ goto fail;
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (!EC_POINT_is_on_curve(group, point, ctx) ||
+ EC_POINT_is_at_infinity(group, point)) {
+ wpa_printf(MSG_ERROR, "DPP: Invalid point");
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
+
+ eckey = EC_KEY_new();
+ if (!eckey ||
+ EC_KEY_set_group(eckey, group) != 1 ||
+ EC_KEY_set_public_key(eckey, point) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to set EC_KEY: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
+ goto fail;
+ }
+
+out:
+ BN_free(x);
+ BN_free(y);
+ EC_KEY_free(eckey);
+ EC_POINT_free(point);
+ BN_CTX_free(ctx);
+ return pkey;
+fail:
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto out;
+}
+
+
+static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
+ const u8 *buf, size_t len)
+{
+ EC_KEY *eckey;
+ const EC_GROUP *group;
+ EVP_PKEY *pkey = NULL;
+
+ if (len & 1)
+ return NULL;
+
+ eckey = EVP_PKEY_get1_EC_KEY(group_key);
+ if (!eckey) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Could not get EC_KEY from group_key");
+ return NULL;
+ }
+
+ group = EC_KEY_get0_group(eckey);
+ if (group)
+ pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
+ len / 2);
+ else
+ wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
+
+ EC_KEY_free(eckey);
+ return pkey;
+}
+
+
+static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
+{
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
+}
+
+
+struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
+ size_t len)
+{
+ struct wpabuf *msg;
+
+ msg = wpabuf_alloc(8 + len);
+ if (!msg)
+ return NULL;
+ wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
+ wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
+ wpabuf_put_be24(msg, OUI_WFA);
+ wpabuf_put_u8(msg, DPP_OUI_TYPE);
+ wpabuf_put_u8(msg, 1); /* Crypto Suite */
+ wpabuf_put_u8(msg, type);
+ return msg;
+}
+
+
+const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
+{
+ u16 id, alen;
+ const u8 *pos = buf, *end = buf + len;
+
+ while (end - pos >= 4) {
+ id = WPA_GET_LE16(pos);
+ pos += 2;
+ alen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (alen > end - pos)
+ return NULL;
+ if (id == req_id) {
+ *ret_len = alen;
+ return pos;
+ }
+ pos += alen;
+ }
+
+ return NULL;
+}
+
+
+int dpp_check_attrs(const u8 *buf, size_t len)
+{
+ const u8 *pos, *end;
+ int wrapped_data = 0;
+
+ pos = buf;
+ end = buf + len;
+ while (end - pos >= 4) {
+ u16 id, alen;
+
+ id = WPA_GET_LE16(pos);
+ pos += 2;
+ alen = WPA_GET_LE16(pos);
+ pos += 2;
+ wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
+ id, alen);
+ if (alen > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Truncated message - not enough room for the attribute - dropped");
+ return -1;
+ }
+ if (wrapped_data) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: An unexpected attribute included after the Wrapped Data attribute");
+ return -1;
+ }
+ if (id == DPP_ATTR_WRAPPED_DATA)
+ wrapped_data = 1;
+ pos += alen;
+ }
+
+ if (end != pos) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected octets (%d) after the last attribute",
+ (int) (end - pos));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
+{
+ if (!info)
+ return;
+ os_free(info->uri);
+ os_free(info->info);
+ EVP_PKEY_free(info->pubkey);
+ os_free(info);
+}
+
+
+const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
+{
+ switch (type) {
+ case DPP_BOOTSTRAP_QR_CODE:
+ return "QRCODE";
+ case DPP_BOOTSTRAP_PKEX:
+ return "PKEX";
+ }
+ return "??";
+}
+
+
+static int dpp_uri_valid_info(const char *info)
+{
+ while (*info) {
+ unsigned char val = *info++;
+
+ if (val < 0x20 || val > 0x7e || val == 0x3b)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
+{
+ bi->uri = os_strdup(uri);
+ return bi->uri ? 0 : -1;
+}
+
+
+int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
+ const char *chan_list)
+{
+ const char *pos = chan_list;
+ int opclass, channel, freq;
+
+ while (pos && *pos && *pos != ';') {
+ opclass = atoi(pos);
+ if (opclass <= 0)
+ goto fail;
+ pos = os_strchr(pos, '/');
+ if (!pos)
+ goto fail;
+ pos++;
+ channel = atoi(pos);
+ if (channel <= 0)
+ goto fail;
+ while (*pos >= '0' && *pos <= '9')
+ pos++;
+ freq = ieee80211_chan_to_freq(NULL, opclass, channel);
+ wpa_printf(MSG_DEBUG,
+ "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
+ opclass, channel, freq);
+ if (freq < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
+ opclass, channel);
+ } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Too many channels in URI channel-list - ignore list");
+ bi->num_freq = 0;
+ break;
+ } else {
+ bi->freq[bi->num_freq++] = freq;
+ }
+
+ if (*pos == ';' || *pos == '\0')
+ break;
+ if (*pos != ',')
+ goto fail;
+ pos++;
+ }
+
+ return 0;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
+ return -1;
+}
+
+
+int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
+{
+ if (!mac)
+ return 0;
+
+ if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
+
+ return 0;
+}
+
+
+int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
+{
+ const char *end;
+
+ if (!info)
+ return 0;
+
+ end = os_strchr(info, ';');
+ if (!end)
+ end = info + os_strlen(info);
+ bi->info = os_malloc(end - info + 1);
+ if (!bi->info)
+ return -1;
+ os_memcpy(bi->info, info, end - info);
+ bi->info[end - info] = '\0';
+ wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
+ if (!dpp_uri_valid_info(bi->info)) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static const struct dpp_curve_params *
+dpp_get_curve_oid(const ASN1_OBJECT *poid)
+{
+ ASN1_OBJECT *oid;
+ int i;
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ oid = OBJ_txt2obj(dpp_curves[i].name, 0);
+ if (oid && OBJ_cmp(poid, oid) == 0)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
+{
+ int i, tmp;
+
+ if (!nid)
+ return NULL;
+ for (i = 0; dpp_curves[i].name; i++) {
+ tmp = OBJ_txt2nid(dpp_curves[i].name);
+ if (tmp == nid)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
+{
+ const char *end;
+ u8 *data;
+ size_t data_len;
+ EVP_PKEY *pkey;
+ const unsigned char *p;
+ int res;
+ X509_PUBKEY *pub = NULL;
+ ASN1_OBJECT *ppkalg;
+ const unsigned char *pk;
+ int ppklen;
+ X509_ALGOR *pa;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20800000L)
+ ASN1_OBJECT *pa_oid;
+#else
+ const ASN1_OBJECT *pa_oid;
+#endif
+ const void *pval;
+ int ptype;
+ const ASN1_OBJECT *poid;
+ char buf[100];
+
+ end = os_strchr(info, ';');
+ if (!end)
+ return -1;
+
+ data = base64_decode((const unsigned char *) info, end - info,
+ &data_len);
+ if (!data) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Invalid base64 encoding on URI public-key");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
+ data, data_len);
+
+ if (sha256_vector(1, (const u8 **) &data, &data_len,
+ bi->pubkey_hash) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+ os_free(data);
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
+ bi->pubkey_hash, SHA256_MAC_LEN);
+
+ /* DER encoded ASN.1 SubjectPublicKeyInfo
+ *
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ *
+ * subjectPublicKey = compressed format public key per ANSI X9.63
+ * algorithm = ecPublicKey (1.2.840.10045.2.1)
+ * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
+ * prime256v1 (1.2.840.10045.3.1.7)
+ */
+
+ p = data;
+ pkey = d2i_PUBKEY(NULL, &p, data_len);
+ os_free(data);
+
+ if (!pkey) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
+ return -1;
+ }
+
+ if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: SubjectPublicKeyInfo does not describe an EC key");
+ EVP_PKEY_free(pkey);
+ return -1;
+ }
+
+ res = X509_PUBKEY_set(&pub, pkey);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
+ goto fail;
+ }
+
+ res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not extract SubjectPublicKeyInfo parameters");
+ goto fail;
+ }
+ res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
+ if (res < 0 || (size_t) res >= sizeof(buf)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not extract SubjectPublicKeyInfo algorithm");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
+ if (os_strcmp(buf, "id-ecPublicKey") != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported SubjectPublicKeyInfo algorithm");
+ goto fail;
+ }
+
+ X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
+ if (ptype != V_ASN1_OBJECT) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
+ goto fail;
+ }
+ poid = pval;
+ res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
+ if (res < 0 || (size_t) res >= sizeof(buf)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
+ bi->curve = dpp_get_curve_oid(poid);
+ if (!bi->curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
+ buf);
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
+
+ X509_PUBKEY_free(pub);
+ bi->pubkey = pkey;
+ return 0;
+fail:
+ X509_PUBKEY_free(pub);
+ EVP_PKEY_free(pkey);
+ return -1;
+}
+
+
+static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
+{
+ const char *pos = uri;
+ const char *end;
+ const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
+ struct dpp_bootstrap_info *bi;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
+
+ if (os_strncmp(pos, "DPP:", 4) != 0) {
+ wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
+ return NULL;
+ }
+ pos += 4;
+
+ for (;;) {
+ end = os_strchr(pos, ';');
+ if (!end)
+ break;
+
+ if (end == pos) {
+ /* Handle terminating ";;" and ignore unexpected ";"
+ * for parsing robustness. */
+ pos++;
+ continue;
+ }
+
+ if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
+ chan_list = pos + 2;
+ else if (pos[0] == 'M' && pos[1] == ':' && !mac)
+ mac = pos + 2;
+ else if (pos[0] == 'I' && pos[1] == ':' && !info)
+ info = pos + 2;
+ else if (pos[0] == 'K' && pos[1] == ':' && !pk)
+ pk = pos + 2;
+ else
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "DPP: Ignore unrecognized URI parameter",
+ pos, end - pos);
+ pos = end + 1;
+ }
+
+ if (!pk) {
+ wpa_printf(MSG_INFO, "DPP: URI missing public-key");
+ return NULL;
+ }
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ return NULL;
+
+ if (dpp_clone_uri(bi, uri) < 0 ||
+ dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
+ dpp_parse_uri_mac(bi, mac) < 0 ||
+ dpp_parse_uri_info(bi, info) < 0 ||
+ dpp_parse_uri_pk(bi, pk) < 0) {
+ dpp_bootstrap_info_free(bi);
+ bi = NULL;
+ }
+
+ return bi;
+}
+
+
+struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_parse_uri(uri);
+ if (bi)
+ bi->type = DPP_BOOTSTRAP_QR_CODE;
+ return bi;
+}
+
+
+static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
+{
+ EC_KEY *eckey;
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+ unsigned char *der = NULL;
+ int der_len;
+ const EC_GROUP *group;
+ const EC_POINT *point;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ EVP_PKEY_print_private(out, key, 0, NULL);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
+ }
+ os_free(txt);
+ }
+ BIO_free(out);
+
+ eckey = EVP_PKEY_get1_EC_KEY(key);
+ if (!eckey)
+ return;
+
+ group = EC_KEY_get0_group(eckey);
+ point = EC_KEY_get0_public_key(eckey);
+ if (group && point)
+ dpp_debug_print_point(title, group, point);
+
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len > 0)
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
+ OPENSSL_free(der);
+ if (der_len <= 0) {
+ der = NULL;
+ der_len = i2d_EC_PUBKEY(eckey, &der);
+ if (der_len > 0)
+ wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
+ OPENSSL_free(der);
+ }
+
+ EC_KEY_free(eckey);
+}
+
+
+static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
+{
+ EVP_PKEY_CTX *kctx = NULL;
+ EC_KEY *ec_params;
+ EVP_PKEY *params = NULL, *key = NULL;
+ int nid;
+
+ wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
+
+ nid = OBJ_txt2nid(curve->name);
+ if (nid == NID_undef) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
+ return NULL;
+ }
+
+ ec_params = EC_KEY_new_by_curve_name(nid);
+ if (!ec_params) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate EC_KEY parameters");
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
+ params = EVP_PKEY_new();
+ if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate EVP_PKEY parameters");
+ goto fail;
+ }
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (!kctx ||
+ EVP_PKEY_keygen_init(kctx) != 1 ||
+ EVP_PKEY_keygen(kctx, &key) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
+ goto fail;
+ }
+
+ if (wpa_debug_show_keys)
+ dpp_debug_print_key("Own generated key", key);
+
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+ return key;
+fail:
+ EVP_PKEY_CTX_free(kctx);
+ EVP_PKEY_free(params);
+ return NULL;
+}
+
+
+static const struct dpp_curve_params *
+dpp_get_curve_name(const char *name)
+{
+ int i;
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ if (os_strcmp(name, dpp_curves[i].name) == 0 ||
+ (dpp_curves[i].jwk_crv &&
+ os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+static const struct dpp_curve_params *
+dpp_get_curve_jwk_crv(const char *name)
+{
+ int i;
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ if (dpp_curves[i].jwk_crv &&
+ os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
+static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
+ const u8 *privkey, size_t privkey_len)
+{
+ EVP_PKEY *pkey;
+ EC_KEY *eckey;
+ const EC_GROUP *group;
+ int nid;
+
+ pkey = EVP_PKEY_new();
+ if (!pkey)
+ return NULL;
+ eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
+ if (!eckey) {
+ wpa_printf(MSG_INFO,
+ "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+ group = EC_KEY_get0_group(eckey);
+ if (!group) {
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+ nid = EC_GROUP_get_curve_name(group);
+ *curve = dpp_get_curve_nid(nid);
+ if (!*curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported curve (nid=%d) in pre-assigned key",
+ nid);
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+
+ if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+ return pkey;
+}
+
+
+typedef struct {
+ /* AlgorithmIdentifier ecPublicKey with optional parameters present
+ * as an OID identifying the curve */
+ X509_ALGOR *alg;
+ /* Compressed format public key per ANSI X9.63 */
+ ASN1_BIT_STRING *pub_key;
+} DPP_BOOTSTRAPPING_KEY;
+
+ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
+ ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
+ ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
+
+IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
+
+
+static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
+{
+ unsigned char *der = NULL;
+ int der_len;
+ EC_KEY *eckey;
+ struct wpabuf *ret = NULL;
+ size_t len;
+ const EC_GROUP *group;
+ const EC_POINT *point;
+ BN_CTX *ctx;
+ DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
+ int nid;
+
+ ctx = BN_CTX_new();
+ eckey = EVP_PKEY_get1_EC_KEY(key);
+ if (!ctx || !eckey)
+ goto fail;
+
+ group = EC_KEY_get0_group(eckey);
+ point = EC_KEY_get0_public_key(eckey);
+ if (!group || !point)
+ goto fail;
+ dpp_debug_print_point("DPP: bootstrap public key", group, point);
+ nid = EC_GROUP_get_curve_name(group);
+
+ bootstrap = DPP_BOOTSTRAPPING_KEY_new();
+ if (!bootstrap ||
+ X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
+ V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
+ goto fail;
+
+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+ NULL, 0, ctx);
+ if (len == 0)
+ goto fail;
+
+ der = OPENSSL_malloc(len);
+ if (!der)
+ goto fail;
+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+ der, len, ctx);
+
+ OPENSSL_free(bootstrap->pub_key->data);
+ bootstrap->pub_key->data = der;
+ der = NULL;
+ bootstrap->pub_key->length = len;
+ /* No unused bits */
+ bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+ der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR,
+ "DDP: Failed to build DER encoded public key");
+ goto fail;
+ }
+
+ ret = wpabuf_alloc_copy(der, der_len);
+fail:
+ DPP_BOOTSTRAPPING_KEY_free(bootstrap);
+ OPENSSL_free(der);
+ EC_KEY_free(eckey);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+
+int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
+{
+ struct wpabuf *der;
+ int res;
+ const u8 *addr[1];
+ size_t len[1];
+
+ der = dpp_bootstrap_key_der(bi->pubkey);
+ if (!der)
+ return -1;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
+ der);
+
+ addr[0] = wpabuf_head(der);
+ len[0] = wpabuf_len(der);
+ res = sha256_vector(1, addr, len, bi->pubkey_hash);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+ else
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
+ SHA256_MAC_LEN);
+ wpabuf_free(der);
+ return res;
+}
+
+
+char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
+ const u8 *privkey, size_t privkey_len)
+{
+ unsigned char *base64 = NULL;
+ char *pos, *end;
+ size_t len;
+ struct wpabuf *der = NULL;
+ const u8 *addr[1];
+ int res;
+
+ if (!curve) {
+ bi->curve = &dpp_curves[0];
+ } else {
+ bi->curve = dpp_get_curve_name(curve);
+ if (!bi->curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
+ curve);
+ return NULL;
+ }
+ }
+ if (privkey)
+ bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
+ else
+ bi->pubkey = dpp_gen_keypair(bi->curve);
+ if (!bi->pubkey)
+ goto fail;
+ bi->own = 1;
+
+ der = dpp_bootstrap_key_der(bi->pubkey);
+ if (!der)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
+ der);
+
+ addr[0] = wpabuf_head(der);
+ len = wpabuf_len(der);
+ res = sha256_vector(1, addr, &len, bi->pubkey_hash);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
+ SHA256_MAC_LEN);
+
+ base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
+ wpabuf_free(der);
+ der = NULL;
+ if (!base64)
+ goto fail;
+ pos = (char *) base64;
+ end = pos + len;
+ for (;;) {
+ pos = os_strchr(pos, '\n');
+ if (!pos)
+ break;
+ os_memmove(pos, pos + 1, end - pos);
+ }
+ return (char *) base64;
+fail:
+ os_free(base64);
+ wpabuf_free(der);
+ return NULL;
+}
+
+
+static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
+ unsigned int hash_len)
+{
+ u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
+ const char *info = "first intermediate key";
+ int res;
+
+ /* k1 = HKDF(<>, "first intermediate key", M.x) */
+
+ /* HKDF-Extract(<>, M.x) */
+ os_memset(salt, 0, hash_len);
+ if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
+ prk, hash_len);
+
+ /* HKDF-Expand(PRK, info, L) */
+ res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
+ k1, hash_len);
+ return 0;
+}
+
+
+static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
+ unsigned int hash_len)
+{
+ u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
+ const char *info = "second intermediate key";
+ int res;
+
+ /* k2 = HKDF(<>, "second intermediate key", N.x) */
+
+ /* HKDF-Extract(<>, N.x) */
+ os_memset(salt, 0, hash_len);
+ res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
+ if (res < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
+ prk, hash_len);
+
+ /* HKDF-Expand(PRK, info, L) */
+ res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
+ k2, hash_len);
+ return 0;
+}
+
+
+static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
+ unsigned int hash_len)
+{
+ size_t nonce_len;
+ u8 nonces[2 * DPP_MAX_NONCE_LEN];
+ const char *info_ke = "DPP Key";
+ u8 prk[DPP_MAX_HASH_LEN];
+ int res;
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem = 0;
+
+ if (!auth->Mx_len || !auth->Nx_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Mx/Nx not available - cannot derive ke");
+ return -1;
+ }
+
+ /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
+
+ /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
+ nonce_len = auth->curve->nonce_len;
+ os_memcpy(nonces, auth->i_nonce, nonce_len);
+ os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
+ addr[num_elem] = auth->Mx;
+ len[num_elem] = auth->Mx_len;
+ num_elem++;
+ addr[num_elem] = auth->Nx;
+ len[num_elem] = auth->Nx_len;
+ num_elem++;
+ if (auth->peer_bi && auth->own_bi) {
+ if (!auth->Lx_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Lx not available - cannot derive ke");
+ return -1;
+ }
+ addr[num_elem] = auth->Lx;
+ len[num_elem] = auth->secret_len;
+ num_elem++;
+ }
+ res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
+ num_elem, addr, len, prk);
+ if (res < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
+ prk, hash_len);
+
+ /* HKDF-Expand(PRK, info, L) */
+ res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
+ ke, hash_len);
+ return 0;
+}
+
+
+static void dpp_build_attr_status(struct wpabuf *msg,
+ enum dpp_status_error status)
+{
+ wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
+ wpabuf_put_le16(msg, DPP_ATTR_STATUS);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, status);
+}
+
+
+static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
+ const u8 *hash)
+{
+ if (hash) {
+ wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
+ wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
+ wpabuf_put_le16(msg, SHA256_MAC_LEN);
+ wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
+ }
+}
+
+
+static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
+ const u8 *hash)
+{
+ if (hash) {
+ wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
+ wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
+ wpabuf_put_le16(msg, SHA256_MAC_LEN);
+ wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
+ }
+}
+
+
+static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
+ const struct wpabuf *pi,
+ size_t nonce_len,
+ const u8 *r_pubkey_hash,
+ const u8 *i_pubkey_hash,
+ unsigned int neg_freq)
+{
+ struct wpabuf *msg;
+ u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
+ u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
+ u8 *pos;
+ const u8 *addr[2];
+ size_t len[2], siv_len, attr_len;
+ u8 *attr_start, *attr_end;
+
+ /* Build DPP Authentication Request frame attributes */
+ attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
+ 4 + sizeof(wrapped_data);
+ if (neg_freq > 0)
+ attr_len += 4 + 2;
+#ifdef CONFIG_DPP2
+ attr_len += 5;
+#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
+ if (!msg)
+ return NULL;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+ /* Initiator Bootstrapping Key Hash */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+ /* Initiator Protocol Key */
+ if (pi) {
+ wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
+ wpabuf_put_le16(msg, wpabuf_len(pi));
+ wpabuf_put_buf(msg, pi);
+ }
+
+ /* Channel */
+ if (neg_freq > 0) {
+ u8 op_class, channel;
+
+ if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
+ &channel) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported negotiation frequency request: %d",
+ neg_freq);
+ wpabuf_free(msg);
+ return NULL;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_u8(msg, op_class);
+ wpabuf_put_u8(msg, channel);
+ }
+
+#ifdef CONFIG_DPP2
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, 2);
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Wrapped data ({I-nonce, I-capabilities}k1) */
+ pos = clear;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ goto skip_i_nonce;
+ }
+ if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len - 1);
+ pos += 2;
+ os_memcpy(pos, auth->i_nonce, nonce_len - 1);
+ pos += nonce_len - 1;
+ goto skip_i_nonce;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, auth->i_nonce, nonce_len);
+ pos += nonce_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_i_nonce:
+ if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
+ goto skip_i_capab;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-capabilities */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
+ pos += 2;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ auth->i_capab = auth->allowed_roles;
+ *pos++ = auth->i_capab;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
+ pos[-1] = 0;
+ }
+skip_i_capab:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ attr_end = wpabuf_put(msg, 0);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ siv_len = pos - clear;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
+ if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
+ 2, addr, len, wrapped_data) < 0) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+ siv_len += AES_BLOCK_SIZE;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, siv_len);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, siv_len);
+ wpabuf_put_data(msg, wrapped_data, siv_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Authentication Request frame attributes", msg);
+
+ return msg;
+}
+
+
+static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
+ enum dpp_status_error status,
+ const struct wpabuf *pr,
+ size_t nonce_len,
+ const u8 *r_pubkey_hash,
+ const u8 *i_pubkey_hash,
+ const u8 *r_nonce, const u8 *i_nonce,
+ const u8 *wrapped_r_auth,
+ size_t wrapped_r_auth_len,
+ const u8 *siv_key)
+{
+ struct wpabuf *msg;
+#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
+ 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
+ u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
+ u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
+ const u8 *addr[2];
+ size_t len[2], siv_len, attr_len;
+ u8 *attr_start, *attr_end, *pos;
+
+ auth->waiting_auth_conf = 1;
+ auth->auth_resp_tries = 0;
+
+ /* Build DPP Authentication Response frame attributes */
+ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
+ 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
+#ifdef CONFIG_DPP2
+ attr_len += 5;
+#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
+ if (!msg)
+ return NULL;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ /* DPP Status */
+ if (status != 255)
+ dpp_build_attr_status(msg, status);
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+ /* Initiator Bootstrapping Key Hash (mutual authentication) */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+ /* Responder Protocol Key */
+ if (pr) {
+ wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
+ wpabuf_put_le16(msg, wpabuf_len(pr));
+ wpabuf_put_buf(msg, pr);
+ }
+
+#ifdef CONFIG_DPP2
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, 2);
+#endif /* CONFIG_DPP2 */
+
+ attr_end = wpabuf_put(msg, 0);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
+ pos = clear;
+
+ if (r_nonce) {
+ /* R-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, r_nonce, nonce_len);
+ pos += nonce_len;
+ }
+
+ if (i_nonce) {
+ /* I-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, i_nonce, nonce_len);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
+ pos[nonce_len / 2] ^= 0x01;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ pos += nonce_len;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
+ goto skip_r_capab;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* R-capabilities */
+ WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
+ pos += 2;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
+ DPP_CAPAB_ENROLLEE;
+ *pos++ = auth->r_capab;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
+ pos[-1] = 0;
+ } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - incompatible R-capabilities");
+ if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
+ (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
+ pos[-1] = 0;
+ else
+ pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
+ DPP_CAPAB_CONFIGURATOR;
+ }
+skip_r_capab:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wrapped_r_auth) {
+ /* {R-auth}ke */
+ WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
+ pos += 2;
+ WPA_PUT_LE16(pos, wrapped_r_auth_len);
+ pos += 2;
+ os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
+ pos += wrapped_r_auth_len;
+ }
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ siv_len = pos - clear;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
+ if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
+ 2, addr, len, wrapped_data) < 0) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+ siv_len += AES_BLOCK_SIZE;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, siv_len);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, siv_len);
+ wpabuf_put_data(msg, wrapped_data, siv_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Authentication Response frame attributes", msg);
+ return msg;
+}
+
+
+static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
+ u16 num_modes, unsigned int freq)
+{
+ u16 m;
+ int c, flag;
+
+ if (!own_modes || !num_modes)
+ return 1;
+
+ for (m = 0; m < num_modes; m++) {
+ for (c = 0; c < own_modes[m].num_channels; c++) {
+ if ((unsigned int) own_modes[m].channels[c].freq !=
+ freq)
+ continue;
+ flag = own_modes[m].channels[c].flag;
+ if (!(flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR)))
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
+ return 0;
+}
+
+
+static int freq_included(const unsigned int freqs[], unsigned int num,
+ unsigned int freq)
+{
+ while (num > 0) {
+ if (freqs[--num] == freq)
+ return 1;
+ }
+ return 0;
+}
+
+
+static void freq_to_start(unsigned int freqs[], unsigned int num,
+ unsigned int freq)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++) {
+ if (freqs[i] == freq)
+ break;
+ }
+ if (i == 0 || i >= num)
+ return;
+ os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
+ freqs[0] = freq;
+}
+
+
+static int dpp_channel_intersect(struct dpp_authentication *auth,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
+ unsigned int i, freq;
+
+ for (i = 0; i < peer_bi->num_freq; i++) {
+ freq = peer_bi->freq[i];
+ if (freq_included(auth->freq, auth->num_freq, freq))
+ continue;
+ if (dpp_channel_ok_init(own_modes, num_modes, freq))
+ auth->freq[auth->num_freq++] = freq;
+ }
+ if (!auth->num_freq) {
+ wpa_printf(MSG_INFO,
+ "DPP: No available channels for initiating DPP Authentication");
+ return -1;
+ }
+ auth->curr_freq = auth->freq[0];
+ return 0;
+}
+
+
+static int dpp_channel_local_list(struct dpp_authentication *auth,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ u16 m;
+ int c, flag;
+ unsigned int freq;
+
+ auth->num_freq = 0;
+
+ if (!own_modes || !num_modes) {
+ auth->freq[0] = 2412;
+ auth->freq[1] = 2437;
+ auth->freq[2] = 2462;
+ auth->num_freq = 3;
+ return 0;
+ }
+
+ for (m = 0; m < num_modes; m++) {
+ for (c = 0; c < own_modes[m].num_channels; c++) {
+ freq = own_modes[m].channels[c].freq;
+ flag = own_modes[m].channels[c].flag;
+ if (flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (freq_included(auth->freq, auth->num_freq, freq))
+ continue;
+ auth->freq[auth->num_freq++] = freq;
+ if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
+ m = num_modes;
+ break;
+ }
+ }
+ }
+
+ return auth->num_freq == 0 ? -1 : 0;
+}
+
+
+static int dpp_prepare_channel_list(struct dpp_authentication *auth,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ int res;
+ char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
+ unsigned int i;
+
+ if (auth->peer_bi->num_freq > 0)
+ res = dpp_channel_intersect(auth, own_modes, num_modes);
+ else
+ res = dpp_channel_local_list(auth, own_modes, num_modes);
+ if (res < 0)
+ return res;
+
+ /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
+ * likely channels first. */
+ freq_to_start(auth->freq, auth->num_freq, 2462);
+ freq_to_start(auth->freq, auth->num_freq, 2412);
+ freq_to_start(auth->freq, auth->num_freq, 2437);
+
+ auth->freq_idx = 0;
+ auth->curr_freq = auth->freq[0];
+
+ pos = freqs;
+ end = pos + sizeof(freqs);
+ for (i = 0; i < auth->num_freq; i++) {
+ res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
+ wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
+ freqs);
+
+ return 0;
+}
+
+
+static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
+{
+ struct dpp_bootstrap_info *bi;
+ char *pk = NULL;
+ size_t len;
+
+ if (auth->own_bi)
+ return 0; /* already generated */
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ return -1;
+ bi->type = DPP_BOOTSTRAP_QR_CODE;
+ pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
+ if (!pk)
+ goto fail;
+
+ len = 4; /* "DPP:" */
+ len += 4 + os_strlen(pk);
+ bi->uri = os_malloc(len + 1);
+ if (!bi->uri)
+ goto fail;
+ os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Auto-generated own bootstrapping key info: URI %s",
+ bi->uri);
+
+ auth->tmp_own_bi = auth->own_bi = bi;
+
+ os_free(pk);
+
+ return 0;
+fail:
+ os_free(pk);
+ dpp_bootstrap_info_free(bi);
+ return -1;
+}
+
+
+struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+ struct dpp_bootstrap_info *peer_bi,
+ struct dpp_bootstrap_info *own_bi,
+ u8 dpp_allowed_roles,
+ unsigned int neg_freq,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ struct dpp_authentication *auth;
+ size_t nonce_len;
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t secret_len;
+ struct wpabuf *pi = NULL;
+ const u8 *r_pubkey_hash, *i_pubkey_hash;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ auth = os_zalloc(sizeof(*auth));
+ if (!auth)
+ return NULL;
+ auth->msg_ctx = msg_ctx;
+ auth->initiator = 1;
+ auth->waiting_auth_resp = 1;
+ auth->allowed_roles = dpp_allowed_roles;
+ auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
+ auth->peer_bi = peer_bi;
+ auth->own_bi = own_bi;
+ auth->curve = peer_bi->curve;
+
+ if (dpp_autogen_bootstrap_key(auth) < 0 ||
+ dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_nonce_override_len > 0) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
+ nonce_len = dpp_nonce_override_len;
+ os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
+ } else {
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->i_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate I-nonce");
+ goto fail;
+ }
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->i_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_protocol_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override protocol key");
+ auth->own_protocol_key = dpp_set_keypair(
+ &tmp_curve, dpp_protocol_key_override,
+ dpp_protocol_key_override_len);
+ } else {
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!auth->own_protocol_key)
+ goto fail;
+
+ pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (!pi)
+ goto fail;
+
+ /* ECDH: M = pI * BR */
+ ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
+ secret_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ auth->secret_len = secret_len;
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
+ auth->Mx, auth->secret_len);
+ auth->Mx_len = auth->secret_len;
+
+ if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
+ auth->curve->hash_len) < 0)
+ goto fail;
+
+ r_pubkey_hash = auth->peer_bi->pubkey_hash;
+ i_pubkey_hash = auth->own_bi->pubkey_hash;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
+ wpabuf_free(pi);
+ pi = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
+ wpabuf_free(pi);
+ pi = wpabuf_alloc(2 * auth->curve->prime_len);
+ if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
+ i_pubkey_hash, neg_freq);
+ if (!auth->req_msg)
+ goto fail;
+
+out:
+ wpabuf_free(pi);
+ EVP_PKEY_CTX_free(ctx);
+ return auth;
+fail:
+ dpp_auth_deinit(auth);
+ auth = NULL;
+ goto out;
+}
+
+
+static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
+ const char *json)
+{
+ size_t nonce_len;
+ size_t json_len, clear_len;
+ struct wpabuf *clear = NULL, *msg = NULL;
+ u8 *wrapped;
+ size_t attr_len;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
+
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->e_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
+ json_len = os_strlen(json);
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
+
+ /* { E-nonce, configAttrib }ke */
+ clear_len = 4 + nonce_len + 4 + json_len;
+ clear = wpabuf_alloc(clear_len);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = wpabuf_alloc(attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
+ goto skip_e_nonce;
+ }
+ if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len - 1);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
+ goto skip_e_nonce;
+ }
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* E-nonce */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_e_nonce:
+ if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
+ goto skip_conf_attr_obj;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* configAttrib */
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
+ wpabuf_put_le16(clear, json_len);
+ wpabuf_put_data(clear, json, json_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_conf_attr_obj:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ /* No AES-SIV AD */
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 0, NULL, NULL, wrapped) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Configuration Request frame attributes", msg);
+ wpabuf_free(clear);
+ return msg;
+
+fail:
+ wpabuf_free(clear);
+ wpabuf_free(msg);
+ return NULL;
+}
+
+
+static void dpp_write_adv_proto(struct wpabuf *buf)
+{
+ /* Advertisement Protocol IE */
+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(buf, 8); /* Length */
+ wpabuf_put_u8(buf, 0x7f);
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 5);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, DPP_OUI_TYPE);
+ wpabuf_put_u8(buf, 0x01);
+}
+
+
+static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
+{
+ /* GAS Query */
+ wpabuf_put_le16(buf, wpabuf_len(query));
+ wpabuf_put_buf(buf, query);
+}
+
+
+struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
+ const char *json)
+{
+ struct wpabuf *buf, *conf_req;
+
+ conf_req = dpp_build_conf_req_attr(auth, json);
+ if (!conf_req) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration request data available");
+ return NULL;
+ }
+
+ buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
+ if (!buf) {
+ wpabuf_free(conf_req);
+ return NULL;
+ }
+
+ dpp_write_adv_proto(buf);
+ dpp_write_gas_query(buf, conf_req);
+ wpabuf_free(conf_req);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
+
+ return buf;
+}
+
+
+static void dpp_auth_success(struct dpp_authentication *auth)
+{
+ wpa_printf(MSG_DEBUG,
+ "DPP: Authentication success - clear temporary keys");
+ os_memset(auth->Mx, 0, sizeof(auth->Mx));
+ auth->Mx_len = 0;
+ os_memset(auth->Nx, 0, sizeof(auth->Nx));
+ auth->Nx_len = 0;
+ os_memset(auth->Lx, 0, sizeof(auth->Lx));
+ auth->Lx_len = 0;
+ os_memset(auth->k1, 0, sizeof(auth->k1));
+ os_memset(auth->k2, 0, sizeof(auth->k2));
+
+ auth->auth_success = 1;
+}
+
+
+static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
+{
+ struct wpabuf *pix, *prx, *bix, *brx;
+ const u8 *addr[7];
+ size_t len[7];
+ size_t i, num_elem = 0;
+ size_t nonce_len;
+ u8 zero = 0;
+ int res = -1;
+
+ /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
+ nonce_len = auth->curve->nonce_len;
+
+ if (auth->initiator) {
+ pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ if (auth->own_bi)
+ bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ else
+ bix = NULL;
+ brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ } else {
+ pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (auth->peer_bi)
+ bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ else
+ bix = NULL;
+ brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ }
+ if (!pix || !prx || !brx)
+ goto fail;
+
+ addr[num_elem] = auth->i_nonce;
+ len[num_elem] = nonce_len;
+ num_elem++;
+
+ addr[num_elem] = auth->r_nonce;
+ len[num_elem] = nonce_len;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(pix);
+ len[num_elem] = wpabuf_len(pix) / 2;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(prx);
+ len[num_elem] = wpabuf_len(prx) / 2;
+ num_elem++;
+
+ if (bix) {
+ addr[num_elem] = wpabuf_head(bix);
+ len[num_elem] = wpabuf_len(bix) / 2;
+ num_elem++;
+ }
+
+ addr[num_elem] = wpabuf_head(brx);
+ len[num_elem] = wpabuf_len(brx) / 2;
+ num_elem++;
+
+ addr[num_elem] = &zero;
+ len[num_elem] = 1;
+ num_elem++;
+
+ wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
+ for (i = 0; i < num_elem; i++)
+ wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
+ res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
+ if (res == 0)
+ wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
+ auth->curve->hash_len);
+fail:
+ wpabuf_free(pix);
+ wpabuf_free(prx);
+ wpabuf_free(bix);
+ wpabuf_free(brx);
+ return res;
+}
+
+
+static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
+{
+ struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
+ const u8 *addr[7];
+ size_t len[7];
+ size_t i, num_elem = 0;
+ size_t nonce_len;
+ u8 one = 1;
+ int res = -1;
+
+ /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
+ nonce_len = auth->curve->nonce_len;
+
+ if (auth->initiator) {
+ pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ if (auth->own_bi)
+ bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ else
+ bix = NULL;
+ if (!auth->peer_bi)
+ goto fail;
+ brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ } else {
+ pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (auth->peer_bi)
+ bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ else
+ bix = NULL;
+ if (!auth->own_bi)
+ goto fail;
+ brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ }
+ if (!pix || !prx || !brx)
+ goto fail;
+
+ addr[num_elem] = auth->r_nonce;
+ len[num_elem] = nonce_len;
+ num_elem++;
+
+ addr[num_elem] = auth->i_nonce;
+ len[num_elem] = nonce_len;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(prx);
+ len[num_elem] = wpabuf_len(prx) / 2;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(pix);
+ len[num_elem] = wpabuf_len(pix) / 2;
+ num_elem++;
+
+ addr[num_elem] = wpabuf_head(brx);
+ len[num_elem] = wpabuf_len(brx) / 2;
+ num_elem++;
+
+ if (bix) {
+ addr[num_elem] = wpabuf_head(bix);
+ len[num_elem] = wpabuf_len(bix) / 2;
+ num_elem++;
+ }
+
+ addr[num_elem] = &one;
+ len[num_elem] = 1;
+ num_elem++;
+
+ wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
+ for (i = 0; i < num_elem; i++)
+ wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
+ res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
+ if (res == 0)
+ wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
+ auth->curve->hash_len);
+fail:
+ wpabuf_free(pix);
+ wpabuf_free(prx);
+ wpabuf_free(bix);
+ wpabuf_free(brx);
+ return res;
+}
+
+
+static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
+{
+ const EC_GROUP *group;
+ EC_POINT *l = NULL;
+ EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
+ const EC_POINT *BI_point;
+ BN_CTX *bnctx;
+ BIGNUM *lx, *sum, *q;
+ const BIGNUM *bR_bn, *pR_bn;
+ int ret = -1;
+
+ /* L = ((bR + pR) modulo q) * BI */
+
+ bnctx = BN_CTX_new();
+ sum = BN_new();
+ q = BN_new();
+ lx = BN_new();
+ if (!bnctx || !sum || !q || !lx)
+ goto fail;
+ BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
+ if (!BI)
+ goto fail;
+ BI_point = EC_KEY_get0_public_key(BI);
+ group = EC_KEY_get0_group(BI);
+ if (!group)
+ goto fail;
+
+ bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
+ pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
+ if (!bR || !pR)
+ goto fail;
+ bR_bn = EC_KEY_get0_private_key(bR);
+ pR_bn = EC_KEY_get0_private_key(pR);
+ if (!bR_bn || !pR_bn)
+ goto fail;
+ if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
+ BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
+ goto fail;
+ l = EC_POINT_new(group);
+ if (!l ||
+ EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
+ bnctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
+ auth->Lx_len = auth->secret_len;
+ ret = 0;
+fail:
+ EC_POINT_clear_free(l);
+ EC_KEY_free(BI);
+ EC_KEY_free(bR);
+ EC_KEY_free(pR);
+ BN_clear_free(lx);
+ BN_clear_free(sum);
+ BN_free(q);
+ BN_CTX_free(bnctx);
+ return ret;
+}
+
+
+static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
+{
+ const EC_GROUP *group;
+ EC_POINT *l = NULL, *sum = NULL;
+ EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
+ const EC_POINT *BR_point, *PR_point;
+ BN_CTX *bnctx;
+ BIGNUM *lx;
+ const BIGNUM *bI_bn;
+ int ret = -1;
+
+ /* L = bI * (BR + PR) */
+
+ bnctx = BN_CTX_new();
+ lx = BN_new();
+ if (!bnctx || !lx)
+ goto fail;
+ BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
+ PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
+ if (!BR || !PR)
+ goto fail;
+ BR_point = EC_KEY_get0_public_key(BR);
+ PR_point = EC_KEY_get0_public_key(PR);
+
+ bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
+ if (!bI)
+ goto fail;
+ group = EC_KEY_get0_group(bI);
+ bI_bn = EC_KEY_get0_private_key(bI);
+ if (!group || !bI_bn)
+ goto fail;
+ sum = EC_POINT_new(group);
+ l = EC_POINT_new(group);
+ if (!sum || !l ||
+ EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
+ EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
+ bnctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
+ auth->Lx_len = auth->secret_len;
+ ret = 0;
+fail:
+ EC_POINT_clear_free(l);
+ EC_POINT_clear_free(sum);
+ EC_KEY_free(bI);
+ EC_KEY_free(BR);
+ EC_KEY_free(PR);
+ BN_clear_free(lx);
+ BN_CTX_free(bnctx);
+ return ret;
+}
+
+
+static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
+{
+ size_t nonce_len;
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t secret_len;
+ struct wpabuf *msg, *pr = NULL;
+ u8 r_auth[4 + DPP_MAX_HASH_LEN];
+ u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
+ size_t wrapped_r_auth_len;
+ int ret = -1;
+ const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
+ enum dpp_status_error status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
+ if (!auth->own_bi)
+ return -1;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_nonce_override_len > 0) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
+ nonce_len = dpp_nonce_override_len;
+ os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
+ } else {
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->r_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate R-nonce");
+ goto fail;
+ }
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->r_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_protocol_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override protocol key");
+ auth->own_protocol_key = dpp_set_keypair(
+ &tmp_curve, dpp_protocol_key_override,
+ dpp_protocol_key_override_len);
+ } else {
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!auth->own_protocol_key)
+ goto fail;
+
+ pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ if (!pr)
+ goto fail;
+
+ /* ECDH: N = pR * PI */
+ ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
+ secret_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
+ auth->Nx, auth->secret_len);
+ auth->Nx_len = auth->secret_len;
+
+ if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
+ auth->curve->hash_len) < 0)
+ goto fail;
+
+ if (auth->own_bi && auth->peer_bi) {
+ /* Mutual authentication */
+ if (dpp_auth_derive_l_responder(auth) < 0)
+ goto fail;
+ }
+
+ if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
+ goto fail;
+
+ /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
+ WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
+ WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
+ if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
+ goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
+ r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ r_auth, 4 + auth->curve->hash_len,
+ 0, NULL, NULL, wrapped_r_auth) < 0)
+ goto fail;
+ wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
+ wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
+ wrapped_r_auth, wrapped_r_auth_len);
+ w_r_auth = wrapped_r_auth;
+
+ r_pubkey_hash = auth->own_bi->pubkey_hash;
+ if (auth->peer_bi)
+ i_pubkey_hash = auth->peer_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+ i_nonce = auth->i_nonce;
+ r_nonce = auth->r_nonce;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
+ wpabuf_free(pr);
+ pr = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
+ wpabuf_free(pr);
+ pr = wpabuf_alloc(2 * auth->curve->prime_len);
+ if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
+ goto fail;
+ } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
+ w_r_auth = NULL;
+ wrapped_r_auth_len = 0;
+ } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ status = 255;
+ } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 254;
+ } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
+ r_nonce = NULL;
+ } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ i_nonce = NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
+ r_pubkey_hash, i_pubkey_hash,
+ r_nonce, i_nonce,
+ w_r_auth, wrapped_r_auth_len,
+ auth->k2);
+ if (!msg)
+ goto fail;
+ wpabuf_free(auth->resp_msg);
+ auth->resp_msg = msg;
+ ret = 0;
+fail:
+ wpabuf_free(pr);
+ return ret;
+}
+
+
+static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
+ enum dpp_status_error status)
+{
+ struct wpabuf *msg;
+ const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!auth->own_bi)
+ return -1;
+ wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
+
+ r_pubkey_hash = auth->own_bi->pubkey_hash;
+ if (auth->peer_bi)
+ i_pubkey_hash = auth->peer_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+ i_nonce = auth->i_nonce;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ status = 255;
+ } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ i_nonce = NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
+ r_pubkey_hash, i_pubkey_hash,
+ NULL, i_nonce, NULL, 0, auth->k1);
+ if (!msg)
+ return -1;
+ wpabuf_free(auth->resp_msg);
+ auth->resp_msg = msg;
+ return 0;
+}
+
+
+struct dpp_authentication *
+dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
+ struct dpp_bootstrap_info *peer_bi,
+ struct dpp_bootstrap_info *own_bi,
+ unsigned int freq, const u8 *hdr, const u8 *attr_start,
+ size_t attr_len)
+{
+ EVP_PKEY *pi = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t secret_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
+ *channel;
+ u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
+ i_bootstrap_len, channel_len;
+ struct dpp_authentication *auth = NULL;
+#ifdef CONFIG_DPP2
+ const u8 *version;
+ u16 version_len;
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Request");
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Wrapped Data attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
+ wrapped_data, wrapped_data_len);
+ attr_len = wrapped_data - 4 - attr_start;
+
+ auth = os_zalloc(sizeof(*auth));
+ if (!auth)
+ goto fail;
+ auth->msg_ctx = msg_ctx;
+ auth->peer_bi = peer_bi;
+ auth->own_bi = own_bi;
+ auth->curve = own_bi->curve;
+ auth->curr_freq = freq;
+
+ auth->peer_version = 1; /* default to the first version */
+#ifdef CONFIG_DPP2
+ version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (version) {
+ if (version_len < 1 || version[0] == 0) {
+ dpp_auth_fail(auth,
+ "Invalid Protocol Version attribute");
+ goto fail;
+ }
+ auth->peer_version = version[0];
+ wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+ auth->peer_version);
+ }
+#endif /* CONFIG_DPP2 */
+
+ channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
+ &channel_len);
+ if (channel) {
+ int neg_freq;
+
+ if (channel_len < 2) {
+ dpp_auth_fail(auth, "Too short Channel attribute");
+ goto fail;
+ }
+
+ neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
+ channel[0], channel[1], neg_freq);
+ if (neg_freq < 0) {
+ dpp_auth_fail(auth,
+ "Unsupported Channel attribute value");
+ goto fail;
+ }
+
+ if (auth->curr_freq != (unsigned int) neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Changing negotiation channel from %u MHz to %u MHz",
+ freq, neg_freq);
+ auth->curr_freq = neg_freq;
+ }
+ }
+
+ i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
+ &i_proto_len);
+ if (!i_proto) {
+ dpp_auth_fail(auth,
+ "Missing required Initiator Protocol Key attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
+ i_proto, i_proto_len);
+
+ /* M = bR * PI */
+ pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
+ if (!pi) {
+ dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
+ goto fail;
+ }
+ dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
+
+ ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
+ secret_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
+ goto fail;
+ }
+ auth->secret_len = secret_len;
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
+ auth->Mx, auth->secret_len);
+ auth->Mx_len = auth->secret_len;
+
+ if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
+ auth->curve->hash_len) < 0)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
+ &i_nonce_len);
+ if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
+ os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
+
+ i_capab = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_I_CAPABILITIES,
+ &i_capab_len);
+ if (!i_capab || i_capab_len < 1) {
+ dpp_auth_fail(auth, "Missing or invalid I-capabilities");
+ goto fail;
+ }
+ auth->i_capab = i_capab[0];
+ wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
+
+ bin_clear_free(unwrapped, unwrapped_len);
+ unwrapped = NULL;
+
+ switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
+ case DPP_CAPAB_ENROLLEE:
+ if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Local policy does not allow Configurator role");
+ goto not_compatible;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
+ auth->configurator = 1;
+ break;
+ case DPP_CAPAB_CONFIGURATOR:
+ if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Local policy does not allow Enrollee role");
+ goto not_compatible;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
+ auth->configurator = 0;
+ break;
+ case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
+ if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
+ auth->configurator = 0;
+ } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
+ auth->configurator = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Local policy does not allow Configurator/Enrollee role");
+ goto not_compatible;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
+ auth->i_capab & DPP_CAPAB_ROLE_MASK);
+ goto fail;
+ }
+
+ auth->peer_protocol_key = pi;
+ pi = NULL;
+ if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
+ char hex[SHA256_MAC_LEN * 2 + 1];
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
+ if (dpp_auth_build_resp_status(auth,
+ DPP_STATUS_RESPONSE_PENDING) < 0)
+ goto fail;
+ i_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
+ auth->response_pending = 1;
+ os_memcpy(auth->waiting_pubkey_hash,
+ i_bootstrap, i_bootstrap_len);
+ wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
+ i_bootstrap_len);
+ } else {
+ hex[0] = '\0';
+ }
+
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
+ "%s", hex);
+ return auth;
+ }
+ if (dpp_auth_build_resp_ok(auth) < 0)
+ goto fail;
+
+ return auth;
+
+not_compatible:
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
+ "i-capab=0x%02x", auth->i_capab);
+ if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
+ auth->configurator = 1;
+ else
+ auth->configurator = 0;
+ auth->peer_protocol_key = pi;
+ pi = NULL;
+ if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
+ goto fail;
+
+ auth->remove_on_tx_status = 1;
+ return auth;
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ EVP_PKEY_free(pi);
+ EVP_PKEY_CTX_free(ctx);
+ dpp_auth_deinit(auth);
+ return NULL;
+}
+
+
+int dpp_notify_new_qr_code(struct dpp_authentication *auth,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ if (!auth || !auth->response_pending ||
+ os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0)
+ return 0;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
+ MACSTR, MAC2STR(auth->peer_mac_addr));
+ auth->peer_bi = peer_bi;
+
+ if (dpp_auth_build_resp_ok(auth) < 0)
+ return -1;
+
+ return 1;
+}
+
+
+static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
+ enum dpp_status_error status)
+{
+ struct wpabuf *msg;
+ u8 i_auth[4 + DPP_MAX_HASH_LEN];
+ size_t i_auth_len;
+ u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
+ size_t r_nonce_len;
+ const u8 *addr[2];
+ size_t len[2], attr_len;
+ u8 *wrapped_i_auth;
+ u8 *wrapped_r_nonce;
+ u8 *attr_start, *attr_end;
+ const u8 *r_pubkey_hash, *i_pubkey_hash;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
+
+ i_auth_len = 4 + auth->curve->hash_len;
+ r_nonce_len = 4 + auth->curve->nonce_len;
+ /* Build DPP Authentication Confirmation frame attributes */
+ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
+ 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
+ if (!msg)
+ goto fail;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ r_pubkey_hash = auth->peer_bi->pubkey_hash;
+ if (auth->own_bi)
+ i_pubkey_hash = auth->own_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ goto skip_status;
+ } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 254;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Status */
+ dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+ /* Initiator Bootstrapping Key Hash (mutual authentication) */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
+ goto skip_wrapped_data;
+ if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
+ i_auth_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ attr_end = wpabuf_put(msg, 0);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ if (status == DPP_STATUS_OK) {
+ /* I-auth wrapped with ke */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
+ wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
+ goto skip_i_auth;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
+ * 1) */
+ WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
+ WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
+ if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
+ i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
+ }
+skip_i_auth:
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ i_auth, i_auth_len,
+ 2, addr, len, wrapped_i_auth) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
+ wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
+ } else {
+ /* R-nonce wrapped with k2 */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
+ wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
+
+ WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
+ WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
+ os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
+
+ if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
+ r_nonce, r_nonce_len,
+ 2, addr, len, wrapped_r_nonce) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
+ wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Authentication Confirmation frame attributes",
+ msg);
+ if (status == DPP_STATUS_OK)
+ dpp_auth_success(auth);
+
+ return msg;
+
+fail:
+ wpabuf_free(msg);
+ return NULL;
+}
+
+
+static void
+dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len,
+ const u8 *wrapped_data, u16 wrapped_data_len,
+ enum dpp_status_error status)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ const u8 *i_nonce, *r_capab;
+ u16 i_nonce_len, r_capab_len;
+
+ if (status == DPP_STATUS_NOT_COMPATIBLE) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder reported incompatible roles");
+ } else if (status == DPP_STATUS_RESPONSE_PENDING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder reported more time needed");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder reported failure (status %d)",
+ status);
+ dpp_auth_fail(auth, "Responder reported failure");
+ return;
+ }
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
+ &i_nonce_len);
+ if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
+ if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
+ dpp_auth_fail(auth, "I-nonce mismatch");
+ goto fail;
+ }
+
+ r_capab = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_R_CAPABILITIES,
+ &r_capab_len);
+ if (!r_capab || r_capab_len < 1) {
+ dpp_auth_fail(auth, "Missing or invalid R-capabilities");
+ goto fail;
+ }
+ auth->r_capab = r_capab[0];
+ wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
+ if (status == DPP_STATUS_NOT_COMPATIBLE) {
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
+ "r-capab=0x%02x", auth->r_capab);
+ } else if (status == DPP_STATUS_RESPONSE_PENDING) {
+ u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
+
+ if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
+ (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
+ role);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue waiting for full DPP Authentication Response");
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_RESPONSE_PENDING "%s",
+ auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
+ }
+ }
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+}
+
+
+struct wpabuf *
+dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ EVP_PKEY *pr;
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t secret_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL, *unwrapped2 = NULL;
+ size_t unwrapped_len = 0, unwrapped2_len = 0;
+ const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
+ *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
+ u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
+ r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
+ wrapped2_len, r_auth_len;
+ u8 r_auth2[DPP_MAX_HASH_LEN];
+ u8 role;
+#ifdef CONFIG_DPP2
+ const u8 *version;
+ u16 version_len;
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Response");
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!auth->initiator || !auth->peer_bi) {
+ dpp_auth_fail(auth, "Unexpected Authentication Response");
+ return NULL;
+ }
+
+ auth->waiting_auth_resp = 0;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ r_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ dpp_auth_fail(auth,
+ "Unexpected Responder Bootstrapping Key Hash value");
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Expected Responder Bootstrapping Key Hash",
+ auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
+ return NULL;
+ }
+
+ i_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (i_bootstrap) {
+ if (i_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Invalid Initiator Bootstrapping Key Hash attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP,
+ "DPP: Initiator Bootstrapping Key Hash",
+ i_bootstrap, i_bootstrap_len);
+ if (!auth->own_bi ||
+ os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ dpp_auth_fail(auth,
+ "Initiator Bootstrapping Key Hash attribute did not match");
+ return NULL;
+ }
+ } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
+ /* PKEX bootstrapping mandates use of mutual authentication */
+ dpp_auth_fail(auth,
+ "Missing Initiator Bootstrapping Key Hash attribute");
+ return NULL;
+ }
+
+ auth->peer_version = 1; /* default to the first version */
+#ifdef CONFIG_DPP2
+ version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (version) {
+ if (version_len < 1 || version[0] == 0) {
+ dpp_auth_fail(auth,
+ "Invalid Protocol Version attribute");
+ return NULL;
+ }
+ auth->peer_version = version[0];
+ wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+ auth->peer_version);
+ }
+#endif /* CONFIG_DPP2 */
+
+ status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
+ &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ auth->auth_resp_status = status[0];
+ if (status[0] != DPP_STATUS_OK) {
+ dpp_auth_resp_rx_status(auth, hdr, attr_start,
+ attr_len, wrapped_data,
+ wrapped_data_len, status[0]);
+ return NULL;
+ }
+
+ if (!i_bootstrap && auth->own_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder decided not to use mutual authentication");
+ auth->own_bi = NULL;
+ }
+
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
+ auth->own_bi != NULL);
+
+ r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
+ &r_proto_len);
+ if (!r_proto) {
+ dpp_auth_fail(auth,
+ "Missing required Responder Protocol Key attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
+ r_proto, r_proto_len);
+
+ /* N = pI * PR */
+ pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
+ if (!pr) {
+ dpp_auth_fail(auth, "Invalid Responder Protocol Key");
+ return NULL;
+ }
+ dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
+
+ ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
+ secret_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
+ goto fail;
+ }
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+ auth->peer_protocol_key = pr;
+ pr = NULL;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
+ auth->Nx, auth->secret_len);
+ auth->Nx_len = auth->secret_len;
+
+ if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
+ auth->curve->hash_len) < 0)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
+ &r_nonce_len);
+ if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
+ os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
+
+ i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
+ &i_nonce_len);
+ if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
+ if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
+ dpp_auth_fail(auth, "I-nonce mismatch");
+ goto fail;
+ }
+
+ if (auth->own_bi) {
+ /* Mutual authentication */
+ if (dpp_auth_derive_l_initiator(auth) < 0)
+ goto fail;
+ }
+
+ r_capab = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_R_CAPABILITIES,
+ &r_capab_len);
+ if (!r_capab || r_capab_len < 1) {
+ dpp_auth_fail(auth, "Missing or invalid R-capabilities");
+ goto fail;
+ }
+ auth->r_capab = r_capab[0];
+ wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
+ role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
+ if ((auth->allowed_roles ==
+ (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
+ (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
+ /* Peer selected its role, so move from "either role" to the
+ * role that is compatible with peer's selection. */
+ auth->configurator = role == DPP_CAPAB_ENROLLEE;
+ wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
+ auth->configurator ? "Configurator" : "Enrollee");
+ } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
+ (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
+ wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Unexpected role in R-capabilities 0x%02x",
+ role);
+ if (role != DPP_CAPAB_ENROLLEE &&
+ role != DPP_CAPAB_CONFIGURATOR)
+ goto fail;
+ bin_clear_free(unwrapped, unwrapped_len);
+ auth->remove_on_tx_status = 1;
+ return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
+ }
+
+ wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
+ if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Secondary Wrapped Data");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped2, wrapped2_len);
+
+ if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
+ goto fail;
+
+ unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
+ unwrapped2 = os_malloc(unwrapped2_len);
+ if (!unwrapped2)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped2, wrapped2_len,
+ 0, NULL, NULL, unwrapped2) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped2, unwrapped2_len);
+
+ if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
+ dpp_auth_fail(auth,
+ "Invalid attribute in secondary unwrapped data");
+ goto fail;
+ }
+
+ r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
+ &r_auth_len);
+ if (!r_auth || r_auth_len != auth->curve->hash_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Responder Authenticating Tag");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
+ r_auth, r_auth_len);
+ /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
+ if (dpp_gen_r_auth(auth, r_auth2) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
+ r_auth2, r_auth_len);
+ if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
+ dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
+ bin_clear_free(unwrapped, unwrapped_len);
+ bin_clear_free(unwrapped2, unwrapped2_len);
+ auth->remove_on_tx_status = 1;
+ return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
+ }
+
+ bin_clear_free(unwrapped, unwrapped_len);
+ bin_clear_free(unwrapped2, unwrapped2_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - Authentication Response in place of Confirm");
+ if (dpp_auth_build_resp_ok(auth) < 0)
+ return NULL;
+ return wpabuf_dup(auth->resp_msg);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return dpp_auth_build_conf(auth, DPP_STATUS_OK);
+
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ bin_clear_free(unwrapped2, unwrapped2_len);
+ EVP_PKEY_free(pr);
+ EVP_PKEY_CTX_free(ctx);
+ return NULL;
+}
+
+
+static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start, size_t attr_len,
+ const u8 *wrapped_data,
+ u16 wrapped_data_len,
+ enum dpp_status_error status)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ const u8 *r_nonce;
+ u16 r_nonce_len;
+
+ /* Authentication Confirm failure cases are expected to include
+ * {R-nonce}k2 in the Wrapped Data attribute. */
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped) {
+ dpp_auth_fail(auth, "Authentication failed");
+ goto fail;
+ }
+ if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
+ &r_nonce_len);
+ if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
+ goto fail;
+ }
+ if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
+ wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
+ r_nonce, r_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
+ auth->r_nonce, r_nonce_len);
+ dpp_auth_fail(auth, "R-nonce mismatch");
+ goto fail;
+ }
+
+ if (status == DPP_STATUS_NOT_COMPATIBLE)
+ dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
+ else if (status == DPP_STATUS_AUTH_FAILURE)
+ dpp_auth_fail(auth, "Peer reported authentication failure)");
+
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ return -1;
+}
+
+
+int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
+ u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
+ i_auth_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ u8 i_auth2[DPP_MAX_HASH_LEN];
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Confirm");
+ return -1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (auth->initiator || !auth->own_bi) {
+ dpp_auth_fail(auth, "Unexpected Authentication Confirm");
+ return -1;
+ }
+
+ auth->waiting_auth_conf = 0;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ r_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Expected Responder Bootstrapping Key Hash",
+ auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
+ dpp_auth_fail(auth,
+ "Responder Bootstrapping Key Hash mismatch");
+ return -1;
+ }
+
+ i_bootstrap = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (i_bootstrap) {
+ if (i_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Invalid Initiator Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP,
+ "DPP: Initiator Bootstrapping Key Hash",
+ i_bootstrap, i_bootstrap_len);
+ if (!auth->peer_bi ||
+ os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ dpp_auth_fail(auth,
+ "Initiator Bootstrapping Key Hash mismatch");
+ return -1;
+ }
+ } else if (auth->peer_bi) {
+ /* Mutual authentication and peer did not include its
+ * Bootstrapping Key Hash attribute. */
+ dpp_auth_fail(auth,
+ "Missing Initiator Bootstrapping Key Hash attribute");
+ return -1;
+ }
+
+ status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
+ &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
+ status[0] == DPP_STATUS_AUTH_FAILURE)
+ return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
+ attr_len, wrapped_data,
+ wrapped_data_len, status[0]);
+
+ if (status[0] != DPP_STATUS_OK) {
+ dpp_auth_fail(auth, "Authentication failed");
+ return -1;
+ }
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ return -1;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
+ &i_auth_len);
+ if (!i_auth || i_auth_len != auth->curve->hash_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Initiator Authenticating Tag");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
+ i_auth, i_auth_len);
+ /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
+ if (dpp_gen_i_auth(auth, i_auth2) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
+ i_auth2, i_auth_len);
+ if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
+ dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
+ goto fail;
+ }
+
+ bin_clear_free(unwrapped, unwrapped_len);
+ dpp_auth_success(auth);
+ return 0;
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ return -1;
+}
+
+
+static int bin_str_eq(const char *val, size_t len, const char *cmp)
+{
+ return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
+}
+
+
+struct dpp_configuration * dpp_configuration_alloc(const char *type)
+{
+ struct dpp_configuration *conf;
+ const char *end;
+ size_t len;
+
+ conf = os_zalloc(sizeof(*conf));
+ if (!conf)
+ goto fail;
+
+ end = os_strchr(type, ' ');
+ if (end)
+ len = end - type;
+ else
+ len = os_strlen(type);
+
+ if (bin_str_eq(type, len, "psk"))
+ conf->akm = DPP_AKM_PSK;
+ else if (bin_str_eq(type, len, "sae"))
+ conf->akm = DPP_AKM_SAE;
+ else if (bin_str_eq(type, len, "psk-sae") ||
+ bin_str_eq(type, len, "psk+sae"))
+ conf->akm = DPP_AKM_PSK_SAE;
+ else if (bin_str_eq(type, len, "sae-dpp") ||
+ bin_str_eq(type, len, "dpp+sae"))
+ conf->akm = DPP_AKM_SAE_DPP;
+ else if (bin_str_eq(type, len, "psk-sae-dpp") ||
+ bin_str_eq(type, len, "dpp+psk+sae"))
+ conf->akm = DPP_AKM_PSK_SAE_DPP;
+ else if (bin_str_eq(type, len, "dpp"))
+ conf->akm = DPP_AKM_DPP;
+ else
+ goto fail;
+
+ return conf;
+fail:
+ dpp_configuration_free(conf);
+ return NULL;
+}
+
+
+int dpp_akm_psk(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
+ akm == DPP_AKM_PSK_SAE_DPP;
+}
+
+
+int dpp_akm_sae(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
+ akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
+}
+
+
+int dpp_akm_legacy(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
+ akm == DPP_AKM_SAE;
+}
+
+
+int dpp_akm_dpp(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
+ akm == DPP_AKM_PSK_SAE_DPP;
+}
+
+
+int dpp_akm_ver2(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
+}
+
+
+int dpp_configuration_valid(const struct dpp_configuration *conf)
+{
+ if (conf->ssid_len == 0)
+ return 0;
+ if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
+ return 0;
+ if (dpp_akm_sae(conf->akm) && !conf->passphrase)
+ return 0;
+ return 1;
+}
+
+
+void dpp_configuration_free(struct dpp_configuration *conf)
+{
+ if (!conf)
+ return;
+ str_clear_free(conf->passphrase);
+ os_free(conf->group_id);
+ bin_clear_free(conf, sizeof(*conf));
+}
+
+
+static int dpp_configuration_parse(struct dpp_authentication *auth,
+ const char *cmd)
+{
+ const char *pos, *end;
+ struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
+ struct dpp_configuration *conf = NULL;
+
+ pos = os_strstr(cmd, " conf=sta-");
+ if (pos) {
+ conf_sta = dpp_configuration_alloc(pos + 10);
+ if (!conf_sta)
+ goto fail;
+ conf = conf_sta;
+ }
+
+ pos = os_strstr(cmd, " conf=ap-");
+ if (pos) {
+ conf_ap = dpp_configuration_alloc(pos + 9);
+ if (!conf_ap)
+ goto fail;
+ conf = conf_ap;
+ }
+
+ if (!conf)
+ return 0;
+
+ pos = os_strstr(cmd, " ssid=");
+ if (pos) {
+ pos += 6;
+ end = os_strchr(pos, ' ');
+ conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
+ conf->ssid_len /= 2;
+ if (conf->ssid_len > sizeof(conf->ssid) ||
+ hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
+ goto fail;
+ } else {
+#ifdef CONFIG_TESTING_OPTIONS
+ /* use a default SSID for legacy testing reasons */
+ os_memcpy(conf->ssid, "test", 4);
+ conf->ssid_len = 4;
+#else /* CONFIG_TESTING_OPTIONS */
+ goto fail;
+#endif /* CONFIG_TESTING_OPTIONS */
+ }
+
+ pos = os_strstr(cmd, " pass=");
+ if (pos) {
+ size_t pass_len;
+
+ pos += 6;
+ end = os_strchr(pos, ' ');
+ pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
+ pass_len /= 2;
+ if (pass_len > 63 || pass_len < 8)
+ goto fail;
+ conf->passphrase = os_zalloc(pass_len + 1);
+ if (!conf->passphrase ||
+ hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
+ goto fail;
+ }
+
+ pos = os_strstr(cmd, " psk=");
+ if (pos) {
+ pos += 5;
+ if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
+ goto fail;
+ conf->psk_set = 1;
+ }
+
+ pos = os_strstr(cmd, " group_id=");
+ if (pos) {
+ size_t group_id_len;
+
+ pos += 10;
+ end = os_strchr(pos, ' ');
+ group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
+ conf->group_id = os_malloc(group_id_len + 1);
+ if (!conf->group_id)
+ goto fail;
+ os_memcpy(conf->group_id, pos, group_id_len);
+ conf->group_id[group_id_len] = '\0';
+ }
+
+ pos = os_strstr(cmd, " expiry=");
+ if (pos) {
+ long int val;
+
+ pos += 8;
+ val = strtol(pos, NULL, 0);
+ if (val <= 0)
+ goto fail;
+ conf->netaccesskey_expiry = val;
+ }
+
+ if (!dpp_configuration_valid(conf))
+ goto fail;
+
+ auth->conf_sta = conf_sta;
+ auth->conf_ap = conf_ap;
+ return 0;
+
+fail:
+ dpp_configuration_free(conf_sta);
+ dpp_configuration_free(conf_ap);
+ return -1;
+}
+
+
+static struct dpp_configurator *
+dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_configurator *conf;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(conf, &dpp->configurator,
+ struct dpp_configurator, list) {
+ if (conf->id == id)
+ return conf;
+ }
+ return NULL;
+}
+
+
+int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
+ struct dpp_authentication *auth,
+ const char *cmd)
+{
+ const char *pos;
+
+ if (!cmd)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
+
+ pos = os_strstr(cmd, " configurator=");
+ if (pos) {
+ pos += 14;
+ auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
+ if (!auth->conf) {
+ wpa_printf(MSG_INFO,
+ "DPP: Could not find the specified configurator");
+ return -1;
+ }
+ }
+
+ if (dpp_configuration_parse(auth, cmd) < 0) {
+ wpa_msg(msg_ctx, MSG_INFO,
+ "DPP: Failed to set configurator parameters");
+ return -1;
+ }
+ return 0;
+}
+
+
+void dpp_auth_deinit(struct dpp_authentication *auth)
+{
+ if (!auth)
+ return;
+ dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf_sta);
+ EVP_PKEY_free(auth->own_protocol_key);
+ EVP_PKEY_free(auth->peer_protocol_key);
+ wpabuf_free(auth->req_msg);
+ wpabuf_free(auth->resp_msg);
+ wpabuf_free(auth->conf_req);
+ os_free(auth->connector);
+ wpabuf_free(auth->net_access_key);
+ wpabuf_free(auth->c_sign_key);
+ dpp_bootstrap_info_free(auth->tmp_own_bi);
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(auth->config_obj_override);
+ os_free(auth->discovery_override);
+ os_free(auth->groups_override);
+#endif /* CONFIG_TESTING_OPTIONS */
+ bin_clear_free(auth, sizeof(*auth));
+}
+
+
+static struct wpabuf *
+dpp_build_conf_start(struct dpp_authentication *auth,
+ struct dpp_configuration *conf, size_t tailroom)
+{
+ struct wpabuf *buf;
+ char ssid[6 * sizeof(conf->ssid) + 1];
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth->discovery_override)
+ tailroom += os_strlen(auth->discovery_override);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ buf = wpabuf_alloc(200 + tailroom);
+ if (!buf)
+ return NULL;
+ wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth->discovery_override) {
+ wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
+ auth->discovery_override);
+ wpabuf_put_str(buf, auth->discovery_override);
+ wpabuf_put_u8(buf, ',');
+ return buf;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpabuf_put_str(buf, "{\"ssid\":\"");
+ json_escape_string(ssid, sizeof(ssid),
+ (const char *) conf->ssid, conf->ssid_len);
+ wpabuf_put_str(buf, ssid);
+ wpabuf_put_str(buf, "\"},");
+
+ return buf;
+}
+
+
+static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
+ const char *kid, const struct dpp_curve_params *curve)
+{
+ struct wpabuf *pub;
+ const u8 *pos;
+ char *x = NULL, *y = NULL;
+ int ret = -1;
+
+ pub = dpp_get_pubkey_point(key, 0);
+ if (!pub)
+ goto fail;
+ pos = wpabuf_head(pub);
+ x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
+ pos += curve->prime_len;
+ y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
+ if (!x || !y)
+ goto fail;
+
+ wpabuf_put_str(buf, "\"");
+ wpabuf_put_str(buf, name);
+ wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
+ wpabuf_put_str(buf, curve->jwk_crv);
+ wpabuf_put_str(buf, "\",\"x\":\"");
+ wpabuf_put_str(buf, x);
+ wpabuf_put_str(buf, "\",\"y\":\"");
+ wpabuf_put_str(buf, y);
+ if (kid) {
+ wpabuf_put_str(buf, "\",\"kid\":\"");
+ wpabuf_put_str(buf, kid);
+ }
+ wpabuf_put_str(buf, "\"}");
+ ret = 0;
+fail:
+ wpabuf_free(pub);
+ os_free(x);
+ os_free(y);
+ return ret;
+}
+
+
+static void dpp_build_legacy_cred_params(struct wpabuf *buf,
+ struct dpp_configuration *conf)
+{
+ if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
+ char pass[63 * 6 + 1];
+
+ json_escape_string(pass, sizeof(pass), conf->passphrase,
+ os_strlen(conf->passphrase));
+ wpabuf_put_str(buf, "\"pass\":\"");
+ wpabuf_put_str(buf, pass);
+ wpabuf_put_str(buf, "\"");
+ os_memset(pass, 0, sizeof(pass));
+ } else if (conf->psk_set) {
+ char psk[2 * sizeof(conf->psk) + 1];
+
+ wpa_snprintf_hex(psk, sizeof(psk),
+ conf->psk, sizeof(conf->psk));
+ wpabuf_put_str(buf, "\"psk_hex\":\"");
+ wpabuf_put_str(buf, psk);
+ wpabuf_put_str(buf, "\"");
+ os_memset(psk, 0, sizeof(psk));
+ }
+}
+
+
+static struct wpabuf *
+dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
+ struct dpp_configuration *conf)
+{
+ struct wpabuf *buf = NULL;
+ char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
+ size_t tailroom;
+ const struct dpp_curve_params *curve;
+ char jws_prot_hdr[100];
+ size_t signed1_len, signed2_len, signed3_len;
+ struct wpabuf *dppcon = NULL;
+ unsigned char *signature = NULL;
+ const unsigned char *p;
+ size_t signature_len;
+ EVP_MD_CTX *md_ctx = NULL;
+ ECDSA_SIG *sig = NULL;
+ char *dot = ".";
+ const EVP_MD *sign_md;
+ const BIGNUM *r, *s;
+ size_t extra_len = 1000;
+ int incl_legacy;
+ enum dpp_akm akm;
+
+ if (!auth->conf) {
+ wpa_printf(MSG_INFO,
+ "DPP: No configurator specified - cannot generate DPP config object");
+ goto fail;
+ }
+ curve = auth->conf->curve;
+ if (curve->hash_len == SHA256_MAC_LEN) {
+ sign_md = EVP_sha256();
+ } else if (curve->hash_len == SHA384_MAC_LEN) {
+ sign_md = EVP_sha384();
+ } else if (curve->hash_len == SHA512_MAC_LEN) {
+ sign_md = EVP_sha512();
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
+ goto fail;
+ }
+
+ akm = conf->akm;
+ if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
+ akm = DPP_AKM_DPP;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth->groups_override)
+ extra_len += os_strlen(auth->groups_override);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (conf->group_id)
+ extra_len += os_strlen(conf->group_id);
+
+ /* Connector (JSON dppCon object) */
+ dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
+ if (!dppcon)
+ goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth->groups_override) {
+ wpabuf_put_u8(dppcon, '{');
+ if (auth->groups_override) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: TESTING - groups override: '%s'",
+ auth->groups_override);
+ wpabuf_put_str(dppcon, "\"groups\":");
+ wpabuf_put_str(dppcon, auth->groups_override);
+ wpabuf_put_u8(dppcon, ',');
+ }
+ goto skip_groups;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
+ conf->group_id ? conf->group_id : "*");
+ wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
+#ifdef CONFIG_TESTING_OPTIONS
+skip_groups:
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
+ auth->curve) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
+ goto fail;
+ }
+ if (conf->netaccesskey_expiry) {
+ struct os_tm tm;
+
+ if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to generate expiry string");
+ goto fail;
+ }
+ wpabuf_printf(dppcon,
+ ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
+ tm.year, tm.month, tm.day,
+ tm.hour, tm.min, tm.sec);
+ }
+ wpabuf_put_u8(dppcon, '}');
+ wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
+ (const char *) wpabuf_head(dppcon));
+
+ os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
+ "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
+ auth->conf->kid, curve->jws_alg);
+ signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
+ os_strlen(jws_prot_hdr),
+ &signed1_len, 0);
+ signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
+ wpabuf_len(dppcon),
+ &signed2_len, 0);
+ if (!signed1 || !signed2)
+ goto fail;
+
+ md_ctx = EVP_MD_CTX_create();
+ if (!md_ctx)
+ goto fail;
+
+ ERR_clear_error();
+ if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
+ auth->conf->csign) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
+ EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
+ EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ signature = os_malloc(signature_len);
+ if (!signature)
+ goto fail;
+ if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
+ signature, signature_len);
+ /* Convert to raw coordinates r,s */
+ p = signature;
+ sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
+ if (!sig)
+ goto fail;
+ ECDSA_SIG_get0(sig, &r, &s);
+ if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(s, signature + curve->prime_len,
+ curve->prime_len) < 0)
+ goto fail;
+ signature_len = 2 * curve->prime_len;
+ wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
+ signature, signature_len);
+ signed3 = (char *) base64_url_encode(signature, signature_len,
+ &signed3_len, 0);
+ if (!signed3)
+ goto fail;
+
+ incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
+ tailroom = 1000;
+ tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
+ tailroom += signed1_len + signed2_len + signed3_len;
+ if (incl_legacy)
+ tailroom += 1000;
+ buf = dpp_build_conf_start(auth, conf, tailroom);
+ if (!buf)
+ goto fail;
+
+ wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
+ if (incl_legacy) {
+ dpp_build_legacy_cred_params(buf, conf);
+ wpabuf_put_str(buf, ",");
+ }
+ wpabuf_put_str(buf, "\"signedConnector\":\"");
+ wpabuf_put_str(buf, signed1);
+ wpabuf_put_u8(buf, '.');
+ wpabuf_put_str(buf, signed2);
+ wpabuf_put_u8(buf, '.');
+ wpabuf_put_str(buf, signed3);
+ wpabuf_put_str(buf, "\",");
+ if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
+ curve) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
+ goto fail;
+ }
+
+ wpabuf_put_str(buf, "}}");
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
+ wpabuf_head(buf), wpabuf_len(buf));
+
+out:
+ EVP_MD_CTX_destroy(md_ctx);
+ ECDSA_SIG_free(sig);
+ os_free(signed1);
+ os_free(signed2);
+ os_free(signed3);
+ os_free(signature);
+ wpabuf_free(dppcon);
+ return buf;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
+ wpabuf_free(buf);
+ buf = NULL;
+ goto out;
+}
+
+
+static struct wpabuf *
+dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
+ struct dpp_configuration *conf)
+{
+ struct wpabuf *buf;
+
+ buf = dpp_build_conf_start(auth, conf, 1000);
+ if (!buf)
+ return NULL;
+
+ wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
+ dpp_build_legacy_cred_params(buf, conf);
+ wpabuf_put_str(buf, "}}");
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ return buf;
+}
+
+
+static struct wpabuf *
+dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
+{
+ struct dpp_configuration *conf;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth->config_obj_override) {
+ wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
+ return wpabuf_alloc_copy(auth->config_obj_override,
+ os_strlen(auth->config_obj_override));
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ conf = ap ? auth->conf_ap : auth->conf_sta;
+ if (!conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration available for Enrollee(%s) - reject configuration request",
+ ap ? "ap" : "sta");
+ return NULL;
+ }
+
+ if (dpp_akm_dpp(conf->akm))
+ return dpp_build_conf_obj_dpp(auth, ap, conf);
+ return dpp_build_conf_obj_legacy(auth, ap, conf);
+}
+
+
+static struct wpabuf *
+dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
+ u16 e_nonce_len, int ap)
+{
+ struct wpabuf *conf;
+ size_t clear_len, attr_len;
+ struct wpabuf *clear = NULL, *msg = NULL;
+ u8 *wrapped;
+ const u8 *addr[1];
+ size_t len[1];
+ enum dpp_status_error status;
+
+ conf = dpp_build_conf_obj(auth, ap);
+ if (conf) {
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
+ wpabuf_head(conf), wpabuf_len(conf));
+ }
+ status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
+ auth->conf_resp_status = status;
+
+ /* { E-nonce, configurationObject}ke */
+ clear_len = 4 + e_nonce_len;
+ if (conf)
+ clear_len += 4 + wpabuf_len(conf);
+ clear = wpabuf_alloc(clear_len);
+ attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = wpabuf_alloc(attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
+ goto skip_e_nonce;
+ }
+ if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, e_nonce_len);
+ wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
+ wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
+ goto skip_e_nonce;
+ }
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* E-nonce */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, e_nonce_len);
+ wpabuf_put_data(clear, e_nonce, e_nonce_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_e_nonce:
+ if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
+ goto skip_config_obj;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (conf) {
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
+ wpabuf_put_le16(clear, wpabuf_len(conf));
+ wpabuf_put_buf(clear, conf);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_config_obj:
+ if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Status");
+ goto skip_status;
+ }
+ if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 255;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Status */
+ dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ addr[0] = wpabuf_head(msg);
+ len[0] = wpabuf_len(msg);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 1, addr, len, wrapped) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Configuration Response attributes", msg);
+out:
+ wpabuf_free(conf);
+ wpabuf_free(clear);
+
+ return msg;
+fail:
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+struct wpabuf *
+dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
+ size_t attr_len)
+{
+ const u8 *wrapped_data, *e_nonce, *config_attr;
+ u16 wrapped_data_len, e_nonce_len, config_attr_len;
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ struct wpabuf *resp = NULL;
+ struct json_token *root = NULL, *token;
+ int ap;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Config Request");
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (dpp_check_attrs(attr_start, attr_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in config request");
+ return NULL;
+ }
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ return NULL;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ return NULL;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 0, NULL, NULL, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE,
+ &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+ os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
+
+ config_attr = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIG_ATTR_OBJ,
+ &config_attr_len);
+ if (!config_attr) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Config Attributes attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
+ config_attr, config_attr_len);
+
+ root = json_parse((const char *) config_attr, config_attr_len);
+ if (!root) {
+ dpp_auth_fail(auth, "Could not parse Config Attributes");
+ goto fail;
+ }
+
+ token = json_get_member(root, "name");
+ if (!token || token->type != JSON_STRING) {
+ dpp_auth_fail(auth, "No Config Attributes - name");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
+
+ token = json_get_member(root, "wi-fi_tech");
+ if (!token || token->type != JSON_STRING) {
+ dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
+ if (os_strcmp(token->string, "infra") != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
+ token->string);
+ dpp_auth_fail(auth, "Unsupported wi-fi_tech");
+ goto fail;
+ }
+
+ token = json_get_member(root, "netRole");
+ if (!token || token->type != JSON_STRING) {
+ dpp_auth_fail(auth, "No Config Attributes - netRole");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
+ if (os_strcmp(token->string, "sta") == 0) {
+ ap = 0;
+ } else if (os_strcmp(token->string, "ap") == 0) {
+ ap = 1;
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
+ token->string);
+ dpp_auth_fail(auth, "Unsupported netRole");
+ goto fail;
+ }
+
+ resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
+
+fail:
+ json_free(root);
+ os_free(unwrapped);
+ return resp;
+}
+
+
+static struct wpabuf *
+dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
+ const u8 *prot_hdr, u16 prot_hdr_len,
+ const EVP_MD **ret_md)
+{
+ struct json_token *root, *token;
+ struct wpabuf *kid = NULL;
+
+ root = json_parse((const char *) prot_hdr, prot_hdr_len);
+ if (!root) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: JSON parsing failed for JWS Protected Header");
+ goto fail;
+ }
+
+ if (root->type != JSON_OBJECT) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: JWS Protected Header root is not an object");
+ goto fail;
+ }
+
+ token = json_get_member(root, "typ");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
+ token->string);
+ if (os_strcmp(token->string, "dppCon") != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported JWS Protected Header typ=%s",
+ token->string);
+ goto fail;
+ }
+
+ token = json_get_member(root, "alg");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
+ token->string);
+ if (os_strcmp(token->string, curve->jws_alg) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
+ token->string, curve->jws_alg);
+ goto fail;
+ }
+ if (os_strcmp(token->string, "ES256") == 0 ||
+ os_strcmp(token->string, "BS256") == 0)
+ *ret_md = EVP_sha256();
+ else if (os_strcmp(token->string, "ES384") == 0 ||
+ os_strcmp(token->string, "BS384") == 0)
+ *ret_md = EVP_sha384();
+ else if (os_strcmp(token->string, "ES512") == 0 ||
+ os_strcmp(token->string, "BS512") == 0)
+ *ret_md = EVP_sha512();
+ else
+ *ret_md = NULL;
+ if (!*ret_md) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported JWS Protected Header alg=%s",
+ token->string);
+ goto fail;
+ }
+
+ kid = json_get_member_base64url(root, "kid");
+ if (!kid) {
+ wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
+ goto fail;
+ }
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
+ kid);
+
+fail:
+ json_free(root);
+ return kid;
+}
+
+
+static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
+ struct json_token *cred)
+{
+ struct json_token *pass, *psk_hex;
+
+ wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
+
+ pass = json_get_member(cred, "pass");
+ psk_hex = json_get_member(cred, "psk_hex");
+
+ if (pass && pass->type == JSON_STRING) {
+ size_t len = os_strlen(pass->string);
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
+ pass->string, len);
+ if (len < 8 || len > 63)
+ return -1;
+ os_strlcpy(auth->passphrase, pass->string,
+ sizeof(auth->passphrase));
+ } else if (psk_hex && psk_hex->type == JSON_STRING) {
+ if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected psk_hex with akm=sae");
+ return -1;
+ }
+ if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
+ hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
+ auth->psk, PMK_LEN);
+ auth->psk_set = 1;
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
+ return -1;
+ }
+
+ if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
+ wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
+ const struct dpp_curve_params **key_curve)
+{
+ struct json_token *token;
+ const struct dpp_curve_params *curve;
+ struct wpabuf *x = NULL, *y = NULL;
+ EC_GROUP *group;
+ EVP_PKEY *pkey = NULL;
+
+ token = json_get_member(jwk, "kty");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
+ goto fail;
+ }
+ if (os_strcmp(token->string, "EC") != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
+ token->string);
+ goto fail;
+ }
+
+ token = json_get_member(jwk, "crv");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
+ goto fail;
+ }
+ curve = dpp_get_curve_jwk_crv(token->string);
+ if (!curve) {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
+ token->string);
+ goto fail;
+ }
+
+ x = json_get_member_base64url(jwk, "x");
+ if (!x) {
+ wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
+ goto fail;
+ }
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
+ if (wpabuf_len(x) != curve->prime_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
+ (unsigned int) wpabuf_len(x),
+ (unsigned int) curve->prime_len, curve->name);
+ goto fail;
+ }
+
+ y = json_get_member_base64url(jwk, "y");
+ if (!y) {
+ wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
+ goto fail;
+ }
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
+ if (wpabuf_len(y) != curve->prime_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
+ (unsigned int) wpabuf_len(y),
+ (unsigned int) curve->prime_len, curve->name);
+ goto fail;
+ }
+
+ group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
+ if (!group) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
+ goto fail;
+ }
+
+ pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
+ wpabuf_len(x));
+ *key_curve = curve;
+
+fail:
+ wpabuf_free(x);
+ wpabuf_free(y);
+
+ return pkey;
+}
+
+
+int dpp_key_expired(const char *timestamp, os_time_t *expiry)
+{
+ struct os_time now;
+ unsigned int year, month, day, hour, min, sec;
+ os_time_t utime;
+ const char *pos;
+
+ /* ISO 8601 date and time:
+ * <date>T<time>
+ * YYYY-MM-DDTHH:MM:SSZ
+ * YYYY-MM-DDTHH:MM:SS+03:00
+ */
+ if (os_strlen(timestamp) < 19) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Too short timestamp - assume expired key");
+ return 1;
+ }
+ if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
+ &year, &month, &day, &hour, &min, &sec) != 6) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to parse expiration day - assume expired key");
+ return 1;
+ }
+
+ if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Invalid date/time information - assume expired key");
+ return 1;
+ }
+
+ pos = timestamp + 19;
+ if (*pos == 'Z' || *pos == '\0') {
+ /* In UTC - no need to adjust */
+ } else if (*pos == '-' || *pos == '+') {
+ int items;
+
+ /* Adjust local time to UTC */
+ items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
+ if (items < 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Invalid time zone designator (%s) - assume expired key",
+ pos);
+ return 1;
+ }
+ if (*pos == '-')
+ utime += 3600 * hour;
+ if (*pos == '+')
+ utime -= 3600 * hour;
+ if (items > 1) {
+ if (*pos == '-')
+ utime += 60 * min;
+ if (*pos == '+')
+ utime -= 60 * min;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Invalid time zone designator (%s) - assume expired key",
+ pos);
+ return 1;
+ }
+ if (expiry)
+ *expiry = utime;
+
+ if (os_get_time(&now) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Cannot get current time - assume expired key");
+ return 1;
+ }
+
+ if (now.sec > utime) {
+ wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
+ utime, now.sec);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int dpp_parse_connector(struct dpp_authentication *auth,
+ const unsigned char *payload,
+ u16 payload_len)
+{
+ struct json_token *root, *groups, *netkey, *token;
+ int ret = -1;
+ EVP_PKEY *key = NULL;
+ const struct dpp_curve_params *curve;
+ unsigned int rules = 0;
+
+ root = json_parse((const char *) payload, payload_len);
+ if (!root) {
+ wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
+ goto fail;
+ }
+
+ groups = json_get_member(root, "groups");
+ if (!groups || groups->type != JSON_ARRAY) {
+ wpa_printf(MSG_DEBUG, "DPP: No groups array found");
+ goto skip_groups;
+ }
+ for (token = groups->child; token; token = token->sibling) {
+ struct json_token *id, *role;
+
+ id = json_get_member(token, "groupId");
+ if (!id || id->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
+ goto fail;
+ }
+
+ role = json_get_member(token, "netRole");
+ if (!role || role->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG,
+ "DPP: connector group: groupId='%s' netRole='%s'",
+ id->string, role->string);
+ rules++;
+ }
+skip_groups:
+
+ if (!rules) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Connector includes no groups");
+ goto fail;
+ }
+
+ token = json_get_member(root, "expiry");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No expiry string found - connector does not expire");
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
+ if (dpp_key_expired(token->string,
+ &auth->net_access_key_expiry)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Connector (netAccessKey) has expired");
+ goto fail;
+ }
+ }
+
+ netkey = json_get_member(root, "netAccessKey");
+ if (!netkey || netkey->type != JSON_OBJECT) {
+ wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
+ goto fail;
+ }
+
+ key = dpp_parse_jwk(netkey, &curve);
+ if (!key)
+ goto fail;
+ dpp_debug_print_key("DPP: Received netAccessKey", key);
+
+ if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: netAccessKey in connector does not match own protocol key");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth->ignore_netaccesskey_mismatch) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: TESTING - skip netAccessKey mismatch");
+ } else {
+ goto fail;
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ goto fail;
+#endif /* CONFIG_TESTING_OPTIONS */
+ }
+
+ ret = 0;
+fail:
+ EVP_PKEY_free(key);
+ json_free(root);
+ return ret;
+}
+
+
+static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
+{
+ struct wpabuf *uncomp;
+ int res;
+ u8 hash[SHA256_MAC_LEN];
+ const u8 *addr[1];
+ size_t len[1];
+
+ if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
+ return -1;
+ uncomp = dpp_get_pubkey_point(pub, 1);
+ if (!uncomp)
+ return -1;
+ addr[0] = wpabuf_head(uncomp);
+ len[0] = wpabuf_len(uncomp);
+ wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
+ addr[0], len[0]);
+ res = sha256_vector(1, addr, len, hash);
+ wpabuf_free(uncomp);
+ if (res < 0)
+ return -1;
+ if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received hash value does not match calculated public key hash value");
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
+ hash, SHA256_MAC_LEN);
+ return -1;
+ }
+ return 0;
+}
+
+
+static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
+{
+ unsigned char *der = NULL;
+ int der_len;
+
+ der_len = i2d_PUBKEY(csign, &der);
+ if (der_len <= 0)
+ return;
+ wpabuf_free(auth->c_sign_key);
+ auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+}
+
+
+static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
+{
+ unsigned char *der = NULL;
+ int der_len;
+ EC_KEY *eckey;
+
+ eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
+ if (!eckey)
+ return;
+
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len <= 0) {
+ EC_KEY_free(eckey);
+ return;
+ }
+ wpabuf_free(auth->net_access_key);
+ auth->net_access_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ EC_KEY_free(eckey);
+}
+
+
+struct dpp_signed_connector_info {
+ unsigned char *payload;
+ size_t payload_len;
+};
+
+static enum dpp_status_error
+dpp_process_signed_connector(struct dpp_signed_connector_info *info,
+ EVP_PKEY *csign_pub, const char *connector)
+{
+ enum dpp_status_error ret = 255;
+ const char *pos, *end, *signed_start, *signed_end;
+ struct wpabuf *kid = NULL;
+ unsigned char *prot_hdr = NULL, *signature = NULL;
+ size_t prot_hdr_len = 0, signature_len = 0;
+ const EVP_MD *sign_md = NULL;
+ unsigned char *der = NULL;
+ int der_len;
+ int res;
+ EVP_MD_CTX *md_ctx = NULL;
+ ECDSA_SIG *sig = NULL;
+ BIGNUM *r = NULL, *s = NULL;
+ const struct dpp_curve_params *curve;
+ EC_KEY *eckey;
+ const EC_GROUP *group;
+ int nid;
+
+ eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
+ if (!eckey)
+ goto fail;
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ goto fail;
+ nid = EC_GROUP_get_curve_name(group);
+ curve = dpp_get_curve_nid(nid);
+ if (!curve)
+ goto fail;
+ wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
+ os_memset(info, 0, sizeof(*info));
+
+ signed_start = pos = connector;
+ end = os_strchr(pos, '.');
+ if (!end) {
+ wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ prot_hdr = base64_url_decode((const unsigned char *) pos,
+ end - pos, &prot_hdr_len);
+ if (!prot_hdr) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to base64url decode signedConnector JWS Protected Header");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "DPP: signedConnector - JWS Protected Header",
+ prot_hdr, prot_hdr_len);
+ kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
+ if (!kid) {
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ if (wpabuf_len(kid) != SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
+ (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ pos = end + 1;
+ end = os_strchr(pos, '.');
+ if (!end) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing dot(2) in signedConnector");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ signed_end = end - 1;
+ info->payload = base64_url_decode((const unsigned char *) pos,
+ end - pos, &info->payload_len);
+ if (!info->payload) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to base64url decode signedConnector JWS Payload");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "DPP: signedConnector - JWS Payload",
+ info->payload, info->payload_len);
+ pos = end + 1;
+ signature = base64_url_decode((const unsigned char *) pos,
+ os_strlen(pos), &signature_len);
+ if (!signature) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to base64url decode signedConnector signature");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
+ signature, signature_len);
+
+ if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
+ ret = DPP_STATUS_NO_MATCH;
+ goto fail;
+ }
+
+ if (signature_len & 0x01) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected signedConnector signature length (%d)",
+ (int) signature_len);
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ /* JWS Signature encodes the signature (r,s) as two octet strings. Need
+ * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
+ r = BN_bin2bn(signature, signature_len / 2, NULL);
+ s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
+ sig = ECDSA_SIG_new();
+ if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
+ goto fail;
+ r = NULL;
+ s = NULL;
+
+ der_len = i2d_ECDSA_SIG(sig, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
+ md_ctx = EVP_MD_CTX_create();
+ if (!md_ctx)
+ goto fail;
+
+ ERR_clear_error();
+ if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
+ signed_end - signed_start + 1) != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
+ res, ERR_error_string(ERR_get_error(), NULL));
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ ret = DPP_STATUS_OK;
+fail:
+ EC_KEY_free(eckey);
+ EVP_MD_CTX_destroy(md_ctx);
+ os_free(prot_hdr);
+ wpabuf_free(kid);
+ os_free(signature);
+ ECDSA_SIG_free(sig);
+ BN_free(r);
+ BN_free(s);
+ OPENSSL_free(der);
+ return ret;
+}
+
+
+static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
+ struct json_token *cred)
+{
+ struct dpp_signed_connector_info info;
+ struct json_token *token, *csign;
+ int ret = -1;
+ EVP_PKEY *csign_pub = NULL;
+ const struct dpp_curve_params *key_curve = NULL;
+ const char *signed_connector;
+
+ os_memset(&info, 0, sizeof(info));
+
+ if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Legacy credential included in Connector credential");
+ if (dpp_parse_cred_legacy(auth, cred) < 0)
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Connector credential");
+
+ csign = json_get_member(cred, "csign");
+ if (!csign || csign->type != JSON_OBJECT) {
+ wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
+ goto fail;
+ }
+
+ csign_pub = dpp_parse_jwk(csign, &key_curve);
+ if (!csign_pub) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
+
+ token = json_get_member(cred, "signedConnector");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
+ token->string, os_strlen(token->string));
+ signed_connector = token->string;
+
+ if (os_strchr(signed_connector, '"') ||
+ os_strchr(signed_connector, '\n')) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected character in signedConnector");
+ goto fail;
+ }
+
+ if (dpp_process_signed_connector(&info, csign_pub,
+ signed_connector) != DPP_STATUS_OK)
+ goto fail;
+
+ if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
+ goto fail;
+ }
+
+ os_free(auth->connector);
+ auth->connector = os_strdup(signed_connector);
+
+ dpp_copy_csign(auth, csign_pub);
+ dpp_copy_netaccesskey(auth);
+
+ ret = 0;
+fail:
+ EVP_PKEY_free(csign_pub);
+ os_free(info.payload);
+ return ret;
+}
+
+
+const char * dpp_akm_str(enum dpp_akm akm)
+{
+ switch (akm) {
+ case DPP_AKM_DPP:
+ return "dpp";
+ case DPP_AKM_PSK:
+ return "psk";
+ case DPP_AKM_SAE:
+ return "sae";
+ case DPP_AKM_PSK_SAE:
+ return "psk+sae";
+ case DPP_AKM_SAE_DPP:
+ return "dpp+sae";
+ case DPP_AKM_PSK_SAE_DPP:
+ return "dpp+psk+sae";
+ default:
+ return "??";
+ }
+}
+
+
+static enum dpp_akm dpp_akm_from_str(const char *akm)
+{
+ if (os_strcmp(akm, "psk") == 0)
+ return DPP_AKM_PSK;
+ if (os_strcmp(akm, "sae") == 0)
+ return DPP_AKM_SAE;
+ if (os_strcmp(akm, "psk+sae") == 0)
+ return DPP_AKM_PSK_SAE;
+ if (os_strcmp(akm, "dpp") == 0)
+ return DPP_AKM_DPP;
+ if (os_strcmp(akm, "dpp+sae") == 0)
+ return DPP_AKM_SAE_DPP;
+ if (os_strcmp(akm, "dpp+psk+sae") == 0)
+ return DPP_AKM_PSK_SAE_DPP;
+ return DPP_AKM_UNKNOWN;
+}
+
+
+static int dpp_parse_conf_obj(struct dpp_authentication *auth,
+ const u8 *conf_obj, u16 conf_obj_len)
+{
+ int ret = -1;
+ struct json_token *root, *token, *discovery, *cred;
+
+ root = json_parse((const char *) conf_obj, conf_obj_len);
+ if (!root)
+ return -1;
+ if (root->type != JSON_OBJECT) {
+ dpp_auth_fail(auth, "JSON root is not an object");
+ goto fail;
+ }
+
+ token = json_get_member(root, "wi-fi_tech");
+ if (!token || token->type != JSON_STRING) {
+ dpp_auth_fail(auth, "No wi-fi_tech string value found");
+ goto fail;
+ }
+ if (os_strcmp(token->string, "infra") != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
+ token->string);
+ dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
+ goto fail;
+ }
+
+ discovery = json_get_member(root, "discovery");
+ if (!discovery || discovery->type != JSON_OBJECT) {
+ dpp_auth_fail(auth, "No discovery object in JSON");
+ goto fail;
+ }
+
+ token = json_get_member(discovery, "ssid");
+ if (!token || token->type != JSON_STRING) {
+ dpp_auth_fail(auth, "No discovery::ssid string value found");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
+ token->string, os_strlen(token->string));
+ if (os_strlen(token->string) > SSID_MAX_LEN) {
+ dpp_auth_fail(auth, "Too long discovery::ssid string value");
+ goto fail;
+ }
+ auth->ssid_len = os_strlen(token->string);
+ os_memcpy(auth->ssid, token->string, auth->ssid_len);
+
+ cred = json_get_member(root, "cred");
+ if (!cred || cred->type != JSON_OBJECT) {
+ dpp_auth_fail(auth, "No cred object in JSON");
+ goto fail;
+ }
+
+ token = json_get_member(cred, "akm");
+ if (!token || token->type != JSON_STRING) {
+ dpp_auth_fail(auth, "No cred::akm string value found");
+ goto fail;
+ }
+ auth->akm = dpp_akm_from_str(token->string);
+
+ if (dpp_akm_legacy(auth->akm)) {
+ if (dpp_parse_cred_legacy(auth, cred) < 0)
+ goto fail;
+ } else if (dpp_akm_dpp(auth->akm)) {
+ if (dpp_parse_cred_dpp(auth, cred) < 0)
+ goto fail;
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
+ token->string);
+ dpp_auth_fail(auth, "Unsupported akm");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
+ ret = 0;
+fail:
+ json_free(root);
+ return ret;
+}
+
+
+int dpp_conf_resp_rx(struct dpp_authentication *auth,
+ const struct wpabuf *resp)
+{
+ const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
+ u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
+ const u8 *addr[1];
+ size_t len[1];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ int ret = -1;
+
+ auth->conf_resp_status = 255;
+
+ if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in config response");
+ return -1;
+ }
+
+ wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
+ DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ return -1;
+
+ addr[0] = wpabuf_head(resp);
+ len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
+
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 1, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE,
+ &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+ if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Enrollee Nonce mismatch");
+ goto fail;
+ }
+
+ status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
+ DPP_ATTR_STATUS, &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ goto fail;
+ }
+ auth->conf_resp_status = status[0];
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ if (status[0] != DPP_STATUS_OK) {
+ dpp_auth_fail(auth, "Configurator rejected configuration");
+ goto fail;
+ }
+
+ conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
+ if (!conf_obj) {
+ dpp_auth_fail(auth,
+ "Missing required Configuration Object attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
+ conf_obj, conf_obj_len);
+ if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
+ goto fail;
+
+ ret = 0;
+
+fail:
+ os_free(unwrapped);
+ return ret;
+}
+
+
+#ifdef CONFIG_DPP2
+enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ const u8 *wrapped_data, *status, *e_nonce;
+ u16 wrapped_data_len, status_len, e_nonce_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ enum dpp_status_error ret = 256;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ len[1] = attr_len;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE,
+ &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+ if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Enrollee Nonce mismatch");
+ wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
+ auth->e_nonce, e_nonce_len);
+ goto fail;
+ }
+
+ status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
+ &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ ret = status[0];
+
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ return ret;
+}
+#endif /* CONFIG_DPP2 */
+
+
+struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
+ enum dpp_status_error status)
+{
+ struct wpabuf *msg, *clear;
+ size_t nonce_len, clear_len, attr_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *wrapped;
+
+ nonce_len = auth->curve->nonce_len;
+ clear_len = 5 + 4 + nonce_len;
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+ clear = wpabuf_alloc(clear_len);
+ msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
+ if (!clear || !msg)
+ return NULL;
+
+ /* DPP Status */
+ dpp_build_attr_status(clear, status);
+
+ /* E-nonce */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data (none) */
+ addr[1] = wpabuf_put(msg, 0);
+ len[1] = 0;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ /* Wrapped Data */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
+ wpabuf_free(clear);
+ return msg;
+fail:
+ wpabuf_free(clear);
+ wpabuf_free(msg);
+ return NULL;
+}
+
+
+void dpp_configurator_free(struct dpp_configurator *conf)
+{
+ if (!conf)
+ return;
+ EVP_PKEY_free(conf->csign);
+ os_free(conf->kid);
+ os_free(conf);
+}
+
+
+int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
+ size_t buflen)
+{
+ EC_KEY *eckey;
+ int key_len, ret = -1;
+ unsigned char *key = NULL;
+
+ if (!conf->csign)
+ return -1;
+
+ eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
+ if (!eckey)
+ return -1;
+
+ key_len = i2d_ECPrivateKey(eckey, &key);
+ if (key_len > 0)
+ ret = wpa_snprintf_hex(buf, buflen, key, key_len);
+
+ EC_KEY_free(eckey);
+ OPENSSL_free(key);
+ return ret;
+}
+
+
+struct dpp_configurator *
+dpp_keygen_configurator(const char *curve, const u8 *privkey,
+ size_t privkey_len)
+{
+ struct dpp_configurator *conf;
+ struct wpabuf *csign_pub = NULL;
+ u8 kid_hash[SHA256_MAC_LEN];
+ const u8 *addr[1];
+ size_t len[1];
+
+ conf = os_zalloc(sizeof(*conf));
+ if (!conf)
+ return NULL;
+
+ if (!curve) {
+ conf->curve = &dpp_curves[0];
+ } else {
+ conf->curve = dpp_get_curve_name(curve);
+ if (!conf->curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
+ curve);
+ os_free(conf);
+ return NULL;
+ }
+ }
+ if (privkey)
+ conf->csign = dpp_set_keypair(&conf->curve, privkey,
+ privkey_len);
+ else
+ conf->csign = dpp_gen_keypair(conf->curve);
+ if (!conf->csign)
+ goto fail;
+ conf->own = 1;
+
+ csign_pub = dpp_get_pubkey_point(conf->csign, 1);
+ if (!csign_pub) {
+ wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
+ goto fail;
+ }
+
+ /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
+ addr[0] = wpabuf_head(csign_pub);
+ len[0] = wpabuf_len(csign_pub);
+ if (sha256_vector(1, addr, len, kid_hash) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to derive kid for C-sign-key");
+ goto fail;
+ }
+
+ conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
+ NULL, 0);
+ if (!conf->kid)
+ goto fail;
+out:
+ wpabuf_free(csign_pub);
+ return conf;
+fail:
+ dpp_configurator_free(conf);
+ conf = NULL;
+ goto out;
+}
+
+
+int dpp_configurator_own_config(struct dpp_authentication *auth,
+ const char *curve, int ap)
+{
+ struct wpabuf *conf_obj;
+ int ret = -1;
+
+ if (!auth->conf) {
+ wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
+ return -1;
+ }
+
+ if (!curve) {
+ auth->curve = &dpp_curves[0];
+ } else {
+ auth->curve = dpp_get_curve_name(curve);
+ if (!auth->curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
+ curve);
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG,
+ "DPP: Building own configuration/connector with curve %s",
+ auth->curve->name);
+
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+ if (!auth->own_protocol_key)
+ return -1;
+ dpp_copy_netaccesskey(auth);
+ auth->peer_protocol_key = auth->own_protocol_key;
+ dpp_copy_csign(auth, auth->conf->csign);
+
+ conf_obj = dpp_build_conf_obj(auth, ap);
+ if (!conf_obj)
+ goto fail;
+ ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
+ wpabuf_len(conf_obj));
+fail:
+ wpabuf_free(conf_obj);
+ auth->peer_protocol_key = NULL;
+ return ret;
+}
+
+
+static int dpp_compatible_netrole(const char *role1, const char *role2)
+{
+ return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
+ (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
+}
+
+
+static int dpp_connector_compatible_group(struct json_token *root,
+ const char *group_id,
+ const char *net_role)
+{
+ struct json_token *groups, *token;
+
+ groups = json_get_member(root, "groups");
+ if (!groups || groups->type != JSON_ARRAY)
+ return 0;
+
+ for (token = groups->child; token; token = token->sibling) {
+ struct json_token *id, *role;
+
+ id = json_get_member(token, "groupId");
+ if (!id || id->type != JSON_STRING)
+ continue;
+
+ role = json_get_member(token, "netRole");
+ if (!role || role->type != JSON_STRING)
+ continue;
+
+ if (os_strcmp(id->string, "*") != 0 &&
+ os_strcmp(group_id, "*") != 0 &&
+ os_strcmp(id->string, group_id) != 0)
+ continue;
+
+ if (dpp_compatible_netrole(role->string, net_role))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int dpp_connector_match_groups(struct json_token *own_root,
+ struct json_token *peer_root)
+{
+ struct json_token *groups, *token;
+
+ groups = json_get_member(peer_root, "groups");
+ if (!groups || groups->type != JSON_ARRAY) {
+ wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
+ return 0;
+ }
+
+ for (token = groups->child; token; token = token->sibling) {
+ struct json_token *id, *role;
+
+ id = json_get_member(token, "groupId");
+ if (!id || id->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing peer groupId string");
+ continue;
+ }
+
+ role = json_get_member(token, "netRole");
+ if (!role || role->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing peer groups::netRole string");
+ continue;
+ }
+ wpa_printf(MSG_DEBUG,
+ "DPP: peer connector group: groupId='%s' netRole='%s'",
+ id->string, role->string);
+ if (dpp_connector_compatible_group(own_root, id->string,
+ role->string)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Compatible group/netRole in own connector");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
+ unsigned int hash_len)
+{
+ u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
+ const char *info = "DPP PMK";
+ int res;
+
+ /* PMK = HKDF(<>, "DPP PMK", N.x) */
+
+ /* HKDF-Extract(<>, N.x) */
+ os_memset(salt, 0, hash_len);
+ if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
+ prk, hash_len);
+
+ /* HKDF-Expand(PRK, info, L) */
+ res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
+ pmk, hash_len);
+ return 0;
+}
+
+
+static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
+ EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
+{
+ struct wpabuf *nkx, *pkx;
+ int ret = -1, res;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 hash[SHA256_MAC_LEN];
+
+ /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
+ nkx = dpp_get_pubkey_point(own_key, 0);
+ pkx = dpp_get_pubkey_point(peer_key, 0);
+ if (!nkx || !pkx)
+ goto fail;
+ addr[0] = wpabuf_head(nkx);
+ len[0] = wpabuf_len(nkx) / 2;
+ addr[1] = wpabuf_head(pkx);
+ len[1] = wpabuf_len(pkx) / 2;
+ if (len[0] != len[1])
+ goto fail;
+ if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
+ addr[0] = wpabuf_head(pkx);
+ addr[1] = wpabuf_head(nkx);
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
+ res = sha256_vector(2, addr, len, hash);
+ if (res < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
+ ret = 0;
+fail:
+ wpabuf_free(nkx);
+ wpabuf_free(pkx);
+ return ret;
+}
+
+
+enum dpp_status_error
+dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
+ const u8 *net_access_key, size_t net_access_key_len,
+ const u8 *csign_key, size_t csign_key_len,
+ const u8 *peer_connector, size_t peer_connector_len,
+ os_time_t *expiry)
+{
+ struct json_token *root = NULL, *netkey, *token;
+ struct json_token *own_root = NULL;
+ enum dpp_status_error ret = 255, res;
+ EVP_PKEY *own_key = NULL, *peer_key = NULL;
+ struct wpabuf *own_key_pub = NULL;
+ const struct dpp_curve_params *curve, *own_curve;
+ struct dpp_signed_connector_info info;
+ const unsigned char *p;
+ EVP_PKEY *csign = NULL;
+ char *signed_connector = NULL;
+ const char *pos, *end;
+ unsigned char *own_conn = NULL;
+ size_t own_conn_len;
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t Nx_len;
+ u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
+
+ os_memset(intro, 0, sizeof(*intro));
+ os_memset(&info, 0, sizeof(info));
+ if (expiry)
+ *expiry = 0;
+
+ p = csign_key;
+ csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ if (!csign) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to parse local C-sign-key information");
+ goto fail;
+ }
+
+ own_key = dpp_set_keypair(&own_curve, net_access_key,
+ net_access_key_len);
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ goto fail;
+ }
+
+ pos = os_strchr(own_connector, '.');
+ if (!pos) {
+ wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
+ goto fail;
+ }
+ pos++;
+ end = os_strchr(pos, '.');
+ if (!end) {
+ wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
+ goto fail;
+ }
+ own_conn = base64_url_decode((const unsigned char *) pos,
+ end - pos, &own_conn_len);
+ if (!own_conn) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to base64url decode own signedConnector JWS Payload");
+ goto fail;
+ }
+
+ own_root = json_parse((const char *) own_conn, own_conn_len);
+ if (!own_root) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
+ goto fail;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
+ peer_connector, peer_connector_len);
+ signed_connector = os_malloc(peer_connector_len + 1);
+ if (!signed_connector)
+ goto fail;
+ os_memcpy(signed_connector, peer_connector, peer_connector_len);
+ signed_connector[peer_connector_len] = '\0';
+
+ res = dpp_process_signed_connector(&info, csign, signed_connector);
+ if (res != DPP_STATUS_OK) {
+ ret = res;
+ goto fail;
+ }
+
+ root = json_parse((const char *) info.payload, info.payload_len);
+ if (!root) {
+ wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ if (!dpp_connector_match_groups(own_root, root)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer connector does not include compatible group netrole with own connector");
+ ret = DPP_STATUS_NO_MATCH;
+ goto fail;
+ }
+
+ token = json_get_member(root, "expiry");
+ if (!token || token->type != JSON_STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No expiry string found - connector does not expire");
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
+ if (dpp_key_expired(token->string, expiry)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Connector (netAccessKey) has expired");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ }
+
+ netkey = json_get_member(root, "netAccessKey");
+ if (!netkey || netkey->type != JSON_OBJECT) {
+ wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ peer_key = dpp_parse_jwk(netkey, &curve);
+ if (!peer_key) {
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
+
+ if (own_curve != curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Mismatching netAccessKey curves (%s != %s)",
+ own_curve->name, curve->name);
+ ret = DPP_STATUS_INVALID_CONNECTOR;
+ goto fail;
+ }
+
+ /* ECDH: N = nk * PK */
+ ctx = EVP_PKEY_CTX_new(own_key, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
+ Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
+ Nx, Nx_len);
+
+ /* PMK = HKDF(<>, "DPP PMK", N.x) */
+ if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
+ goto fail;
+ }
+ intro->pmk_len = curve->hash_len;
+
+ /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
+ if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
+ goto fail;
+ }
+
+ ret = DPP_STATUS_OK;
+fail:
+ if (ret != DPP_STATUS_OK)
+ os_memset(intro, 0, sizeof(*intro));
+ os_memset(Nx, 0, sizeof(Nx));
+ EVP_PKEY_CTX_free(ctx);
+ os_free(own_conn);
+ os_free(signed_connector);
+ os_free(info.payload);
+ EVP_PKEY_free(own_key);
+ wpabuf_free(own_key_pub);
+ EVP_PKEY_free(peer_key);
+ EVP_PKEY_free(csign);
+ json_free(root);
+ json_free(own_root);
+ return ret;
+}
+
+
+static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
+ int init)
+{
+ EC_GROUP *group;
+ size_t len = curve->prime_len;
+ const u8 *x, *y;
+
+ switch (curve->ike_group) {
+ case 19:
+ x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
+ y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
+ break;
+ case 20:
+ x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
+ y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
+ break;
+ case 21:
+ x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
+ y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
+ break;
+ case 28:
+ x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
+ y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
+ break;
+ case 29:
+ x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
+ y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
+ break;
+ case 30:
+ x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
+ y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
+ break;
+ default:
+ return NULL;
+ }
+
+ group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
+ if (!group)
+ return NULL;
+ return dpp_set_pubkey_point_group(group, x, y, len);
+}
+
+
+static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
+ const u8 *mac_init, const char *code,
+ const char *identifier, BN_CTX *bnctx,
+ const EC_GROUP **ret_group)
+{
+ u8 hash[DPP_MAX_HASH_LEN];
+ const u8 *addr[3];
+ size_t len[3];
+ unsigned int num_elem = 0;
+ EC_POINT *Qi = NULL;
+ EVP_PKEY *Pi = NULL;
+ EC_KEY *Pi_ec = NULL;
+ const EC_POINT *Pi_point;
+ BIGNUM *hash_bn = NULL;
+ const EC_GROUP *group = NULL;
+ EC_GROUP *group2 = NULL;
+
+ /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+
+ wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
+ addr[num_elem] = mac_init;
+ len[num_elem] = ETH_ALEN;
+ num_elem++;
+ if (identifier) {
+ wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
+ identifier);
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
+ addr[num_elem] = (const u8 *) code;
+ len[num_elem] = os_strlen(code);
+ num_elem++;
+ if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: H(MAC-Initiator | [identifier |] code)",
+ hash, curve->hash_len);
+ Pi = dpp_pkex_get_role_elem(curve, 1);
+ if (!Pi)
+ goto fail;
+ dpp_debug_print_key("DPP: Pi", Pi);
+ Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
+ if (!Pi_ec)
+ goto fail;
+ Pi_point = EC_KEY_get0_public_key(Pi_ec);
+
+ group = EC_KEY_get0_group(Pi_ec);
+ if (!group)
+ goto fail;
+ group2 = EC_GROUP_dup(group);
+ if (!group2)
+ goto fail;
+ Qi = EC_POINT_new(group2);
+ if (!Qi) {
+ EC_GROUP_free(group2);
+ goto fail;
+ }
+ hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
+ if (!hash_bn ||
+ EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
+ goto fail;
+ if (EC_POINT_is_at_infinity(group, Qi)) {
+ wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: Qi", group, Qi);
+out:
+ EC_KEY_free(Pi_ec);
+ EVP_PKEY_free(Pi);
+ BN_clear_free(hash_bn);
+ if (ret_group)
+ *ret_group = group2;
+ return Qi;
+fail:
+ EC_POINT_free(Qi);
+ Qi = NULL;
+ goto out;
+}
+
+
+static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
+ const u8 *mac_resp, const char *code,
+ const char *identifier, BN_CTX *bnctx,
+ const EC_GROUP **ret_group)
+{
+ u8 hash[DPP_MAX_HASH_LEN];
+ const u8 *addr[3];
+ size_t len[3];
+ unsigned int num_elem = 0;
+ EC_POINT *Qr = NULL;
+ EVP_PKEY *Pr = NULL;
+ EC_KEY *Pr_ec = NULL;
+ const EC_POINT *Pr_point;
+ BIGNUM *hash_bn = NULL;
+ const EC_GROUP *group = NULL;
+ EC_GROUP *group2 = NULL;
+
+ /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
+
+ wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
+ addr[num_elem] = mac_resp;
+ len[num_elem] = ETH_ALEN;
+ num_elem++;
+ if (identifier) {
+ wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
+ identifier);
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
+ addr[num_elem] = (const u8 *) code;
+ len[num_elem] = os_strlen(code);
+ num_elem++;
+ if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: H(MAC-Responder | [identifier |] code)",
+ hash, curve->hash_len);
+ Pr = dpp_pkex_get_role_elem(curve, 0);
+ if (!Pr)
+ goto fail;
+ dpp_debug_print_key("DPP: Pr", Pr);
+ Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
+ if (!Pr_ec)
+ goto fail;
+ Pr_point = EC_KEY_get0_public_key(Pr_ec);
+
+ group = EC_KEY_get0_group(Pr_ec);
+ if (!group)
+ goto fail;
+ group2 = EC_GROUP_dup(group);
+ if (!group2)
+ goto fail;
+ Qr = EC_POINT_new(group2);
+ if (!Qr) {
+ EC_GROUP_free(group2);
+ goto fail;
+ }
+ hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
+ if (!hash_bn ||
+ EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
+ goto fail;
+ if (EC_POINT_is_at_infinity(group, Qr)) {
+ wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: Qr", group, Qr);
+out:
+ EC_KEY_free(Pr_ec);
+ EVP_PKEY_free(Pr);
+ BN_clear_free(hash_bn);
+ if (ret_group)
+ *ret_group = group2;
+ return Qr;
+fail:
+ EC_POINT_free(Qr);
+ Qr = NULL;
+ goto out;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+static int dpp_test_gen_invalid_key(struct wpabuf *msg,
+ const struct dpp_curve_params *curve)
+{
+ BN_CTX *ctx;
+ BIGNUM *x, *y;
+ int ret = -1;
+ EC_GROUP *group;
+ EC_POINT *point;
+
+ group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
+ if (!group)
+ return -1;
+
+ ctx = BN_CTX_new();
+ point = EC_POINT_new(group);
+ x = BN_new();
+ y = BN_new();
+ if (!ctx || !point || !x || !y)
+ goto fail;
+
+ if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
+ goto fail;
+
+ /* Generate a random y coordinate that results in a point that is not
+ * on the curve. */
+ for (;;) {
+ if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
+ goto fail;
+
+ if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
+ ctx) != 1) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
+ /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
+ * return an error from EC_POINT_set_affine_coordinates_GFp()
+ * when the point is not on the curve. */
+ break;
+#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
+ goto fail;
+#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
+ }
+
+ if (!EC_POINT_is_on_curve(group, point, ctx))
+ break;
+ }
+
+ if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ if (ret < 0)
+ wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
+ BN_free(x);
+ BN_free(y);
+ EC_POINT_free(point);
+ BN_CTX_free(ctx);
+
+ return ret;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
+{
+ EC_KEY *X_ec = NULL;
+ const EC_POINT *X_point;
+ BN_CTX *bnctx = NULL;
+ const EC_GROUP *group;
+ EC_POINT *Qi = NULL, *M = NULL;
+ struct wpabuf *M_buf = NULL;
+ BIGNUM *Mx = NULL, *My = NULL;
+ struct wpabuf *msg = NULL;
+ size_t attr_len;
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
+
+ /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ goto fail;
+ Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
+ pkex->identifier, bnctx, &group);
+ if (!Qi)
+ goto fail;
+
+ /* Generate a random ephemeral keypair x/X */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_pkex_ephemeral_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override ephemeral key x/X");
+ pkex->x = dpp_set_keypair(&tmp_curve,
+ dpp_pkex_ephemeral_key_override,
+ dpp_pkex_ephemeral_key_override_len);
+ } else {
+ pkex->x = dpp_gen_keypair(curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ pkex->x = dpp_gen_keypair(curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!pkex->x)
+ goto fail;
+
+ /* M = X + Qi */
+ X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
+ if (!X_ec)
+ goto fail;
+ X_point = EC_KEY_get0_public_key(X_ec);
+ if (!X_point)
+ goto fail;
+ dpp_debug_print_point("DPP: X", group, X_point);
+ M = EC_POINT_new(group);
+ Mx = BN_new();
+ My = BN_new();
+ if (!M || !Mx || !My ||
+ EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
+ goto fail;
+ dpp_debug_print_point("DPP: M", group, M);
+
+ /* Initiator -> Responder: group, [identifier,] M */
+ attr_len = 4 + 2;
+ if (pkex->identifier)
+ attr_len += 4 + os_strlen(pkex->identifier);
+ attr_len += 4 + 2 * curve->prime_len;
+ msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
+ if (!msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
+ goto skip_finite_cyclic_group;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Finite Cyclic Group attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_le16(msg, curve->ike_group);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_finite_cyclic_group:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Code Identifier attribute */
+ if (pkex->identifier) {
+ wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
+ wpabuf_put_le16(msg, os_strlen(pkex->identifier));
+ wpabuf_put_str(msg, pkex->identifier);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
+ goto out;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* M in Encrypted Key attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
+ wpabuf_put_le16(msg, 2 * curve->prime_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
+ if (dpp_test_gen_invalid_key(msg, curve) < 0)
+ goto fail;
+ goto out;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
+ goto fail;
+
+out:
+ wpabuf_free(M_buf);
+ EC_KEY_free(X_ec);
+ EC_POINT_free(M);
+ EC_POINT_free(Qi);
+ BN_clear_free(Mx);
+ BN_clear_free(My);
+ BN_CTX_free(bnctx);
+ return msg;
+fail:
+ wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
+{
+ wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
+}
+
+
+struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
+ const u8 *own_mac,
+ const char *identifier,
+ const char *code)
+{
+ struct dpp_pkex *pkex;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
+ MAC2STR(dpp_pkex_own_mac_override));
+ own_mac = dpp_pkex_own_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ pkex = os_zalloc(sizeof(*pkex));
+ if (!pkex)
+ return NULL;
+ pkex->msg_ctx = msg_ctx;
+ pkex->initiator = 1;
+ pkex->own_bi = bi;
+ os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
+ if (identifier) {
+ pkex->identifier = os_strdup(identifier);
+ if (!pkex->identifier)
+ goto fail;
+ }
+ pkex->code = os_strdup(code);
+ if (!pkex->code)
+ goto fail;
+ pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
+ if (!pkex->exchange_req)
+ goto fail;
+ return pkex;
+fail:
+ dpp_pkex_free(pkex);
+ return NULL;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
+ enum dpp_status_error status,
+ const BIGNUM *Nx, const BIGNUM *Ny)
+{
+ struct wpabuf *msg = NULL;
+ size_t attr_len;
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+
+ /* Initiator -> Responder: DPP Status, [identifier,] N */
+ attr_len = 4 + 1;
+ if (pkex->identifier)
+ attr_len += 4 + os_strlen(pkex->identifier);
+ attr_len += 4 + 2 * curve->prime_len;
+ msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
+ if (!msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ goto skip_status;
+ }
+
+ if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 255;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Status */
+ dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Code Identifier attribute */
+ if (pkex->identifier) {
+ wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
+ wpabuf_put_le16(msg, os_strlen(pkex->identifier));
+ wpabuf_put_str(msg, pkex->identifier);
+ }
+
+ if (status != DPP_STATUS_OK)
+ goto skip_encrypted_key;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
+ goto skip_encrypted_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* N in Encrypted Key attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
+ wpabuf_put_le16(msg, 2 * curve->prime_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
+ if (dpp_test_gen_invalid_key(msg, curve) < 0)
+ goto fail;
+ goto skip_encrypted_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
+ goto fail;
+
+skip_encrypted_key:
+ if (status == DPP_STATUS_BAD_GROUP) {
+ /* Finite Cyclic Group attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_le16(msg, curve->ike_group);
+ }
+
+ return msg;
+fail:
+ wpabuf_free(msg);
+ return NULL;
+}
+
+
+static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
+ const u8 *Mx, size_t Mx_len,
+ const u8 *Nx, size_t Nx_len,
+ const char *code,
+ const u8 *Kx, size_t Kx_len,
+ u8 *z, unsigned int hash_len)
+{
+ u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
+ int res;
+ u8 *info, *pos;
+ size_t info_len;
+
+ /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+ */
+
+ /* HKDF-Extract(<>, IKM=K.x) */
+ os_memset(salt, 0, hash_len);
+ if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
+ prk, hash_len);
+ info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
+ info = os_malloc(info_len);
+ if (!info)
+ return -1;
+ pos = info;
+ os_memcpy(pos, mac_init, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, mac_resp, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, Mx, Mx_len);
+ pos += Mx_len;
+ os_memcpy(pos, Nx, Nx_len);
+ pos += Nx_len;
+ os_memcpy(pos, code, os_strlen(code));
+
+ /* HKDF-Expand(PRK, info, L) */
+ if (hash_len == 32)
+ res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
+ z, hash_len);
+ else if (hash_len == 48)
+ res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
+ z, hash_len);
+ else if (hash_len == 64)
+ res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
+ z, hash_len);
+ else
+ res = -1;
+ os_free(info);
+ os_memset(prk, 0, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
+ z, hash_len);
+ return 0;
+}
+
+
+static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
+ const char *identifier)
+{
+ if (!attr_id && identifier) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No PKEX code identifier received, but expected one");
+ return 0;
+ }
+
+ if (attr_id && !identifier) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX code identifier received, but not expecting one");
+ return 0;
+ }
+
+ if (attr_id && identifier &&
+ (os_strlen(identifier) != attr_id_len ||
+ os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
+ wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
+ struct dpp_bootstrap_info *bi,
+ const u8 *own_mac,
+ const u8 *peer_mac,
+ const char *identifier,
+ const char *code,
+ const u8 *buf, size_t len)
+{
+ const u8 *attr_group, *attr_id, *attr_key;
+ u16 attr_group_len, attr_id_len, attr_key_len;
+ const struct dpp_curve_params *curve = bi->curve;
+ u16 ike_group;
+ struct dpp_pkex *pkex = NULL;
+ EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
+ BN_CTX *bnctx = NULL;
+ const EC_GROUP *group;
+ BIGNUM *Mx = NULL, *My = NULL;
+ EC_KEY *Y_ec = NULL, *X_ec = NULL;;
+ const EC_POINT *Y_point;
+ BIGNUM *Nx = NULL, *Ny = NULL;
+ u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Kx_len;
+ int res;
+ EVP_PKEY_CTX *ctx = NULL;
+
+ if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "PKEX counter t limit reached - ignore message");
+ return NULL;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
+ MAC2STR(dpp_pkex_peer_mac_override));
+ peer_mac = dpp_pkex_peer_mac_override;
+ }
+ if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
+ MAC2STR(dpp_pkex_own_mac_override));
+ own_mac = dpp_pkex_own_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ attr_id_len = 0;
+ attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
+ &attr_id_len);
+ if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
+ return NULL;
+
+ attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &attr_group_len);
+ if (!attr_group || attr_group_len != 2) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid Finite Cyclic Group attribute");
+ return NULL;
+ }
+ ike_group = WPA_GET_LE16(attr_group);
+ if (ike_group != curve->ike_group) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Mismatching PKEX curve: peer=%u own=%u",
+ ike_group, curve->ike_group);
+ pkex = os_zalloc(sizeof(*pkex));
+ if (!pkex)
+ goto fail;
+ pkex->own_bi = bi;
+ pkex->failed = 1;
+ pkex->exchange_resp = dpp_pkex_build_exchange_resp(
+ pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
+ if (!pkex->exchange_resp)
+ goto fail;
+ return pkex;
+ }
+
+ /* M in Encrypted Key attribute */
+ attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
+ &attr_key_len);
+ if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
+ attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing Encrypted Key attribute");
+ return NULL;
+ }
+
+ /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ goto fail;
+ Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
+ &group);
+ if (!Qi)
+ goto fail;
+
+ /* X' = M - Qi */
+ X = EC_POINT_new(group);
+ M = EC_POINT_new(group);
+ Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
+ My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
+ if (!X || !M || !Mx || !My ||
+ EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, M) ||
+ !EC_POINT_is_on_curve(group, M, bnctx) ||
+ EC_POINT_invert(group, Qi, bnctx) != 1 ||
+ EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, X) ||
+ !EC_POINT_is_on_curve(group, X, bnctx)) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Invalid Encrypted Key value");
+ bi->pkex_t++;
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: M", group, M);
+ dpp_debug_print_point("DPP: X'", group, X);
+
+ pkex = os_zalloc(sizeof(*pkex));
+ if (!pkex)
+ goto fail;
+ pkex->t = bi->pkex_t;
+ pkex->msg_ctx = msg_ctx;
+ pkex->own_bi = bi;
+ os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
+ os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+ if (identifier) {
+ pkex->identifier = os_strdup(identifier);
+ if (!pkex->identifier)
+ goto fail;
+ }
+ pkex->code = os_strdup(code);
+ if (!pkex->code)
+ goto fail;
+
+ os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
+
+ X_ec = EC_KEY_new();
+ if (!X_ec ||
+ EC_KEY_set_group(X_ec, group) != 1 ||
+ EC_KEY_set_public_key(X_ec, X) != 1)
+ goto fail;
+ pkex->x = EVP_PKEY_new();
+ if (!pkex->x ||
+ EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
+ goto fail;
+
+ /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
+ Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
+ if (!Qr)
+ goto fail;
+
+ /* Generate a random ephemeral keypair y/Y */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_pkex_ephemeral_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override ephemeral key y/Y");
+ pkex->y = dpp_set_keypair(&tmp_curve,
+ dpp_pkex_ephemeral_key_override,
+ dpp_pkex_ephemeral_key_override_len);
+ } else {
+ pkex->y = dpp_gen_keypair(curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ pkex->y = dpp_gen_keypair(curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!pkex->y)
+ goto fail;
+
+ /* N = Y + Qr */
+ Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
+ if (!Y_ec)
+ goto fail;
+ Y_point = EC_KEY_get0_public_key(Y_ec);
+ if (!Y_point)
+ goto fail;
+ dpp_debug_print_point("DPP: Y", group, Y_point);
+ N = EC_POINT_new(group);
+ Nx = BN_new();
+ Ny = BN_new();
+ if (!N || !Nx || !Ny ||
+ EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
+ goto fail;
+ dpp_debug_print_point("DPP: N", group, N);
+
+ pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
+ Nx, Ny);
+ if (!pkex->exchange_resp)
+ goto fail;
+
+ /* K = y * X' */
+ ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
+ Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
+ Kx, Kx_len);
+
+ /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+ */
+ res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
+ pkex->Mx, curve->prime_len,
+ pkex->Nx, curve->prime_len, pkex->code,
+ Kx, Kx_len, pkex->z, curve->hash_len);
+ os_memset(Kx, 0, Kx_len);
+ if (res < 0)
+ goto fail;
+
+ pkex->exchange_done = 1;
+
+out:
+ EVP_PKEY_CTX_free(ctx);
+ BN_CTX_free(bnctx);
+ EC_POINT_free(Qi);
+ EC_POINT_free(Qr);
+ BN_free(Mx);
+ BN_free(My);
+ BN_free(Nx);
+ BN_free(Ny);
+ EC_POINT_free(M);
+ EC_POINT_free(N);
+ EC_POINT_free(X);
+ EC_KEY_free(X_ec);
+ EC_KEY_free(Y_ec);
+ return pkex;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
+ dpp_pkex_free(pkex);
+ pkex = NULL;
+ goto out;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
+ const struct wpabuf *A_pub, const u8 *u)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ struct wpabuf *msg = NULL;
+ size_t clear_len, attr_len;
+ struct wpabuf *clear = NULL;
+ u8 *wrapped;
+ u8 octet;
+ const u8 *addr[2];
+ size_t len[2];
+
+ /* {A, u, [bootstrapping info]}z */
+ clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
+ clear = wpabuf_alloc(clear_len);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
+ goto skip_bootstrap_key;
+ }
+ if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, 2 * curve->prime_len);
+ if (dpp_test_gen_invalid_key(clear, curve) < 0)
+ goto fail;
+ goto skip_bootstrap_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* A in Bootstrap Key attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(A_pub));
+ wpabuf_put_buf(clear, A_pub);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_bootstrap_key:
+ if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
+ goto skip_i_auth_tag;
+ }
+ if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
+ wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, u, curve->hash_len - 1);
+ wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
+ goto skip_i_auth_tag;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* u in I-Auth tag attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, u, curve->hash_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_i_auth_tag:
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = DPP_HDR_LEN;
+ octet = 0;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(pkex->z, curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+out:
+ wpabuf_free(clear);
+ return msg;
+
+fail:
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
+ const u8 *peer_mac,
+ const u8 *buf, size_t buflen)
+{
+ const u8 *attr_status, *attr_id, *attr_key, *attr_group;
+ u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
+ const EC_GROUP *group;
+ BN_CTX *bnctx = NULL;
+ struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
+ BIGNUM *Nx = NULL, *Ny = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ EC_KEY *Y_ec = NULL;
+ size_t Jx_len, Kx_len;
+ u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 u[DPP_MAX_HASH_LEN];
+ int res;
+
+ if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
+ return NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX Exchange Response");
+ pkex->failed = 1;
+ return NULL;
+ }
+
+ if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
+ MAC2STR(dpp_pkex_peer_mac_override));
+ peer_mac = dpp_pkex_peer_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+
+ attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
+ &attr_status_len);
+ if (!attr_status || attr_status_len != 1) {
+ dpp_pkex_fail(pkex, "No DPP Status attribute");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
+
+ if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
+ attr_group = dpp_get_attr(buf, buflen,
+ DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &attr_group_len);
+ if (attr_group && attr_group_len == 2) {
+ wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Peer indicated mismatching PKEX group - proposed %u",
+ WPA_GET_LE16(attr_group));
+ return NULL;
+ }
+ }
+
+ if (attr_status[0] != DPP_STATUS_OK) {
+ dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
+ return NULL;
+ }
+
+ attr_id_len = 0;
+ attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
+ &attr_id_len);
+ if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
+ pkex->identifier)) {
+ dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
+ return NULL;
+ }
+
+ /* N in Encrypted Key attribute */
+ attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
+ &attr_key_len);
+ if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
+ dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
+ return NULL;
+ }
+
+ /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ goto fail;
+ Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
+ pkex->identifier, bnctx, &group);
+ if (!Qr)
+ goto fail;
+
+ /* Y' = N - Qr */
+ Y = EC_POINT_new(group);
+ N = EC_POINT_new(group);
+ Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
+ Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
+ if (!Y || !N || !Nx || !Ny ||
+ EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, N) ||
+ !EC_POINT_is_on_curve(group, N, bnctx) ||
+ EC_POINT_invert(group, Qr, bnctx) != 1 ||
+ EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, Y) ||
+ !EC_POINT_is_on_curve(group, Y, bnctx)) {
+ dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
+ pkex->t++;
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: N", group, N);
+ dpp_debug_print_point("DPP: Y'", group, Y);
+
+ pkex->exchange_done = 1;
+
+ /* ECDH: J = a * Y’ */
+ Y_ec = EC_KEY_new();
+ if (!Y_ec ||
+ EC_KEY_set_group(Y_ec, group) != 1 ||
+ EC_KEY_set_public_key(Y_ec, Y) != 1)
+ goto fail;
+ pkex->y = EVP_PKEY_new();
+ if (!pkex->y ||
+ EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
+ goto fail;
+ ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
+ Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
+ Jx, Jx_len);
+
+ /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
+ A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
+ Y_pub = dpp_get_pubkey_point(pkex->y, 0);
+ X_pub = dpp_get_pubkey_point(pkex->x, 0);
+ if (!A_pub || !Y_pub || !X_pub)
+ goto fail;
+ addr[0] = pkex->own_mac;
+ len[0] = ETH_ALEN;
+ addr[1] = wpabuf_head(A_pub);
+ len[1] = wpabuf_len(A_pub) / 2;
+ addr[2] = wpabuf_head(Y_pub);
+ len[2] = wpabuf_len(Y_pub) / 2;
+ addr[3] = wpabuf_head(X_pub);
+ len[3] = wpabuf_len(X_pub) / 2;
+ if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
+
+ /* K = x * Y’ */
+ EVP_PKEY_CTX_free(ctx);
+ ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
+ Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
+ Kx, Kx_len);
+
+ /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+ */
+ res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
+ pkex->Mx, curve->prime_len,
+ attr_key /* N.x */, attr_key_len / 2,
+ pkex->code, Kx, Kx_len,
+ pkex->z, curve->hash_len);
+ os_memset(Kx, 0, Kx_len);
+ if (res < 0)
+ goto fail;
+
+ msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
+ if (!msg)
+ goto fail;
+
+out:
+ wpabuf_free(A_pub);
+ wpabuf_free(X_pub);
+ wpabuf_free(Y_pub);
+ EC_POINT_free(Qr);
+ EC_POINT_free(Y);
+ EC_POINT_free(N);
+ BN_free(Nx);
+ BN_free(Ny);
+ EC_KEY_free(Y_ec);
+ EVP_PKEY_CTX_free(ctx);
+ BN_CTX_free(bnctx);
+ return msg;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
+ goto out;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
+ const struct wpabuf *B_pub, const u8 *v)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ struct wpabuf *msg = NULL;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 octet;
+ u8 *wrapped;
+ struct wpabuf *clear = NULL;
+ size_t clear_len, attr_len;
+
+ /* {B, v [bootstrapping info]}z */
+ clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
+ clear = wpabuf_alloc(clear_len);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
+ goto skip_bootstrap_key;
+ }
+ if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, 2 * curve->prime_len);
+ if (dpp_test_gen_invalid_key(clear, curve) < 0)
+ goto fail;
+ goto skip_bootstrap_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* B in Bootstrap Key attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(B_pub));
+ wpabuf_put_buf(clear, B_pub);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_bootstrap_key:
+ if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
+ goto skip_r_auth_tag;
+ }
+ if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
+ wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, v, curve->hash_len - 1);
+ wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
+ goto skip_r_auth_tag;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* v in R-Auth tag attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, v, curve->hash_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_r_auth_tag:
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = DPP_HDR_LEN;
+ octet = 1;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(pkex->z, curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+out:
+ wpabuf_free(clear);
+ return msg;
+
+fail:
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
+ const u8 *hdr,
+ const u8 *buf, size_t buflen)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t Jx_len, Lx_len;
+ u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
+ u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
+ const u8 *wrapped_data, *b_key, *peer_u;
+ u16 wrapped_data_len, b_key_len, peer_u_len = 0;
+ const u8 *addr[4];
+ size_t len[4];
+ u8 octet;
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
+ struct wpabuf *B_pub = NULL;
+ u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX CR Request");
+ pkex->failed = 1;
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!pkex->exchange_done || pkex->failed ||
+ pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
+ goto fail;
+
+ wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_pkex_fail(pkex,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ octet = 0;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ if (aes_siv_decrypt(pkex->z, curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_pkex_fail(pkex,
+ "AES-SIV decryption failed - possible PKEX code mismatch");
+ pkex->failed = 1;
+ pkex->t++;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
+ &b_key_len);
+ if (!b_key || b_key_len != 2 * curve->prime_len) {
+ dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
+ goto fail;
+ }
+ pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
+ b_key_len);
+ if (!pkex->peer_bootstrap_key) {
+ dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Peer bootstrap public key",
+ pkex->peer_bootstrap_key);
+
+ /* ECDH: J' = y * A' */
+ ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
+ Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
+ Jx, Jx_len);
+
+ /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
+ A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
+ Y_pub = dpp_get_pubkey_point(pkex->y, 0);
+ X_pub = dpp_get_pubkey_point(pkex->x, 0);
+ if (!A_pub || !Y_pub || !X_pub)
+ goto fail;
+ addr[0] = pkex->peer_mac;
+ len[0] = ETH_ALEN;
+ addr[1] = wpabuf_head(A_pub);
+ len[1] = wpabuf_len(A_pub) / 2;
+ addr[2] = wpabuf_head(Y_pub);
+ len[2] = wpabuf_len(Y_pub) / 2;
+ addr[3] = wpabuf_head(X_pub);
+ len[3] = wpabuf_len(X_pub) / 2;
+ if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
+ goto fail;
+
+ peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
+ &peer_u_len);
+ if (!peer_u || peer_u_len != curve->hash_len ||
+ os_memcmp(peer_u, u, curve->hash_len) != 0) {
+ dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
+ u, curve->hash_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
+ pkex->t++;
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
+
+ /* ECDH: L = b * X' */
+ EVP_PKEY_CTX_free(ctx);
+ ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
+ Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
+ Lx, Lx_len);
+
+ /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
+ B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
+ if (!B_pub)
+ goto fail;
+ addr[0] = pkex->own_mac;
+ len[0] = ETH_ALEN;
+ addr[1] = wpabuf_head(B_pub);
+ len[1] = wpabuf_len(B_pub) / 2;
+ addr[2] = wpabuf_head(X_pub);
+ len[2] = wpabuf_len(X_pub) / 2;
+ addr[3] = wpabuf_head(Y_pub);
+ len[3] = wpabuf_len(Y_pub) / 2;
+ if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
+
+ msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
+ if (!msg)
+ goto fail;
+
+out:
+ EVP_PKEY_CTX_free(ctx);
+ os_free(unwrapped);
+ wpabuf_free(A_pub);
+ wpabuf_free(B_pub);
+ wpabuf_free(X_pub);
+ wpabuf_free(Y_pub);
+ return msg;
+fail:
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX Commit-Reveal Request processing failed");
+ goto out;
+}
+
+
+int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
+ const u8 *buf, size_t buflen)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ const u8 *wrapped_data, *b_key, *peer_v;
+ u16 wrapped_data_len, b_key_len, peer_v_len = 0;
+ const u8 *addr[4];
+ size_t len[4];
+ u8 octet;
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ int ret = -1;
+ u8 v[DPP_MAX_HASH_LEN];
+ size_t Lx_len;
+ u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
+ EVP_PKEY_CTX *ctx = NULL;
+ struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX CR Response");
+ pkex->failed = 1;
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!pkex->exchange_done || pkex->failed ||
+ pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
+ goto fail;
+
+ wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_pkex_fail(pkex,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ octet = 1;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ if (aes_siv_decrypt(pkex->z, curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_pkex_fail(pkex,
+ "AES-SIV decryption failed - possible PKEX code mismatch");
+ pkex->t++;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
+ &b_key_len);
+ if (!b_key || b_key_len != 2 * curve->prime_len) {
+ dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
+ goto fail;
+ }
+ pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
+ b_key_len);
+ if (!pkex->peer_bootstrap_key) {
+ dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Peer bootstrap public key",
+ pkex->peer_bootstrap_key);
+
+ /* ECDH: L' = x * B' */
+ ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
+ Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
+ Lx, Lx_len);
+
+ /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
+ B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
+ X_pub = dpp_get_pubkey_point(pkex->x, 0);
+ Y_pub = dpp_get_pubkey_point(pkex->y, 0);
+ if (!B_pub || !X_pub || !Y_pub)
+ goto fail;
+ addr[0] = pkex->peer_mac;
+ len[0] = ETH_ALEN;
+ addr[1] = wpabuf_head(B_pub);
+ len[1] = wpabuf_len(B_pub) / 2;
+ addr[2] = wpabuf_head(X_pub);
+ len[2] = wpabuf_len(X_pub) / 2;
+ addr[3] = wpabuf_head(Y_pub);
+ len[3] = wpabuf_len(Y_pub) / 2;
+ if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
+ goto fail;
+
+ peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
+ &peer_v_len);
+ if (!peer_v || peer_v_len != curve->hash_len ||
+ os_memcmp(peer_v, v, curve->hash_len) != 0) {
+ dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
+ wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
+ v, curve->hash_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
+ pkex->t++;
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
+
+ ret = 0;
+out:
+ wpabuf_free(B_pub);
+ wpabuf_free(X_pub);
+ wpabuf_free(Y_pub);
+ EVP_PKEY_CTX_free(ctx);
+ os_free(unwrapped);
+ return ret;
+fail:
+ goto out;
+}
+
+
+void dpp_pkex_free(struct dpp_pkex *pkex)
+{
+ if (!pkex)
+ return;
+
+ os_free(pkex->identifier);
+ os_free(pkex->code);
+ EVP_PKEY_free(pkex->x);
+ EVP_PKEY_free(pkex->y);
+ EVP_PKEY_free(pkex->peer_bootstrap_key);
+ wpabuf_free(pkex->exchange_req);
+ wpabuf_free(pkex->exchange_resp);
+ os_free(pkex);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+char * dpp_corrupt_connector_signature(const char *connector)
+{
+ char *tmp, *pos, *signed3 = NULL;
+ unsigned char *signature = NULL;
+ size_t signature_len = 0, signed3_len;
+
+ tmp = os_zalloc(os_strlen(connector) + 5);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, connector, os_strlen(connector));
+
+ pos = os_strchr(tmp, '.');
+ if (!pos)
+ goto fail;
+
+ pos = os_strchr(pos + 1, '.');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
+ pos);
+ signature = base64_url_decode((const unsigned char *) pos,
+ os_strlen(pos), &signature_len);
+ if (!signature || signature_len == 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
+ signature, signature_len);
+ signature[signature_len - 1] ^= 0x01;
+ wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
+ signature, signature_len);
+ signed3 = (char *) base64_url_encode(signature, signature_len,
+ &signed3_len, 0);
+ if (!signed3)
+ goto fail;
+ os_memcpy(pos, signed3, signed3_len);
+ pos[signed3_len] = '\0';
+ wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
+ pos);
+
+out:
+ os_free(signature);
+ os_free(signed3);
+ return tmp;
+fail:
+ os_free(tmp);
+ tmp = NULL;
+ goto out;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+#ifdef CONFIG_DPP2
+
+struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
+ size_t net_access_key_len)
+{
+ struct wpabuf *pub = NULL;
+ EVP_PKEY *own_key;
+ struct dpp_pfs *pfs;
+
+ pfs = os_zalloc(sizeof(*pfs));
+ if (!pfs)
+ return NULL;
+
+ own_key = dpp_set_keypair(&pfs->curve, net_access_key,
+ net_access_key_len);
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ goto fail;
+ }
+ EVP_PKEY_free(own_key);
+
+ pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
+ if (!pfs->ecdh)
+ goto fail;
+
+ pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
+ pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
+ if (!pub)
+ goto fail;
+
+ pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
+ if (!pfs->ie)
+ goto fail;
+ wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
+ wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
+ wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
+ wpabuf_put_buf(pfs->ie, pub);
+ wpabuf_free(pub);
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
+ pfs->ie);
+
+ return pfs;
+fail:
+ wpabuf_free(pub);
+ dpp_pfs_free(pfs);
+ return NULL;
+}
+
+
+int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
+{
+ if (peer_ie_len < 2)
+ return -1;
+ if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
+ return -1;
+ }
+
+ pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
+ peer_ie_len - 2);
+ pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
+ if (!pfs->secret) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
+ return -1;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
+ return 0;
+}
+
+
+void dpp_pfs_free(struct dpp_pfs *pfs)
+{
+ if (!pfs)
+ return;
+ crypto_ecdh_deinit(pfs->ecdh);
+ wpabuf_free(pfs->ie);
+ wpabuf_clear_free(pfs->secret);
+ os_free(pfs);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+static unsigned int dpp_next_id(struct dpp_global *dpp)
+{
+ struct dpp_bootstrap_info *bi;
+ unsigned int max_id = 0;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (bi->id > max_id)
+ max_id = bi->id;
+ }
+ return max_id + 1;
+}
+
+
+static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_bootstrap_info *bi, *tmp;
+ int found = 0;
+
+ if (!dpp)
+ return -1;
+
+ dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
+ struct dpp_bootstrap_info, list) {
+ if (id && bi->id != id)
+ continue;
+ found = 1;
+ dl_list_del(&bi->list);
+ dpp_bootstrap_info_free(bi);
+ }
+
+ if (id == 0)
+ return 0; /* flush succeeds regardless of entries found */
+ return found ? 0 : -1;
+}
+
+
+struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
+ const char *uri)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ bi = dpp_parse_qr_code(uri);
+ if (!bi)
+ return NULL;
+
+ bi->id = dpp_next_id(dpp);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ return bi;
+}
+
+
+int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
+{
+ char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
+ char *key = NULL;
+ u8 *privkey = NULL;
+ size_t privkey_len = 0;
+ size_t len;
+ int ret = -1;
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return -1;
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ goto fail;
+
+ if (os_strstr(cmd, "type=qrcode"))
+ bi->type = DPP_BOOTSTRAP_QR_CODE;
+ else if (os_strstr(cmd, "type=pkex"))
+ bi->type = DPP_BOOTSTRAP_PKEX;
+ else
+ goto fail;
+
+ chan = get_param(cmd, " chan=");
+ mac = get_param(cmd, " mac=");
+ info = get_param(cmd, " info=");
+ curve = get_param(cmd, " curve=");
+ key = get_param(cmd, " key=");
+
+ if (key) {
+ privkey_len = os_strlen(key) / 2;
+ privkey = os_malloc(privkey_len);
+ if (!privkey ||
+ hexstr2bin(key, privkey, privkey_len) < 0)
+ goto fail;
+ }
+
+ pk = dpp_keygen(bi, curve, privkey, privkey_len);
+ if (!pk)
+ goto fail;
+
+ len = 4; /* "DPP:" */
+ if (chan) {
+ if (dpp_parse_uri_chan_list(bi, chan) < 0)
+ goto fail;
+ len += 3 + os_strlen(chan); /* C:...; */
+ }
+ if (mac) {
+ if (dpp_parse_uri_mac(bi, mac) < 0)
+ goto fail;
+ len += 3 + os_strlen(mac); /* M:...; */
+ }
+ if (info) {
+ if (dpp_parse_uri_info(bi, info) < 0)
+ goto fail;
+ len += 3 + os_strlen(info); /* I:...; */
+ }
+ len += 4 + os_strlen(pk);
+ bi->uri = os_malloc(len + 1);
+ if (!bi->uri)
+ goto fail;
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
+ chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
+ mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
+ info ? "I:" : "", info ? info : "", info ? ";" : "",
+ pk);
+ bi->id = dpp_next_id(dpp);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ ret = bi->id;
+ bi = NULL;
+fail:
+ os_free(curve);
+ os_free(pk);
+ os_free(chan);
+ os_free(mac);
+ os_free(info);
+ str_clear_free(key);
+ bin_clear_free(privkey, privkey_len);
+ dpp_bootstrap_info_free(bi);
+ return ret;
+}
+
+
+struct dpp_bootstrap_info *
+dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (bi->id == id)
+ return bi;
+ }
+ return NULL;
+}
+
+
+int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
+{
+ unsigned int id_val;
+
+ if (os_strcmp(id, "*") == 0) {
+ id_val = 0;
+ } else {
+ id_val = atoi(id);
+ if (id_val == 0)
+ return -1;
+ }
+
+ return dpp_bootstrap_del(dpp, id_val);
+}
+
+
+struct dpp_bootstrap_info *
+dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
+ unsigned int freq)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ return NULL;
+ bi->id = dpp_next_id(dpp);
+ bi->type = DPP_BOOTSTRAP_PKEX;
+ os_memcpy(bi->mac_addr, peer, ETH_ALEN);
+ bi->num_freq = 1;
+ bi->freq[0] = freq;
+ bi->curve = pkex->own_bi->curve;
+ bi->pubkey = pkex->peer_bootstrap_key;
+ pkex->peer_bootstrap_key = NULL;
+ if (dpp_bootstrap_key_hash(bi) < 0) {
+ dpp_bootstrap_info_free(bi);
+ return NULL;
+ }
+ dpp_pkex_free(pkex);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ return bi;
+}
+
+
+const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_bootstrap_get_id(dpp, id);
+ if (!bi)
+ return NULL;
+ return bi->uri;
+}
+
+
+int dpp_bootstrap_info(struct dpp_global *dpp, int id,
+ char *reply, int reply_size)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_bootstrap_get_id(dpp, id);
+ if (!bi)
+ return -1;
+ return os_snprintf(reply, reply_size, "type=%s\n"
+ "mac_addr=" MACSTR "\n"
+ "info=%s\n"
+ "num_freq=%u\n"
+ "curve=%s\n",
+ dpp_bootstrap_type_txt(bi->type),
+ MAC2STR(bi->mac_addr),
+ bi->info ? bi->info : "",
+ bi->num_freq,
+ bi->curve->name);
+}
+
+
+void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
+ const u8 *r_bootstrap,
+ struct dpp_bootstrap_info **own_bi,
+ struct dpp_bootstrap_info **peer_bi)
+{
+ struct dpp_bootstrap_info *bi;
+
+ *own_bi = NULL;
+ *peer_bi = NULL;
+ if (!dpp)
+ return;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (!*own_bi && bi->own &&
+ os_memcmp(bi->pubkey_hash, r_bootstrap,
+ SHA256_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Found matching own bootstrapping information");
+ *own_bi = bi;
+ }
+
+ if (!*peer_bi && !bi->own &&
+ os_memcmp(bi->pubkey_hash, i_bootstrap,
+ SHA256_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Found matching peer bootstrapping information");
+ *peer_bi = bi;
+ }
+
+ if (*own_bi && *peer_bi)
+ break;
+ }
+
+}
+
+
+static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
+{
+ struct dpp_configurator *conf;
+ unsigned int max_id = 0;
+
+ dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
+ list) {
+ if (conf->id > max_id)
+ max_id = conf->id;
+ }
+ return max_id + 1;
+}
+
+
+int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
+{
+ char *curve = NULL;
+ char *key = NULL;
+ u8 *privkey = NULL;
+ size_t privkey_len = 0;
+ int ret = -1;
+ struct dpp_configurator *conf = NULL;
+
+ curve = get_param(cmd, " curve=");
+ key = get_param(cmd, " key=");
+
+ if (key) {
+ privkey_len = os_strlen(key) / 2;
+ privkey = os_malloc(privkey_len);
+ if (!privkey ||
+ hexstr2bin(key, privkey, privkey_len) < 0)
+ goto fail;
+ }
+
+ conf = dpp_keygen_configurator(curve, privkey, privkey_len);
+ if (!conf)
+ goto fail;
+
+ conf->id = dpp_next_configurator_id(dpp);
+ dl_list_add(&dpp->configurator, &conf->list);
+ ret = conf->id;
+ conf = NULL;
+fail:
+ os_free(curve);
+ str_clear_free(key);
+ bin_clear_free(privkey, privkey_len);
+ dpp_configurator_free(conf);
+ return ret;
+}
+
+
+static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_configurator *conf, *tmp;
+ int found = 0;
+
+ if (!dpp)
+ return -1;
+
+ dl_list_for_each_safe(conf, tmp, &dpp->configurator,
+ struct dpp_configurator, list) {
+ if (id && conf->id != id)
+ continue;
+ found = 1;
+ dl_list_del(&conf->list);
+ dpp_configurator_free(conf);
+ }
+
+ if (id == 0)
+ return 0; /* flush succeeds regardless of entries found */
+ return found ? 0 : -1;
+}
+
+
+int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
+{
+ unsigned int id_val;
+
+ if (os_strcmp(id, "*") == 0) {
+ id_val = 0;
+ } else {
+ id_val = atoi(id);
+ if (id_val == 0)
+ return -1;
+ }
+
+ return dpp_configurator_del(dpp, id_val);
+}
+
+
+int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
+ char *buf, size_t buflen)
+{
+ struct dpp_configurator *conf;
+
+ conf = dpp_configurator_get_id(dpp, id);
+ if (!conf)
+ return -1;
+
+ return dpp_configurator_get_key(conf, buf, buflen);
+}
+
+
+struct dpp_global * dpp_global_init(void)
+{
+ struct dpp_global *dpp;
+
+ dpp = os_zalloc(sizeof(*dpp));
+ if (!dpp)
+ return NULL;
+
+ dl_list_init(&dpp->bootstrap);
+ dl_list_init(&dpp->configurator);
+
+ return dpp;
+}
+
+
+void dpp_global_clear(struct dpp_global *dpp)
+{
+ if (!dpp)
+ return;
+
+ dpp_bootstrap_del(dpp, 0);
+ dpp_configurator_del(dpp, 0);
+}
+
+
+void dpp_global_deinit(struct dpp_global *dpp)
+{
+ dpp_global_clear(dpp);
+ os_free(dpp);
+}
diff --git a/contrib/wpa/src/common/dpp.h b/contrib/wpa/src/common/dpp.h
new file mode 100644
index 0000000..5a6d8cc
--- /dev/null
+++ b/contrib/wpa/src/common/dpp.h
@@ -0,0 +1,505 @@
+/*
+ * DPP functionality shared between hostapd and wpa_supplicant
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DPP_H
+#define DPP_H
+
+#ifdef CONFIG_DPP
+#include <openssl/x509.h>
+
+#include "utils/list.h"
+#include "common/wpa_common.h"
+#include "crypto/sha256.h"
+
+struct crypto_ecdh;
+struct dpp_global;
+
+#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
+
+enum dpp_public_action_frame_type {
+ DPP_PA_AUTHENTICATION_REQ = 0,
+ DPP_PA_AUTHENTICATION_RESP = 1,
+ DPP_PA_AUTHENTICATION_CONF = 2,
+ DPP_PA_PEER_DISCOVERY_REQ = 5,
+ DPP_PA_PEER_DISCOVERY_RESP = 6,
+ DPP_PA_PKEX_EXCHANGE_REQ = 7,
+ DPP_PA_PKEX_EXCHANGE_RESP = 8,
+ DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
+ DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
+ DPP_PA_CONFIGURATION_RESULT = 11,
+};
+
+enum dpp_attribute_id {
+ DPP_ATTR_STATUS = 0x1000,
+ DPP_ATTR_I_BOOTSTRAP_KEY_HASH = 0x1001,
+ DPP_ATTR_R_BOOTSTRAP_KEY_HASH = 0x1002,
+ DPP_ATTR_I_PROTOCOL_KEY = 0x1003,
+ DPP_ATTR_WRAPPED_DATA = 0x1004,
+ DPP_ATTR_I_NONCE = 0x1005,
+ DPP_ATTR_I_CAPABILITIES = 0x1006,
+ DPP_ATTR_R_NONCE = 0x1007,
+ DPP_ATTR_R_CAPABILITIES = 0x1008,
+ DPP_ATTR_R_PROTOCOL_KEY = 0x1009,
+ DPP_ATTR_I_AUTH_TAG = 0x100A,
+ DPP_ATTR_R_AUTH_TAG = 0x100B,
+ DPP_ATTR_CONFIG_OBJ = 0x100C,
+ DPP_ATTR_CONNECTOR = 0x100D,
+ DPP_ATTR_CONFIG_ATTR_OBJ = 0x100E,
+ DPP_ATTR_BOOTSTRAP_KEY = 0x100F,
+ DPP_ATTR_OWN_NET_NK_HASH = 0x1011,
+ DPP_ATTR_FINITE_CYCLIC_GROUP = 0x1012,
+ DPP_ATTR_ENCRYPTED_KEY = 0x1013,
+ DPP_ATTR_ENROLLEE_NONCE = 0x1014,
+ DPP_ATTR_CODE_IDENTIFIER = 0x1015,
+ DPP_ATTR_TRANSACTION_ID = 0x1016,
+ DPP_ATTR_BOOTSTRAP_INFO = 0x1017,
+ DPP_ATTR_CHANNEL = 0x1018,
+ DPP_ATTR_PROTOCOL_VERSION = 0x1019,
+ DPP_ATTR_ENVELOPED_DATA = 0x101A,
+};
+
+enum dpp_status_error {
+ DPP_STATUS_OK = 0,
+ DPP_STATUS_NOT_COMPATIBLE = 1,
+ DPP_STATUS_AUTH_FAILURE = 2,
+ DPP_STATUS_UNWRAP_FAILURE = 3,
+ DPP_STATUS_BAD_GROUP = 4,
+ DPP_STATUS_CONFIGURE_FAILURE = 5,
+ DPP_STATUS_RESPONSE_PENDING = 6,
+ DPP_STATUS_INVALID_CONNECTOR = 7,
+ DPP_STATUS_NO_MATCH = 8,
+ DPP_STATUS_CONFIG_REJECTED = 9,
+};
+
+#define DPP_CAPAB_ENROLLEE BIT(0)
+#define DPP_CAPAB_CONFIGURATOR BIT(1)
+#define DPP_CAPAB_ROLE_MASK (BIT(0) | BIT(1))
+
+#define DPP_BOOTSTRAP_MAX_FREQ 30
+#define DPP_MAX_NONCE_LEN 32
+#define DPP_MAX_HASH_LEN 64
+#define DPP_MAX_SHARED_SECRET_LEN 66
+
+struct dpp_curve_params {
+ const char *name;
+ size_t hash_len;
+ size_t aes_siv_key_len;
+ size_t nonce_len;
+ size_t prime_len;
+ const char *jwk_crv;
+ u16 ike_group;
+ const char *jws_alg;
+};
+
+enum dpp_bootstrap_type {
+ DPP_BOOTSTRAP_QR_CODE,
+ DPP_BOOTSTRAP_PKEX,
+};
+
+struct dpp_bootstrap_info {
+ struct dl_list list;
+ unsigned int id;
+ enum dpp_bootstrap_type type;
+ char *uri;
+ u8 mac_addr[ETH_ALEN];
+ char *info;
+ unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
+ unsigned int num_freq;
+ int own;
+ EVP_PKEY *pubkey;
+ u8 pubkey_hash[SHA256_MAC_LEN];
+ const struct dpp_curve_params *curve;
+ unsigned int pkex_t; /* number of failures before dpp_pkex
+ * instantiation */
+};
+
+#define PKEX_COUNTER_T_LIMIT 5
+
+struct dpp_pkex {
+ void *msg_ctx;
+ unsigned int initiator:1;
+ unsigned int exchange_done:1;
+ unsigned int failed:1;
+ struct dpp_bootstrap_info *own_bi;
+ u8 own_mac[ETH_ALEN];
+ u8 peer_mac[ETH_ALEN];
+ char *identifier;
+ char *code;
+ EVP_PKEY *x;
+ EVP_PKEY *y;
+ u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
+ u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
+ u8 z[DPP_MAX_HASH_LEN];
+ EVP_PKEY *peer_bootstrap_key;
+ struct wpabuf *exchange_req;
+ struct wpabuf *exchange_resp;
+ unsigned int t; /* number of failures on code use */
+ unsigned int exch_req_wait_time;
+ unsigned int exch_req_tries;
+ unsigned int freq;
+};
+
+enum dpp_akm {
+ DPP_AKM_UNKNOWN,
+ DPP_AKM_DPP,
+ DPP_AKM_PSK,
+ DPP_AKM_SAE,
+ DPP_AKM_PSK_SAE,
+ DPP_AKM_SAE_DPP,
+ DPP_AKM_PSK_SAE_DPP,
+};
+
+struct dpp_configuration {
+ u8 ssid[32];
+ size_t ssid_len;
+ enum dpp_akm akm;
+
+ /* For DPP configuration (connector) */
+ os_time_t netaccesskey_expiry;
+
+ /* TODO: groups */
+ char *group_id;
+
+ /* For legacy configuration */
+ char *passphrase;
+ u8 psk[32];
+ int psk_set;
+};
+
+struct dpp_authentication {
+ void *msg_ctx;
+ u8 peer_version;
+ const struct dpp_curve_params *curve;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_bootstrap_info *own_bi;
+ struct dpp_bootstrap_info *tmp_own_bi;
+ u8 waiting_pubkey_hash[SHA256_MAC_LEN];
+ int response_pending;
+ enum dpp_status_error auth_resp_status;
+ enum dpp_status_error conf_resp_status;
+ u8 peer_mac_addr[ETH_ALEN];
+ u8 i_nonce[DPP_MAX_NONCE_LEN];
+ u8 r_nonce[DPP_MAX_NONCE_LEN];
+ u8 e_nonce[DPP_MAX_NONCE_LEN];
+ u8 i_capab;
+ u8 r_capab;
+ EVP_PKEY *own_protocol_key;
+ EVP_PKEY *peer_protocol_key;
+ struct wpabuf *req_msg;
+ struct wpabuf *resp_msg;
+ /* Intersection of possible frequencies for initiating DPP
+ * Authentication exchange */
+ unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
+ unsigned int num_freq, freq_idx;
+ unsigned int curr_freq;
+ unsigned int neg_freq;
+ unsigned int num_freq_iters;
+ size_t secret_len;
+ u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Mx_len;
+ u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Nx_len;
+ u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Lx_len;
+ u8 k1[DPP_MAX_HASH_LEN];
+ u8 k2[DPP_MAX_HASH_LEN];
+ u8 ke[DPP_MAX_HASH_LEN];
+ int initiator;
+ int waiting_auth_resp;
+ int waiting_auth_conf;
+ int auth_req_ack;
+ unsigned int auth_resp_tries;
+ u8 allowed_roles;
+ int configurator;
+ int remove_on_tx_status;
+ int connect_on_tx_status;
+ int waiting_conf_result;
+ int auth_success;
+ struct wpabuf *conf_req;
+ const struct wpabuf *conf_resp; /* owned by GAS server */
+ struct dpp_configuration *conf_ap;
+ struct dpp_configuration *conf_sta;
+ struct dpp_configurator *conf;
+ char *connector; /* received signedConnector */
+ u8 ssid[SSID_MAX_LEN];
+ u8 ssid_len;
+ char passphrase[64];
+ u8 psk[PMK_LEN];
+ int psk_set;
+ enum dpp_akm akm;
+ struct wpabuf *net_access_key;
+ os_time_t net_access_key_expiry;
+ struct wpabuf *c_sign_key;
+#ifdef CONFIG_TESTING_OPTIONS
+ char *config_obj_override;
+ char *discovery_override;
+ char *groups_override;
+ unsigned int ignore_netaccesskey_mismatch:1;
+#endif /* CONFIG_TESTING_OPTIONS */
+};
+
+struct dpp_configurator {
+ struct dl_list list;
+ unsigned int id;
+ int own;
+ EVP_PKEY *csign;
+ char *kid;
+ const struct dpp_curve_params *curve;
+};
+
+struct dpp_introduction {
+ u8 pmkid[PMKID_LEN];
+ u8 pmk[PMK_LEN_MAX];
+ size_t pmk_len;
+};
+
+#ifdef CONFIG_TESTING_OPTIONS
+enum dpp_test_behavior {
+ DPP_TEST_DISABLED = 0,
+ DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ = 1,
+ DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP = 2,
+ DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF = 3,
+ DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ = 4,
+ DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP = 5,
+ DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ = 6,
+ DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP = 7,
+ DPP_TEST_ZERO_I_CAPAB = 8,
+ DPP_TEST_ZERO_R_CAPAB = 9,
+ DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 10,
+ DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 11,
+ DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ = 12,
+ DPP_TEST_NO_I_NONCE_AUTH_REQ = 13,
+ DPP_TEST_NO_I_CAPAB_AUTH_REQ = 14,
+ DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ = 15,
+ DPP_TEST_NO_STATUS_AUTH_RESP = 16,
+ DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 17,
+ DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 18,
+ DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP = 19,
+ DPP_TEST_NO_R_NONCE_AUTH_RESP = 20,
+ DPP_TEST_NO_I_NONCE_AUTH_RESP = 21,
+ DPP_TEST_NO_R_CAPAB_AUTH_RESP = 22,
+ DPP_TEST_NO_R_AUTH_AUTH_RESP = 23,
+ DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP = 24,
+ DPP_TEST_NO_STATUS_AUTH_CONF = 25,
+ DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 26,
+ DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 27,
+ DPP_TEST_NO_I_AUTH_AUTH_CONF = 28,
+ DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF = 29,
+ DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP = 30,
+ DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP = 31,
+ DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP = 32,
+ DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF = 33,
+ DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ = 34,
+ DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 35,
+ DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP = 36,
+ DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 37,
+ DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ = 38,
+ DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ = 39,
+ DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ = 40,
+ DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP = 41,
+ DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP = 42,
+ DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP = 43,
+ DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 44,
+ DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 45,
+ DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP = 46,
+ DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ = 47,
+ DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP = 48,
+ DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ = 49,
+ DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP = 50,
+ DPP_TEST_NO_E_NONCE_CONF_REQ = 51,
+ DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ = 52,
+ DPP_TEST_NO_WRAPPED_DATA_CONF_REQ = 53,
+ DPP_TEST_NO_E_NONCE_CONF_RESP = 54,
+ DPP_TEST_NO_CONFIG_OBJ_CONF_RESP = 55,
+ DPP_TEST_NO_STATUS_CONF_RESP = 56,
+ DPP_TEST_NO_WRAPPED_DATA_CONF_RESP = 57,
+ DPP_TEST_INVALID_STATUS_CONF_RESP = 58,
+ DPP_TEST_E_NONCE_MISMATCH_CONF_RESP = 59,
+ DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ = 60,
+ DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ = 61,
+ DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP = 62,
+ DPP_TEST_NO_STATUS_PEER_DISC_RESP = 63,
+ DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP = 64,
+ DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF = 65,
+ DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ = 66,
+ DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP = 67,
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 68,
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 69,
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 70,
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 71,
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 72,
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 73,
+ DPP_TEST_INVALID_STATUS_AUTH_RESP = 74,
+ DPP_TEST_INVALID_STATUS_AUTH_CONF = 75,
+ DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ = 76,
+ DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP = 77,
+ DPP_TEST_INVALID_STATUS_PEER_DISC_RESP = 78,
+ DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP = 79,
+ DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ = 80,
+ DPP_TEST_INVALID_I_NONCE_AUTH_REQ = 81,
+ DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ = 82,
+ DPP_TEST_INVALID_E_NONCE_CONF_REQ = 83,
+ DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP = 84,
+ DPP_TEST_STOP_AT_PKEX_CR_REQ = 85,
+ DPP_TEST_STOP_AT_PKEX_CR_RESP = 86,
+ DPP_TEST_STOP_AT_AUTH_REQ = 87,
+ DPP_TEST_STOP_AT_AUTH_RESP = 88,
+ DPP_TEST_STOP_AT_AUTH_CONF = 89,
+ DPP_TEST_STOP_AT_CONF_REQ = 90,
+ DPP_TEST_REJECT_CONFIG = 91,
+};
+
+extern enum dpp_test_behavior dpp_test;
+extern u8 dpp_pkex_own_mac_override[ETH_ALEN];
+extern u8 dpp_pkex_peer_mac_override[ETH_ALEN];
+extern u8 dpp_pkex_ephemeral_key_override[600];
+extern size_t dpp_pkex_ephemeral_key_override_len;
+extern u8 dpp_protocol_key_override[600];
+extern size_t dpp_protocol_key_override_len;
+extern u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
+extern size_t dpp_nonce_override_len;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
+const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
+int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
+int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
+ const char *chan_list);
+int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
+int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
+struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri);
+char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
+ const u8 *privkey, size_t privkey_len);
+struct hostapd_hw_modes;
+struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+ struct dpp_bootstrap_info *peer_bi,
+ struct dpp_bootstrap_info *own_bi,
+ u8 dpp_allowed_roles,
+ unsigned int neg_freq,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes);
+struct dpp_authentication *
+dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
+ struct dpp_bootstrap_info *peer_bi,
+ struct dpp_bootstrap_info *own_bi,
+ unsigned int freq, const u8 *hdr, const u8 *attr_start,
+ size_t attr_len);
+struct wpabuf *
+dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len);
+struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
+ const char *json);
+int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len);
+int dpp_notify_new_qr_code(struct dpp_authentication *auth,
+ struct dpp_bootstrap_info *peer_bi);
+struct dpp_configuration * dpp_configuration_alloc(const char *type);
+int dpp_akm_psk(enum dpp_akm akm);
+int dpp_akm_sae(enum dpp_akm akm);
+int dpp_akm_legacy(enum dpp_akm akm);
+int dpp_akm_dpp(enum dpp_akm akm);
+int dpp_akm_ver2(enum dpp_akm akm);
+int dpp_configuration_valid(const struct dpp_configuration *conf);
+void dpp_configuration_free(struct dpp_configuration *conf);
+int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
+ struct dpp_authentication *auth,
+ const char *cmd);
+void dpp_auth_deinit(struct dpp_authentication *auth);
+struct wpabuf *
+dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
+ size_t attr_len);
+int dpp_conf_resp_rx(struct dpp_authentication *auth,
+ const struct wpabuf *resp);
+enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start, size_t attr_len);
+struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
+ enum dpp_status_error status);
+struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
+ size_t len);
+const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
+int dpp_check_attrs(const u8 *buf, size_t len);
+int dpp_key_expired(const char *timestamp, os_time_t *expiry);
+const char * dpp_akm_str(enum dpp_akm akm);
+int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
+ size_t buflen);
+void dpp_configurator_free(struct dpp_configurator *conf);
+struct dpp_configurator *
+dpp_keygen_configurator(const char *curve, const u8 *privkey,
+ size_t privkey_len);
+int dpp_configurator_own_config(struct dpp_authentication *auth,
+ const char *curve, int ap);
+enum dpp_status_error
+dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
+ const u8 *net_access_key, size_t net_access_key_len,
+ const u8 *csign_key, size_t csign_key_len,
+ const u8 *peer_connector, size_t peer_connector_len,
+ os_time_t *expiry);
+struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
+ const u8 *own_mac,
+ const char *identifier,
+ const char *code);
+struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
+ struct dpp_bootstrap_info *bi,
+ const u8 *own_mac,
+ const u8 *peer_mac,
+ const char *identifier,
+ const char *code,
+ const u8 *buf, size_t len);
+struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
+ const u8 *peer_mac,
+ const u8 *buf, size_t len);
+struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
+ const u8 *hdr,
+ const u8 *buf, size_t len);
+int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
+ const u8 *buf, size_t len);
+void dpp_pkex_free(struct dpp_pkex *pkex);
+
+char * dpp_corrupt_connector_signature(const char *connector);
+
+
+struct dpp_pfs {
+ struct crypto_ecdh *ecdh;
+ const struct dpp_curve_params *curve;
+ struct wpabuf *ie;
+ struct wpabuf *secret;
+};
+
+struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
+ size_t net_access_key_len);
+int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
+void dpp_pfs_free(struct dpp_pfs *pfs);
+
+struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
+ const char *uri);
+int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd);
+struct dpp_bootstrap_info *
+dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id);
+int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id);
+struct dpp_bootstrap_info *
+dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
+ unsigned int freq);
+const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
+int dpp_bootstrap_info(struct dpp_global *dpp, int id,
+ char *reply, int reply_size);
+void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
+ const u8 *r_bootstrap,
+ struct dpp_bootstrap_info **own_bi,
+ struct dpp_bootstrap_info **peer_bi);
+int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
+int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
+int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
+ char *buf, size_t buflen);
+struct dpp_global * dpp_global_init(void);
+void dpp_global_clear(struct dpp_global *dpp);
+void dpp_global_deinit(struct dpp_global *dpp);
+
+#endif /* CONFIG_DPP */
+#endif /* DPP_H */
diff --git a/contrib/wpa/src/common/eapol_common.h b/contrib/wpa/src/common/eapol_common.h
index 6958661..d773348 100644
--- a/contrib/wpa/src/common/eapol_common.h
+++ b/contrib/wpa/src/common/eapol_common.h
@@ -25,7 +25,7 @@ struct ieee802_1x_hdr {
struct ieee8023_hdr {
u8 dest[ETH_ALEN];
u8 src[ETH_ALEN];
- u16 ethertype;
+ be16 ethertype;
} STRUCT_PACKED;
#ifdef _MSC_VER
diff --git a/contrib/wpa/src/common/gas.c b/contrib/wpa/src/common/gas.c
index cff9254..ba21b22 100644
--- a/contrib/wpa/src/common/gas.c
+++ b/contrib/wpa/src/common/gas.c
@@ -75,7 +75,7 @@ gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
}
-static struct wpabuf *
+struct wpabuf *
gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
u16 comeback_delay, size_t size)
{
diff --git a/contrib/wpa/src/common/gas.h b/contrib/wpa/src/common/gas.h
index 306adc5..4c93e31 100644
--- a/contrib/wpa/src/common/gas.h
+++ b/contrib/wpa/src/common/gas.h
@@ -14,6 +14,9 @@ struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size);
struct wpabuf * gas_build_comeback_req(u8 dialog_token);
struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
u16 comeback_delay, size_t size);
+struct wpabuf *
+gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
+ u16 comeback_delay, size_t size);
struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
u16 comeback_delay, size_t size);
diff --git a/contrib/wpa/src/common/gas_server.c b/contrib/wpa/src/common/gas_server.c
new file mode 100644
index 0000000..ca46758
--- /dev/null
+++ b/contrib/wpa/src/common/gas_server.c
@@ -0,0 +1,487 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "utils/list.h"
+#include "utils/eloop.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
+#include "gas_server.h"
+
+
+#define MAX_ADV_PROTO_ID_LEN 10
+#define GAS_QUERY_TIMEOUT 10
+
+struct gas_server_handler {
+ struct dl_list list;
+ u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
+ u8 adv_proto_id_len;
+ struct wpabuf * (*req_cb)(void *ctx, const u8 *sa,
+ const u8 *query, size_t query_len);
+ void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
+ void *ctx;
+ struct gas_server *gas;
+};
+
+struct gas_server_response {
+ struct dl_list list;
+ size_t offset;
+ u8 frag_id;
+ struct wpabuf *resp;
+ int freq;
+ u8 dst[ETH_ALEN];
+ u8 dialog_token;
+ struct gas_server_handler *handler;
+};
+
+struct gas_server {
+ struct dl_list handlers; /* struct gas_server_handler::list */
+ struct dl_list responses; /* struct gas_server_response::list */
+ void (*tx)(void *ctx, int freq, const u8 *da, struct wpabuf *resp,
+ unsigned int wait_time);
+ void *ctx;
+};
+
+static void gas_server_free_response(struct gas_server_response *response);
+
+
+static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
+{
+ struct gas_server_response *response = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "GAS: Response @%p timeout for " MACSTR
+ " (dialog_token=%u freq=%d frag_id=%u sent=%lu/%lu) - drop pending data",
+ response, MAC2STR(response->dst), response->dialog_token,
+ response->freq, response->frag_id,
+ (unsigned long) response->offset,
+ (unsigned long) wpabuf_len(response->resp));
+ response->handler->status_cb(response->handler->ctx,
+ response->resp, 0);
+ response->resp = NULL;
+ dl_list_del(&response->list);
+ gas_server_free_response(response);
+}
+
+
+static void gas_server_free_response(struct gas_server_response *response)
+{
+ if (!response)
+ return;
+ wpa_printf(MSG_DEBUG, "DPP: Free GAS response @%p", response);
+ eloop_cancel_timeout(gas_server_response_timeout, response, NULL);
+ wpabuf_free(response->resp);
+ os_free(response);
+}
+
+
+static void
+gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
+ const u8 *da, int freq, u8 dialog_token,
+ struct wpabuf *query_resp)
+{
+ size_t max_len = (freq > 56160) ? 928 : 1400;
+ size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
+ size_t resp_frag_len;
+ struct wpabuf *resp;
+ u16 comeback_delay;
+ struct gas_server_response *response;
+
+ if (!query_resp)
+ return;
+
+ response = os_zalloc(sizeof(*response));
+ if (!response) {
+ wpabuf_free(query_resp);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
+ response->freq = freq;
+ response->handler = handler;
+ os_memcpy(response->dst, da, ETH_ALEN);
+ response->dialog_token = dialog_token;
+ if (hdr_len + wpabuf_len(query_resp) > max_len) {
+ /* Need to use comeback to initiate fragmentation */
+ comeback_delay = 1;
+ resp_frag_len = 0;
+ } else {
+ /* Full response fits into the initial response */
+ comeback_delay = 0;
+ resp_frag_len = wpabuf_len(query_resp);
+ }
+
+ resp = gas_build_initial_resp(dialog_token, WLAN_STATUS_SUCCESS,
+ comeback_delay,
+ handler->adv_proto_id_len +
+ resp_frag_len);
+ if (!resp) {
+ wpabuf_free(query_resp);
+ gas_server_free_response(response);
+ return;
+ }
+
+ /* Advertisement Protocol element */
+ wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
+ wpabuf_put_u8(resp, 0x7f);
+ /* Advertisement Protocol ID */
+ wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len);
+
+ /* Query Response Length */
+ wpabuf_put_le16(resp, resp_frag_len);
+ if (!comeback_delay)
+ wpabuf_put_buf(resp, query_resp);
+
+ if (comeback_delay) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: Need to fragment query response");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GAS: Full query response fits in the GAS Initial Response frame");
+ }
+ response->offset = resp_frag_len;
+ response->resp = query_resp;
+ dl_list_add(&gas->responses, &response->list);
+ gas->tx(gas->ctx, freq, da, resp, comeback_delay ? 2000 : 0);
+ wpabuf_free(resp);
+ eloop_register_timeout(GAS_QUERY_TIMEOUT, 0,
+ gas_server_response_timeout, response, NULL);
+}
+
+
+static int
+gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
+ const u8 *bssid, int freq, u8 dialog_token,
+ const u8 *data, size_t len)
+{
+ const u8 *pos, *end, *adv_proto, *query_req;
+ u8 adv_proto_len;
+ u16 query_req_len;
+ struct gas_server_handler *handler;
+ struct wpabuf *resp;
+
+ wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
+ data, len);
+ pos = data;
+ end = data + len;
+
+ if (end - pos < 2 || pos[0] != WLAN_EID_ADV_PROTO) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: No Advertisement Protocol element found");
+ return -1;
+ }
+ pos++;
+ adv_proto_len = *pos++;
+ if (end - pos < adv_proto_len || adv_proto_len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: Truncated Advertisement Protocol element");
+ return -1;
+ }
+
+ adv_proto = pos;
+ pos += adv_proto_len;
+ wpa_hexdump(MSG_MSGDUMP, "GAS: Advertisement Protocol element",
+ adv_proto, adv_proto_len);
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "GAS: No Query Request Length field");
+ return -1;
+ }
+ query_req_len = WPA_GET_LE16(pos);
+ pos += 2;
+ if (end - pos < query_req_len) {
+ wpa_printf(MSG_DEBUG, "GAS: Truncated Query Request field");
+ return -1;
+ }
+ query_req = pos;
+ pos += query_req_len;
+ wpa_hexdump(MSG_MSGDUMP, "GAS: Query Request",
+ query_req, query_req_len);
+
+ if (pos < end) {
+ wpa_hexdump(MSG_MSGDUMP,
+ "GAS: Ignored extra data after Query Request field",
+ pos, end - pos);
+ }
+
+ dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
+ list) {
+ if (adv_proto_len < 1 + handler->adv_proto_id_len ||
+ os_memcmp(adv_proto + 1, handler->adv_proto_id,
+ handler->adv_proto_id_len) != 0)
+ continue;
+
+ wpa_printf(MSG_DEBUG,
+ "GAS: Calling handler for the requested Advertisement Protocol ID");
+ resp = handler->req_cb(handler->ctx, sa, query_req,
+ query_req_len);
+ wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
+ resp);
+ gas_server_send_resp(gas, handler, sa, freq, dialog_token,
+ resp);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "GAS: No registered handler for the requested Advertisement Protocol ID");
+ return -1;
+}
+
+
+static void
+gas_server_handle_rx_comeback_req(struct gas_server_response *response)
+{
+ struct gas_server_handler *handler = response->handler;
+ struct gas_server *gas = handler->gas;
+ size_t max_len = (response->freq > 56160) ? 928 : 1400;
+ size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
+ size_t remaining, resp_frag_len;
+ struct wpabuf *resp;
+
+ remaining = wpabuf_len(response->resp) - response->offset;
+ if (hdr_len + remaining > max_len)
+ resp_frag_len = max_len - hdr_len;
+ else
+ resp_frag_len = remaining;
+ wpa_printf(MSG_DEBUG,
+ "GAS: Sending out %u/%u remaining Query Response octets",
+ (unsigned int) resp_frag_len, (unsigned int) remaining);
+
+ resp = gas_build_comeback_resp(response->dialog_token,
+ WLAN_STATUS_SUCCESS,
+ response->frag_id++,
+ resp_frag_len < remaining, 0,
+ handler->adv_proto_id_len +
+ resp_frag_len);
+ if (!resp) {
+ dl_list_del(&response->list);
+ gas_server_free_response(response);
+ return;
+ }
+
+ /* Advertisement Protocol element */
+ wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
+ wpabuf_put_u8(resp, 0x7f);
+ /* Advertisement Protocol ID */
+ wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len);
+
+ /* Query Response Length */
+ wpabuf_put_le16(resp, resp_frag_len);
+ wpabuf_put_data(resp, wpabuf_head_u8(response->resp) + response->offset,
+ resp_frag_len);
+
+ response->offset += resp_frag_len;
+
+ gas->tx(gas->ctx, response->freq, response->dst, resp,
+ remaining > resp_frag_len ? 2000 : 0);
+ wpabuf_free(resp);
+}
+
+
+static int
+gas_server_rx_comeback_req(struct gas_server *gas, const u8 *da, const u8 *sa,
+ const u8 *bssid, int freq, u8 dialog_token)
+{
+ struct gas_server_response *response;
+
+ dl_list_for_each(response, &gas->responses, struct gas_server_response,
+ list) {
+ if (response->dialog_token != dialog_token ||
+ os_memcmp(sa, response->dst, ETH_ALEN) != 0)
+ continue;
+ gas_server_handle_rx_comeback_req(response);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "GAS: No pending GAS response for " MACSTR
+ " (dialog token %u)", MAC2STR(sa), dialog_token);
+ return -1;
+}
+
+
+/**
+ * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame
+ * @gas: GAS query data from gas_server_init()
+ * @da: Destination MAC address of the Action frame
+ * @sa: Source MAC address of the Action frame
+ * @bssid: BSSID of the Action frame
+ * @categ: Category of the Action frame
+ * @data: Payload of the Action frame
+ * @len: Length of @data
+ * @freq: Frequency (in MHz) on which the frame was received
+ * Returns: 0 if the Public Action frame was a GAS request frame or -1 if not
+ */
+int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
+ const u8 *bssid, u8 categ, const u8 *data, size_t len,
+ int freq)
+{
+ u8 action, dialog_token;
+ const u8 *pos, *end;
+
+ if (!gas || len < 2)
+ return -1;
+
+ if (categ == WLAN_ACTION_PROTECTED_DUAL)
+ return -1; /* Not supported for now */
+
+ pos = data;
+ end = data + len;
+ action = *pos++;
+ dialog_token = *pos++;
+
+ if (action != WLAN_PA_GAS_INITIAL_REQ &&
+ action != WLAN_PA_GAS_COMEBACK_REQ)
+ return -1; /* Not a GAS request */
+
+ wpa_printf(MSG_DEBUG, "GAS: Received GAS %s Request frame DA=" MACSTR
+ " SA=" MACSTR " BSSID=" MACSTR
+ " freq=%d dialog_token=%u len=%u",
+ action == WLAN_PA_GAS_INITIAL_REQ ? "Initial" : "Comeback",
+ MAC2STR(da), MAC2STR(sa), MAC2STR(bssid), freq, dialog_token,
+ (unsigned int) len);
+
+ if (action == WLAN_PA_GAS_INITIAL_REQ)
+ return gas_server_rx_initial_req(gas, da, sa, bssid,
+ freq, dialog_token,
+ pos, end - pos);
+ return gas_server_rx_comeback_req(gas, da, sa, bssid,
+ freq, dialog_token);
+}
+
+
+static void gas_server_handle_tx_status(struct gas_server_response *response,
+ int ack)
+{
+ if (ack && response->offset < wpabuf_len(response->resp)) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: More fragments remaining - keep pending entry");
+ return;
+ }
+
+ if (!ack)
+ wpa_printf(MSG_DEBUG,
+ "GAS: No ACK received - drop pending entry");
+ else
+ wpa_printf(MSG_DEBUG,
+ "GAS: Last fragment of the response sent out - drop pending entry");
+
+ response->handler->status_cb(response->handler->ctx,
+ response->resp, ack);
+ response->resp = NULL;
+ dl_list_del(&response->list);
+ gas_server_free_response(response);
+}
+
+
+void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
+ size_t data_len, int ack)
+{
+ const u8 *pos;
+ u8 action, code, dialog_token;
+ struct gas_server_response *response;
+
+ if (data_len < 24 + 3)
+ return;
+ pos = data + 24;
+ action = *pos++;
+ code = *pos++;
+ dialog_token = *pos++;
+ if (action != WLAN_ACTION_PUBLIC ||
+ (code != WLAN_PA_GAS_INITIAL_RESP &&
+ code != WLAN_PA_GAS_COMEBACK_RESP))
+ return;
+ wpa_printf(MSG_DEBUG, "GAS: TX status dst=" MACSTR
+ " ack=%d %s dialog_token=%u",
+ MAC2STR(dst), ack,
+ code == WLAN_PA_GAS_INITIAL_RESP ? "initial" : "comeback",
+ dialog_token);
+ dl_list_for_each(response, &gas->responses, struct gas_server_response,
+ list) {
+ if (response->dialog_token != dialog_token ||
+ os_memcmp(dst, response->dst, ETH_ALEN) != 0)
+ continue;
+ gas_server_handle_tx_status(response, ack);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "GAS: No pending response matches TX status");
+}
+
+
+struct gas_server * gas_server_init(void *ctx,
+ void (*tx)(void *ctx, int freq,
+ const u8 *da,
+ struct wpabuf *buf,
+ unsigned int wait_time))
+{
+ struct gas_server *gas;
+
+ gas = os_zalloc(sizeof(*gas));
+ if (!gas)
+ return NULL;
+ gas->ctx = ctx;
+ gas->tx = tx;
+ dl_list_init(&gas->handlers);
+ dl_list_init(&gas->responses);
+ return gas;
+}
+
+
+void gas_server_deinit(struct gas_server *gas)
+{
+ struct gas_server_handler *handler, *tmp;
+ struct gas_server_response *response, *tmp_r;
+
+ if (!gas)
+ return;
+
+ dl_list_for_each_safe(handler, tmp, &gas->handlers,
+ struct gas_server_handler, list) {
+ dl_list_del(&handler->list);
+ os_free(handler);
+ }
+
+ dl_list_for_each_safe(response, tmp_r, &gas->responses,
+ struct gas_server_response, list) {
+ dl_list_del(&response->list);
+ gas_server_free_response(response);
+ }
+
+ os_free(gas);
+}
+
+
+int gas_server_register(struct gas_server *gas,
+ const u8 *adv_proto_id, u8 adv_proto_id_len,
+ struct wpabuf *
+ (*req_cb)(void *ctx, const u8 *sa,
+ const u8 *query, size_t query_len),
+ void (*status_cb)(void *ctx, struct wpabuf *resp,
+ int ok),
+ void *ctx)
+{
+ struct gas_server_handler *handler;
+
+ if (!gas || adv_proto_id_len > MAX_ADV_PROTO_ID_LEN)
+ return -1;
+ handler = os_zalloc(sizeof(*handler));
+ if (!handler)
+ return -1;
+
+ os_memcpy(handler->adv_proto_id, adv_proto_id, adv_proto_id_len);
+ handler->adv_proto_id_len = adv_proto_id_len;
+ handler->req_cb = req_cb;
+ handler->status_cb = status_cb;
+ handler->ctx = ctx;
+ handler->gas = gas;
+ dl_list_add(&gas->handlers, &handler->list);
+
+ return 0;
+}
diff --git a/contrib/wpa/src/common/gas_server.h b/contrib/wpa/src/common/gas_server.h
new file mode 100644
index 0000000..299f529
--- /dev/null
+++ b/contrib/wpa/src/common/gas_server.h
@@ -0,0 +1,44 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_SERVER_H
+#define GAS_SERVER_H
+
+#ifdef CONFIG_GAS_SERVER
+
+struct gas_server;
+
+struct gas_server * gas_server_init(void *ctx,
+ void (*tx)(void *ctx, int freq,
+ const u8 *da,
+ struct wpabuf *buf,
+ unsigned int wait_time));
+void gas_server_deinit(struct gas_server *gas);
+int gas_server_register(struct gas_server *gas,
+ const u8 *adv_proto_id, u8 adv_proto_id_len,
+ struct wpabuf *
+ (*req_cb)(void *ctx, const u8 *sa,
+ const u8 *query, size_t query_len),
+ void (*status_cb)(void *ctx, struct wpabuf *resp,
+ int ok),
+ void *ctx);
+int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
+ const u8 *bssid, u8 categ, const u8 *data, size_t len,
+ int freq);
+void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
+ size_t data_len, int ack);
+
+#else /* CONFIG_GAS_SERVER */
+
+static inline void gas_server_deinit(struct gas_server *gas)
+{
+}
+
+#endif /* CONFIG_GAS_SERVER */
+
+#endif /* GAS_SERVER_H */
diff --git a/contrib/wpa/src/common/hw_features_common.c b/contrib/wpa/src/common/hw_features_common.c
index 9c37ea6..49ed806 100644
--- a/contrib/wpa/src/common/hw_features_common.c
+++ b/contrib/wpa/src/common/hw_features_common.c
@@ -87,13 +87,29 @@ int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
int sec_chan)
{
- int ok, j, first;
+ int ok, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
- 149, 157, 184, 192 };
+ 149, 157, 165, 184, 192 };
size_t k;
+ struct hostapd_channel_data *p_chan, *s_chan;
+ const int ht40_plus = pri_chan < sec_chan;
- if (pri_chan == sec_chan || !sec_chan)
- return 1; /* HT40 not used */
+ p_chan = hw_get_channel_chan(mode, pri_chan, NULL);
+ if (!p_chan)
+ return 0;
+
+ if (pri_chan == sec_chan || !sec_chan) {
+ if (chan_pri_allowed(p_chan))
+ return 1; /* HT40 not used */
+
+ wpa_printf(MSG_ERROR, "Channel %d is not allowed as primary",
+ pri_chan);
+ return 0;
+ }
+
+ s_chan = hw_get_channel_chan(mode, sec_chan, NULL);
+ if (!s_chan)
+ return 0;
wpa_printf(MSG_DEBUG,
"HT40: control channel: %d secondary channel: %d",
@@ -101,16 +117,9 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
/* Verify that HT40 secondary channel is an allowed 20 MHz
* channel */
- ok = 0;
- for (j = 0; j < mode->num_channels; j++) {
- struct hostapd_channel_data *chan = &mode->channels[j];
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
- chan->chan == sec_chan) {
- ok = 1;
- break;
- }
- }
- if (!ok) {
+ if ((s_chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ (ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) ||
+ (!ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))) {
wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
sec_chan);
return 0;
@@ -388,8 +397,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
/* fall through */
case VHT_CHANWIDTH_80MHZ:
data->bandwidth = 80;
- if ((vht_oper_chwidth == 1 && center_segment1) ||
- (vht_oper_chwidth == 3 && !center_segment1) ||
+ if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
+ center_segment1) ||
+ (vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
+ !center_segment1) ||
!sec_channel_offset)
return -1;
if (!center_segment0) {
@@ -453,3 +464,157 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return 0;
}
+
+
+void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
+ int disabled)
+{
+ /* Masking these out disables HT40 */
+ le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
+ HT_CAP_INFO_SHORT_GI40MHZ);
+
+ if (disabled)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+}
+
+
+#ifdef CONFIG_IEEE80211AC
+
+static int _ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap,
+ const char *name)
+{
+ u32 req_cap = conf & cap;
+
+ /*
+ * Make sure we support all requested capabilities.
+ * NOTE: We assume that 'cap' represents a capability mask,
+ * not a discrete value.
+ */
+ if ((hw & req_cap) != req_cap) {
+ wpa_printf(MSG_ERROR,
+ "Driver does not support configured VHT capability [%s]",
+ name);
+ return 0;
+ }
+ return 1;
+}
+
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
+ unsigned int shift,
+ const char *name)
+{
+ u32 hw_max = hw & mask;
+ u32 conf_val = conf & mask;
+
+ if (conf_val > hw_max) {
+ wpa_printf(MSG_ERROR,
+ "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
+ name, conf_val >> shift, hw_max >> shift);
+ return 0;
+ }
+ return 1;
+}
+
+
+int ieee80211ac_cap_check(u32 hw, u32 conf)
+{
+#define VHT_CAP_CHECK(cap) \
+ do { \
+ if (!_ieee80211ac_cap_check(hw, conf, cap, #cap)) \
+ return 0; \
+ } while (0)
+
+#define VHT_CAP_CHECK_MAX(cap) \
+ do { \
+ if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
+ #cap)) \
+ return 0; \
+ } while (0)
+
+ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
+ VHT_CAP_CHECK_MAX(VHT_CAP_SUPP_CHAN_WIDTH_MASK);
+ VHT_CAP_CHECK(VHT_CAP_RXLDPC);
+ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
+ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
+ VHT_CAP_CHECK(VHT_CAP_TXSTBC);
+ VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
+ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+ VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
+ VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
+ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
+ VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
+ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
+ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
+ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+ VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+ VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
+
+#undef VHT_CAP_CHECK
+#undef VHT_CAP_CHECK_MAX
+
+ return 1;
+}
+
+#endif /* CONFIG_IEEE80211AC */
+
+
+u32 num_chan_to_bw(int num_chans)
+{
+ switch (num_chans) {
+ case 2:
+ case 4:
+ case 8:
+ return num_chans * 20;
+ default:
+ return 20;
+ }
+}
+
+
+/* check if BW is applicable for channel */
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+ int ht40_plus, int pri)
+{
+ u32 bw_mask;
+
+ switch (bw) {
+ case 20:
+ bw_mask = HOSTAPD_CHAN_WIDTH_20;
+ break;
+ case 40:
+ /* HT 40 MHz support declared only for primary channel,
+ * just skip 40 MHz secondary checking */
+ if (pri && ht40_plus)
+ bw_mask = HOSTAPD_CHAN_WIDTH_40P;
+ else if (pri && !ht40_plus)
+ bw_mask = HOSTAPD_CHAN_WIDTH_40M;
+ else
+ bw_mask = 0;
+ break;
+ case 80:
+ bw_mask = HOSTAPD_CHAN_WIDTH_80;
+ break;
+ case 160:
+ bw_mask = HOSTAPD_CHAN_WIDTH_160;
+ break;
+ default:
+ bw_mask = 0;
+ break;
+ }
+
+ return (chan->allowed_bw & bw_mask) == bw_mask;
+}
+
+
+/* check if channel is allowed to be used as primary */
+int chan_pri_allowed(const struct hostapd_channel_data *chan)
+{
+ return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
+}
diff --git a/contrib/wpa/src/common/hw_features_common.h b/contrib/wpa/src/common/hw_features_common.h
index 7360b4e..eb1f1c5 100644
--- a/contrib/wpa/src/common/hw_features_common.h
+++ b/contrib/wpa/src/common/hw_features_common.h
@@ -35,5 +35,13 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
int vht_enabled, int sec_channel_offset,
int vht_oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps);
+void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
+ int disabled);
+int ieee80211ac_cap_check(u32 hw, u32 conf);
+
+u32 num_chan_to_bw(int num_chans);
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+ int ht40_plus, int pri);
+int chan_pri_allowed(const struct hostapd_channel_data *chan);
#endif /* HW_FEATURES_COMMON_H */
diff --git a/contrib/wpa/src/common/ieee802_11_common.c b/contrib/wpa/src/common/ieee802_11_common.c
index d07a316..e42a3274 100644
--- a/contrib/wpa/src/common/ieee802_11_common.c
+++ b/contrib/wpa/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "common.h"
#include "defs.h"
#include "wpa_common.h"
+#include "drivers/driver.h"
#include "qca-vendor.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
@@ -115,6 +116,20 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->osen = pos;
elems->osen_len = elen;
break;
+ case MBO_OUI_TYPE:
+ /* MBO-OCE */
+ elems->mbo = pos;
+ elems->mbo_len = elen;
+ break;
+ case HS20_ROAMING_CONS_SEL_OUI_TYPE:
+ /* Hotspot 2.0 Roaming Consortium Selection */
+ elems->roaming_cons_sel = pos;
+ elems->roaming_cons_sel_len = elen;
+ break;
+ case MULTI_AP_OUI_TYPE:
+ elems->multi_ap = pos;
+ elems->multi_ap_len = elen;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -174,6 +189,108 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
}
+static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
+ struct ieee802_11_elems *elems,
+ int show_errors)
+{
+ u8 ext_id;
+
+ if (elen < 1) {
+ if (show_errors) {
+ wpa_printf(MSG_MSGDUMP,
+ "short information element (Ext)");
+ }
+ return -1;
+ }
+
+ ext_id = *pos++;
+ elen--;
+
+ switch (ext_id) {
+ case WLAN_EID_EXT_ASSOC_DELAY_INFO:
+ if (elen != 1)
+ break;
+ elems->assoc_delay_info = pos;
+ break;
+ case WLAN_EID_EXT_FILS_REQ_PARAMS:
+ if (elen < 3)
+ break;
+ elems->fils_req_params = pos;
+ elems->fils_req_params_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_KEY_CONFIRM:
+ elems->fils_key_confirm = pos;
+ elems->fils_key_confirm_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_SESSION:
+ if (elen != FILS_SESSION_LEN)
+ break;
+ elems->fils_session = pos;
+ break;
+ case WLAN_EID_EXT_FILS_HLP_CONTAINER:
+ if (elen < 2 * ETH_ALEN)
+ break;
+ elems->fils_hlp = pos;
+ elems->fils_hlp_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
+ if (elen < 1)
+ break;
+ elems->fils_ip_addr_assign = pos;
+ elems->fils_ip_addr_assign_len = elen;
+ break;
+ case WLAN_EID_EXT_KEY_DELIVERY:
+ if (elen < WPA_KEY_RSC_LEN)
+ break;
+ elems->key_delivery = pos;
+ elems->key_delivery_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_WRAPPED_DATA:
+ elems->fils_wrapped_data = pos;
+ elems->fils_wrapped_data_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_PUBLIC_KEY:
+ if (elen < 1)
+ break;
+ elems->fils_pk = pos;
+ elems->fils_pk_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_NONCE:
+ if (elen != FILS_NONCE_LEN)
+ break;
+ elems->fils_nonce = pos;
+ break;
+ case WLAN_EID_EXT_OWE_DH_PARAM:
+ if (elen < 2)
+ break;
+ elems->owe_dh = pos;
+ elems->owe_dh_len = elen;
+ break;
+ case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
+ elems->password_id = pos;
+ elems->password_id_len = elen;
+ break;
+ case WLAN_EID_EXT_HE_CAPABILITIES:
+ elems->he_capabilities = pos;
+ elems->he_capabilities_len = elen;
+ break;
+ case WLAN_EID_EXT_OCV_OCI:
+ elems->oci = pos;
+ elems->oci_len = elen;
+ break;
+ default:
+ if (show_errors) {
+ wpa_printf(MSG_MSGDUMP,
+ "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)",
+ ext_id, (unsigned int) elen);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+
/**
* ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
@@ -186,29 +303,17 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
struct ieee802_11_elems *elems,
int show_errors)
{
- size_t left = len;
- const u8 *pos = start;
+ const struct element *elem;
int unknown = 0;
os_memset(elems, 0, sizeof(*elems));
- while (left >= 2) {
- u8 id, elen;
+ if (!start)
+ return ParseOK;
- id = *pos++;
- elen = *pos++;
- left -= 2;
-
- if (elen > left) {
- if (show_errors) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
- "parse failed (id=%d elen=%d "
- "left=%lu)",
- id, elen, (unsigned long) left);
- wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
- }
- return ParseFailed;
- }
+ for_each_element(elem, start, len) {
+ u8 id = elem->id, elen = elem->datalen;
+ const u8 *pos = elem->data;
switch (id) {
case WLAN_EID_SSID:
@@ -257,6 +362,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->rsn_ie_len = elen;
break;
case WLAN_EID_PWR_CAPABILITY:
+ if (elen < 2)
+ break;
+ elems->power_capab = pos;
+ elems->power_capab_len = elen;
break;
case WLAN_EID_SUPPORTED_CHANNELS:
elems->supp_channels = pos;
@@ -352,8 +461,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->mic = pos;
elems->mic_len = elen;
/* after mic everything is encrypted, so stop. */
- left = elen;
- break;
+ goto done;
case WLAN_EID_MULTI_BAND:
if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
wpa_printf(MSG_MSGDUMP,
@@ -366,6 +474,43 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
elems->mb_ies.nof_ies++;
break;
+ case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
+ elems->supp_op_classes = pos;
+ elems->supp_op_classes_len = elen;
+ break;
+ case WLAN_EID_RRM_ENABLED_CAPABILITIES:
+ elems->rrm_enabled = pos;
+ elems->rrm_enabled_len = elen;
+ break;
+ case WLAN_EID_CAG_NUMBER:
+ elems->cag_number = pos;
+ elems->cag_number_len = elen;
+ break;
+ case WLAN_EID_AP_CSN:
+ if (elen < 1)
+ break;
+ elems->ap_csn = pos;
+ break;
+ case WLAN_EID_FILS_INDICATION:
+ if (elen < 2)
+ break;
+ elems->fils_indic = pos;
+ elems->fils_indic_len = elen;
+ break;
+ case WLAN_EID_DILS:
+ if (elen < 2)
+ break;
+ elems->dils = pos;
+ elems->dils_len = elen;
+ break;
+ case WLAN_EID_FRAGMENT:
+ /* TODO */
+ break;
+ case WLAN_EID_EXTENSION:
+ if (ieee802_11_parse_extension(pos, elen, elems,
+ show_errors))
+ unknown++;
+ break;
default:
unknown++;
if (!show_errors)
@@ -375,35 +520,33 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
id, elen);
break;
}
-
- left -= elen;
- pos += elen;
}
- if (left)
+ if (!for_each_element_completed(elem, start, len)) {
+ if (show_errors) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.11 element parse failed @%d",
+ (int) (start + len - (const u8 *) elem));
+ wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
+ }
return ParseFailed;
+ }
+done:
return unknown ? ParseUnknown : ParseOK;
}
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
{
+ const struct element *elem;
int count = 0;
- const u8 *pos, *end;
if (ies == NULL)
return 0;
- pos = ies;
- end = ies + ies_len;
-
- while (pos + 2 <= end) {
- if (pos + 2 + pos[1] > end)
- break;
+ for_each_element(elem, ies, ies_len)
count++;
- pos += 2 + pos[1];
- }
return count;
}
@@ -413,24 +556,17 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type)
{
struct wpabuf *buf;
- const u8 *end, *pos, *ie;
-
- pos = ies;
- end = ies + ies_len;
- ie = NULL;
+ const struct element *elem, *found = NULL;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- return NULL;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- WPA_GET_BE32(&pos[2]) == oui_type) {
- ie = pos;
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
+ if (elem->datalen >= 4 &&
+ WPA_GET_BE32(elem->data) == oui_type) {
+ found = elem;
break;
}
- pos += 2 + pos[1];
}
- if (ie == NULL)
+ if (!found)
return NULL; /* No specified vendor IE found */
buf = wpabuf_alloc(ies_len);
@@ -441,13 +577,9 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
* There may be multiple vendor IEs in the message, so need to
* concatenate their data fields.
*/
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- WPA_GET_BE32(&pos[2]) == oui_type)
- wpabuf_put_data(buf, pos + 6, pos[1] - 4);
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
+ if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type)
+ wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4);
}
return buf;
@@ -570,7 +702,8 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{
u8 op_class;
- return ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, channel);
+ return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+ &op_class, channel);
}
@@ -579,7 +712,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
* for HT40 and VHT. DFS channels are not covered.
* @freq: Frequency (MHz) to convert
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
- * @vht: 0 - non-VHT, 1 - 80 MHz
+ * @vht: VHT channel width (VHT_CHANWIDTH_*)
* @op_class: Buffer for returning operating class
* @channel: Buffer for returning channel number
* Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
@@ -588,6 +721,8 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
int sec_channel, int vht,
u8 *op_class, u8 *channel)
{
+ u8 vht_opclass;
+
/* TODO: more operating classes */
if (sec_channel > 1 || sec_channel < -1)
@@ -631,17 +766,32 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
+ switch (vht) {
+ case VHT_CHANWIDTH_80MHZ:
+ vht_opclass = 128;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ vht_opclass = 129;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ vht_opclass = 130;
+ break;
+ default:
+ vht_opclass = 0;
+ break;
+ }
+
/* 5 GHz, channels 36..48 */
if (freq >= 5180 && freq <= 5240) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
- if (sec_channel == 1)
+ if (vht_opclass)
+ *op_class = vht_opclass;
+ else if (sec_channel == 1)
*op_class = 116;
else if (sec_channel == -1)
*op_class = 117;
- else if (vht)
- *op_class = 128;
else
*op_class = 115;
@@ -650,19 +800,19 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
- /* 5 GHz, channels 149..161 */
- if (freq >= 5745 && freq <= 5805) {
+ /* 5 GHz, channels 52..64 */
+ if (freq >= 5260 && freq <= 5320) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
- if (sec_channel == 1)
- *op_class = 126;
+ if (vht_opclass)
+ *op_class = vht_opclass;
+ else if (sec_channel == 1)
+ *op_class = 119;
else if (sec_channel == -1)
- *op_class = 127;
- else if (vht)
- *op_class = 128;
+ *op_class = 120;
else
- *op_class = 124;
+ *op_class = 118;
*channel = (freq - 5000) / 5;
@@ -674,7 +824,35 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
- *op_class = 125;
+ if (vht_opclass)
+ *op_class = vht_opclass;
+ else if (sec_channel == 1)
+ *op_class = 126;
+ else if (sec_channel == -1)
+ *op_class = 127;
+ else if (freq <= 5805)
+ *op_class = 124;
+ else
+ *op_class = 125;
+
+ *channel = (freq - 5000) / 5;
+
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* 5 GHz, channels 100..140 */
+ if (freq >= 5000 && freq <= 5700) {
+ if ((freq - 5000) % 5)
+ return NUM_HOSTAPD_MODES;
+
+ if (vht_opclass)
+ *op_class = vht_opclass;
+ else if (sec_channel == 1)
+ *op_class = 122;
+ else if (sec_channel == -1)
+ *op_class = 123;
+ else
+ *op_class = 121;
*channel = (freq - 5000) / 5;
@@ -704,6 +882,41 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
}
+int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
+ int sec_channel, u8 *op_class, u8 *channel)
+{
+ int vht = CHAN_WIDTH_UNKNOWN;
+
+ switch (chanwidth) {
+ case CHAN_WIDTH_UNKNOWN:
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ case CHAN_WIDTH_40:
+ vht = VHT_CHANWIDTH_USE_HT;
+ break;
+ case CHAN_WIDTH_80:
+ vht = VHT_CHANWIDTH_80MHZ;
+ break;
+ case CHAN_WIDTH_80P80:
+ vht = VHT_CHANWIDTH_80P80MHZ;
+ break;
+ case CHAN_WIDTH_160:
+ vht = VHT_CHANWIDTH_160MHZ;
+ break;
+ }
+
+ if (ieee80211_freq_to_channel_ext(freq, sec_channel, vht, op_class,
+ channel) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_WARNING,
+ "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
+ freq, chanwidth, sec_channel);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static const char *const us_op_class_cc[] = {
"US", "CA", NULL
};
@@ -941,7 +1154,7 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
return -1;
return 5000 + 5 * chan;
case 129: /* center freqs 50, 114; 160 MHz */
- if (chan < 50 || chan > 114)
+ if (chan < 36 || chan > 128)
return -1;
return 5000 + 5 * chan;
case 180: /* 60 GHz band, channels 1..4 */
@@ -991,10 +1204,24 @@ int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
}
-int ieee80211_is_dfs(int freq)
+int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
+ u16 num_modes)
{
- /* TODO: this could be more accurate to better cover all domains */
- return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
+ int i, j;
+
+ if (!modes || !num_modes)
+ return (freq >= 5260 && freq <= 5320) ||
+ (freq >= 5500 && freq <= 5700);
+
+ for (i = 0; i < num_modes; i++) {
+ for (j = 0; j < modes[i].num_channels; j++) {
+ if (modes[i].channels[j].freq == freq &&
+ (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR))
+ return 1;
+ }
+ }
+
+ return 0;
}
@@ -1091,27 +1318,27 @@ const char * fc2str(u16 fc)
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
size_t ies_len)
{
+ const struct element *elem;
+
os_memset(info, 0, sizeof(*info));
- while (ies_buf && ies_len >= 2 &&
- info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
- size_t len = 2 + ies_buf[1];
+ if (!ies_buf)
+ return 0;
- if (len > ies_len) {
- wpa_hexdump(MSG_DEBUG, "Truncated IEs",
- ies_buf, ies_len);
- return -1;
- }
+ for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) {
+ if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED)
+ return 0;
- if (ies_buf[0] == WLAN_EID_MULTI_BAND) {
- wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len);
- info->ies[info->nof_ies].ie = ies_buf + 2;
- info->ies[info->nof_ies].ie_len = ies_buf[1];
- info->nof_ies++;
- }
+ wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
+ elem->datalen + 2);
+ info->ies[info->nof_ies].ie = elem->data;
+ info->ies[info->nof_ies].ie_len = elem->datalen;
+ info->nof_ies++;
+ }
- ies_len -= len;
- ies_buf += len;
+ if (!for_each_element_completed(elem, ies_buf, ies_len)) {
+ wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len);
+ return -1;
}
return 0;
@@ -1145,3 +1372,460 @@ struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
return mb_ies;
}
+
+
+const struct oper_class_map global_op_class[] = {
+ { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP },
+
+ /* Do not enable HT40 on 2.4 GHz for P2P use for now */
+ { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP },
+
+ { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP },
+
+ /*
+ * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
+ * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
+ * 80 MHz, but currently use the following definition for simplicity
+ * (these center frequencies are not actual channels, which makes
+ * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take
+ * care of removing invalid channels.
+ */
+ { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
+ { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
+};
+
+
+static enum phy_type ieee80211_phy_type_by_freq(int freq)
+{
+ enum hostapd_hw_mode hw_mode;
+ u8 channel;
+
+ hw_mode = ieee80211_freq_to_chan(freq, &channel);
+
+ switch (hw_mode) {
+ case HOSTAPD_MODE_IEEE80211A:
+ return PHY_TYPE_OFDM;
+ case HOSTAPD_MODE_IEEE80211B:
+ return PHY_TYPE_HRDSSS;
+ case HOSTAPD_MODE_IEEE80211G:
+ return PHY_TYPE_ERP;
+ case HOSTAPD_MODE_IEEE80211AD:
+ return PHY_TYPE_DMG;
+ default:
+ return PHY_TYPE_UNSPECIFIED;
+ };
+}
+
+
+/* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */
+enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht)
+{
+ if (vht)
+ return PHY_TYPE_VHT;
+ if (ht)
+ return PHY_TYPE_HT;
+
+ return ieee80211_phy_type_by_freq(freq);
+}
+
+
+size_t global_op_class_size = ARRAY_SIZE(global_op_class);
+
+
+/**
+ * get_ie - Fetch a specified information element from IEs buffer
+ * @ies: Information elements buffer
+ * @len: Information elements buffer length
+ * @eid: Information element identifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the IEs
+ * buffer or %NULL in case the element is not found.
+ */
+const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
+{
+ const struct element *elem;
+
+ if (!ies)
+ return NULL;
+
+ for_each_element_id(elem, eid, ies, len)
+ return &elem->id;
+
+ return NULL;
+}
+
+
+/**
+ * get_ie_ext - Fetch a specified extended information element from IEs buffer
+ * @ies: Information elements buffer
+ * @len: Information elements buffer length
+ * @ext: Information element extension identifier (WLAN_EID_EXT_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the IEs
+ * buffer or %NULL in case the element is not found.
+ */
+const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
+{
+ const struct element *elem;
+
+ if (!ies)
+ return NULL;
+
+ for_each_element_extid(elem, ext, ies, len)
+ return &elem->id;
+
+ return NULL;
+}
+
+
+const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
+{
+ const struct element *elem;
+
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
+ }
+
+ return NULL;
+}
+
+
+size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
+{
+ /*
+ * MBO IE requires 6 bytes without the attributes: EID (1), length (1),
+ * OUI (3), OUI type (1).
+ */
+ if (len < 6 + attr_len) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
+ len, attr_len);
+ return 0;
+ }
+
+ *buf++ = WLAN_EID_VENDOR_SPECIFIC;
+ *buf++ = attr_len + 4;
+ WPA_PUT_BE24(buf, OUI_WFA);
+ buf += 3;
+ *buf++ = MBO_OUI_TYPE;
+ os_memcpy(buf, attr, attr_len);
+
+ return 6 + attr_len;
+}
+
+
+size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value)
+{
+ u8 *pos = buf;
+
+ if (len < 9)
+ return 0;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 7; /* len */
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = MULTI_AP_OUI_TYPE;
+ *pos++ = MULTI_AP_SUB_ELEM_TYPE;
+ *pos++ = 1; /* len */
+ *pos++ = value;
+
+ return pos - buf;
+}
+
+
+static const struct country_op_class us_op_class[] = {
+ { 1, 115 },
+ { 2, 118 },
+ { 3, 124 },
+ { 4, 121 },
+ { 5, 125 },
+ { 12, 81 },
+ { 22, 116 },
+ { 23, 119 },
+ { 24, 122 },
+ { 25, 126 },
+ { 26, 126 },
+ { 27, 117 },
+ { 28, 120 },
+ { 29, 123 },
+ { 30, 127 },
+ { 31, 127 },
+ { 32, 83 },
+ { 33, 84 },
+ { 34, 180 },
+};
+
+static const struct country_op_class eu_op_class[] = {
+ { 1, 115 },
+ { 2, 118 },
+ { 3, 121 },
+ { 4, 81 },
+ { 5, 116 },
+ { 6, 119 },
+ { 7, 122 },
+ { 8, 117 },
+ { 9, 120 },
+ { 10, 123 },
+ { 11, 83 },
+ { 12, 84 },
+ { 17, 125 },
+ { 18, 180 },
+};
+
+static const struct country_op_class jp_op_class[] = {
+ { 1, 115 },
+ { 30, 81 },
+ { 31, 82 },
+ { 32, 118 },
+ { 33, 118 },
+ { 34, 121 },
+ { 35, 121 },
+ { 36, 116 },
+ { 37, 119 },
+ { 38, 119 },
+ { 39, 122 },
+ { 40, 122 },
+ { 41, 117 },
+ { 42, 120 },
+ { 43, 120 },
+ { 44, 123 },
+ { 45, 123 },
+ { 56, 83 },
+ { 57, 84 },
+ { 58, 121 },
+ { 59, 180 },
+};
+
+static const struct country_op_class cn_op_class[] = {
+ { 1, 115 },
+ { 2, 118 },
+ { 3, 125 },
+ { 4, 116 },
+ { 5, 119 },
+ { 6, 126 },
+ { 7, 81 },
+ { 8, 83 },
+ { 9, 84 },
+};
+
+static u8
+global_op_class_from_country_array(u8 op_class, size_t array_size,
+ const struct country_op_class *country_array)
+{
+ size_t i;
+
+ for (i = 0; i < array_size; i++) {
+ if (country_array[i].country_op_class == op_class)
+ return country_array[i].global_op_class;
+ }
+
+ return 0;
+}
+
+
+u8 country_to_global_op_class(const char *country, u8 op_class)
+{
+ const struct country_op_class *country_array;
+ size_t size;
+ u8 g_op_class;
+
+ if (country_match(us_op_class_cc, country)) {
+ country_array = us_op_class;
+ size = ARRAY_SIZE(us_op_class);
+ } else if (country_match(eu_op_class_cc, country)) {
+ country_array = eu_op_class;
+ size = ARRAY_SIZE(eu_op_class);
+ } else if (country_match(jp_op_class_cc, country)) {
+ country_array = jp_op_class;
+ size = ARRAY_SIZE(jp_op_class);
+ } else if (country_match(cn_op_class_cc, country)) {
+ country_array = cn_op_class;
+ size = ARRAY_SIZE(cn_op_class);
+ } else {
+ /*
+ * Countries that do not match any of the above countries use
+ * global operating classes
+ */
+ return op_class;
+ }
+
+ g_op_class = global_op_class_from_country_array(op_class, size,
+ country_array);
+
+ /*
+ * If the given operating class did not match any of the country's
+ * operating classes, assume that global operating class is used.
+ */
+ return g_op_class ? g_op_class : op_class;
+}
+
+
+const struct oper_class_map * get_oper_class(const char *country, u8 op_class)
+{
+ const struct oper_class_map *op;
+
+ if (country)
+ op_class = country_to_global_op_class(country, op_class);
+
+ op = &global_op_class[0];
+ while (op->op_class && op->op_class != op_class)
+ op++;
+
+ if (!op->op_class)
+ return NULL;
+
+ return op;
+}
+
+
+int oper_class_bw_to_int(const struct oper_class_map *map)
+{
+ switch (map->bw) {
+ case BW20:
+ return 20;
+ case BW40PLUS:
+ case BW40MINUS:
+ return 40;
+ case BW80:
+ return 80;
+ case BW80P80:
+ case BW160:
+ return 160;
+ case BW2160:
+ return 2160;
+ default:
+ return 0;
+ }
+}
+
+
+int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
+ size_t nei_rep_len)
+{
+ u8 *nei_pos = nei_rep;
+ const char *end;
+
+ /*
+ * BSS Transition Candidate List Entries - Neighbor Report elements
+ * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
+ * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
+ */
+ while (pos) {
+ u8 *nei_start;
+ long int val;
+ char *endptr, *tmp;
+
+ pos = os_strstr(pos, " neighbor=");
+ if (!pos)
+ break;
+ if (nei_pos + 15 > nei_rep + nei_rep_len) {
+ wpa_printf(MSG_DEBUG,
+ "Not enough room for additional neighbor");
+ return -1;
+ }
+ pos += 10;
+
+ nei_start = nei_pos;
+ *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
+ nei_pos++; /* length to be filled in */
+
+ if (hwaddr_aton(pos, nei_pos)) {
+ wpa_printf(MSG_DEBUG, "Invalid BSSID");
+ return -1;
+ }
+ nei_pos += ETH_ALEN;
+ pos += 17;
+ if (*pos != ',') {
+ wpa_printf(MSG_DEBUG, "Missing BSSID Information");
+ return -1;
+ }
+ pos++;
+
+ val = strtol(pos, &endptr, 0);
+ WPA_PUT_LE32(nei_pos, val);
+ nei_pos += 4;
+ if (*endptr != ',') {
+ wpa_printf(MSG_DEBUG, "Missing Operating Class");
+ return -1;
+ }
+ pos = endptr + 1;
+
+ *nei_pos++ = atoi(pos); /* Operating Class */
+ pos = os_strchr(pos, ',');
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "Missing Channel Number");
+ return -1;
+ }
+ pos++;
+
+ *nei_pos++ = atoi(pos); /* Channel Number */
+ pos = os_strchr(pos, ',');
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "Missing PHY Type");
+ return -1;
+ }
+ pos++;
+
+ *nei_pos++ = atoi(pos); /* PHY Type */
+ end = os_strchr(pos, ' ');
+ tmp = os_strchr(pos, ',');
+ if (tmp && (!end || tmp < end)) {
+ /* Optional Subelements (hexdump) */
+ size_t len;
+
+ pos = tmp + 1;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
+ wpa_printf(MSG_DEBUG,
+ "Not enough room for neighbor subelements");
+ return -1;
+ }
+ if (len & 0x01 ||
+ hexstr2bin(pos, nei_pos, len / 2) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid neighbor subelement info");
+ return -1;
+ }
+ nei_pos += len / 2;
+ pos = end;
+ }
+
+ nei_start[1] = nei_pos - nei_start - 2;
+ }
+
+ return nei_pos - nei_rep;
+}
+
+
+int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
+{
+ if (!ie || ie[1] <= capab / 8)
+ return 0;
+ return !!(ie[2 + capab / 8] & BIT(capab % 8));
+}
diff --git a/contrib/wpa/src/common/ieee802_11_common.h b/contrib/wpa/src/common/ieee802_11_common.h
index 55ce022..d41bd39 100644
--- a/contrib/wpa/src/common/ieee802_11_common.h
+++ b/contrib/wpa/src/common/ieee802_11_common.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +9,17 @@
#ifndef IEEE802_11_COMMON_H
#define IEEE802_11_COMMON_H
+#include "defs.h"
+#include "ieee802_11_defs.h"
+
+struct element {
+ u8 id;
+ u8 datalen;
+ u8 data[];
+} STRUCT_PACKED;
+
+struct hostapd_hw_modes;
+
#define MAX_NOF_MB_IES_SUPPORTED 5
struct mb_ies_info {
@@ -56,9 +67,33 @@ struct ieee802_11_elems {
const u8 *bss_max_idle_period;
const u8 *ssid_list;
const u8 *osen;
+ const u8 *mbo;
const u8 *ampe;
const u8 *mic;
const u8 *pref_freq_list;
+ const u8 *supp_op_classes;
+ const u8 *rrm_enabled;
+ const u8 *cag_number;
+ const u8 *ap_csn;
+ const u8 *fils_indic;
+ const u8 *dils;
+ const u8 *assoc_delay_info;
+ const u8 *fils_req_params;
+ const u8 *fils_key_confirm;
+ const u8 *fils_session;
+ const u8 *fils_hlp;
+ const u8 *fils_ip_addr_assign;
+ const u8 *key_delivery;
+ const u8 *fils_wrapped_data;
+ const u8 *fils_pk;
+ const u8 *fils_nonce;
+ const u8 *owe_dh;
+ const u8 *power_capab;
+ const u8 *roaming_cons_sel;
+ const u8 *password_id;
+ const u8 *oci;
+ const u8 *multi_ap;
+ const u8 *he_capabilities;
u8 ssid_len;
u8 supp_rates_len;
@@ -85,9 +120,30 @@ struct ieee802_11_elems {
u8 ext_capab_len;
u8 ssid_list_len;
u8 osen_len;
+ u8 mbo_len;
u8 ampe_len;
u8 mic_len;
u8 pref_freq_list_len;
+ u8 supp_op_classes_len;
+ u8 rrm_enabled_len;
+ u8 cag_number_len;
+ u8 fils_indic_len;
+ u8 dils_len;
+ u8 fils_req_params_len;
+ u8 fils_key_confirm_len;
+ u8 fils_hlp_len;
+ u8 fils_ip_addr_assign_len;
+ u8 key_delivery_len;
+ u8 fils_wrapped_data_len;
+ u8 fils_pk_len;
+ u8 owe_dh_len;
+ u8 power_capab_len;
+ u8 roaming_cons_sel_len;
+ u8 password_id_len;
+ u8 oci_len;
+ u8 multi_ap_len;
+ u8 he_capabilities_len;
+
struct mb_ies_info mb_ies;
};
@@ -117,7 +173,11 @@ int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
int sec_channel, int vht,
u8 *op_class, u8 *channel);
-int ieee80211_is_dfs(int freq);
+int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
+ int sec_channel, u8 *op_class, u8 *channel);
+int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
+ u16 num_modes);
+enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
@@ -125,4 +185,88 @@ int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
const char * fc2str(u16 fc);
+
+struct oper_class_map {
+ enum hostapd_hw_mode mode;
+ u8 op_class;
+ u8 min_chan;
+ u8 max_chan;
+ u8 inc;
+ enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80 } bw;
+ enum { P2P_SUPP, NO_P2P_SUPP } p2p;
+};
+
+extern const struct oper_class_map global_op_class[];
+extern size_t global_op_class_size;
+
+const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
+const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
+const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
+
+size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
+
+size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value);
+
+struct country_op_class {
+ u8 country_op_class;
+ u8 global_op_class;
+};
+
+u8 country_to_global_op_class(const char *country, u8 op_class);
+
+const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
+int oper_class_bw_to_int(const struct oper_class_map *map);
+
+int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
+ size_t nei_rep_len);
+
+int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
+
+/* element iteration helpers */
+#define for_each_element(_elem, _data, _datalen) \
+ for (_elem = (const struct element *) (_data); \
+ (const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
+ (int) sizeof(*_elem) && \
+ (const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
+ (int) sizeof(*_elem) + _elem->datalen; \
+ _elem = (const struct element *) (_elem->data + _elem->datalen))
+
+#define for_each_element_id(element, _id, data, datalen) \
+ for_each_element(element, data, datalen) \
+ if (element->id == (_id))
+
+#define for_each_element_extid(element, extid, _data, _datalen) \
+ for_each_element(element, _data, _datalen) \
+ if (element->id == WLAN_EID_EXTENSION && \
+ element->datalen > 0 && \
+ element->data[0] == (extid))
+
+#define for_each_subelement(sub, element) \
+ for_each_element(sub, (element)->data, (element)->datalen)
+
+#define for_each_subelement_id(sub, id, element) \
+ for_each_element_id(sub, id, (element)->data, (element)->datalen)
+
+#define for_each_subelement_extid(sub, extid, element) \
+ for_each_element_extid(sub, extid, (element)->data, (element)->datalen)
+
+/**
+ * for_each_element_completed - Determine if element parsing consumed all data
+ * @element: Element pointer after for_each_element() or friends
+ * @data: Same data pointer as passed to for_each_element() or friends
+ * @datalen: Same data length as passed to for_each_element() or friends
+ *
+ * This function returns 1 if all the data was parsed or considered
+ * while walking the elements. Only use this if your for_each_element()
+ * loop cannot be broken out of, otherwise it always returns 0.
+ *
+ * If some data was malformed, this returns %false since the last parsed
+ * element will not fill the whole remaining data.
+ */
+static inline int for_each_element_completed(const struct element *element,
+ const void *data, size_t datalen)
+{
+ return (const u8 *) element == (const u8 *) data + datalen;
+}
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/contrib/wpa/src/common/ieee802_11_defs.h b/contrib/wpa/src/common/ieee802_11_defs.h
index 44530ce..adaa893 100644
--- a/contrib/wpa/src/common/ieee802_11_defs.h
+++ b/contrib/wpa/src/common/ieee802_11_defs.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* This software may be distributed under the terms of the BSD license.
@@ -81,6 +81,9 @@
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
#define WLAN_AUTH_SAE 3
+#define WLAN_AUTH_FILS_SK 4
+#define WLAN_AUTH_FILS_SK_PFS 5
+#define WLAN_AUTH_FILS_PK 6
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@@ -94,10 +97,15 @@
#define WLAN_CAPABILITY_PBCC BIT(6)
#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
+#define WLAN_CAPABILITY_QOS BIT(9)
#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
+#define WLAN_CAPABILITY_APSD BIT(11)
+#define WLAN_CAPABILITY_RADIO_MEASUREMENT BIT(12)
#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
+#define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14)
+#define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15)
-/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
+/* Status codes (IEEE Std 802.11-2016, 9.4.1.9, Table 9-46) */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
@@ -114,27 +122,23 @@
#define WLAN_STATUS_AUTH_TIMEOUT 16
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
#define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* IEEE 802.11b */
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
-/* IEEE 802.11h */
#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
-/* IEEE 802.11g */
#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
-#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
#define WLAN_STATUS_R0KH_UNREACHABLE 28
#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
-/* IEEE 802.11w */
#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
+#define WLAN_STATUS_DENIED_INSUFFICIENT_BANDWIDTH 33
+#define WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS 34
+#define WLAN_STATUS_DENIED_QOS_NOT_SUPPORTED 35
#define WLAN_STATUS_REQUEST_DECLINED 37
#define WLAN_STATUS_INVALID_PARAMETERS 38
-/* IEEE 802.11i */
+#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_CHANGES 39
#define WLAN_STATUS_INVALID_IE 40
#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
@@ -147,11 +151,13 @@
#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
-/* IEEE 802.11r */
#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
#define WLAN_STATUS_INVALID_PMKID 53
#define WLAN_STATUS_INVALID_MDIE 54
#define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_REQUESTED_TCLAS_NOT_SUPPORTED 56
+#define WLAN_STATUS_INSUFFICIENT_TCLAS_PROCESSING_RESOURCES 57
+#define WLAN_STATUS_TRY_ANOTHER_BSS 58
#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
@@ -162,16 +168,44 @@
#define WLAN_STATUS_REQ_REFUSED_SSPN 67
#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
#define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_U_APSD_COEX_NOT_SUPPORTED 73
+#define WLAN_STATUS_U_APSD_COEX_MODE_NOT_SUPPORTED 74
+#define WLAN_STATUS_BAD_INTERVAL_WITH_U_APSD_COEX 75
#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
+#define WLAN_STATUS_CANNOT_FIND_ALT_TBTT 78
#define WLAN_STATUS_TRANSMISSION_FAILURE 79
+#define WLAN_STATUS_REQ_TCLAS_NOT_SUPPORTED 80
+#define WLAN_STATUS_TCLAS_RESOURCES_EXCHAUSTED 81
#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82
+#define WLAN_STATUS_REJECT_WITH_SCHEDULE 83
+#define WLAN_STATUS_REJECT_NO_WAKEUP_SPECIFIED 84
+#define WLAN_STATUS_SUCCESS_POWER_SAVE_MODE 85
#define WLAN_STATUS_PENDING_ADMITTING_FST_SESSION 86
+#define WLAN_STATUS_PERFORMING_FST_NOW 87
+#define WLAN_STATUS_PENDING_GAP_IN_BA_WINDOW 88
+#define WLAN_STATUS_REJECT_U_PID_SETTING 89
+#define WLAN_STATUS_REFUSED_EXTERNAL_REASON 92
+#define WLAN_STATUS_REFUSED_AP_OUT_OF_MEMORY 93
+#define WLAN_STATUS_REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED 94
#define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95
+#define WLAN_STATUS_REJECT_DSE_BAND 96
+#define WLAN_STATUS_TCLAS_PROCESSING_TERMINATED 97
+#define WLAN_STATUS_TS_SCHEDULE_CONFLICT 98
#define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99
+#define WLAN_STATUS_MCCAOP_RESERVATION_CONFLICT 100
+#define WLAN_STATUS_MAF_LIMIT_EXCEEDED 101
+#define WLAN_STATUS_MCCA_TRACK_LIMIT_EXCEEDED 102
+#define WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT 103
#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
-
-/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
+#define WLAN_STATUS_ENABLEMENT_DENIED 105
+#define WLAN_STATUS_RESTRICTION_FROM_AUTHORIZED_GDB 106
+#define WLAN_STATUS_AUTHORIZATION_DEENABLED 107
+#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
+#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
+#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
+
+/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
#define WLAN_REASON_DEAUTH_LEAVING 3
@@ -181,10 +215,9 @@
#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
-/* IEEE 802.11h */
#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
-/* IEEE 802.11i */
+#define WLAN_REASON_BSS_TRANSITION_DISASSOC 12
#define WLAN_REASON_INVALID_IE 13
#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
@@ -199,9 +232,26 @@
#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
-/* IEEE 802.11e */
+#define WLAN_REASON_SSP_REQUESTED_DISASSOC 27
+#define WLAN_REASON_NO_SSP_ROAMING_AGREEMENT 28
+#define WLAN_REASON_BAD_CIPHER_OR_AKM 29
+#define WLAN_REASON_NOT_AUTHORIZED_THIS_LOCATION 30
+#define WLAN_REASON_SERVICE_CHANGE_PRECLUDES_TS 31
+#define WLAN_REASON_UNSPECIFIED_QOS_REASON 32
+#define WLAN_REASON_NOT_ENOUGH_BANDWIDTH 33
#define WLAN_REASON_DISASSOC_LOW_ACK 34
-/* IEEE 802.11s */
+#define WLAN_REASON_EXCEEDED_TXOP 35
+#define WLAN_REASON_STA_LEAVING 36
+#define WLAN_REASON_END_TS_BA_DLS 37
+#define WLAN_REASON_UNKNOWN_TS_BA 38
+#define WLAN_REASON_TIMEOUT 39
+#define WLAN_REASON_PEERKEY_MISMATCH 45
+#define WLAN_REASON_AUTHORIZED_ACCESS_LIMIT_REACHED 46
+#define WLAN_REASON_EXTERNAL_SERVICE_REQUIREMENTS 47
+#define WLAN_REASON_INVALID_FT_ACTION_FRAME_COUNT 48
+#define WLAN_REASON_INVALID_PMKID 49
+#define WLAN_REASON_INVALID_MDE 50
+#define WLAN_REASON_INVALID_FTE 51
#define WLAN_REASON_MESH_PEERING_CANCELLED 52
#define WLAN_REASON_MESH_MAX_PEERS 53
#define WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION 54
@@ -211,20 +261,29 @@
#define WLAN_REASON_MESH_INVALID_GTK 58
#define WLAN_REASON_MESH_INCONSISTENT_PARAMS 59
#define WLAN_REASON_MESH_INVALID_SECURITY_CAP 60
+#define WLAN_REASON_MESH_PATH_ERROR_NO_PROXY_INFO 61
+#define WLAN_REASON_MESH_PATH_ERROR_NO_FORWARDING_INFO 62
+#define WLAN_REASON_MESH_PATH_ERROR_DEST_UNREACHABLE 63
+#define WLAN_REASON_MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS 64
+#define WLAN_REASON_MESH_CHANNEL_SWITCH_REGULATORY_REQ 65
+#define WLAN_REASON_MESH_CHANNEL_SWITCH_UNSPECIFIED 66
-/* Information Element IDs */
+/* Information Element IDs (IEEE Std 802.11-2016, 9.4.2.1, Table 9-77) */
#define WLAN_EID_SSID 0
#define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
#define WLAN_EID_DS_PARAMS 3
#define WLAN_EID_CF_PARAMS 4
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_REQUEST 10
#define WLAN_EID_BSS_LOAD 11
+#define WLAN_EID_EDCA_PARAM_SET 12
+#define WLAN_EID_TSPEC 13
+#define WLAN_EID_TCLAS 14
+#define WLAN_EID_SCHEDULE 15
#define WLAN_EID_CHALLENGE 16
-/* EIDs defined by IEEE 802.11h - START */
#define WLAN_EID_PWR_CONSTRAINT 32
#define WLAN_EID_PWR_CAPABILITY 33
#define WLAN_EID_TPC_REQUEST 34
@@ -233,49 +292,139 @@
#define WLAN_EID_CHANNEL_SWITCH 37
#define WLAN_EID_MEASURE_REQUEST 38
#define WLAN_EID_MEASURE_REPORT 39
-#define WLAN_EID_QUITE 40
+#define WLAN_EID_QUIET 40
#define WLAN_EID_IBSS_DFS 41
-/* EIDs defined by IEEE 802.11h - END */
#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_TS_DELAY 43
+#define WLAN_EID_TCLAS_PROCESSING 44
#define WLAN_EID_HT_CAP 45
#define WLAN_EID_QOS 46
#define WLAN_EID_RSN 48
#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_AP_CHANNEL_REPORT 51
#define WLAN_EID_NEIGHBOR_REPORT 52
+#define WLAN_EID_RCPI 53
#define WLAN_EID_MOBILITY_DOMAIN 54
#define WLAN_EID_FAST_BSS_TRANSITION 55
#define WLAN_EID_TIMEOUT_INTERVAL 56
#define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_DSE_REGISTERED_LOCATION 58
#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
+#define WLAN_EID_EXT_CHANSWITCH_ANN 60
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
-#define WLAN_EID_WAPI 68
+#define WLAN_EID_BSS_AVERAGE_ACCESS_DELAY 63
+#define WLAN_EID_ANTENNA 64
+#define WLAN_EID_RSNI 65
+#define WLAN_EID_MEASUREMENT_PILOT_TRANSMISSION 66
+#define WLAN_EID_BSS_AVAILABLE_ADM_CAPA 67
+#define WLAN_EID_BSS_AC_ACCESS_DELAY 68 /* note: also used by WAPI */
#define WLAN_EID_TIME_ADVERTISEMENT 69
#define WLAN_EID_RRM_ENABLED_CAPABILITIES 70
+#define WLAN_EID_MULTIPLE_BSSID 71
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
+#define WLAN_EID_RIC_DESCRIPTOR 75
#define WLAN_EID_MMIE 76
+#define WLAN_EID_EVENT_REQUEST 78
+#define WLAN_EID_EVENT_REPORT 79
+#define WLAN_EID_DIAGNOSTIC_REQUEST 80
+#define WLAN_EID_DIAGNOSTIC_REPORT 81
+#define WLAN_EID_LOCATION_PARAMETERS 82
+#define WLAN_EID_NONTRANSMITTED_BSSID_CAPA 83
#define WLAN_EID_SSID_LIST 84
+#define WLAN_EID_MULTIPLE_BSSID_INDEX 85
+#define WLAN_EID_FMS_DESCRIPTOR 86
+#define WLAN_EID_FMS_REQUEST 87
+#define WLAN_EID_FMS_RESPONSE 88
+#define WLAN_EID_QOS_TRAFFIC_CAPABILITY 89
#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
#define WLAN_EID_TFS_REQ 91
#define WLAN_EID_TFS_RESP 92
#define WLAN_EID_WNMSLEEP 93
+#define WLAN_EID_TIM_BROADCAST_REQUEST 94
+#define WLAN_EID_TIM_BROADCAST_RESPONSE 95
+#define WLAN_EID_COLLOCATED_INTERFERENCE_REPORT 96
+#define WLAN_EID_CHANNEL_USAGE 97
#define WLAN_EID_TIME_ZONE 98
+#define WLAN_EID_DMS_REQUEST 99
+#define WLAN_EID_DMS_RESPONSE 100
#define WLAN_EID_LINK_ID 101
+#define WLAN_EID_WAKEUP_SCHEDULE 102
+#define WLAN_EID_CHANNEL_SWITCH_TIMING 104
+#define WLAN_EID_PTI_CONTROL 105
+#define WLAN_EID_TPU_BUFFER_STATUS 106
#define WLAN_EID_INTERWORKING 107
#define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_EXPEDITED_BANDWIDTH_REQ 109
#define WLAN_EID_QOS_MAP_SET 110
#define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_EMERGENCY_ALERT_ID 112
#define WLAN_EID_MESH_CONFIG 113
#define WLAN_EID_MESH_ID 114
+#define WLAN_EID_MESH_LINK_METRIC_REPORT 115
+#define WLAN_EID_CONGESTION_NOTIFICATION 116
#define WLAN_EID_PEER_MGMT 117
+#define WLAN_EID_MESH_CHANNEL_SWITCH_PARAMETERS 118
+#define WLAN_EID_MESH_AWAKE_WINDOW 119
+#define WLAN_EID_BEACON_TIMING 120
+#define WLAN_EID_MCCAOP_SETUP_REQUEST 121
+#define WLAN_EID_MCCAOP_SETUP_REPLY 122
+#define WLAN_EID_MCCAOP_ADVERTISEMENT 123
+#define WLAN_EID_MCCAOP_TEARDOWN 124
+#define WLAN_EID_GANN 125
+#define WLAN_EID_RANN 126
#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_PREQ 130
+#define WLAN_EID_PREP 131
+#define WLAN_EID_PERR 132
+#define WLAN_EID_PXU 137
+#define WLAN_EID_PXUC 138
#define WLAN_EID_AMPE 139
#define WLAN_EID_MIC 140
+#define WLAN_EID_DESTINATION_URI 141
+#define WLAN_EID_U_APSD_COEX 142
+#define WLAN_EID_DMG_WAKEUP_SCHEDULE 143
+#define WLAN_EID_EXTENDED_SCHEDULE 144
+#define WLAN_EID_STA_AVAILABILITY 145
+#define WLAN_EID_DMG_TSPEC 146
+#define WLAN_EID_NEXT_DMG_ATI 147
+#define WLAN_EID_DMG_CAPABILITIES 148
+#define WLAN_EID_DMG_OPERATION 151
+#define WLAN_EID_DMG_BSS_PARAMETER_CHANGE 152
+#define WLAN_EID_DMG_BEAM_REFINEMENT 153
+#define WLAN_EID_CHANNEL_MEASUREMENT_FEEDBACK 154
#define WLAN_EID_CCKM 156
+#define WLAN_EID_AWAKE_WINDOW 157
#define WLAN_EID_MULTI_BAND 158
+#define WLAN_EID_ADDBA_EXTENSION 159
+#define WLAN_EID_NEXTPCP_LIST 160
+#define WLAN_EID_PCP_HANDOVER 161
+#define WLAN_EID_DMG_LINK_MARGIN 162
+#define WLAN_EID_SWITCHING_STREAM 163
#define WLAN_EID_SESSION_TRANSITION 164
+#define WLAN_EID_DYNAMIC_TONE_PAIRING_REPORT 165
+#define WLAN_EID_CLUSTER_REPORT 166
+#define WLAN_EID_REPLAY_CAPABILITIES 167
+#define WLAN_EID_RELAY_TRANSFER_PARAM_SET 168
+#define WLAN_EID_BEAMLINK_MAINTENANCE 169
+#define WLAN_EID_MULTIPLE_MAC_SUBLAYERS 170
+#define WLAN_EID_U_PID 171
+#define WLAN_EID_DMG_LINK_ADAPTATION_ACK 172
+#define WLAN_EID_MCCAOP_ADVERTISEMENT_OVERVIEW 174
+#define WLAN_EID_QUIET_PERIOD_REQUEST 175
+#define WLAN_EID_QUIET_PERIOD_RESPONSE 177
+#define WLAN_EID_QMF_POLICY 181
+#define WLAN_EID_ECAPC_POLICY 182
+#define WLAN_EID_CLUSTER_TIME_OFFSET 183
+#define WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY 184
+#define WLAN_EID_SCS_DESCRIPTOR 185
+#define WLAN_EID_QLOAD_REPORT 186
+#define WLAN_EID_HCCA_TXOP_UPDATE_COUNT 187
+#define WLAN_EID_HIGHER_LAYER_STREAM_ID 188
+#define WLAN_EID_GCR_GROUP_ADDRESS 189
+#define WLAN_EID_ANTENNA_SECTOR_ID_PATTERN 190
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
@@ -285,10 +434,124 @@
#define WLAN_EID_VHT_AID 197
#define WLAN_EID_VHT_QUIET_CHANNEL 198
#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
+#define WLAN_EID_UPSIM 200
+#define WLAN_EID_REDUCED_NEIGHBOR_REPORT 201
+#define WLAN_EID_TVHT_OPERATION 202
+#define WLAN_EID_DEVICE_LOCATION 204
+#define WLAN_EID_WHITE_SPACE_MAP 205
+#define WLAN_EID_FTM_PARAMETERS 206
#define WLAN_EID_VENDOR_SPECIFIC 221
-
-
-/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
+#define WLAN_EID_CAG_NUMBER 237
+#define WLAN_EID_AP_CSN 239
+#define WLAN_EID_FILS_INDICATION 240
+#define WLAN_EID_DILS 241
+#define WLAN_EID_FRAGMENT 242
+#define WLAN_EID_EXTENSION 255
+
+/* Element ID Extension (EID 255) values */
+#define WLAN_EID_EXT_ASSOC_DELAY_INFO 1
+#define WLAN_EID_EXT_FILS_REQ_PARAMS 2
+#define WLAN_EID_EXT_FILS_KEY_CONFIRM 3
+#define WLAN_EID_EXT_FILS_SESSION 4
+#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
+#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
+#define WLAN_EID_EXT_KEY_DELIVERY 7
+#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
+#define WLAN_EID_EXT_FTM_SYNC_INFO 9
+#define WLAN_EID_EXT_EXTENDED_REQUEST 10
+#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
+#define WLAN_EID_EXT_FILS_PUBLIC_KEY 12
+#define WLAN_EID_EXT_FILS_NONCE 13
+#define WLAN_EID_EXT_FUTURE_CHANNEL_GUIDANCE 14
+#define WLAN_EID_EXT_OWE_DH_PARAM 32
+#define WLAN_EID_EXT_PASSWORD_IDENTIFIER 33
+#define WLAN_EID_EXT_HE_CAPABILITIES 35
+#define WLAN_EID_EXT_HE_OPERATION 36
+#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
+#define WLAN_EID_EXT_OCV_OCI 54
+
+/* Extended Capabilities field */
+#define WLAN_EXT_CAPAB_20_40_COEX 0
+#define WLAN_EXT_CAPAB_GLK 1
+#define WLAN_EXT_CAPAB_EXT_CHAN_SWITCH 2
+#define WLAN_EXT_CAPAB_GLK_GCR 3
+#define WLAN_EXT_CAPAB_PSMP 4
+/* 5 - Reserved */
+#define WLAN_EXT_CAPAB_S_PSMP 6
+#define WLAN_EXT_CAPAB_EVENT 7
+#define WLAN_EXT_CAPAB_DIAGNOSTICS 8
+#define WLAN_EXT_CAPAB_MULTICAST_DIAGNOSTICS 9
+#define WLAN_EXT_CAPAB_LOCATION_TRACKING 10
+#define WLAN_EXT_CAPAB_FMS 11
+#define WLAN_EXT_CAPAB_PROXY_ARP 12
+#define WLAN_EXT_CAPAB_COLL_INTERF_REP 13
+#define WLAN_EXT_CAPAB_CIVIC_LOCATION 14
+#define WLAN_EXT_CAPAB_GEOSPATIAL_LOCATION 15
+#define WLAN_EXT_CAPAB_TFS 16
+#define WLAN_EXT_CAPAB_WNM_SLEEP_MODE 17
+#define WLAN_EXT_CAPAB_TIM_BROADCAST 18
+#define WLAN_EXT_CAPAB_BSS_TRANSITION 19
+#define WLAN_EXT_CAPAB_QOS_TRAFFIC 20
+#define WLAN_EXT_CAPAB_AC_STA_COUNT 21
+#define WLAN_EXT_CAPAB_MULTIPLE_BSSID 22
+#define WLAN_EXT_CAPAB_TIMING_MEASUREMENT 23
+#define WLAN_EXT_CAPAB_CHANNEL_USAGE 24
+#define WLAN_EXT_CAPAB_SSID_LIST 25
+#define WLAN_EXT_CAPAB_DMS 26
+#define WLAN_EXT_CAPAB_UTF_TSF_OFFSET 27
+#define WLAN_EXT_CAPAB_TPU_BUFFER_STA 28
+#define WLAN_EXT_CAPAB_TDLS_PEER_PSM 29
+#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH 30
+#define WLAN_EXT_CAPAB_INTERWORKING 31
+#define WLAN_EXT_CAPAB_QOS_MAP 32
+#define WLAN_EXT_CAPAB_EBR 33
+#define WLAN_EXT_CAPAB_SSPN_INTERFACE 34
+/* 35 - Reserved */
+#define WLAN_EXT_CAPAB_MSGCF 36
+#define WLAN_EXT_CAPAB_TDLS 37
+#define WLAN_EXT_CAPAB_TDLS_PROHIBITED 38
+#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH_PROHIBITED 39
+#define WLAN_EXT_CAPAB_REJECT_UNADMITTED_FRAME 40
+#define WLAN_EXT_CAPAB_
+/* 41-43 - Service Interval Granularity */
+#define WLAN_EXT_CAPAB_IDENTIFIER_LOCATION 44
+#define WLAN_EXT_CAPAB_U_APSD_COEX 45
+#define WLAN_EXT_CAPAB_WNM_NOTIFCATION 46
+#define WLAN_EXT_CAPAB_QAB 47
+#define WLAN_EXT_CAPAB_UTF_8_SSID 48
+#define WLAN_EXT_CAPAB_QMF 49
+#define WLAN_EXT_CAPAB_QMF_RECONFIG 50
+#define WLAN_EXT_CAPAB_ROBUST_AV_STREAMING 51
+#define WLAN_EXT_CAPAB_ADVANCED_GCR 52
+#define WLAN_EXT_CAPAB_MESH_GCR 53
+#define WLAN_EXT_CAPAB_SCS 54
+#define WLAN_EXT_CAPAB_QLOAD_REPORT 55
+#define WLAN_EXT_CAPAB_ALT_EDCA 56
+#define WLAN_EXT_CAPAB_UNPROT_TXOP_NEG 57
+#define WLAN_EXT_CAPAB_PROT_TXOP_NEG 58
+/* 59 - Reserved */
+#define WLAN_EXT_CAPAB_PROT_QLOAD_REPORT 60
+#define WLAN_EXT_CAPAB_TDLS_WIDER_BW 61
+#define WLAN_EXT_CAPAB_OPMODE_NOTIF 62
+#define WLAN_EXT_CAPAB_
+/* 63-64 - Max Number of MSDUs In A-MSDU */
+#define WLAN_EXT_CAPAB_CHANNEL_SCHEDULE_MGMT 65
+#define WLAN_EXT_CAPAB_GEODB_INBAND_ENABLING_SIGNAL 66
+#define WLAN_EXT_CAPAB_NETWORK_CHANNEL_CTRL 67
+#define WLAN_EXT_CAPAB_WHITE_SPACE_MAP 68
+#define WLAN_EXT_CAPAB_CHANNEL_AVAIL_QUERY 69
+#define WLAN_EXT_CAPAB_FTM_RESPONDER 70
+#define WLAN_EXT_CAPAB_FTM_INITIATOR 71
+#define WLAN_EXT_CAPAB_FILS 72
+#define WLAN_EXT_CAPAB_EXT_SPECTRUM_MGMT 73
+#define WLAN_EXT_CAPAB_FUTURE_CHANNEL_GUIDANCE 74
+#define WLAN_EXT_CAPAB_PAD 75
+/* 76-79 - Reserved */
+#define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
+#define WLAN_EXT_CAPAB_SAE_PW_ID 81
+#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
+
+/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
#define WLAN_ACTION_QOS 1
#define WLAN_ACTION_DLS 2
@@ -302,21 +565,59 @@
#define WLAN_ACTION_WNM 10
#define WLAN_ACTION_UNPROTECTED_WNM 11
#define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_MESH 13
+#define WLAN_ACTION_MULTIHOP 14
#define WLAN_ACTION_SELF_PROTECTED 15
+#define WLAN_ACTION_DMG 16
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_FST 18
+#define WLAN_ACTION_ROBUST_AV_STREAMING 19
+#define WLAN_ACTION_UNPROTECTED_DMG 20
+#define WLAN_ACTION_VHT 21
+#define WLAN_ACTION_FILS 26
+#define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
#define WLAN_ACTION_VENDOR_SPECIFIC 127
+/* Note: 128-255 used to report errors by setting category | 0x80 */
-/* Public action codes */
+/* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */
#define WLAN_PA_20_40_BSS_COEX 0
+#define WLAN_PA_DSE_ENABLEMENT 1
+#define WLAN_PA_DSE_DEENABLEMENT 2
+#define WLAN_PA_DSE_REG_LOCATION_ANNOUNCE 3
+#define WLAN_PA_EXT_CHANNEL_SWITCH_ANNOUNCE 4
+#define WLAN_PA_DSE_MEASUREMENT_REQ 5
+#define WLAN_PA_DSE_MEASUREMENT_RESP 6
+#define WLAN_PA_MEASUREMENT_PILOT 7
+#define WLAN_PA_DSE_POWER_CONSTRAINT 8
#define WLAN_PA_VENDOR_SPECIFIC 9
#define WLAN_PA_GAS_INITIAL_REQ 10
#define WLAN_PA_GAS_INITIAL_RESP 11
#define WLAN_PA_GAS_COMEBACK_REQ 12
#define WLAN_PA_GAS_COMEBACK_RESP 13
#define WLAN_TDLS_DISCOVERY_RESPONSE 14
-
-/* Protected Dual of Public Action frames */
+#define WLAN_PA_LOCATION_TRACK_NOTIFICATION 15
+#define WLAN_PA_QAB_REQUEST_FRAME 16
+#define WLAN_PA_QAB_RESPONSE_FRAME 17
+#define WLAN_PA_QMF_POLICY 18
+#define WLAN_PA_QMF_POLICY_CHANGE 19
+#define WLAN_PA_QLOAD_REQUEST 20
+#define WLAN_PA_QLOAD_REPORT 21
+#define WLAN_PA_HCCA_TXOP_ADVERTISEMENT 22
+#define WLAN_PA_HCCA_TXOP_RESPONSE 23
+#define WLAN_PA_PUBLIC_KEY 24
+#define WLAN_PA_CHANNEL_AVAILABILITY_QUERY 25
+#define WLAN_PA_CHANNEL_SCHEDULE_MANAGEMENT 26
+#define WLAN_PA_CONTACT_VERIFICATION_SIGNAL 27
+#define WLAN_PA_GDD_ENABLEMENT_REQ 28
+#define WLAN_PA_GDD_ENABLEMENT_RESP 29
+#define WLAN_PA_NETWORK_CHANNEL_CONTROL 30
+#define WLAN_PA_WHITE_SPACE_MAP_ANNOUNCEMENT 31
+#define WLAN_PA_FTM_REQUEST 32
+#define WLAN_PA_FTM 33
+#define WLAN_PA_FILS_DISCOVERY 34
+
+/* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11,
+ * Table 9-332) */
#define WLAN_PROT_DSE_ENABLEMENT 1
#define WLAN_PROT_DSE_DEENABLEMENT 2
#define WLAN_PROT_EXT_CSA 4
@@ -328,6 +629,21 @@
#define WLAN_PROT_GAS_INITIAL_RESP 11
#define WLAN_PROT_GAS_COMEBACK_REQ 12
#define WLAN_PROT_GAS_COMEBACK_RESP 13
+#define WLAN_PROT_QAB_REQUEST_FRAME 16
+#define WLAN_PROT_QAB_RESPONSE_FRAME 17
+#define WLAN_PROT_QMF_POLICY 18
+#define WLAN_PROT_QMF_POLICY_CHANGE 19
+#define WLAN_PROT_QLOAD_REQUEST 20
+#define WLAN_PROT_QLOAD_REPORT 21
+#define WLAN_PROT_HCCA_TXOP_ADVERTISEMENT 22
+#define WLAN_PROT_HCCA_TXOP_RESPONSE 23
+#define WLAN_PROT_CHANNEL_AVAILABILITY_QUERY 25
+#define WLAN_PROT_CHANNEL_SCHEDULE_MANAGEMENT 26
+#define WLAN_PROT_CONTACT_VERIFICATION_SIGNAL 27
+#define WLAN_PROT_GDD_ENABLEMENT_REQ 28
+#define WLAN_PROT_GDD_ENABLEMENT_RESP 29
+#define WLAN_PROT_NETWORK_CHANNEL_CONTROL 30
+#define WLAN_PROT_WHITE_SPACE_MAP_ANNOUNCEMENT 31
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
#define WLAN_SA_QUERY_REQUEST 0
@@ -356,10 +672,24 @@
#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
-/* Radio Measurement capabilities (from RRM Capabilities IE) */
+/* Radio Measurement capabilities (from RM Enabled Capabilities element)
+ * IEEE Std 802.11-2016, 9.4.2.45, Table 9-157 */
/* byte 1 (out of 5) */
#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
+#define WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE BIT(4)
+#define WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE BIT(5)
+#define WLAN_RRM_CAPS_BEACON_REPORT_TABLE BIT(6)
+/* byte 2 (out of 5) */
+#define WLAN_RRM_CAPS_LCI_MEASUREMENT BIT(4)
+/* byte 5 (out of 5) */
+#define WLAN_RRM_CAPS_FTM_RANGE_REPORT BIT(2)
+
+/*
+ * IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 (Fine Timing Measurement Range
+ * request) - Minimum AP count
+ */
+#define WLAN_RRM_RANGE_REQ_MAX_MIN_AP 15
/* Timeout Interval Type */
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
@@ -382,16 +712,18 @@
#define INTERWORKING_ANT_TEST 6
#define INTERWORKING_ANT_WILDCARD 15
-/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
+/* Advertisement Protocol ID definitions (IEEE Std 802.11-2016, Table 9-215) */
enum adv_proto_id {
ACCESS_NETWORK_QUERY_PROTOCOL = 0,
MIH_INFO_SERVICE = 1,
MIH_CMD_AND_EVENT_DISCOVERY = 2,
EMERGENCY_ALERT_SYSTEM = 3,
+ REGISTERED_LOCATION_QUERY_PROTO = 4,
ADV_PROTO_VENDOR_SPECIFIC = 221
};
-/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11-2016,
+ * Table 9-271; P802.11ai) */
enum anqp_info_id {
ANQP_QUERY_LIST = 256,
ANQP_CAPABILITY_LIST = 257,
@@ -407,7 +739,17 @@ enum anqp_info_id {
ANQP_AP_LOCATION_PUBLIC_URI = 267,
ANQP_DOMAIN_NAME = 268,
ANQP_EMERGENCY_ALERT_URI = 269,
+ ANQP_TDLS_CAPABILITY = 270,
ANQP_EMERGENCY_NAI = 271,
+ ANQP_NEIGHBOR_REPORT = 272,
+ ANQP_QUERY_AP_LIST = 273,
+ ANQP_AP_LIST_RESPONSE = 274,
+ ANQP_FILS_REALM_INFO = 275,
+ ANQP_CAG = 276,
+ ANQP_VENUE_URL = 277,
+ ANQP_ADVICE_OF_CHARGE = 278,
+ ANQP_LOCAL_CONTENT = 279,
+ ANQP_NETWORK_AUTH_TYPE_TIMESTAMP = 280,
ANQP_VENDOR_SPECIFIC = 56797
};
@@ -442,6 +784,53 @@ enum nai_realm_eap_cred_type {
NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
};
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
+ * measurement requests
+ */
+enum measure_type {
+ MEASURE_TYPE_BASIC = 0,
+ MEASURE_TYPE_CCA = 1,
+ MEASURE_TYPE_RPI_HIST = 2,
+ MEASURE_TYPE_CHANNEL_LOAD = 3,
+ MEASURE_TYPE_NOISE_HIST = 4,
+ MEASURE_TYPE_BEACON = 5,
+ MEASURE_TYPE_FRAME = 6,
+ MEASURE_TYPE_STA_STATISTICS = 7,
+ MEASURE_TYPE_LCI = 8,
+ MEASURE_TYPE_TRANSMIT_STREAM = 9,
+ MEASURE_TYPE_MULTICAST_DIAG = 10,
+ MEASURE_TYPE_LOCATION_CIVIC = 11,
+ MEASURE_TYPE_LOCATION_ID = 12,
+ MEASURE_TYPE_DIRECTIONAL_CHAN_QUALITY = 13,
+ MEASURE_TYPE_DIRECTIONAL_MEASURE = 14,
+ MEASURE_TYPE_DIRECTIONAL_STATS = 15,
+ MEASURE_TYPE_FTM_RANGE = 16,
+ MEASURE_TYPE_MEASURE_PAUSE = 255,
+};
+
+/* IEEE Std 802.11-2012 Table 8-71 - Location subject definition */
+enum location_subject {
+ LOCATION_SUBJECT_LOCAL = 0,
+ LOCATION_SUBJECT_REMOTE = 1,
+ LOCATION_SUBJECT_3RD_PARTY = 2,
+};
+
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-94 - Optional subelement IDs for LCI request
+ */
+enum lci_req_subelem {
+ LCI_REQ_SUBELEM_AZIMUTH_REQ = 1,
+ LCI_REQ_SUBELEM_ORIGINATOR_MAC_ADDR = 2,
+ LCI_REQ_SUBELEM_TARGET_MAC_ADDR = 3,
+ LCI_REQ_SUBELEM_MAX_AGE = 4,
+};
+
+#define FILS_NONCE_LEN 16
+#define FILS_SESSION_LEN 8
+#define FILS_CACHE_ID_LEN 2
+#define FILS_MAX_KEY_AUTH_LEN 48
+
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
@@ -516,10 +905,7 @@ struct ieee80211_mgmt {
* FH Params, DS Params, CF Params, IBSS Params, TIM */
u8 variable[];
} STRUCT_PACKED beacon;
- struct {
- /* only variable items: SSID, Supported rates */
- u8 variable[0];
- } STRUCT_PACKED probe_req;
+ /* probe_req: only variable items: SSID, Supported rates */
struct {
u8 timestamp[8];
le16 beacon_int;
@@ -561,10 +947,12 @@ struct ieee80211_mgmt {
struct {
u8 action;
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+ u8 variable[]; /* OCI element */
} STRUCT_PACKED sa_query_req;
struct {
u8 action; /* */
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+ u8 variable[]; /* OCI element */
} STRUCT_PACKED sa_query_resp;
struct {
u8 action;
@@ -618,6 +1006,16 @@ struct ieee80211_mgmt {
u8 variable[];
} STRUCT_PACKED bss_tm_query;
struct {
+ u8 action; /* 11 */
+ u8 dialog_token;
+ u8 req_info;
+ } STRUCT_PACKED coloc_intf_req;
+ struct {
+ u8 action; /* 12 */
+ u8 dialog_token;
+ u8 variable[];
+ } STRUCT_PACKED coloc_intf_report;
+ struct {
u8 action; /* 15 */
u8 variable[];
} STRUCT_PACKED slf_prot_action;
@@ -625,12 +1023,19 @@ struct ieee80211_mgmt {
u8 action;
u8 variable[];
} STRUCT_PACKED fst_action;
+ struct {
+ u8 action;
+ u8 dialog_token;
+ u8 variable[];
+ } STRUCT_PACKED rrm;
} u;
} STRUCT_PACKED action;
} u;
} STRUCT_PACKED;
+#define IEEE80211_MAX_MMPDU_SIZE 2304
+
/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
#define IEEE80211_HT_MCS_MASK_LEN 10
@@ -690,9 +1095,14 @@ struct ieee80211_ampe_ie {
u8 selected_pairwise_suite[4];
u8 local_nonce[32];
u8 peer_nonce[32];
- u8 mgtk[16];
- u8 key_rsc[8];
- u8 key_expiration[4];
+ /* Followed by
+ * Key Replay Counter[8] (optional)
+ * (only in Mesh Group Key Inform/Acknowledge frames)
+ * GTKdata[variable] (optional)
+ * (MGTK[variable] || Key RSC[8] || GTKExpirationTime[4])
+ * IGTKdata[variable] (optional)
+ * (Key ID[2], IPN[6], IGTK[variable] in IGTK KDE format)
+ */
} STRUCT_PACKED;
#ifdef _MSC_VER
@@ -815,6 +1225,7 @@ struct ieee80211_ampe_ie {
#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ((u32) BIT(2))
#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3))
#define VHT_CAP_SUPP_CHAN_WIDTH_MASK ((u32) BIT(2) | BIT(3))
+#define VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT 2
#define VHT_CAP_RXLDPC ((u32) BIT(4))
#define VHT_CAP_SHORT_GI_80 ((u32) BIT(5))
#define VHT_CAP_SHORT_GI_160 ((u32) BIT(6))
@@ -879,6 +1290,17 @@ struct ieee80211_ampe_ie {
#define WFD_OUI_TYPE 10
#define HS20_IE_VENDOR_TYPE 0x506f9a10
#define OSEN_IE_VENDOR_TYPE 0x506f9a12
+#define MBO_IE_VENDOR_TYPE 0x506f9a16
+#define MBO_OUI_TYPE 22
+#define OWE_IE_VENDOR_TYPE 0x506f9a1c
+#define OWE_OUI_TYPE 28
+#define MULTI_AP_OUI_TYPE 0x1B
+
+#define MULTI_AP_SUB_ELEM_TYPE 0x06
+#define MULTI_AP_TEAR_DOWN BIT(4)
+#define MULTI_AP_FRONTHAUL_BSS BIT(5)
+#define MULTI_AP_BACKHAUL_BSS BIT(6)
+#define MULTI_AP_BACKHAUL_STA BIT(7)
#define WMM_OUI_TYPE 2
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -998,6 +1420,7 @@ enum wmm_ac {
#define HS20_INDICATION_OUI_TYPE 16
#define HS20_ANQP_OUI_TYPE 17
#define HS20_OSEN_OUI_TYPE 18
+#define HS20_ROAMING_CONS_SEL_OUI_TYPE 29
#define HS20_STYPE_QUERY_LIST 1
#define HS20_STYPE_CAPABILITY_LIST 2
#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
@@ -1008,19 +1431,122 @@ enum wmm_ac {
#define HS20_STYPE_OSU_PROVIDERS_LIST 8
#define HS20_STYPE_ICON_REQUEST 10
#define HS20_STYPE_ICON_BINARY_FILE 11
+#define HS20_STYPE_OPERATOR_ICON_METADATA 12
+#define HS20_STYPE_OSU_PROVIDERS_NAI_LIST 13
#define HS20_DGAF_DISABLED 0x01
#define HS20_PPS_MO_ID_PRESENT 0x02
#define HS20_ANQP_DOMAIN_ID_PRESENT 0x04
-#define HS20_VERSION 0x10 /* Release 2 */
+#ifndef HS20_VERSION
+#define HS20_VERSION 0x20 /* Release 3 */
+#endif /* HS20_VERSION */
/* WNM-Notification WFA vendors specific subtypes */
#define HS20_WNM_SUB_REM_NEEDED 0
#define HS20_WNM_DEAUTH_IMMINENT_NOTICE 1
+#define WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT 2
+#define WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA 3
+#define HS20_WNM_T_C_ACCEPTANCE 4
#define HS20_DEAUTH_REASON_CODE_BSS 0
#define HS20_DEAUTH_REASON_CODE_ESS 1
+/* MBO v0.0_r19, 4.2: MBO Attributes */
+/* Table 4-5: MBO Attributes */
+/* OCE v0.0.10, Table 4-3: OCE Attributes */
+enum mbo_attr_id {
+ MBO_ATTR_ID_AP_CAPA_IND = 1,
+ MBO_ATTR_ID_NON_PREF_CHAN_REPORT = 2,
+ MBO_ATTR_ID_CELL_DATA_CAPA = 3,
+ MBO_ATTR_ID_ASSOC_DISALLOW = 4,
+ MBO_ATTR_ID_CELL_DATA_PREF = 5,
+ MBO_ATTR_ID_TRANSITION_REASON = 6,
+ MBO_ATTR_ID_TRANSITION_REJECT_REASON = 7,
+ MBO_ATTR_ID_ASSOC_RETRY_DELAY = 8,
+ OCE_ATTR_ID_CAPA_IND = 101,
+ OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT = 102,
+ OCE_ATTR_ID_REDUCED_WAN_METRICS = 103,
+ OCE_ATTR_ID_RNR_COMPLETENESS = 104,
+};
+
+/* MBO v0.0_r19, 4.2.1: MBO AP Capability Indication Attribute */
+/* Table 4-7: MBO AP Capability Indication Field Values */
+#define MBO_AP_CAPA_CELL_AWARE BIT(6)
+
+/* MBO v0.0_r19, 4.2.2: Non-preferred Channel Report Attribute */
+/* Table 4-10: Reason Code Field Values */
+enum mbo_non_pref_chan_reason {
+ MBO_NON_PREF_CHAN_REASON_UNSPECIFIED = 0,
+ MBO_NON_PREF_CHAN_REASON_RSSI = 1,
+ MBO_NON_PREF_CHAN_REASON_EXT_INTERFERENCE = 2,
+ MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE = 3,
+};
+
+/* MBO v0.0_r19, 4.2.3: Cellular Data Capabilities Attribute */
+/* Table 4-13: Cellular Data Connectivity Field */
+enum mbo_cellular_capa {
+ MBO_CELL_CAPA_AVAILABLE = 1,
+ MBO_CELL_CAPA_NOT_AVAILABLE = 2,
+ MBO_CELL_CAPA_NOT_SUPPORTED = 3,
+};
+
+/* MBO v0.0_r19, 4.2.4: Association Disallowed Attribute */
+/* Table 4-15: Reason Code Field Values */
+enum mbo_assoc_disallow_reason {
+ MBO_ASSOC_DISALLOW_REASON_UNSPECIFIED = 1,
+ MBO_ASSOC_DISALLOW_REASON_MAX_STA = 2,
+ MBO_ASSOC_DISALLOW_REASON_AIR_INTERFERENCE = 3,
+ MBO_ASSOC_DISALLOW_REASON_AUTH_SERVER_OVERLOAD = 4,
+ MBO_ASSOC_DISALLOW_REASON_LOW_RSSI = 5,
+};
+
+/* MBO v0.0_r19, 4.2.5: Cellular Data Connection Preference Attribute */
+/* Table 4-17: Cellular Preference Field Values */
+enum mbo_cell_pref {
+ MBO_CELL_PREF_EXCLUDED = 0,
+ MBO_CELL_PREF_NO_USE = 1,
+ MBO_CELL_PREF_USE = 255
+};
+
+/* MBO v0.0_r19, 4.2.6: Transition Reason Code Attribute */
+/* Table 4-19: Transition Reason Code Field Values */
+enum mbo_transition_reason {
+ MBO_TRANSITION_REASON_UNSPECIFIED = 0,
+ MBO_TRANSITION_REASON_FRAME_LOSS = 1,
+ MBO_TRANSITION_REASON_DELAY = 2,
+ MBO_TRANSITION_REASON_BANDWIDTH = 3,
+ MBO_TRANSITION_REASON_LOAD_BALANCE = 4,
+ MBO_TRANSITION_REASON_RSSI = 5,
+ MBO_TRANSITION_REASON_RETRANSMISSIONS = 6,
+ MBO_TRANSITION_REASON_INTERFERENCE = 7,
+ MBO_TRANSITION_REASON_GRAY_ZONE = 8,
+ MBO_TRANSITION_REASON_PREMIUM_AP = 9,
+};
+
+/* MBO v0.0_r19, 4.2.7: Transition Rejection Reason Code Attribute */
+/* Table 4-21: Transition Rejection Reason Code Field Values */
+enum mbo_transition_reject_reason {
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED = 0,
+ MBO_TRANSITION_REJECT_REASON_FRAME_LOSS = 1,
+ MBO_TRANSITION_REJECT_REASON_DELAY = 2,
+ MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY = 3,
+ MBO_TRANSITION_REJECT_REASON_RSSI = 4,
+ MBO_TRANSITION_REJECT_REASON_INTERFERENCE = 5,
+ MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
+};
+
+/* MBO v0.0_r27, 4.3: MBO ANQP-elements */
+#define MBO_ANQP_OUI_TYPE 0x12
+#define MBO_ANQP_SUBTYPE_QUERY_LIST 1
+#define MBO_ANQP_SUBTYPE_CELL_CONN_PREF 2
+#define MAX_MBO_ANQP_SUBTYPE MBO_ANQP_SUBTYPE_CELL_CONN_PREF
+
+/* OCE v0.0.10, 4.2.1: OCE Capability Indication Attribute */
+#define OCE_RELEASE 1
+#define OCE_RELEASE_MASK (BIT(0) | BIT(1) | BIT(2))
+#define OCE_IS_STA_CFON BIT(3)
+#define OCE_IS_NON_OCE_AP_PRESENT BIT(4)
+
/* Wi-Fi Direct (P2P) */
#define P2P_OUI_TYPE 9
@@ -1168,7 +1694,9 @@ enum wifi_display_subelem {
WFD_SUBELEM_COUPLED_SINK = 6,
WFD_SUBELEM_EXT_CAPAB = 7,
WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
- WFD_SUBELEM_SESSION_INFO = 9
+ WFD_SUBELEM_SESSION_INFO = 9,
+ WFD_SUBELEM_MAC_INFO = 10,
+ WFD_SUBELEM_R2_DEVICE_INFO = 11,
};
/* 802.11s */
@@ -1178,6 +1706,14 @@ enum wifi_display_subelem {
#define MESH_PATH_PROTOCOL_VENDOR 255
#define MESH_PATH_METRIC_AIRTIME 1
#define MESH_PATH_METRIC_VENDOR 255
+/* IEEE 802.11s - Mesh Capability */
+#define MESH_CAP_ACCEPT_ADDITIONAL_PEER BIT(0)
+#define MESH_CAP_MCCA_SUPPORTED BIT(1)
+#define MESH_CAP_MCCA_ENABLED BIT(2)
+#define MESH_CAP_FORWARDING BIT(3)
+#define MESH_CAP_MBCA_ENABLED BIT(4)
+#define MESH_CAP_TBTT_ADJUSTING BIT(5)
+#define MESH_CAP_MESH_PS_LEVEL BIT(6)
enum plink_action_field {
PLINK_OPEN = 1,
@@ -1192,41 +1728,6 @@ enum plink_action_field {
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
-/* cipher suite selectors */
-#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
-#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
-#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
-/* reserved: 0x000FAC03 */
-#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
-#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
-#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
-#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07
-#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
-#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC09
-#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0A
-#define WLAN_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B
-#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C
-#define WLAN_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D
-
-#define WLAN_CIPHER_SUITE_SMS4 0x00147201
-
-#define WLAN_CIPHER_SUITE_CKIP 0x00409600
-#define WLAN_CIPHER_SUITE_CKIP_CMIC 0x00409601
-#define WLAN_CIPHER_SUITE_CMIC 0x00409602
-#define WLAN_CIPHER_SUITE_KRK 0x004096FF /* for nl80211 use only */
-
-/* AKM suite selectors */
-#define WLAN_AKM_SUITE_8021X 0x000FAC01
-#define WLAN_AKM_SUITE_PSK 0x000FAC02
-#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03
-#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04
-#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
-#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
-#define WLAN_AKM_SUITE_8021X_SUITE_B 0x000FAC11
-#define WLAN_AKM_SUITE_8021X_SUITE_B_192 0x000FAC12
-#define WLAN_AKM_SUITE_CCKM 0x00409600
-#define WLAN_AKM_SUITE_OSEN 0x506f9a01
-
/* IEEE 802.11v - WNM Action field values */
enum wnm_action {
@@ -1280,14 +1781,25 @@ enum bss_trans_mgmt_status_code {
WNM_BSS_TM_REJECT_LEAVING_ESS = 8
};
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-150 - Optional subelement IDs for
+ * neighbor report
+ */
#define WNM_NEIGHBOR_TSF 1
#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2
#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3
#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4
#define WNM_NEIGHBOR_BEARING 5
+#define WNM_NEIGHBOR_WIDE_BW_CHAN 6
+#define WNM_NEIGHBOR_MEASUREMENT_REPORT 39
+#define WNM_NEIGHBOR_HT_CAPAB 45
+#define WNM_NEIGHBOR_HT_OPER 61
+#define WNM_NEIGHBOR_SEC_CHAN_OFFSET 62
#define WNM_NEIGHBOR_MEASUREMENT_PILOT 66
#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70
#define WNM_NEIGHBOR_MULTIPLE_BSSID 71
+#define WNM_NEIGHBOR_VHT_CAPAB 191
+#define WNM_NEIGHBOR_VHT_OPER 192
/* QoS action */
enum qos_action {
@@ -1356,6 +1868,8 @@ struct tpc_report {
u8 link_margin;
} STRUCT_PACKED;
+#define RRM_CAPABILITIES_IE_LEN 5
+
/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
struct rrm_link_measurement_request {
u8 dialog_token;
@@ -1375,7 +1889,116 @@ struct rrm_link_measurement_report {
u8 variable[0];
} STRUCT_PACKED;
-#define SSID_MAX_LEN 32
+/* IEEE Std 802.11-2016, 9.4.2.21 - Measurement Request element */
+struct rrm_measurement_request_element {
+ u8 eid; /* Element ID */
+ u8 len; /* Length */
+ u8 token; /* Measurement Token */
+ u8 mode; /* Measurement Request Mode */
+ u8 type; /* Measurement Type */
+ u8 variable[0]; /* Measurement Request */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Figure 9-148 - Measurement Request Mode field */
+#define MEASUREMENT_REQUEST_MODE_PARALLEL BIT(0)
+#define MEASUREMENT_REQUEST_MODE_ENABLE BIT(1)
+#define MEASUREMENT_REQUEST_MODE_REQUEST BIT(2)
+#define MEASUREMENT_REQUEST_MODE_REPORT BIT(3)
+#define MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY BIT(4)
+
+/* IEEE Std 802.11-2016, 9.4.2.21.7 - Beacon request */
+struct rrm_measurement_beacon_request {
+ u8 oper_class; /* Operating Class */
+ u8 channel; /* Channel Number */
+ le16 rand_interval; /* Randomization Interval (in TUs) */
+ le16 duration; /* Measurement Duration (in TUs) */
+ u8 mode; /* Measurement Mode */
+ u8 bssid[ETH_ALEN]; /* BSSID */
+ u8 variable[0]; /* Optional Subelements */
+} STRUCT_PACKED;
+
+/*
+ * IEEE Std 802.11-2016, Table 9-87 - Measurement Mode definitions for Beacon
+ * request
+ */
+enum beacon_report_mode {
+ BEACON_REPORT_MODE_PASSIVE = 0,
+ BEACON_REPORT_MODE_ACTIVE = 1,
+ BEACON_REPORT_MODE_TABLE = 2,
+};
+
+/* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */
+/* IEEE P802.11-REVmd/D2.0, Table 9-106 - Optional subelement IDs for
+ * Beacon request */
+#define WLAN_BEACON_REQUEST_SUBELEM_SSID 0
+#define WLAN_BEACON_REQUEST_SUBELEM_INFO 1 /* Beacon Reporting */
+#define WLAN_BEACON_REQUEST_SUBELEM_DETAIL 2 /* Reporting Detail */
+#define WLAN_BEACON_REQUEST_SUBELEM_REQUEST 10
+#define WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL 51 /* AP Channel Report */
+#define WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION 164
+#define WLAN_BEACON_REQUEST_SUBELEM_VENDOR 221
+
+/*
+ * IEEE Std 802.11-2016, Table 9-90 - Reporting Detail values
+ */
+enum beacon_report_detail {
+ /* No fixed-length fields or elements */
+ BEACON_REPORT_DETAIL_NONE = 0,
+ /* All fixed-length fields and any requested elements in the Request
+ * element if present */
+ BEACON_REPORT_DETAIL_REQUESTED_ONLY = 1,
+ /* All fixed-length fields and elements (default, used when Reporting
+ * Detail subelement is not included in a Beacon request) */
+ BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS = 2,
+};
+
+/* IEEE Std 802.11-2016, 9.4.2.22 - Measurement Report element */
+struct rrm_measurement_report_element {
+ u8 eid; /* Element ID */
+ u8 len; /* Length */
+ u8 token; /* Measurement Token */
+ u8 mode; /* Measurement Report Mode */
+ u8 type; /* Measurement Type */
+ u8 variable[0]; /* Measurement Report */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Figure 9-192 - Measurement Report Mode field */
+#define MEASUREMENT_REPORT_MODE_ACCEPT 0
+#define MEASUREMENT_REPORT_MODE_REJECT_LATE BIT(0)
+#define MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE BIT(1)
+#define MEASUREMENT_REPORT_MODE_REJECT_REFUSED BIT(2)
+
+/* IEEE Std 802.11-2016, 9.4.2.22.7 - Beacon report */
+struct rrm_measurement_beacon_report {
+ u8 op_class; /* Operating Class */
+ u8 channel; /* Channel Number */
+ le64 start_time; /* Actual Measurement Start Time
+ * (in TSF of the BSS requesting the measurement) */
+ le16 duration; /* in TUs */
+ u8 report_info; /* Reported Frame Information */
+ u8 rcpi; /* RCPI */
+ u8 rsni; /* RSNI */
+ u8 bssid[ETH_ALEN]; /* BSSID */
+ u8 antenna_id; /* Antenna ID */
+ le32 parent_tsf; /* Parent TSF */
+ u8 variable[0]; /* Optional Subelements */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */
+/* IEEE P802.11-REVmd/D2.0, Table 9-130 - Optional subelement IDs for
+ * Beacon report */
+#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY 1
+#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID 2
+#define WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION 164
+#define WLAN_BEACON_REPORT_SUBELEM_VENDOR 221
+
+/* IEEE P802.11-REVmd/D2.0, Table 9-232 - Data field format of the
+ * Reported Frame Body Fragment ID subelement */
+#define REPORTED_FRAME_BODY_SUBELEM_LEN 4
+#define REPORTED_FRAME_BODY_MORE_FRAGMENTS BIT(7)
+
+/* IEEE P802.11-REVmd/D2.0, 9.4.2.21.7 - Beacon report */
+#define BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN 3
/* IEEE Std 802.11ad-2012 - Multi-band element */
struct multi_band_ie {
@@ -1433,4 +2056,128 @@ enum fst_action {
FST_ACTION_ON_CHANNEL_TUNNEL = 5,
};
+/* IEEE Std 802.11ac-2013, Annex C - dot11PHYType */
+enum phy_type {
+ PHY_TYPE_UNSPECIFIED = 0,
+ PHY_TYPE_FHSS = 1,
+ PHY_TYPE_DSSS = 2,
+ PHY_TYPE_IRBASEBAND = 3,
+ PHY_TYPE_OFDM = 4,
+ PHY_TYPE_HRDSSS = 5,
+ PHY_TYPE_ERP = 6,
+ PHY_TYPE_HT = 7,
+ PHY_TYPE_DMG = 8,
+ PHY_TYPE_VHT = 9,
+};
+
+/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
+/* BSSID Information Field */
+#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
+#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
+#define NEI_REP_BSSID_INFO_AP_REACHABLE (BIT(0) | BIT(1))
+#define NEI_REP_BSSID_INFO_SECURITY BIT(2)
+#define NEI_REP_BSSID_INFO_KEY_SCOPE BIT(3)
+#define NEI_REP_BSSID_INFO_SPECTRUM_MGMT BIT(4)
+#define NEI_REP_BSSID_INFO_QOS BIT(5)
+#define NEI_REP_BSSID_INFO_APSD BIT(6)
+#define NEI_REP_BSSID_INFO_RM BIT(7)
+#define NEI_REP_BSSID_INFO_DELAYED_BA BIT(8)
+#define NEI_REP_BSSID_INFO_IMM_BA BIT(9)
+#define NEI_REP_BSSID_INFO_MOBILITY_DOMAIN BIT(10)
+#define NEI_REP_BSSID_INFO_HT BIT(11)
+#define NEI_REP_BSSID_INFO_VHT BIT(12)
+#define NEI_REP_BSSID_INFO_FTM BIT(13)
+
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
+ * subfields.
+ * Note: These definitions are not the same as other VHT_CHANWIDTH_*.
+ */
+enum nr_chan_width {
+ NR_CHAN_WIDTH_20 = 0,
+ NR_CHAN_WIDTH_40 = 1,
+ NR_CHAN_WIDTH_80 = 2,
+ NR_CHAN_WIDTH_160 = 3,
+ NR_CHAN_WIDTH_80P80 = 4,
+};
+
+struct ieee80211_he_capabilities {
+ u8 he_mac_capab_info[6];
+ u8 he_phy_capab_info[11];
+ u8 he_txrx_mcs_support[12]; /* TODO: 4, 8, or 12 octets */
+ /* PPE Thresholds (optional) */
+} STRUCT_PACKED;
+
+struct ieee80211_he_operation {
+ u32 he_oper_params; /* HE Operation Parameters[3] and
+ * BSS Color Information[1] */
+ u8 he_mcs_nss_set[2];
+ u8 vht_op_info_chwidth;
+ u8 vht_op_info_chan_center_freq_seg0_idx;
+ u8 vht_op_info_chan_center_freq_seg1_idx;
+ /* Followed by conditional MaxBSSID Indicator subfield (u8) */
+} STRUCT_PACKED;
+
+/* HE Capabilities Information defines */
+#define HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX 3
+#define HE_PHYCAP_SU_BEAMFORMER_CAPAB ((u8) BIT(7))
+#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX 4
+#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB ((u8) BIT(0))
+#define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX 4
+#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
+
+/* HE Operation defines */
+/* HE Operation Parameters and BSS Color Information fields */
+#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(0) | BIT(1) | \
+ BIT(2) | BIT(3) | \
+ BIT(4) | BIT(5)))
+#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(6))
+#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(7))
+#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(8) | BIT(9) | \
+ BIT(10)))
+#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 8
+#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(11))
+#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(12) | BIT(13) | \
+ BIT(14) | BIT(15) | \
+ BIT(16) | BIT(17) | \
+ BIT(18) | BIT(19) | \
+ BIT(20) | BIT(21)))
+#define HE_OPERATION_RTS_THRESHOLD_OFFSET 12
+
+struct ieee80211_he_mu_edca_parameter_set {
+ u8 he_qos_info;
+ u8 he_mu_ac_be_param[3];
+ u8 he_mu_ac_bk_param[3];
+ u8 he_mu_ac_vi_param[3];
+ u8 he_mu_ac_vo_param[3];
+} STRUCT_PACKED;
+
+/* HE MU AC parameter record field format */
+/* ACI/AIFSN */
+#define HE_MU_AC_PARAM_ACI_IDX 0
+#define HE_MU_AC_PARAM_AIFSN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3)))
+#define HE_MU_AC_PARAM_ACM ((u8) BIT(4))
+#define HE_MU_AC_PARAM_ACI ((u8) (BIT(5) | BIT(6)))
+/* B7: Reserved */
+
+/* ECWmin/ECWmax */
+#define HE_MU_AC_PARAM_ECW_IDX 1
+#define HE_MU_AC_PARAM_ECWMIN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3)))
+#define HE_MU_AC_PARAM_ECWMAX ((u8) (BIT(4) | BIT(5) | BIT(6) | BIT(7)))
+
+/* MU EDCA Timer */
+#define HE_MU_AC_PARAM_TIMER_IDX 2
+
+/* HE QoS Info field */
+#define HE_QOS_INFO_EDCA_PARAM_SET_COUNT ((u8) (BIT(0) | BIT(1) | \
+ BIT(2) | BIT(3)))
+#define HE_QOS_INFO_Q_ACK ((u8) (BIT(4)))
+#define HE_QOS_INFO_QUEUE_REQUEST ((u8) (BIT(5)))
+#define HE_QOS_INFO_TXOP_REQUEST ((u8) (BIT(6)))
+/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
+#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
+
+/* DPP Public Action frame identifiers - OUI_WFA */
+#define DPP_OUI_TYPE 0x1A
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/contrib/wpa/src/common/ieee802_1x_defs.h b/contrib/wpa/src/common/ieee802_1x_defs.h
index cc88caa..e7acff1 100644
--- a/contrib/wpa/src/common/ieee802_1x_defs.h
+++ b/contrib/wpa/src/common/ieee802_1x_defs.h
@@ -10,8 +10,10 @@
#define IEEE802_1X_DEFS_H
#define CS_ID_LEN 8
-#define CS_ID_GCM_AES_128 {0x00, 0x80, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01}
+#define CS_ID_GCM_AES_128 0x0080020001000001ULL
#define CS_NAME_GCM_AES_128 "GCM-AES-128"
+#define CS_ID_GCM_AES_256 0x0080c20001000002ULL
+#define CS_NAME_GCM_AES_256 "GCM-AES-256"
enum macsec_policy {
/**
@@ -25,6 +27,12 @@ enum macsec_policy {
* Disabled MACsec - do not secure sessions.
*/
DO_NOT_SECURE,
+
+ /**
+ * Should secure sessions, and try to use encryption.
+ * Like @SHOULD_SECURE, this follows the key server's decision.
+ */
+ SHOULD_ENCRYPT,
};
diff --git a/contrib/wpa/src/common/ocv.c b/contrib/wpa/src/common/ocv.c
new file mode 100644
index 0000000..06badfb
--- /dev/null
+++ b/contrib/wpa/src/common/ocv.c
@@ -0,0 +1,172 @@
+/*
+ * Operating Channel Validation (OCV)
+ * Copyright (c) 2018, Mathy Vanhoef
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "drivers/driver.h"
+#include "common/ieee802_11_common.h"
+#include "ocv.h"
+
+/**
+ * Caller of OCV functionality may use various debug output functions, so store
+ * the error here and let the caller use an appropriate debug output function.
+ */
+char ocv_errorstr[256];
+
+
+int ocv_derive_all_parameters(struct oci_info *oci)
+{
+ const struct oper_class_map *op_class_map;
+
+ oci->freq = ieee80211_chan_to_freq(NULL, oci->op_class, oci->channel);
+ if (oci->freq < 0) {
+ wpa_printf(MSG_INFO,
+ "Error interpreting OCI: unrecognized opclass/channel pair (%d/%d)",
+ oci->op_class, oci->channel);
+ return -1;
+ }
+
+ op_class_map = get_oper_class(NULL, oci->op_class);
+ if (!op_class_map) {
+ wpa_printf(MSG_INFO,
+ "Error interpreting OCI: Unrecognized opclass (%d)",
+ oci->op_class);
+ return -1;
+ }
+
+ oci->chanwidth = oper_class_bw_to_int(op_class_map);
+ oci->sec_channel = 0;
+ if (op_class_map->bw == BW40PLUS)
+ oci->sec_channel = 1;
+ else if (op_class_map->bw == BW40MINUS)
+ oci->sec_channel = -1;
+
+ return 0;
+}
+
+
+int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos)
+{
+ u8 op_class, channel;
+ u8 *pos = *argpos;
+
+ if (ieee80211_chaninfo_to_channel(ci->frequency, ci->chanwidth,
+ ci->sec_channel,
+ &op_class, &channel) < 0) {
+ wpa_printf(MSG_WARNING,
+ "Cannot determine operating class and channel for OCI element");
+ return -1;
+ }
+
+ *pos++ = op_class;
+ *pos++ = channel;
+ *pos++ = ci->seg1_idx;
+
+ *argpos = pos;
+ return 0;
+}
+
+
+int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos)
+{
+ u8 *pos = *argpos;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 3;
+ RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_OCI);
+ pos += RSN_SELECTOR_LEN;
+
+ *argpos = pos;
+ return ocv_insert_oci(ci, argpos);
+}
+
+
+int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos)
+{
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + OCV_OCI_LEN;
+ *pos++ = WLAN_EID_EXT_OCV_OCI;
+ return ocv_insert_oci(ci, &pos);
+}
+
+
+int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx)
+{
+ struct oci_info oci;
+
+ if (!oci_ie) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: did not receive mandatory OCI");
+ return -1;
+ }
+
+ if (oci_ie_len != 3) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: received OCI of unexpected length (%d)",
+ (int) oci_ie_len);
+ return -1;
+ }
+
+ os_memset(&oci, 0, sizeof(oci));
+ oci.op_class = oci_ie[0];
+ oci.channel = oci_ie[1];
+ oci.seg1_idx = oci_ie[2];
+ if (ocv_derive_all_parameters(&oci) != 0) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: unable to interpret received OCI");
+ return -1;
+ }
+
+ /* Primary frequency used to send frames to STA must match the STA's */
+ if ((int) ci->frequency != oci.freq) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ ci->frequency, oci.freq);
+ return -1;
+ }
+
+ /* We shouldn't transmit with a higher bandwidth than the STA supports
+ */
+ if (tx_chanwidth > oci.chanwidth) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
+ tx_chanwidth, oci.chanwidth);
+ return -1;
+ }
+
+ /*
+ * Secondary channel only needs be checked for 40 MHz in the 2.4 GHz
+ * band. In the 5 GHz band it's verified through the primary frequency.
+ * Note that the field ci->sec_channel is only filled in when we use
+ * 40 MHz.
+ */
+ if (tx_chanwidth == 40 && ci->frequency < 2500 &&
+ ci->sec_channel != oci.sec_channel) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ ci->sec_channel, oci.sec_channel);
+ return -1;
+ }
+
+ /*
+ * When using a 160 or 80+80 MHz channel to transmit, verify that we use
+ * the same segments as the receiver by comparing frequency segment 1.
+ */
+ if ((ci->chanwidth == CHAN_WIDTH_160 ||
+ ci->chanwidth == CHAN_WIDTH_80P80) &&
+ tx_seg1_idx != oci.seg1_idx) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
+ tx_seg1_idx, oci.seg1_idx);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/common/ocv.h b/contrib/wpa/src/common/ocv.h
new file mode 100644
index 0000000..6379d9d
--- /dev/null
+++ b/contrib/wpa/src/common/ocv.h
@@ -0,0 +1,40 @@
+/*
+ * Operating Channel Validation (OCV)
+ * Copyright (c) 2018, Mathy Vanhoef
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OCV_H
+#define OCV_H
+
+struct wpa_channel_info;
+
+struct oci_info {
+ /* Values in the OCI element */
+ u8 op_class;
+ u8 channel;
+ u8 seg1_idx;
+
+ /* Derived values for easier verification */
+ int freq;
+ int sec_channel;
+ int chanwidth;
+};
+
+#define OCV_OCI_LEN 3
+#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
+#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
+
+extern char ocv_errorstr[256];
+
+int ocv_derive_all_parameters(struct oci_info *oci);
+int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
+int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
+int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
+int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx);
+
+#endif /* OCV_H */
diff --git a/contrib/wpa/src/common/privsep_commands.h b/contrib/wpa/src/common/privsep_commands.h
index 8dff303..b85c6c3 100644
--- a/contrib/wpa/src/common/privsep_commands.h
+++ b/contrib/wpa/src/common/privsep_commands.h
@@ -9,6 +9,7 @@
#ifndef PRIVSEP_COMMANDS_H
#define PRIVSEP_COMMANDS_H
+#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
enum privsep_cmd {
@@ -29,8 +30,17 @@ enum privsep_cmd {
PRIVSEP_CMD_AUTHENTICATE,
};
-struct privsep_cmd_authenticate
-{
+#define PRIVSEP_MAX_SCAN_FREQS 50
+
+struct privsep_cmd_scan {
+ unsigned int num_ssids;
+ u8 ssids[WPAS_MAX_SCAN_SSIDS][32];
+ u8 ssid_lens[WPAS_MAX_SCAN_SSIDS];
+ unsigned int num_freqs;
+ u16 freqs[PRIVSEP_MAX_SCAN_FREQS];
+};
+
+struct privsep_cmd_authenticate {
int freq;
u8 bssid[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
@@ -42,13 +52,12 @@ struct privsep_cmd_authenticate
int wep_tx_keyidx;
int local_state_change;
int p2p;
- size_t sae_data_len;
+ size_t auth_data_len;
/* followed by ie_len bytes of ie */
- /* followed by sae_data_len bytes of sae_data */
+ /* followed by auth_data_len bytes of auth_data */
};
-struct privsep_cmd_associate
-{
+struct privsep_cmd_associate {
u8 bssid[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
@@ -64,8 +73,7 @@ struct privsep_cmd_associate
/* followed by wpa_ie_len bytes of wpa_ie */
};
-struct privsep_cmd_set_key
-{
+struct privsep_cmd_set_key {
int alg;
u8 addr[ETH_ALEN];
int key_idx;
@@ -84,7 +92,6 @@ enum privsep_event {
PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
PRIVSEP_EVENT_INTERFACE_STATUS,
PRIVSEP_EVENT_PMKID_CANDIDATE,
- PRIVSEP_EVENT_STKSTART,
PRIVSEP_EVENT_FT_RESPONSE,
PRIVSEP_EVENT_RX_EAPOL,
PRIVSEP_EVENT_SCAN_STARTED,
diff --git a/contrib/wpa/src/common/qca-vendor.h b/contrib/wpa/src/common/qca-vendor.h
index 28985f5..c34a3bc 100644
--- a/contrib/wpa/src/common/qca-vendor.h
+++ b/contrib/wpa/src/common/qca-vendor.h
@@ -1,6 +1,7 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
- * Copyright (c) 2014-2015, Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -41,15 +42,22 @@ enum qca_radiotap_vendor_ids {
*
* @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency
* ranges to avoid to reduce issues due to interference or internal
- * co-existence information in the driver. The event data structure is
- * defined in struct qca_avoid_freq_list.
+ * co-existence information in the driver. These frequencies aim to
+ * minimize the traffic but not to totally avoid the traffic. That said
+ * for a P2P use case, these frequencies are allowed for the P2P
+ * discovery/negotiation but avoid the group to get formed on these
+ * frequencies. The event data structure is defined in
+ * struct qca_avoid_freq_list.
*
* @QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: Command to check driver support
* for DFS offloading.
*
* @QCA_NL80211_VENDOR_SUBCMD_NAN: NAN command/event which is used to pass
* NAN Request/Response and NAN Indication messages. These messages are
- * interpreted between the framework and the firmware component.
+ * interpreted between the framework and the firmware component. While
+ * sending the command from userspace to the driver, payload is not
+ * encapsulated inside any attribute. Attribute QCA_WLAN_VENDOR_ATTR_NAN
+ * is used when receiving vendor events in userspace from the driver.
*
* @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Set key operation that can be
* used to configure PMK to the driver even when not connected. This can
@@ -89,6 +97,433 @@ enum qca_radiotap_vendor_ids {
* @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Event used by driver,
* which supports DFS offloading, to indicate a radar pattern has been
* detected. The channel is now unusable.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: Get the feature bitmap
+ * based on enum wifi_logger_supported_features. Attributes defined in
+ * enum qca_wlan_vendor_attr_get_logger_features.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA: Get the ring data from a particular
+ * logger ring, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID is passed as the
+ * attribute for this command. Attributes defined in
+ * enum qca_wlan_vendor_attr_wifi_logger_start.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES: Get the supported TDLS
+ * capabilities of the driver, parameters includes the attributes defined
+ * in enum qca_wlan_vendor_attr_tdls_get_capabilities.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS: Vendor command used to offload
+ * sending of certain periodic IP packet to firmware, attributes defined in
+ * enum qca_wlan_vendor_attr_offloaded_packets.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI: Command used to configure RSSI
+ * monitoring, defines min and max RSSI which are configured for RSSI
+ * monitoring. Also used to notify the RSSI breach and provides the BSSID
+ * and RSSI value that was breached. Attributes defined in
+ * enum qca_wlan_vendor_attr_rssi_monitoring.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NDP: Command used for performing various NAN
+ * Data Path (NDP) related operations, attributes defined in
+ * enum qca_wlan_vendor_attr_ndp_params.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD: Command used to enable/disable
+ * Neighbour Discovery offload, attributes defined in
+ * enum qca_wlan_vendor_attr_nd_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER: Used to set/get the various
+ * configuration parameter for BPF packet filter, attributes defined in
+ * enum qca_wlan_vendor_attr_packet_filter.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE: Gets the driver-firmware
+ * maximum supported size, attributes defined in
+ * enum qca_wlan_vendor_drv_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS: Command to get various
+ * data about wake reasons and datapath IP statistics, attributes defined
+ * in enum qca_wlan_vendor_attr_wake_stats.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG: Command used to set configuration
+ * for IEEE 802.11 communicating outside the context of a basic service
+ * set, called OCB command. Uses the attributes defines in
+ * enum qca_wlan_vendor_attr_ocb_set_config.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME: Command used to set OCB
+ * UTC time. Use the attributes defines in
+ * enum qca_wlan_vendor_attr_ocb_set_utc_time.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT: Command used to start
+ * sending OCB timing advert frames. Uses the attributes defines in
+ * enum qca_wlan_vendor_attr_ocb_start_timing_advert.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT: Command used to stop
+ * OCB timing advert. Uses the attributes defines in
+ * enum qca_wlan_vendor_attr_ocb_stop_timing_advert.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER: Command used to get TSF
+ * timer value. Uses the attributes defines in
+ * enum qca_wlan_vendor_attr_ocb_get_tsf_resp.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES: Command/event to update the
+ * link properties of the respective interface. As an event, is used
+ * to notify the connected station's status. The attributes for this
+ * command are defined in enum qca_wlan_vendor_attr_link_properties.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to
+ * start the P2P Listen offload function in device and pass the listen
+ * channel, period, interval, count, device types, and vendor specific
+ * information elements to the device driver and firmware.
+ * Uses the attributes defines in
+ * enum qca_wlan_vendor_attr_p2p_listen_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: Command/event used to
+ * indicate stop request/response of the P2P Listen offload function in
+ * device. As an event, it indicates either the feature stopped after it
+ * was already running or feature has actually failed to start. Uses the
+ * attributes defines in enum qca_wlan_vendor_attr_p2p_listen_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH: After AP starts
+ * beaconing, this sub command provides the driver, the frequencies on the
+ * 5 GHz band to check for any radar activity. Driver selects one channel
+ * from this priority list provided through
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST and starts
+ * to check for radar activity on it. If no radar activity is detected
+ * during the channel availability check period, driver internally switches
+ * to the selected frequency of operation. If the frequency is zero, driver
+ * internally selects a channel. The status of this conditional switch is
+ * indicated through an event using the same sub command through
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS. Attributes are
+ * listed in qca_wlan_vendor_attr_sap_conditional_chan_switch.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND: Set GPIO pins. This uses the
+ * attributes defined in enum qca_wlan_gpio_attr.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY: Fetch hardware capabilities.
+ * This uses @QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY to indicate which
+ * capabilities are to be fetched and other
+ * enum qca_wlan_vendor_attr_get_hw_capability attributes to return the
+ * requested capabilities.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT: Link layer statistics extension.
+ * enum qca_wlan_vendor_attr_ll_stats_ext attributes are used with this
+ * command and event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA: Get capabilities for
+ * indoor location features. Capabilities are reported in
+ * QCA_WLAN_VENDOR_ATTR_LOC_CAPA.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION: Start an FTM
+ * (fine timing measurement) session with one or more peers.
+ * Specify Session cookie in QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE and
+ * peer information in QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS.
+ * On success, 0 or more QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT
+ * events will be reported, followed by
+ * QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE event to indicate
+ * end of session.
+ * Refer to IEEE P802.11-REVmc/D7.0, 11.24.6
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION: Abort a running session.
+ * A QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE will be reported with
+ * status code indicating session was aborted.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT: Event with measurement
+ * results for one peer. Results are reported in
+ * QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE: Event triggered when
+ * FTM session is finished, either successfully or aborted by
+ * request.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER: Configure FTM responder
+ * mode. QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE specifies whether
+ * to enable or disable the responder. LCI/LCR reports can be
+ * configured with QCA_WLAN_VENDOR_ATTR_FTM_LCI and
+ * QCA_WLAN_VENDOR_ATTR_FTM_LCR. Can be called multiple
+ * times to update the LCI/LCR reports.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS: Perform a standalone AOA (angle of
+ * arrival) measurement with a single peer. Specify peer MAC address in
+ * QCA_WLAN_VENDOR_ATTR_MAC_ADDR and optionally frequency (MHz) in
+ * QCA_WLAN_VENDOR_ATTR_FREQ (if not specified, locate peer in kernel
+ * scan results cache and use the frequency from there).
+ * Also specify measurement type in QCA_WLAN_VENDOR_ATTR_AOA_TYPE.
+ * Measurement result is reported in
+ * QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS: Abort an AOA measurement. Specify
+ * peer MAC address in QCA_WLAN_VENDOR_ATTR_MAC_ADDR.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT: Event that reports
+ * the AOA measurement result.
+ * Peer MAC address reported in QCA_WLAN_VENDOR_ATTR_MAC_ADDR.
+ * success/failure status is reported in
+ * QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS.
+ * Measurement data is reported in QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT.
+ * The antenna array(s) used in the measurement are reported in
+ * QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST: Encrypt/decrypt the given
+ * data as per the given parameters.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI: Get antenna RSSI value for a
+ * specific chain.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG: Get low level
+ * configuration for a DMG RF sector. Specify sector index in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX, sector type in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE and RF modules
+ * to return sector information for in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_MODULE_MASK. Returns sector configuration
+ * in QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG. Also return the
+ * exact time where information was captured in
+ * QCA_WLAN_VENDOR_ATTR_TSF.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG: Set low level
+ * configuration for a DMG RF sector. Specify sector index in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX, sector type in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE and sector configuration
+ * for one or more DMG RF modules in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR: Get selected
+ * DMG RF sector for a station. This is the sector that the HW
+ * will use to communicate with the station. Specify the MAC address
+ * of associated station/AP/PCP in QCA_WLAN_VENDOR_ATTR_MAC_ADDR (not
+ * needed for unassociated station). Specify sector type to return in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE. Returns the selected
+ * sector index in QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX.
+ * Also return the exact time where the information was captured
+ * in QCA_WLAN_VENDOR_ATTR_TSF.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR: Set the
+ * selected DMG RF sector for a station. This is the sector that
+ * the HW will use to communicate with the station.
+ * Specify the MAC address of associated station/AP/PCP in
+ * QCA_WLAN_VENDOR_ATTR_MAC_ADDR, the sector type to select in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE and the sector index
+ * in QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX.
+ * The selected sector will be locked such that it will not be
+ * modified like it normally does (for example when station
+ * moves around). To unlock the selected sector for a station
+ * pass the special value 0xFFFF in the sector index. To unlock
+ * all connected stations also pass a broadcast MAC address.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS: Configure the TDLS behavior
+ * in the host driver. The different TDLS configurations are defined
+ * by the attributes in enum qca_wlan_vendor_attr_tdls_configuration.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES: Query device IEEE 802.11ax HE
+ * capabilities. The response uses the attributes defined in
+ * enum qca_wlan_vendor_attr_get_he_capabilities.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN: Abort an ongoing vendor scan that was
+ * started with QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN. This command
+ * carries the scan cookie of the corresponding scan request. The scan
+ * cookie is represented by QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS: Set the Specific
+ * Absorption Rate (SAR) power limits. A critical regulation for
+ * FCC compliance, OEMs require methods to set SAR limits on TX
+ * power of WLAN/WWAN. enum qca_vendor_attr_sar_limits
+ * attributes are used with this command.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS: This command/event is used by the
+ * host driver for offloading the implementation of Auto Channel Selection
+ * (ACS) to an external user space entity. This interface is used as the
+ * event from the host driver to the user space entity and also as the
+ * request from the user space entity to the host driver. The event from
+ * the host driver is used by the user space entity as an indication to
+ * start the ACS functionality. The attributes used by this event are
+ * represented by the enum qca_wlan_vendor_attr_external_acs_event.
+ * User space entity uses the same interface to inform the host driver with
+ * selected channels after the ACS operation using the attributes defined
+ * by enum qca_wlan_vendor_attr_external_acs_channels.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE: Vendor event carrying the
+ * requisite information leading to a power save failure. The information
+ * carried as part of this event is represented by the
+ * enum qca_attr_chip_power_save_failure attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET: Start/Stop the NUD statistics
+ * collection. Uses attributes defined in enum qca_attr_nud_stats_set.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET: Get the NUD statistics. These
+ * statistics are represented by the enum qca_attr_nud_stats_get
+ * attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS: Sub-command to fetch
+ * the BSS transition status, whether accept or reject, for a list of
+ * candidate BSSIDs provided by the userspace. This uses the vendor
+ * attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO. The userspace shall specify
+ * the attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and an
+ * array of QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID nested in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO in the request. In the response
+ * the driver shall specify array of
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID and
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS pairs nested in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL: Set the trace level for a
+ * specific QCA module. The trace levels are represented by
+ * enum qca_attr_trace_level attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_BRP_SET_ANT_LIMIT: Set the Beam Refinement
+ * Protocol antenna limit in different modes. See enum
+ * qca_wlan_vendor_attr_brp_ant_limit_mode.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START: Start spectral scan. The scan
+ * parameters are specified by enum qca_wlan_vendor_attr_spectral_scan.
+ * This returns a cookie (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE)
+ * identifying the operation in success case.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP: Stop spectral scan. This uses
+ * a cookie (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE) from
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START to identify the scan to
+ * be stopped.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ACTIVE_TOS: Set the active Type Of Service on the
+ * specific interface. This can be used to modify some of the low level
+ * scan parameters (off channel dwell time, home channel time) in the
+ * driver/firmware. These parameters are maintained within the host driver.
+ * This command is valid only when the interface is in the connected state.
+ * These scan parameters shall be reset by the driver/firmware once
+ * disconnected. The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_active_tos.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_HANG: Event indicating to the user space that the
+ * driver has detected an internal failure. This event carries the
+ * information indicating the reason that triggered this detection. The
+ * attributes for this command are defined in
+ * enum qca_wlan_vendor_attr_hang.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CONFIG: Get the current values
+ * of spectral parameters used. The spectral scan parameters are specified
+ * by enum qca_wlan_vendor_attr_spectral_scan.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS: Get the debug stats
+ * for spectral scan functionality. The debug stats are specified by
+ * enum qca_wlan_vendor_attr_spectral_diag_stats.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO: Get spectral
+ * scan system capabilities. The capabilities are specified
+ * by enum qca_wlan_vendor_attr_spectral_cap.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS: Get the current
+ * status of spectral scan. The status values are specified
+ * by enum qca_wlan_vendor_attr_spectral_scan_status.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING: Sub-command to flush
+ * peer pending packets. Specify the peer MAC address in
+ * QCA_WLAN_VENDOR_ATTR_PEER_ADDR and the access category of the packets
+ * in QCA_WLAN_VENDOR_ATTR_AC. The attributes are listed
+ * in enum qca_wlan_vendor_attr_flush_pending.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO: Get vendor specific Representative
+ * RF Operating Parameter (RROP) information. The attributes for this
+ * information are defined in enum qca_wlan_vendor_attr_rrop_info. This is
+ * intended for use by external Auto Channel Selection applications.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS: Get the Specific Absorption Rate
+ * (SAR) power limits. This is a companion to the command
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS and is used to retrieve the
+ * settings currently in use. The attributes returned by this command are
+ * defined by enum qca_vendor_attr_sar_limits.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO: Provides the current behavior of
+ * the WLAN hardware MAC. Also, provides the WLAN netdev interface
+ * information attached to the respective MAC.
+ * This works both as a query (user space asks the current mode) or event
+ * interface (driver advertising the current mode to the user space).
+ * Driver does not trigger this event for temporary hardware mode changes.
+ * Mode changes w.r.t Wi-Fi connection update (VIZ creation / deletion,
+ * channel change, etc.) are updated with this event. Attributes for this
+ * interface are defined in enum qca_wlan_vendor_attr_mac.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH: Set MSDU queue depth threshold
+ * per peer per TID. Attributes for this command are define in
+ * enum qca_wlan_set_qdepth_thresh_attr.
+ * @QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD: Provides the thermal shutdown action
+ * guide for WLAN driver. Request to suspend of driver and FW if the
+ * temperature is higher than the suspend threshold; resume action is
+ * requested to driver if the temperature is lower than the resume
+ * threshold. In user poll mode, request temperature data by user. For test
+ * purpose, getting thermal shutdown configuration parameters is needed.
+ * Attributes for this interface are defined in
+ * enum qca_wlan_vendor_attr_thermal_cmd.
+ * @QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT: Thermal events reported from
+ * driver. Thermal temperature and indication of resume completion are
+ * reported as thermal events. The attributes for this command are defined
+ * in enum qca_wlan_vendor_attr_thermal_event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION: Sub command to set WiFi
+ * test configuration. Attributes for this command are defined in
+ * enum qca_wlan_vendor_attr_wifi_test_config.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER: This command is used to configure an
+ * RX filter to receive frames from stations that are active on the
+ * operating channel, but not associated with the local device (e.g., STAs
+ * associated with other APs). Filtering is done based on a list of BSSIDs
+ * and STA MAC addresses added by the user. This command is also used to
+ * fetch the statistics of unassociated stations. The attributes used with
+ * this command are defined in enum qca_wlan_vendor_attr_bss_filter.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NAN_EXT: An extendable version of NAN vendor
+ * command. The earlier command for NAN, QCA_NL80211_VENDOR_SUBCMD_NAN,
+ * carried a payload which was a binary blob of data. The command was not
+ * extendable to send more information. The newer version carries the
+ * legacy blob encapsulated within an attribute and can be extended with
+ * additional vendor attributes that can enhance the NAN command interface.
+ * @QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT: Event to indicate scan triggered
+ * or stopped within driver/firmware in order to initiate roaming. The
+ * attributes used with this event are defined in enum
+ * qca_wlan_vendor_attr_roam_scan. Some drivers may not send these events
+ * in few cases, e.g., if the host processor is sleeping when this event
+ * is generated in firmware.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG: This command is used to
+ * configure parameters per peer to capture Channel Frequency Response
+ * (CFR) and enable Periodic CFR capture. The attributes for this command
+ * are defined in enum qca_wlan_vendor_peer_cfr_capture_attr.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT: Event to indicate changes
+ * in throughput dynamically. The driver estimates the throughput based on
+ * number of packets being transmitted/received per second and indicates
+ * the changes in throughput to user space. Userspace tools can use this
+ * information to configure kernel's TCP parameters in order to achieve
+ * peak throughput. Optionally, the driver will also send guidance on
+ * modifications to kernel's TCP parameters which can be referred by
+ * userspace tools. The attributes used with this event are defined in enum
+ * qca_wlan_vendor_attr_throughput_change.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG: This command is used to set
+ * priorities among different types of traffic during coex scenarios.
+ * Current supported prioritization is among WLAN/BT/ZIGBEE with different
+ * profiles mentioned in enum qca_coex_config_profiles. The associated
+ * attributes used with this command are defined in enum
+ * qca_vendor_attr_coex_config.
+ *
+ * Based on the config provided, FW will boost the weight and prioritize
+ * the traffic for that subsystem (WLAN/BT/Zigbee).
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS: This command is used to query
+ * the supported AKM suite selectorss from the driver. It returns the list
+ * of supported AKMs in the attribute NL80211_ATTR_AKM_SUITES.
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE: This command is used to get firmware
+ * state from the driver. It returns the firmware state in the attribute
+ * QCA_WLAN_VENDOR_ATTR_FW_STATE.
+ * @QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH: This vendor subcommand
+ * is used by the driver to flush per-peer cached statistics to user space
+ * application. This interface is used as an event from the driver to
+ * user space application. Attributes for this event are specified in
+ * enum qca_wlan_vendor_attr_peer_stats_cache_params.
+ * QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA attribute is expected to be
+ * sent in the event.
+ * @QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG: This sub command is used to
+ * improve the success rate of Zigbee joining network.
+ * Due to PTA master limitation, Zigbee joining network success rate is
+ * low while WLAN is working. The WLAN driver needs to configure some
+ * parameters including Zigbee state and specific WLAN periods to enhance
+ * PTA master. All these parameters are delivered by the attributes
+ * defined in enum qca_mpta_helper_vendor_attr.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -98,7 +533,7 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11,
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
- QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
+ QCA_NL80211_VENDOR_SUBCMD_STATS_EXT = 13,
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET = 14,
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET = 15,
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR = 16,
@@ -140,7 +575,33 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58,
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59,
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
- /* 61-90 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO = 61,
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START = 62,
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP = 63,
+ QCA_NL80211_VENDOR_SUBCMD_ROAM = 64,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SSID_HOTLIST = 65,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SSID_HOTLIST = 66,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_SSID_FOUND = 67,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_SSID_LOST = 68,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST = 69,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST = 70,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_RESET_PASSPOINT_LIST = 71,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND = 72,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND = 73,
+ /* Wi-Fi configuration subcommands */
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
+ QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75,
+ QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET = 76,
+ QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA = 77,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES = 78,
+ QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS = 79,
+ QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI = 80,
+ QCA_NL80211_VENDOR_SUBCMD_NDP = 81,
+ QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD = 82,
+ QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER = 83,
+ QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE = 84,
+ QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS = 85,
+ /* 86-90 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
@@ -156,21 +617,99 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103,
QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104,
QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105,
+ QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN = 106,
+ QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE = 107,
+ QCA_NL80211_VENDOR_SUBCMD_OTA_TEST = 108,
+ QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
+ /* 110..114 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
+ /* 116..117 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118,
+ QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
+ QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
+ /* 121 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122,
+ QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123,
+ QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124,
+ QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND = 125,
+ QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY = 126,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT = 127,
+ /* FTM/indoor location subcommands */
+ QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT = 131,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE = 132,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER = 133,
+ QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134,
+ QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135,
+ QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136,
+ QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137,
+ QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI = 138,
+ /* DMG low level RF sector operations */
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG = 139,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG = 140,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142,
+ QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS = 143,
+ QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES = 144,
+ QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN = 145,
+ QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS = 146,
+ QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS = 147,
+ QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE = 148,
+ QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149,
+ QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150,
+ QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS = 151,
+ QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL = 152,
+ QCA_NL80211_VENDOR_SUBCMD_BRP_SET_ANT_LIMIT = 153,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START = 154,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP = 155,
+ QCA_NL80211_VENDOR_SUBCMD_ACTIVE_TOS = 156,
+ QCA_NL80211_VENDOR_SUBCMD_HANG = 157,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CONFIG = 158,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS = 159,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO = 160,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS = 161,
+ /* Flush peer pending data */
+ QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING = 162,
+ QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO = 163,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS = 164,
+ QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO = 165,
+ QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH = 166,
+ /* Thermal shutdown commands to protect wifi chip */
+ QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD = 167,
+ QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT = 168,
+ /* Wi-Fi test configuration subcommand */
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION = 169,
+ /* Frame filter operations for other BSSs/unassociated STAs */
+ QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER = 170,
+ QCA_NL80211_VENDOR_SUBCMD_NAN_EXT = 171,
+ QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT = 172,
+ QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG = 173,
+ QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT = 174,
+ QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG = 175,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS = 176,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE = 177,
+ QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH = 178,
+ QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG = 179,
};
-
enum qca_wlan_vendor_attr {
QCA_WLAN_VENDOR_ATTR_INVALID = 0,
/* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
QCA_WLAN_VENDOR_ATTR_DFS = 1,
- /* used by QCA_NL80211_VENDOR_SUBCMD_NAN */
+ /* Used only when driver sends vendor events to the userspace under the
+ * command QCA_NL80211_VENDOR_SUBCMD_NAN. Not used when userspace sends
+ * commands to the driver.
+ */
QCA_WLAN_VENDOR_ATTR_NAN = 2,
/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3,
/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
QCA_WLAN_VENDOR_ATTR_IFINDEX = 4,
/* used by QCA_NL80211_VENDOR_SUBCMD_ROAMING, u32 with values defined
- * by enum qca_roaming_policy. */
+ * by enum qca_roaming_policy.
+ */
QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
@@ -185,17 +724,220 @@ enum qca_wlan_vendor_attr {
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11,
/* Unsigned 32-bit value from enum qca_set_band. */
QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
+ /* Dummy (NOP) attribute for 64 bit padding */
+ QCA_WLAN_VENDOR_ATTR_PAD = 13,
+ /* Unique FTM session cookie (Unsigned 64 bit). Specified in
+ * QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION. Reported in
+ * the session in QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT and
+ * QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE = 14,
+ /* Indoor location capabilities, returned by
+ * QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA.
+ * see enum qca_wlan_vendor_attr_loc_capa.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA = 15,
+ /* Array of nested attributes containing information about each peer
+ * in FTM measurement session. See enum qca_wlan_vendor_attr_peer_info
+ * for supported attributes for each peer.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS = 16,
+ /* Array of nested attributes containing measurement results for
+ * one or more peers, reported by the
+ * QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT event.
+ * See enum qca_wlan_vendor_attr_peer_result for list of supported
+ * attributes.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS = 17,
+ /* Flag attribute for enabling or disabling responder functionality. */
+ QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE = 18,
+ /* Used in the QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+ * command to specify the LCI report that will be sent by
+ * the responder during a measurement exchange. The format is
+ * defined in IEEE P802.11-REVmc/D7.0, 9.4.2.22.10.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_LCI = 19,
+ /* Used in the QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+ * command to specify the location civic report that will
+ * be sent by the responder during a measurement exchange.
+ * The format is defined in IEEE P802.11-REVmc/D7.0, 9.4.2.22.13.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_LCR = 20,
+ /* Session/measurement completion status code,
+ * reported in QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE and
+ * QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
+ * see enum qca_vendor_attr_loc_session_status.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS = 21,
+ /* Initial dialog token used by responder (0 if not specified),
+ * unsigned 8 bit value.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN = 22,
+ /* AOA measurement type. Requested in QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS
+ * and optionally in QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION if
+ * AOA measurements are needed as part of an FTM session.
+ * Reported by QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT. See
+ * enum qca_wlan_vendor_attr_aoa_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23,
+ /* A bit mask (unsigned 32 bit value) of antenna arrays used
+ * by indoor location measurements. Refers to the antenna
+ * arrays described by QCA_VENDOR_ATTR_LOC_CAPA_ANTENNA_ARRAYS.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24,
+ /* AOA measurement data. Its contents depends on the AOA measurement
+ * type and antenna array mask:
+ * QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: array of U16 values,
+ * phase of the strongest CIR path for each antenna in the measured
+ * array(s).
+ * QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: array of 2 U16
+ * values, phase and amplitude of the strongest CIR path for each
+ * antenna in the measured array(s).
+ */
+ QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
+ * to specify the chain number (unsigned 32 bit value) to inquire
+ * the corresponding antenna RSSI value
+ */
+ QCA_WLAN_VENDOR_ATTR_CHAIN_INDEX = 26,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
+ * to report the specific antenna RSSI value (unsigned 32 bit value)
+ */
+ QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI = 27,
+ /* Frequency in MHz, various uses. Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_FREQ = 28,
+ /* TSF timer value, unsigned 64 bit value.
+ * May be returned by various commands.
+ */
+ QCA_WLAN_VENDOR_ATTR_TSF = 29,
+ /* DMG RF sector index, unsigned 16 bit number. Valid values are
+ * 0..127 for sector indices or 65535 as special value used to
+ * unlock sector selection in
+ * QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR.
+ */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX = 30,
+ /* DMG RF sector type, unsigned 8 bit value. One of the values
+ * in enum qca_wlan_vendor_attr_dmg_rf_sector_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE = 31,
+ /* Bitmask of DMG RF modules for which information is requested. Each
+ * bit corresponds to an RF module with the same index as the bit
+ * number. Unsigned 32 bit number but only low 8 bits can be set since
+ * all DMG chips currently have up to 8 RF modules.
+ */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_MODULE_MASK = 32,
+ /* Array of nested attributes where each entry is DMG RF sector
+ * configuration for a single RF module.
+ * Attributes for each entry are taken from enum
+ * qca_wlan_vendor_attr_dmg_rf_sector_cfg.
+ * Specified in QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG
+ * and returned by QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG.
+ */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG = 33,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_STATS_EXT command
+ * to report frame aggregation statistics to userspace.
+ */
+ QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM = 34,
+ QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO = 35,
+ /* Unsigned 8-bit value representing MBO transition reason code as
+ * provided by the AP used by subcommand
+ * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS. This is
+ * specified by the userspace in the request to the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON = 36,
+ /* Array of nested attributes, BSSID and status code, used by subcommand
+ * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, where each
+ * entry is taken from enum qca_wlan_vendor_attr_btm_candidate_info.
+ * The userspace space specifies the list/array of candidate BSSIDs in
+ * the order of preference in the request. The driver specifies the
+ * status code, for each BSSID in the list, in the response. The
+ * acceptable candidates are listed in the order preferred by the
+ * driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO = 37,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_BRP_SET_ANT_LIMIT command
+ * See enum qca_wlan_vendor_attr_brp_ant_limit_mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE = 38,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_BRP_SET_ANT_LIMIT command
+ * to define the number of antennas to use for BRP.
+ * different purpose in each ANT_LIMIT_MODE:
+ * DISABLE - ignored
+ * EFFECTIVE - upper limit to number of antennas to be used
+ * FORCE - exact number of antennas to be used
+ * unsigned 8 bit value
+ */
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_NUM_LIMIT = 39,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
+ * to report the corresponding antenna index to the chain RSSI value
+ */
+ QCA_WLAN_VENDOR_ATTR_ANTENNA_INFO = 40,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command to report
+ * the specific antenna EVM value (unsigned 32 bit value). With a
+ * determinate group of antennas, the driver specifies the EVM value
+ * for each antenna ID, and application extract them in user space.
+ */
+ QCA_WLAN_VENDOR_ATTR_CHAIN_EVM = 41,
+ /*
+ * Used in QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE command to report
+ * wlan firmware current state. FW state is an unsigned 8 bit value,
+ * one of the values in enum qca_wlan_vendor_attr_fw_state.
+ */
+ QCA_WLAN_VENDOR_ATTR_FW_STATE = 42,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
};
-
enum qca_roaming_policy {
QCA_ROAMING_NOT_ALLOWED,
QCA_ROAMING_ALLOWED_WITHIN_ESS,
};
+/**
+ * enum qca_roam_reason - Represents the reason codes for roaming. Used by
+ * QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON.
+ *
+ * @QCA_ROAM_REASON_UNKNOWN: Any reason that do not classify under the below
+ * reasons.
+ *
+ * @QCA_ROAM_REASON_PER: Roam triggered when packet error rates (PER) breached
+ * the configured threshold.
+ *
+ * @QCA_ROAM_REASON_BEACON_MISS: Roam triggered due to the continuous configured
+ * beacon misses from the then connected AP.
+ *
+ * @QCA_ROAM_REASON_POOR_RSSI: Roam triggered due to the poor RSSI reported
+ * by the connected AP.
+ *
+ * @QCA_ROAM_REASON_BETTER_RSSI: Roam triggered for finding a BSS with a better
+ * RSSI than the connected BSS. Here the RSSI of the current BSS is not poor.
+ *
+ * @QCA_ROAM_REASON_CONGESTION: Roam triggered considering the connected channel
+ * or environment being very noisy or congested.
+ *
+ * @QCA_ROAM_REASON_EXPLICIT_REQUEST: Roam triggered due to an explicit request
+ * from the user (user space).
+ *
+ * @QCA_ROAM_REASON_BTM: Roam triggered due to BTM Request frame received from
+ * the connected AP.
+ *
+ * @QCA_ROAM_REASON_BSS_LOAD: Roam triggered due to the channel utilization
+ * breaching out the configured threshold.
+ */
+enum qca_roam_reason {
+ QCA_ROAM_REASON_UNKNOWN,
+ QCA_ROAM_REASON_PER,
+ QCA_ROAM_REASON_BEACON_MISS,
+ QCA_ROAM_REASON_POOR_RSSI,
+ QCA_ROAM_REASON_BETTER_RSSI,
+ QCA_ROAM_REASON_CONGESTION,
+ QCA_ROAM_REASON_USER_TRIGGER,
+ QCA_ROAM_REASON_BTM,
+ QCA_ROAM_REASON_BSS_LOAD,
+};
+
enum qca_wlan_vendor_attr_roam_auth {
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
@@ -205,12 +947,87 @@ enum qca_wlan_vendor_attr_roam_auth {
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR,
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK,
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS,
+ /* Indicates the status of re-association requested by user space for
+ * the BSSID specified by QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID.
+ * Type u16.
+ * Represents the status code from AP. Use
+ * %WLAN_STATUS_UNSPECIFIED_FAILURE if the device cannot give you the
+ * real status code for failures.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_STATUS,
+ /* This attribute indicates that the old association was maintained when
+ * a re-association is requested by user space and that re-association
+ * attempt fails (i.e., cannot connect to the requested BSS, but can
+ * remain associated with the BSS with which the association was in
+ * place when being requested to roam). Used along with
+ * WLAN_VENDOR_ATTR_ROAM_AUTH_STATUS to indicate the current
+ * re-association status. Type flag.
+ * This attribute is applicable only for re-association failure cases.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RETAIN_CONNECTION,
+ /* This attribute specifies the PMK if one was newly generated during
+ * FILS roaming. This is added to the PMKSA cache and is used in
+ * subsequent connections with PMKSA caching.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK = 11,
+ /* This attribute specifies the PMKID used/generated for the current
+ * FILS roam. This is used in subsequent connections with PMKSA caching.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID = 12,
+ /* A 16-bit unsigned value specifying the next sequence number to use
+ * in ERP message in the currently associated realm. This is used in
+ * doing subsequent ERP based connections in the same realm.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM = 13,
+ /* A 16-bit unsigned value representing the reasons for the roaming.
+ * Defined by enum qca_roam_reason.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON = 14,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX =
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1
};
+enum qca_wlan_vendor_attr_p2p_listen_offload {
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INVALID = 0,
+ /* A 32-bit unsigned value; the P2P listen frequency (MHz); must be one
+ * of the social channels.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
+ /* A 32-bit unsigned value; the P2P listen offload period (ms).
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
+ /* A 32-bit unsigned value; the P2P listen interval duration (ms).
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
+ /* A 32-bit unsigned value; number of interval times the firmware needs
+ * to run the offloaded P2P listen operation before it stops.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
+ /* An array of arbitrary binary data with one or more 8-byte values.
+ * The device types include both primary and secondary device types.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
+ /* An array of unsigned 8-bit characters; vendor information elements.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
+ /* A 32-bit unsigned value; a control flag to indicate whether listen
+ * results need to be flushed to wpa_supplicant.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG,
+ /* A 8-bit unsigned value; reason code for P2P listen offload stop
+ * event.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX =
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
+};
+
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
@@ -247,11 +1064,38 @@ enum qca_wlan_vendor_acs_hw_mode {
* after roaming, rather than having the user space wpa_supplicant do it.
* @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
* band selection based on channel selection results.
+ * @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports
+ * simultaneous off-channel operations.
+ * @QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD: Device supports P2P
+ * Listen offload; a mechanism where the station's firmware takes care of
+ * responding to incoming Probe Request frames received from other P2P
+ * Devices whilst in Listen state, rather than having the user space
+ * wpa_supplicant do it. Information from received P2P requests are
+ * forwarded from firmware to host whenever the host processor wakes up.
+ * @QCA_WLAN_VENDOR_FEATURE_OCE_STA: Device supports all OCE non-AP STA
+ * specific features.
+ * @QCA_WLAN_VENDOR_FEATURE_OCE_AP: Device supports all OCE AP specific
+ * features.
+ * @QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON: Device supports OCE STA-CFON
+ * specific features only. If a Device sets this bit but not the
+ * %QCA_WLAN_VENDOR_FEATURE_OCE_AP, the userspace shall assume that
+ * this Device may not support all OCE AP functionalities but can support
+ * only OCE STA-CFON functionalities.
+ * @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
+ * managed regulatory.
+ * @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1,
+ QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2,
+ QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD = 3,
+ QCA_WLAN_VENDOR_FEATURE_OCE_STA = 4,
+ QCA_WLAN_VENDOR_FEATURE_OCE_AP = 5,
+ QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6,
+ QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
+ QCA_WLAN_VENDOR_FEATURE_TWT = 8,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -277,6 +1121,112 @@ enum qca_wlan_vendor_attr_data_offload_ind {
QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_attr_ocb_set_config - Vendor subcmd attributes to set
+ * OCB config
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT: Number of channels in the
+ * configuration
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE: Size of the schedule
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY: Array of channels
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY: Array of channels to be
+ * scheduled
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY: Array of NDL channel
+ * information
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY: Array of NDL
+ * active state configuration
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS: Configuration flags such as
+ * OCB_CONFIG_FLAG_80211_FRAME_MODE
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM: Default TX parameters to
+ * use in the case that a packet is sent without a TX control header
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_TA_MAX_DURATION: Max duration after the
+ * last TA received that the local time set by TA is synchronous to other
+ * communicating OCB STAs.
+ */
+enum qca_wlan_vendor_attr_ocb_set_config {
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT = 1,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE = 2,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY = 3,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY = 4,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY = 5,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY = 6,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS = 7,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM = 8,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_TA_MAX_DURATION = 9,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ocb_set_utc_time - Vendor subcmd attributes to set
+ * UTC time
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE: The UTC time as an array of
+ * 10 bytes
+ * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR: The time error as an array of
+ * 5 bytes
+ */
+enum qca_wlan_vendor_attr_ocb_set_utc_time {
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE = 1,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR = 2,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ocb_start_timing_advert - Vendor subcmd attributes
+ * to start sending timing advert frames
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ: Cannel frequency
+ * on which to send the frames
+ * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE: Number of times
+ * the frame is sent in 5 seconds
+ */
+enum qca_wlan_vendor_attr_ocb_start_timing_advert {
+ QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ = 1,
+ QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE = 2,
+ QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ocb_stop_timing_advert - Vendor subcmd attributes
+ * to stop timing advert
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ: The channel
+ * frequency on which to stop the timing advert
+ */
+enum qca_wlan_vendor_attr_ocb_stop_timing_advert {
+ QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ = 1,
+ QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ocb_get_tsf_response - Vendor subcmd attributes to
+ * get TSF timer value
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH: Higher 32 bits of the
+ * timer
+ * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW: Lower 32 bits of the timer
+ */
+enum qca_wlan_vendor_attr_ocb_get_tsf_resp {
+ QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH = 1,
+ QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW = 2,
+ QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST - 1
+};
+
enum qca_vendor_attr_get_preferred_freq_list {
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID,
/* A 32-unsigned value; the interface type/mode for which the preferred
@@ -289,6 +1239,12 @@ enum qca_vendor_attr_get_preferred_freq_list {
* from kernel space to user space.
*/
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST,
+ /* An array of nested values as per enum qca_wlan_vendor_attr_pcl
+ * attribute. Each element contains frequency (MHz), weight, and flag
+ * bit mask indicating how the frequency should be used in P2P
+ * negotiation; sent from kernel space to user space.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX =
@@ -324,6 +1280,67 @@ enum qca_set_band {
QCA_SETBAND_2G,
};
+/**
+ * enum qca_access_policy - Access control policy
+ *
+ * Access control policy is applied on the configured IE
+ * (QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE).
+ * To be set with QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY.
+ *
+ * @QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED: Deny Wi-Fi connections which match
+ * the specific configuration (IE) set, i.e., allow all the
+ * connections which do not match the configuration.
+ * @QCA_ACCESS_POLICY_DENY_UNLESS_LISTED: Accept Wi-Fi connections which match
+ * the specific configuration (IE) set, i.e., deny all the
+ * connections which do not match the configuration.
+ */
+enum qca_access_policy {
+ QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED,
+ QCA_ACCESS_POLICY_DENY_UNLESS_LISTED,
+};
+
+/**
+ * enum qca_vendor_attr_get_tsf: Vendor attributes for TSF capture
+ * @QCA_WLAN_VENDOR_ATTR_TSF_CMD: enum qca_tsf_operation (u32)
+ * @QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE: Unsigned 64 bit TSF timer value
+ * @QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE: Unsigned 64 bit Synchronized
+ * SOC timer value at TSF capture
+ */
+enum qca_vendor_attr_tsf_cmd {
+ QCA_WLAN_VENDOR_ATTR_TSF_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TSF_CMD,
+ QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
+ QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
+ QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TSF_MAX =
+ QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_tsf_operation: TSF driver commands
+ * @QCA_TSF_CAPTURE: Initiate TSF Capture
+ * @QCA_TSF_GET: Get TSF capture value
+ * @QCA_TSF_SYNC_GET: Initiate TSF capture and return with captured value
+ */
+enum qca_tsf_cmd {
+ QCA_TSF_CAPTURE,
+ QCA_TSF_GET,
+ QCA_TSF_SYNC_GET,
+};
+
+/**
+ * enum qca_vendor_attr_wisa_cmd
+ * @QCA_WLAN_VENDOR_ATTR_WISA_MODE: WISA mode value (u32)
+ * WISA setup vendor commands
+ */
+enum qca_vendor_attr_wisa_cmd {
+ QCA_WLAN_VENDOR_ATTR_WISA_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_WISA_MODE,
+ QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_WISA_MAX =
+ QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST - 1
+};
+
/* IEEE 802.11 Vendor Specific elements */
/**
@@ -349,9 +1366,5347 @@ enum qca_set_band {
*
* This vendor element may be included in GO Negotiation Request, P2P
* Invitation Request, and Provision Discovery Request frames.
+ *
+ * @QCA_VENDOR_ELEM_HE_CAPAB: HE Capabilities element.
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID. The payload of this
+ * vendor specific element is defined by the latest P802.11ax draft.
+ * Please note that the draft is still work in progress and this element
+ * payload is subject to change.
+ *
+ * @QCA_VENDOR_ELEM_HE_OPER: HE Operation element.
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID. The payload of this
+ * vendor specific element is defined by the latest P802.11ax draft.
+ * Please note that the draft is still work in progress and this element
+ * payload is subject to change.
+ *
+ * @QCA_VENDOR_ELEM_RAPS: RAPS element (OFDMA-based Random Access Parameter Set
+ * element).
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID extension. The payload of
+ * this vendor specific element is defined by the latest P802.11ax draft
+ * (not including the Element ID Extension field). Please note that the
+ * draft is still work in progress and this element payload is subject to
+ * change.
+ *
+ * @QCA_VENDOR_ELEM_MU_EDCA_PARAMS: MU EDCA Parameter Set element.
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID extension. The payload of
+ * this vendor specific element is defined by the latest P802.11ax draft
+ * (not including the Element ID Extension field). Please note that the
+ * draft is still work in progress and this element payload is subject to
+ * change.
+ *
+ * @QCA_VENDOR_ELEM_BSS_COLOR_CHANGE: BSS Color Change Announcement element.
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID extension. The payload of
+ * this vendor specific element is defined by the latest P802.11ax draft
+ * (not including the Element ID Extension field). Please note that the
+ * draft is still work in progress and this element payload is subject to
+ * change.
*/
enum qca_vendor_element_id {
QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
+ QCA_VENDOR_ELEM_HE_CAPAB = 1,
+ QCA_VENDOR_ELEM_HE_OPER = 2,
+ QCA_VENDOR_ELEM_RAPS = 3,
+ QCA_VENDOR_ELEM_MU_EDCA_PARAMS = 4,
+ QCA_VENDOR_ELEM_BSS_COLOR_CHANGE = 5,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_scan - Specifies vendor scan attributes
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_IE: IEs that should be included as part of scan
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES: Nested unsigned 32-bit attributes
+ * with frequencies to be scanned (in MHz)
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS: Nested attribute with SSIDs to be scanned
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES: Nested array attribute of supported
+ * rates to be included
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE: flag used to send probe requests
+ * at non CCK rate in 2GHz band
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS: Unsigned 32-bit scan flags
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE: Unsigned 64-bit cookie provided by the
+ * driver for the specific scan request
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_STATUS: Unsigned 8-bit status of the scan
+ * request decoded as in enum scan_status
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC: 6-byte MAC address to use when randomisation
+ * scan flag is set
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with
+ * randomisation
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
+ * specific BSSID to scan for.
+ */
+enum qca_wlan_vendor_attr_scan {
+ QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
+ QCA_WLAN_VENDOR_ATTR_SCAN_IE = 1,
+ QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES = 2,
+ QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS = 3,
+ QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES = 4,
+ QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE = 5,
+ QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS = 6,
+ QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE = 7,
+ QCA_WLAN_VENDOR_ATTR_SCAN_STATUS = 8,
+ QCA_WLAN_VENDOR_ATTR_SCAN_MAC = 9,
+ QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10,
+ QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
+ QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
+ QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
+};
+
+/**
+ * enum scan_status - Specifies the valid values the vendor scan attribute
+ * QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take
+ *
+ * @VENDOR_SCAN_STATUS_NEW_RESULTS: implies the vendor scan is successful with
+ * new scan results
+ * @VENDOR_SCAN_STATUS_ABORTED: implies the vendor scan was aborted in-between
+ */
+enum scan_status {
+ VENDOR_SCAN_STATUS_NEW_RESULTS,
+ VENDOR_SCAN_STATUS_ABORTED,
+ VENDOR_SCAN_STATUS_MAX,
+};
+
+/**
+ * enum qca_vendor_attr_ota_test - Specifies the values for vendor
+ * command QCA_NL80211_VENDOR_SUBCMD_OTA_TEST
+ * @QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE: enable ota test
+ */
+enum qca_vendor_attr_ota_test {
+ QCA_WLAN_VENDOR_ATTR_OTA_TEST_INVALID,
+ /* 8-bit unsigned value to indicate if OTA test is enabled */
+ QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX =
+ QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_vendor_attr_txpower_scale - vendor sub commands index
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE: scaling value
+ */
+enum qca_vendor_attr_txpower_scale {
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_INVALID,
+ /* 8-bit unsigned value to indicate the scaling of tx power */
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX =
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_vendor_attr_txpower_decr_db - Attributes for TX power decrease
+ *
+ * These attributes are used with QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB.
+ */
+enum qca_vendor_attr_txpower_decr_db {
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_INVALID,
+ /* 8-bit unsigned value to indicate the reduction of TX power in dB for
+ * a virtual interface.
+ */
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_MAX =
+ QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST - 1
+};
+
+/* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION and
+ * QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION subcommands.
+ */
+enum qca_wlan_vendor_attr_config {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID = 0,
+ /* Unsigned 32-bit value to set the DTIM period.
+ * Whether the wifi chipset wakes at every dtim beacon or a multiple of
+ * the DTIM period. If DTIM is set to 3, the STA shall wake up every 3
+ * DTIM beacons.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM = 1,
+ /* Unsigned 32-bit value to set the wifi_iface stats averaging factor
+ * used to calculate statistics like average the TSF offset or average
+ * number of frame leaked.
+ * For instance, upon Beacon frame reception:
+ * current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000
+ * For instance, when evaluating leaky APs:
+ * current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 - factor)) / 0x10000
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR = 2,
+ /* Unsigned 32-bit value to configure guard time, i.e., when
+ * implementing IEEE power management based on frame control PM bit, how
+ * long the driver waits before shutting down the radio and after
+ * receiving an ACK frame for a Data frame with PM bit set.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME = 3,
+ /* Unsigned 32-bit value to change the FTM capability dynamically */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT = 4,
+ /* Unsigned 16-bit value to configure maximum TX rate dynamically */
+ QCA_WLAN_VENDOR_ATTR_CONF_TX_RATE = 5,
+ /* Unsigned 32-bit value to configure the number of continuous
+ * Beacon Miss which shall be used by the firmware to penalize
+ * the RSSI.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS = 6,
+ /* Unsigned 8-bit value to configure the channel avoidance indication
+ * behavior. Firmware to send only one indication and ignore duplicate
+ * indications when set to avoid multiple Apps wakeups.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND = 7,
+ /* 8-bit unsigned value to configure the maximum TX MPDU for
+ * aggregation.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION = 8,
+ /* 8-bit unsigned value to configure the maximum RX MPDU for
+ * aggregation.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION = 9,
+ /* 8-bit unsigned value to configure the Non aggregrate/11g sw
+ * retry threshold (0 disable, 31 max).
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY = 10,
+ /* 8-bit unsigned value to configure the aggregrate sw
+ * retry threshold (0 disable, 31 max).
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY = 11,
+ /* 8-bit unsigned value to configure the MGMT frame
+ * retry threshold (0 disable, 31 max).
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY = 12,
+ /* 8-bit unsigned value to configure the CTRL frame
+ * retry threshold (0 disable, 31 max).
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY = 13,
+ /* 8-bit unsigned value to configure the propagation delay for
+ * 2G/5G band (0~63, units in us)
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY = 14,
+ /* Unsigned 32-bit value to configure the number of unicast TX fail
+ * packet count. The peer is disconnected once this threshold is
+ * reached.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT = 15,
+ /* Attribute used to set scan default IEs to the driver.
+ *
+ * These IEs can be used by scan operations that will be initiated by
+ * the driver/firmware.
+ *
+ * For further scan requests coming to the driver, these IEs should be
+ * merged with the IEs received along with scan request coming to the
+ * driver. If a particular IE is present in the scan default IEs but not
+ * present in the scan request, then that IE should be added to the IEs
+ * sent in the Probe Request frames for that scan request.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES = 16,
+ /* Unsigned 32-bit attribute for generic commands */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND = 17,
+ /* Unsigned 32-bit value attribute for generic commands */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE = 18,
+ /* Unsigned 32-bit data attribute for generic command response */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA = 19,
+ /* Unsigned 32-bit length attribute for
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH = 20,
+ /* Unsigned 32-bit flags attribute for
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS = 21,
+ /* Unsigned 32-bit, defining the access policy.
+ * See enum qca_access_policy. Used with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY = 22,
+ /* Sets the list of full set of IEs for which a specific access policy
+ * has to be applied. Used along with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY to control the access.
+ * Zero length payload can be used to clear this access constraint.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST = 23,
+ /* Unsigned 32-bit, specifies the interface index (netdev) for which the
+ * corresponding configurations are applied. If the interface index is
+ * not specified, the configurations are attributed to the respective
+ * wiphy.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX = 24,
+ /* 8-bit unsigned value to trigger QPower: 1-Enable, 0-Disable */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER = 25,
+ /* 8-bit unsigned value to configure the driver and below layers to
+ * ignore the assoc disallowed set by APs while connecting
+ * 1-Ignore, 0-Don't ignore
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED = 26,
+ /* 32-bit unsigned value to trigger antenna diversity features:
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA = 27,
+ /* 32-bit unsigned value to configure specific chain antenna */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN = 28,
+ /* 32-bit unsigned value to trigger cycle selftest
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST = 29,
+ /* 32-bit unsigned to configure the cycle time of selftest
+ * the unit is micro-second
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL = 30,
+ /* 32-bit unsigned value to set reorder timeout for AC_VO */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VOICE = 31,
+ /* 32-bit unsigned value to set reorder timeout for AC_VI */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VIDEO = 32,
+ /* 32-bit unsigned value to set reorder timeout for AC_BE */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BESTEFFORT = 33,
+ /* 32-bit unsigned value to set reorder timeout for AC_BK */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BACKGROUND = 34,
+ /* 6-byte MAC address to point out the specific peer */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_PEER_MAC = 35,
+ /* 32-bit unsigned value to set window size for specific peer */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_WINLIMIT = 36,
+ /* 8-bit unsigned value to set the beacon miss threshold in 2.4 GHz */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_MISS_THRESHOLD_24 = 37,
+ /* 8-bit unsigned value to set the beacon miss threshold in 5 GHz */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_MISS_THRESHOLD_5 = 38,
+ /* 32-bit unsigned value to configure 5 or 10 MHz channel width for
+ * station device while in disconnect state. The attribute use the
+ * value of enum nl80211_chan_width: NL80211_CHAN_WIDTH_5 means 5 MHz,
+ * NL80211_CHAN_WIDTH_10 means 10 MHz. If set, the device work in 5 or
+ * 10 MHz channel width, the station will not connect to a BSS using 20
+ * MHz or higher bandwidth. Set to NL80211_CHAN_WIDTH_20_NOHT to
+ * clear this constraint.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_SUB20_CHAN_WIDTH = 39,
+ /* 32-bit unsigned value to configure the propagation absolute delay
+ * for 2G/5G band (units in us)
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_ABS_DELAY = 40,
+ /* 32-bit unsigned value to set probe period */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_PERIOD = 41,
+ /* 32-bit unsigned value to set stay period */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_STAY_PERIOD = 42,
+ /* 32-bit unsigned value to set snr diff */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SNR_DIFF = 43,
+ /* 32-bit unsigned value to set probe dwell time */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_DWELL_TIME = 44,
+ /* 32-bit unsigned value to set mgmt snr weight */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_MGMT_SNR_WEIGHT = 45,
+ /* 32-bit unsigned value to set data snr weight */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_DATA_SNR_WEIGHT = 46,
+ /* 32-bit unsigned value to set ack snr weight */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ACK_SNR_WEIGHT = 47,
+ /* 32-bit unsigned value to configure the listen interval.
+ * This is in units of beacon intervals. This configuration alters
+ * the negotiated listen interval with the AP during the connection.
+ * It is highly recommended to configure a value less than or equal to
+ * the one negotiated during the association. Configuring any greater
+ * value can have adverse effects (frame loss, AP disassociating STA,
+ * etc.).
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL = 48,
+ /*
+ * 8 bit unsigned value that is set on an AP/GO virtual interface to
+ * disable operations that would cause the AP/GO to leave its operating
+ * channel.
+ *
+ * This will restrict the scans to the AP/GO operating channel and the
+ * channels of the other band, if DBS is supported.A STA/CLI interface
+ * brought up after this setting is enabled, will be restricted to
+ * connecting to devices only on the AP/GO interface's operating channel
+ * or on the other band in DBS case. P2P supported channel list is
+ * modified, to only include AP interface's operating-channel and the
+ * channels of the other band if DBS is supported.
+ *
+ * These restrictions are only applicable as long as the AP/GO interface
+ * is alive. If the AP/GO interface is brought down then this
+ * setting/restriction is forgotten.
+ *
+ * If this variable is set on an AP/GO interface while a multi-channel
+ * concurrent session is active, it has no effect on the operation of
+ * the current interfaces, other than restricting the scan to the AP/GO
+ * operating channel and the other band channels if DBS is supported.
+ * However, if the STA is brought down and restarted then the new STA
+ * connection will either be formed on the AP/GO channel or on the
+ * other band in a DBS case. This is because of the scan being
+ * restricted on these channels as mentioned above.
+ *
+ * 1-Restrict / 0-Don't restrict offchannel operations.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL = 49,
+ /*
+ * 8 bit unsigned value to enable/disable LRO (Large Receive Offload)
+ * on an interface.
+ * 1 - Enable, 0 - Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LRO = 50,
+
+ /*
+ * 8 bit unsigned value to globally enable/disable scan
+ * 1 - Enable, 0 - Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE = 51,
+
+ /* 8-bit unsigned value to set the total beacon miss count
+ * This parameter will set the total beacon miss count.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TOTAL_BEACON_MISS_COUNT = 52,
+
+ /* Unsigned 32-bit value to configure the number of continuous
+ * Beacon Miss which shall be used by the firmware to penalize
+ * the RSSI for BTC.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS_BTC = 53,
+
+ /* 8-bit unsigned value to configure the driver and below layers to
+ * enable/disable all FILS features.
+ * 0-enable, 1-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS = 54,
+
+ /* 16-bit unsigned value to configure the level of WLAN latency
+ * module. See enum qca_wlan_vendor_attr_config_latency_level.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL = 55,
+
+ /* 8-bit unsigned value indicating the driver to use the RSNE as-is from
+ * the connect interface. Exclusively used for the scenarios where the
+ * device is used as a test bed device with special functionality and
+ * not recommended for production. This helps driver to not validate the
+ * RSNE passed from user space and thus allow arbitrary IE data to be
+ * used for testing purposes.
+ * 1-enable, 0-disable.
+ * Applications set/reset this configuration. If not reset, this
+ * parameter remains in use until the driver is unloaded.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE = 56,
+
+ /* 8-bit unsigned value to trigger green Tx power saving.
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ */
+enum qca_wlan_vendor_attr_sap_config {
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
+ /* 1 - reserved for QCA */
+ /* List of frequencies on which AP is expected to operate.
+ * This is irrespective of ACS configuration. This list is a priority
+ * based one and is looked for before the AP is created to ensure the
+ * best concurrency sessions (avoid MCC and use DBS/SCC) co-exist in
+ * the system.
+ */
+ QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sap_conditional_chan_switch - Parameters for AP
+ * conditional channel switch
+ */
+enum qca_wlan_vendor_attr_sap_conditional_chan_switch {
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID = 0,
+ /* Priority based frequency list (an array of u32 values in host byte
+ * order)
+ */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST = 1,
+ /* Status of the conditional switch (u32).
+ * 0: Success, Non-zero: Failure
+ */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS = 2,
+
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX =
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_gpio_attr - Parameters for GPIO configuration
+ */
+enum qca_wlan_gpio_attr {
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INVALID = 0,
+ /* Unsigned 32-bit attribute for GPIO command */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND,
+ /* Unsigned 32-bit attribute for GPIO PIN number to configure */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM,
+ /* Unsigned 32-bit attribute for GPIO value to configure */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE,
+ /* Unsigned 32-bit attribute for GPIO pull type */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE,
+ /* Unsigned 32-bit attribute for GPIO interrupt mode */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST - 1
+};
+
+/**
+ * qca_wlan_set_qdepth_thresh_attr - Parameters for setting
+ * MSDUQ depth threshold per peer per tid in the target
+ *
+ * Associated Vendor Command:
+ * QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH
+ */
+enum qca_wlan_set_qdepth_thresh_attr {
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_INVALID = 0,
+ /* 6-byte MAC address */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_MAC_ADDR,
+ /* Unsigned 32-bit attribute for holding the TID */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_TID,
+ /* Unsigned 32-bit attribute for holding the update mask
+ * bit 0 - Update high priority msdu qdepth threshold
+ * bit 1 - Update low priority msdu qdepth threshold
+ * bit 2 - Update UDP msdu qdepth threshold
+ * bit 3 - Update Non UDP msdu qdepth threshold
+ * rest of bits are reserved
+ */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_UPDATE_MASK,
+ /* Unsigned 32-bit attribute for holding the threshold value */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_VALUE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_LAST,
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_MAX =
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
+ */
+enum qca_wlan_vendor_attr_get_hw_capability {
+ QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_INVALID,
+ /* Antenna isolation
+ * An attribute used in the response.
+ * The content of this attribute is encoded in a byte array. Each byte
+ * value is an antenna isolation value. The array length is the number
+ * of antennas.
+ */
+ QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION,
+ /* Request HW capability
+ * An attribute used in the request.
+ * The content of this attribute is a u32 array for one or more of
+ * hardware capabilities (attribute IDs) that are being requested. Each
+ * u32 value has a value from this
+ * enum qca_wlan_vendor_attr_get_hw_capability
+ * identifying which capabilities are requested.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_MAX =
+ QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ll_stats_ext - Attributes for MAC layer monitoring
+ * offload which is an extension for LL_STATS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD: Monitoring period. Unit in ms.
+ * If MAC counters do not exceed the threshold, FW will report monitored
+ * link layer counters periodically as this setting. The first report is
+ * always triggered by this timer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD: It is a percentage (1-99).
+ * For each MAC layer counter, FW holds two copies. One is the current value.
+ * The other is the last report. Once a current counter's increment is larger
+ * than the threshold, FW will indicate that counter to host even if the
+ * monitoring timer does not expire.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG: Peer STA power state change
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID: TID of MSDU
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU: Count of MSDU with the same
+ * failure code.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS: TX failure code
+ * 1: TX packet discarded
+ * 2: No ACK
+ * 3: Postpone
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS: peer MAC address
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE: Peer STA current state
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL: Global threshold.
+ * Threshold for all monitored parameters. If per counter dedicated threshold
+ * is not enabled, this threshold will take effect.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE: Indicate what triggers this
+ * event, PERORID_TIMEOUT == 1, THRESH_EXCEED == 0.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID: interface ID
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID: peer ID
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP: bitmap for TX counters
+ * Bit0: TX counter unit in MSDU
+ * Bit1: TX counter unit in MPDU
+ * Bit2: TX counter unit in PPDU
+ * Bit3: TX counter unit in byte
+ * Bit4: Dropped MSDUs
+ * Bit5: Dropped Bytes
+ * Bit6: MPDU retry counter
+ * Bit7: MPDU failure counter
+ * Bit8: PPDU failure counter
+ * Bit9: MPDU aggregation counter
+ * Bit10: MCS counter for ACKed MPDUs
+ * Bit11: MCS counter for Failed MPDUs
+ * Bit12: TX Delay counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP: bitmap for RX counters
+ * Bit0: MAC RX counter unit in MPDU
+ * Bit1: MAC RX counter unit in byte
+ * Bit2: PHY RX counter unit in PPDU
+ * Bit3: PHY RX counter unit in byte
+ * Bit4: Disorder counter
+ * Bit5: Retry counter
+ * Bit6: Duplication counter
+ * Bit7: Discard counter
+ * Bit8: MPDU aggregation size counter
+ * Bit9: MCS counter
+ * Bit10: Peer STA power state change (wake to sleep) counter
+ * Bit11: Peer STA power save counter, total time in PS mode
+ * Bit12: Probe request counter
+ * Bit13: Other management frames counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP: bitmap for CCA
+ * Bit0: Idle time
+ * Bit1: TX time
+ * Bit2: time RX in current bss
+ * Bit3: Out of current bss time
+ * Bit4: Wireless medium busy time
+ * Bit5: RX in bad condition time
+ * Bit6: TX in bad condition time
+ * Bit7: time wlan card not available
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP: bitmap for signal
+ * Bit0: Per channel SNR counter
+ * Bit1: Per channel noise floor counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM: number of peers
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM: number of channels
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_AC_RX_NUM: number of RX stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS: per channel BSS CCA stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER: container for per PEER stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU: Number of total TX MSDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU: Number of total TX MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU: Number of total TX PPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES: bytes of TX data
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP: Number of dropped TX packets
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES: Bytes dropped
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY: waiting time without an ACK
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK: number of MPDU not-ACKed
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK: number of PPDU not-ACKed
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM:
+ * aggregation stats buffer length
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM: length of mcs stats
+ * buffer for ACKed MPDUs.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM: length of mcs stats
+ * buffer for failed MPDUs.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE:
+ * length of delay stats array.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR: TX aggregation stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS: MCS stats for ACKed MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS: MCS stats for failed MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY: tx delay stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU: MPDUs received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES: bytes received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU: PPDU received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES: PPDU bytes received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST: packets lost
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY: number of RX packets
+ * flagged as retransmissions
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP: number of RX packets
+ * flagged as duplicated
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD: number of RX
+ * packets discarded
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM: length of RX aggregation
+ * stats buffer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM: length of RX mcs
+ * stats buffer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS: RX mcs stats buffer
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR: aggregation stats buffer
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES: times STAs go to sleep
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION: STAs' total sleep time
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ: number of probe
+ * requests received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT: number of other mgmt
+ * frames received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME: Percentage of idle time
+ * there is no TX, nor RX, nor interference.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME: percentage of time
+ * transmitting packets.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME: percentage of time
+ * for receiving.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY: percentage of time
+ * interference detected.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD: percentage of time
+ * receiving packets with errors.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD: percentage of time
+ * TX no-ACK.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL: percentage of time
+ * the chip is unable to work in normal conditions.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME: percentage of time
+ * receiving packets in current BSS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME: percentage of time
+ * receiving packets not in current BSS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM: number of antennas
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL:
+ * This is a container for per antenna signal stats.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR: per antenna SNR value
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF: per antenna NF value
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON: RSSI of beacon
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON: SNR of beacon
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_REPORT_TIME: u64
+ * Absolute timestamp from 1970/1/1, unit in ms. After receiving the
+ * message, user layer APP could call gettimeofday to get another
+ * timestamp and calculate transfer delay for the message.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME: u32
+ * Real period for this measurement, unit in us.
+ */
+enum qca_wlan_vendor_attr_ll_stats_ext {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0,
+
+ /* Attributes for configurations */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD,
+
+ /* Peer STA power state change */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG,
+
+ /* TX failure event */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
+
+ /* MAC counters */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER,
+
+ /* Sub-attributes for PEER_AC_TX */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
+
+ /* Sub-attributes for PEER_AC_RX */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
+
+ /* Sub-attributes for CCA_BSS */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
+
+ /* sub-attribute for BSS_RX_TIME */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
+
+ /* Sub-attributes for PEER_SIGNAL */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
+
+ /* Sub-attributes for IFACE_BSS */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_REPORT_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST - 1
+};
+
+/* Attributes for FTM commands and events */
+
+/**
+ * enum qca_wlan_vendor_attr_loc_capa - Indoor location capabilities
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS: Various flags. See
+ * enum qca_wlan_vendor_attr_loc_capa_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS: Maximum number
+ * of measurement sessions that can run concurrently.
+ * Default is one session (no session concurrency).
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS: The total number of unique
+ * peers that are supported in running sessions. For example,
+ * if the value is 8 and maximum number of sessions is 2, you can
+ * have one session with 8 unique peers, or 2 sessions with 4 unique
+ * peers each, and so on.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP: Maximum number
+ * of bursts per peer, as an exponent (2^value). Default is 0,
+ * meaning no multi-burst support.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST: Maximum number
+ * of measurement exchanges allowed in a single burst.
+ * @QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES: Supported AOA measurement
+ * types. A bit mask (unsigned 32 bit value), each bit corresponds
+ * to an AOA type as defined by enum qca_vendor_attr_aoa_type.
+ */
+enum qca_wlan_vendor_attr_loc_capa {
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_INVALID,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS,
+ QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS,
+ QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS,
+ QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP,
+ QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST,
+ QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_MAX =
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_loc_capa_flags: Indoor location capability flags
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER: Set if driver
+ * can be configured as an FTM responder (for example, an AP that
+ * services FTM requests). QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+ * will be supported if set.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR: Set if driver
+ * can run FTM sessions. QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION
+ * will be supported if set.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
+ * supports immediate (ASAP) response.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA: Set if driver supports standalone
+ * AOA measurement using QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM: Set if driver supports
+ * requesting AOA measurements as part of an FTM session.
+ */
+enum qca_wlan_vendor_attr_loc_capa_flags {
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER = 1 << 0,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR = 1 << 1,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP = 1 << 2,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA = 1 << 3,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM = 1 << 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_info: Information about
+ * a single peer in a measurement session.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR: The MAC address of the peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS: Various flags related
+ * to measurement. See enum qca_wlan_vendor_attr_ftm_peer_meas_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS: Nested attribute of
+ * FTM measurement parameters, as specified by IEEE P802.11-REVmc/D7.0
+ * 9.4.2.167. See enum qca_wlan_vendor_attr_ftm_meas_param for
+ * list of supported attributes.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID: Initial token ID for
+ * secure measurement.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD: Request AOA
+ * measurement every <value> bursts. If 0 or not specified,
+ * AOA measurements will be disabled for this peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ: Frequency in MHz where
+ * the measurement frames are exchanged. Optional; if not
+ * specified, try to locate the peer in the kernel scan
+ * results cache and use frequency from there.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_info {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_INVALID,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX =
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_meas_flags: Measurement request flags,
+ * per-peer
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP: If set, request
+ * immediate (ASAP) response from peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI: If set, request
+ * LCI report from peer. The LCI report includes the absolute
+ * location of the peer in "official" coordinates (similar to GPS).
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.7 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR: If set, request
+ * Location civic report from peer. The LCR includes the location
+ * of the peer in free-form format. See IEEE P802.11-REVmc/D7.0,
+ * 11.24.6.7 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE: If set,
+ * request a secure measurement.
+ * QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID must also be provided.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_meas_flags {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP = 1 << 0,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI = 1 << 1,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR = 1 << 2,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE = 1 << 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_meas_param: Measurement parameters
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST: Number of measurements
+ * to perform in a single burst.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP: Number of bursts to
+ * perform, specified as an exponent (2^value).
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION: Duration of burst
+ * instance, as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD: Time between bursts,
+ * as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167. Must
+ * be larger than QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION.
+ */
+enum qca_wlan_vendor_attr_ftm_meas_param {
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_INVALID,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result: Per-peer results
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR: MAC address of the reported
+ * peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS: Status of measurement
+ * request for this peer.
+ * See enum qca_wlan_vendor_attr_ftm_peer_result_status.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS: Various flags related
+ * to measurement results for this peer.
+ * See enum qca_wlan_vendor_attr_ftm_peer_result_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS: Specified when
+ * request failed and peer requested not to send an additional request
+ * for this number of seconds.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI: LCI report when received
+ * from peer. In the format specified by IEEE P802.11-REVmc/D7.0,
+ * 9.4.2.22.10.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR: Location civic report when
+ * received from peer. In the format specified by IEEE P802.11-REVmc/D7.0,
+ * 9.4.2.22.13.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS: Reported when peer
+ * overridden some measurement request parameters. See
+ * enum qca_wlan_vendor_attr_ftm_meas_param.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS: AOA measurement
+ * for this peer. Same contents as @QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS: Array of measurement
+ * results. Each entry is a nested attribute defined
+ * by enum qca_wlan_vendor_attr_ftm_meas.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_INVALID,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAX =
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result_status
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK: Request sent ok and results
+ * will be provided. Peer may have overridden some measurement parameters,
+ * in which case overridden parameters will be report by
+ * QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAM attribute.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE: Peer is incapable
+ * of performing the measurement request. No more results will be sent
+ * for this peer in this session.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED: Peer reported request
+ * failed, and requested not to send an additional request for number
+ * of seconds specified by QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS
+ * attribute.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID: Request validation
+ * failed. Request was not sent over the air.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result_status {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result_flags: Various flags
+ * for measurement result, per-peer
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE: If set,
+ * measurement completed for this peer. No more results will be reported
+ * for this peer in this session.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result_flags {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE = 1 << 0,
+};
+
+/**
+ * enum qca_vendor_attr_loc_session_status: Session completion status code
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK: Session completed
+ * successfully.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED: Session aborted
+ * by request.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID: Session request
+ * was invalid and was not started.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED: Session had an error
+ * and did not complete normally (for example out of resources).
+ */
+enum qca_vendor_attr_loc_session_status {
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK,
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED,
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID,
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_meas: Single measurement data
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1: Time of departure (TOD) of FTM packet as
+ * recorded by responder, in picoseconds.
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2: Time of arrival (TOA) of FTM packet at
+ * initiator, in picoseconds.
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3: TOD of ACK packet as recorded by
+ * initiator, in picoseconds.
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4: TOA of ACK packet at
+ * responder, in picoseconds.
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI: RSSI (signal level) as recorded
+ * during this measurement exchange. Optional and will be provided if
+ * the hardware can measure it.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR: TOD error reported by
+ * responder. Not always provided.
+ * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR: TOA error reported by
+ * responder. Not always provided.
+ * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR: TOD error measured by
+ * initiator. Not always provided.
+ * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR: TOA error measured by
+ * initiator. Not always provided.
+ * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Dummy attribute for padding.
+ */
+enum qca_wlan_vendor_attr_ftm_meas {
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INVALID,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_MAX =
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_aoa_type - AOA measurement type
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: Phase of the strongest
+ * CIR (channel impulse response) path for each antenna.
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: Phase and amplitude
+ * of the strongest CIR path for each antenna.
+ */
+enum qca_wlan_vendor_attr_aoa_type {
+ QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE,
+ QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP,
+ QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX
+};
+
+/**
+ * enum qca_wlan_vendor_attr_encryption_test - Attributes to
+ * validate encryption engine
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION: Flag attribute.
+ * This will be included if the request is for decryption; if not included,
+ * the request is treated as a request for encryption by default.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER: Unsigned 32-bit value
+ * indicating the key cipher suite. Takes same values as
+ * NL80211_ATTR_KEY_CIPHER.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID: Unsigned 8-bit value
+ * Key Id to be used for encryption
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK: Array of 8-bit values.
+ * Key (TK) to be used for encryption/decryption
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN: Array of 8-bit values.
+ * Packet number to be specified for encryption/decryption
+ * 6 bytes for TKIP/CCMP/GCMP.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA: Array of 8-bit values
+ * representing the 802.11 packet (header + payload + FCS) that
+ * needs to be encrypted/decrypted.
+ * Encrypted/decrypted response from the driver will also be sent
+ * to userspace with the same attribute.
+ */
+enum qca_wlan_vendor_attr_encryption_test {
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX =
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_dmg_rf_sector_type - Type of
+ * sector for DMG RF sector operations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_RX: RX sector
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_TX: TX sector
+ */
+enum qca_wlan_vendor_attr_dmg_rf_sector_type {
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_RX,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_TX,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_MAX
+};
+
+/**
+ * enum qca_wlan_vendor_attr_fw_state - State of firmware
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_STATE_ERROR: FW is in bad state
+ * @QCA_WLAN_VENDOR_ATTR_FW_STATE_ACTIVE: FW is active
+ */
+enum qca_wlan_vendor_attr_fw_state {
+ QCA_WLAN_VENDOR_ATTR_FW_STATE_ERROR,
+ QCA_WLAN_VENDOR_ATTR_FW_STATE_ACTIVE,
+ QCA_WLAN_VENDOR_ATTR_FW_STATE_MAX
+};
+
+/**
+ * BRP antenna limit mode
+ *
+ * @QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_DISABLE: Disable BRP force
+ * antenna limit, BRP will be performed as usual.
+ * @QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_EFFECTIVE: Define maximal
+ * antennas limit. the hardware may use less antennas than the
+ * maximum limit.
+ * @QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_FORCE: The hardware will
+ * use exactly the specified number of antennas for BRP.
+ */
+enum qca_wlan_vendor_attr_brp_ant_limit_mode {
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_DISABLE,
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_EFFECTIVE,
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_FORCE,
+ QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_MAX
+};
+
+/**
+ * enum qca_wlan_vendor_attr_dmg_rf_sector_cfg - Attributes for
+ * DMG RF sector configuration for a single RF module.
+ * The values are defined in a compact way which closely matches
+ * the way it is stored in HW registers.
+ * The configuration provides values for 32 antennas and 8 distribution
+ * amplifiers, and together describes the characteristics of the RF
+ * sector - such as a beam in some direction with some gain.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX: Index
+ * of RF module for this configuration.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE0: Bit 0 of edge
+ * amplifier gain index. Unsigned 32 bit number containing
+ * bits for all 32 antennas.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE1: Bit 1 of edge
+ * amplifier gain index. Unsigned 32 bit number containing
+ * bits for all 32 antennas.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE2: Bit 2 of edge
+ * amplifier gain index. Unsigned 32 bit number containing
+ * bits for all 32 antennas.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_PSH_HI: Phase values
+ * for first 16 antennas, 2 bits per antenna.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_PSH_LO: Phase values
+ * for last 16 antennas, 2 bits per antenna.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16: Contains
+ * DTYPE values (3 bits) for each distribution amplifier, followed
+ * by X16 switch bits for each distribution amplifier. There are
+ * total of 8 distribution amplifiers.
+ */
+enum qca_wlan_vendor_attr_dmg_rf_sector_cfg {
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX = 1,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE0 = 2,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE1 = 3,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE2 = 4,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_PSH_HI = 5,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_PSH_LO = 6,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16 = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_MAX =
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST - 1
+};
+
+enum qca_wlan_vendor_attr_ll_stats_set {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_INVALID = 0,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD = 1,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING = 2,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_ll_stats_clr {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID = 0,
+ /* Unsigned 32bit bitmap for clearing statistics
+ * All radio statistics 0x00000001
+ * cca_busy_time (within radio statistics) 0x00000002
+ * All channel stats (within radio statistics) 0x00000004
+ * All scan statistics (within radio statistics) 0x00000008
+ * All interface statistics 0x00000010
+ * All tx rate statistics (within interface statistics) 0x00000020
+ * All ac statistics (with in interface statistics) 0x00000040
+ * All contention (min, max, avg) statistics (within ac statisctics)
+ * 0x00000080.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK = 1,
+ /* Unsigned 8 bit value: Request to stop statistics collection */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ = 2,
+
+ /* Unsigned 32 bit bitmap: Response from the driver
+ * for the cleared statistics
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK = 3,
+ /* Unsigned 8 bit value: Response from driver/firmware
+ * for the stop request
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP = 4,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_ll_stats_get {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID = 0,
+ /* Unsigned 32 bit value provided by the caller issuing the GET stats
+ * command. When reporting the stats results, the driver uses the same
+ * value to indicate which GET request the results correspond to.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID = 1,
+ /* Unsigned 32 bit value - bit mask to identify what statistics are
+ * requested for retrieval.
+ * Radio Statistics 0x00000001
+ * Interface Statistics 0x00000020
+ * All Peer Statistics 0x00000040
+ * Peer Statistics 0x00000080
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK = 2,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_ll_stats_results {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID = 0,
+ /* Unsigned 32bit value. Used by the driver; must match the request id
+ * provided with the QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET command.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID = 1,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX = 2,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX = 3,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX = 4,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX = 5,
+ /* Signed 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT = 6,
+ /* Signed 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA = 7,
+ /* Signed 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK = 8,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_* are
+ * nested within the interface stats.
+ */
+
+ /* Interface mode, e.g., STA, SOFTAP, IBSS, etc.
+ * Type = enum wifi_interface_mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE = 9,
+ /* Interface MAC address. An array of 6 Unsigned int8 */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR = 10,
+ /* Type = enum wifi_connection_state, e.g., DISCONNECTED,
+ * AUTHENTICATING, etc. valid for STA, CLI only.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE = 11,
+ /* Type = enum wifi_roam_state. Roaming state, e.g., IDLE or ACTIVE
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING = 12,
+ /* Unsigned 32 bit value. WIFI_CAPABILITY_XXX */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES = 13,
+ /* NULL terminated SSID. An array of 33 Unsigned 8bit values */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID = 14,
+ /* BSSID. An array of 6 unsigned 8 bit values */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID = 15,
+ /* Country string advertised by AP. An array of 3 unsigned 8 bit
+ * values.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR = 16,
+ /* Country string for this association. An array of 3 unsigned 8 bit
+ * values.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR = 17,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* could
+ * be nested within the interface stats.
+ */
+
+ /* Type = enum wifi_traffic_ac, e.g., V0, VI, BE and BK */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC = 18,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU = 19,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU = 20,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST = 21,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST = 22,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU = 23,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU = 24,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST = 25,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES = 26,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT = 27,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG = 28,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN = 29,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX = 30,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG = 31,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES = 32,
+ /* Unsigned 32 bit value. Number of peers */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS = 33,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_* are
+ * nested within the interface stats.
+ */
+
+ /* Type = enum wifi_peer_type. Peer type, e.g., STA, AP, P2P GO etc. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE = 34,
+ /* MAC addr corresponding to respective peer. An array of 6 unsigned
+ * 8 bit values.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS = 35,
+ /* Unsigned int 32 bit value representing capabilities corresponding
+ * to respective peer.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES = 36,
+ /* Unsigned 32 bit value. Number of rates */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES = 37,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_*
+ * are nested within the rate stat.
+ */
+
+ /* Wi-Fi Rate - separate attributes defined for individual fields */
+
+ /* Unsigned int 8 bit value; 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE = 38,
+ /* Unsigned int 8 bit value; 0:1x1, 1:2x2, 3:3x3, 4:4x4 */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS = 39,
+ /* Unsigned int 8 bit value; 0:20 MHz, 1:40 MHz, 2:80 MHz, 3:160 MHz */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW = 40,
+ /* Unsigned int 8 bit value; OFDM/CCK rate code would be as per IEEE Std
+ * in the units of 0.5 Mbps HT/VHT it would be MCS index
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX = 41,
+
+ /* Unsigned 32 bit value. Bit rate in units of 100 kbps */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE = 42,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_STAT_* could be
+ * nested within the peer info stats.
+ */
+
+ /* Unsigned int 32 bit value. Number of successfully transmitted data
+ * packets, i.e., with ACK received corresponding to the respective
+ * rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU = 43,
+ /* Unsigned int 32 bit value. Number of received data packets
+ * corresponding to the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU = 44,
+ /* Unsigned int 32 bit value. Number of data packet losses, i.e., no ACK
+ * received corresponding to the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST = 45,
+ /* Unsigned int 32 bit value. Total number of data packet retries for
+ * the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES = 46,
+ /* Unsigned int 32 bit value. Total number of short data packet retries
+ * for the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT = 47,
+ /* Unsigned int 32 bit value. Total number of long data packet retries
+ * for the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG = 48,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID = 49,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake
+ * accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME = 50,
+ /* Unsigned 32 bit value. Total number of msecs the radio is
+ * transmitting accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME = 51,
+ /* Unsigned 32 bit value. Total number of msecs the radio is in active
+ * receive accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME = 52,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to all scan accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN = 53,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to NAN accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD = 54,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to GSCAN accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN = 55,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to roam scan accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN = 56,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to PNO scan accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN = 57,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to Hotspot 2.0 scans and GAS exchange accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20 = 58,
+ /* Unsigned 32 bit value. Number of channels. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS = 59,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_* could
+ * be nested within the channel stats.
+ */
+
+ /* Type = enum wifi_channel_width. Channel width, e.g., 20, 40, 80 */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH = 60,
+ /* Unsigned 32 bit value. Primary 20 MHz channel. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ = 61,
+ /* Unsigned 32 bit value. Center frequency (MHz) first segment. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0 = 62,
+ /* Unsigned 32 bit value. Center frequency (MHz) second segment. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1 = 63,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_* could be
+ * nested within the radio stats.
+ */
+
+ /* Unsigned int 32 bit value representing total number of msecs the
+ * radio is awake on that channel accruing over time, corresponding to
+ * the respective channel.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME = 64,
+ /* Unsigned int 32 bit value representing total number of msecs the CCA
+ * register is busy accruing over time corresponding to the respective
+ * channel.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME = 65,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS = 66,
+
+ /* Signifies the nested list of channel attributes
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_*
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO = 67,
+
+ /* Signifies the nested list of peer info attributes
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_*
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO = 68,
+
+ /* Signifies the nested list of rate info attributes
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_*
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO = 69,
+
+ /* Signifies the nested list of wmm info attributes
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_*
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO = 70,
+
+ /* Unsigned 8 bit value. Used by the driver; if set to 1, it indicates
+ * that more stats, e.g., peers or radio, are to follow in the next
+ * QCA_NL80211_VENDOR_SUBCMD_LL_STATS_*_RESULTS event.
+ * Otherwise, it is set to 0.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA = 71,
+
+ /* Unsigned 64 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET = 72,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED = 73,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED = 74,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME = 75,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE = 76,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS = 77,
+
+ /* Number of msecs the radio spent in transmitting for each power level
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL = 78,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT = 79,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT = 80,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT = 81,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT = 82,
+
+ /* Unsigned int 32 value.
+ * Pending MSDUs corresponding to respective AC.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_PENDING_MSDU = 83,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_ll_stats_type {
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_INVALID = 0,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO = 1,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE = 2,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS = 3,
+
+ /* keep last */
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_AFTER_LAST,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_MAX =
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_tdls_configuration - Attributes for
+ * TDLS configuration to the host driver.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE: Configure the TDLS trigger
+ * mode in the host driver. enum qca_wlan_vendor_tdls_trigger_mode
+ * represents the different TDLS trigger modes.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD: Duration (u32) within
+ * which QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD number
+ * of packets shall meet the criteria for implicit TDLS setup.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD: Number (u32) of Tx/Rx packets
+ * within a duration QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD
+ * to initiate a TDLS setup.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD: Time (u32) to initiate
+ * a TDLS Discovery to the peer.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT: Max number (u32) of
+ * discovery attempts to know the TDLS capability of the peer. A peer is
+ * marked as TDLS not capable if there is no response for all the attempts.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT: Represents a duration (u32)
+ * within which QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD
+ * number of TX / RX frames meet the criteria for TDLS teardown.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD: Minimum number (u32)
+ * of Tx/Rx packets within a duration
+ * QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT to tear down a TDLS link.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD: Threshold
+ * corresponding to the RSSI of the peer below which a TDLS setup is
+ * triggered.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD: Threshold
+ * corresponding to the RSSI of the peer above which a TDLS teardown is
+ * triggered.
+ */
+enum qca_wlan_vendor_attr_tdls_configuration {
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE = 1,
+
+ /* Attributes configuring the TDLS Implicit Trigger */
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD = 2,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD = 3,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD = 4,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT = 5,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT = 6,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD = 7,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD = 8,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD = 9,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_tdls_trigger_mode: Represents the TDLS trigger mode in
+ * the driver
+ *
+ * The following are the different values for
+ * QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE.
+ *
+ * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: The trigger to initiate/teardown
+ * the TDLS connection to a respective peer comes from the user space.
+ * wpa_supplicant provides the commands TDLS_SETUP, TDLS_TEARDOWN,
+ * TDLS_DISCOVER to do this.
+ * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: Host driver triggers this TDLS
+ * setup/teardown to the eligible peer once the configured criteria
+ * (such as TX/RX threshold, RSSI) is met. The attributes
+ * in QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IMPLICIT_PARAMS correspond to
+ * the different configuration criteria for the TDLS trigger from the
+ * host driver.
+ * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: Enables the driver to trigger
+ * the TDLS setup / teardown through the implicit mode only to the
+ * configured MAC addresses (wpa_supplicant, with tdls_external_control=1,
+ * configures the MAC address through TDLS_SETUP / TDLS_TEARDOWN commands).
+ * External mode works on top of the implicit mode. Thus the host driver
+ * is expected to configure in TDLS Implicit mode too to operate in
+ * External mode.
+ * Configuring External mode alone without Implicit mode is invalid.
+ *
+ * All the above implementations work as expected only when the host driver
+ * advertises the capability WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP - representing
+ * that the TDLS message exchange is not internal to the host driver, but
+ * depends on wpa_supplicant to do the message exchange.
+ */
+enum qca_wlan_vendor_tdls_trigger_mode {
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT = 1 << 0,
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT = 1 << 1,
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = 1 << 2,
+};
+
+/**
+ * enum qca_vendor_attr_sar_limits_selections - Source of SAR power limits
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0: Select SAR profile #0
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1: Select SAR profile #1
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2: Select SAR profile #2
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3: Select SAR profile #3
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4: Select SAR profile #4
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE: Do not select any
+ * source of SAR power limits, thereby disabling the SAR power
+ * limit feature.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: Select the SAR power
+ * limits configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0: Select the SAR power
+ * limits version 2.0 configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
+ *
+ * This enumerates the valid set of values that may be supplied for
+ * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT in an instance of
+ * the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command or in
+ * the response to an instance of the
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS vendor command.
+ */
+enum qca_vendor_attr_sar_limits_selections {
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 = 0,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1 = 1,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2 = 2,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3 = 3,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4 = 4,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE = 5,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER = 6,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0 = 7,
+};
+
+/**
+ * enum qca_vendor_attr_sar_limits_spec_modulations -
+ * SAR limits specification modulation
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK -
+ * CCK modulation
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM -
+ * OFDM modulation
+ *
+ * This enumerates the valid set of values that may be supplied for
+ * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION in an
+ * instance of attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC in an
+ * instance of the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor
+ * command or in the response to an instance of the
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS vendor command.
+ */
+enum qca_vendor_attr_sar_limits_spec_modulations {
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK = 0,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM = 1,
+};
+
+/**
+ * enum qca_vendor_attr_sar_limits - Attributes for SAR power limits
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE: Optional (u32) value to
+ * select which SAR power limit table should be used. Valid
+ * values are enumerated in enum
+ * %qca_vendor_attr_sar_limits_selections. The existing SAR
+ * power limit selection is unchanged if this attribute is not
+ * present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS: Optional (u32) value
+ * which specifies the number of SAR power limit specifications
+ * which will follow.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC: Nested array of SAR power
+ * limit specifications. The number of specifications is
+ * specified by @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS. Each
+ * specification contains a set of
+ * QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_* attributes. A
+ * specification is uniquely identified by the attributes
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND,
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN, and
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION and always
+ * contains as a payload the attribute
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT,
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX.
+ * Either %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT or
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX is
+ * needed based upon the value of
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND: Optional (u32) value to
+ * indicate for which band this specification applies. Valid
+ * values are enumerated in enum %nl80211_band (although not all
+ * bands may be supported by a given device). If the attribute is
+ * not supplied then the specification will be applied to all
+ * supported bands.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN: Optional (u32) value
+ * to indicate for which antenna chain this specification
+ * applies, i.e. 1 for chain 1, 2 for chain 2, etc. If the
+ * attribute is not supplied then the specification will be
+ * applied to all chains.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION: Optional (u32)
+ * value to indicate for which modulation scheme this
+ * specification applies. Valid values are enumerated in enum
+ * %qca_vendor_attr_sar_limits_spec_modulations. If the attribute
+ * is not supplied then the specification will be applied to all
+ * modulation schemes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT: Required (u32)
+ * value to specify the actual power limit value in units of 0.5
+ * dBm (i.e., a value of 11 represents 5.5 dBm).
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT is
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX: Required (u32)
+ * value to indicate SAR V2 indices (0 - 11) to select SAR V2 profiles.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT is
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0.
+ *
+ * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS
+ * and %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS.
+ */
+enum qca_vendor_attr_sar_limits {
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE = 1,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS = 2,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC = 3,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND = 4,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN = 5,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION = 6,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT = 7,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX = 8,
+
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX =
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_wifi_info: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO sub command.
+ */
+enum qca_wlan_vendor_attr_get_wifi_info {
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION = 1,
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX =
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_wifi_logger_start: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START sub command.
+ */
+enum qca_wlan_vendor_attr_wifi_logger_start {
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL = 2,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_GET_MAX =
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_logger_results {
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_INVALID = 0,
+
+ /* Unsigned 32-bit value; must match the request Id supplied by
+ * Wi-Fi HAL in the corresponding subcmd NL msg.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_REQUEST_ID = 1,
+
+ /* Unsigned 32-bit value; used to indicate the size of memory
+ * dump to be allocated.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX =
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_roaming_config_params {
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0,
+
+ QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD = 1,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID = 2,
+
+ /* Attributes for wifi_set_ssid_white_list */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS = 3,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST = 4,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID = 5,
+
+ /* Attributes for set_roam_params */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD = 6,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD = 7,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR = 8,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR = 9,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST = 10,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS = 11,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER = 12,
+
+ /* Attribute for set_lazy_roam */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE = 13,
+
+ /* Attribute for set_lazy_roam with preferences */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS = 14,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID = 15,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID = 16,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER = 17,
+
+ /* Attribute for set_blacklist bssid params */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20,
+ /* Flag attribute indicates this BSSID blacklist as a hint */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_roam_subcmd: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ */
+enum qca_wlan_vendor_attr_roam_subcmd {
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_gscan_config_params {
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_INVALID = 0,
+
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID = 1,
+
+ /* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS sub command.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND
+ = 2,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS
+ = 3,
+
+ /* Attributes for input params used by
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_START sub command.
+ */
+
+ /* Unsigned 32-bit value; channel frequency */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_CHANNEL = 4,
+ /* Unsigned 32-bit value; dwell time in ms. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_DWELL_TIME = 5,
+ /* Unsigned 8-bit value; 0: active; 1: passive; N/A for DFS */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_PASSIVE = 6,
+ /* Unsigned 8-bit value; channel class */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_CLASS = 7,
+
+ /* Unsigned 8-bit value; bucket index, 0 based */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_INDEX = 8,
+ /* Unsigned 8-bit value; band. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BAND = 9,
+ /* Unsigned 32-bit value; desired period, in ms. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_PERIOD = 10,
+ /* Unsigned 8-bit value; report events semantics. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_REPORT_EVENTS = 11,
+ /* Unsigned 32-bit value. Followed by a nested array of
+ * GSCAN_CHANNEL_SPEC_* attributes.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS = 12,
+
+ /* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_* attributes.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC = 13,
+
+ /* Unsigned 32-bit value; base timer period in ms. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_BASE_PERIOD = 14,
+ /* Unsigned 32-bit value; number of APs to store in each scan in the
+ * BSSID/RSSI history buffer (keep the highest RSSI APs).
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN = 15,
+ /* Unsigned 8-bit value; in %, when scan buffer is this much full, wake
+ * up AP.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT
+ = 16,
+
+ /* Unsigned 8-bit value; number of scan bucket specs; followed by a
+ * nested array of_GSCAN_BUCKET_SPEC_* attributes and values. The size
+ * of the array is determined by NUM_BUCKETS.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS = 17,
+
+ /* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_* attributes.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC = 18,
+
+ /* Unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH
+ = 19,
+ /* Unsigned 32-bit value; maximum number of results to be returned. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX
+ = 20,
+
+ /* An array of 6 x unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_BSSID = 21,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_LOW = 22,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH = 23,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_CHANNEL = 24,
+
+ /* Number of hotlist APs as unsigned 32-bit value, followed by a nested
+ * array of AP_THRESHOLD_PARAM attributes and values. The size of the
+ * array is determined by NUM_AP.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_NUM_AP = 25,
+
+ /* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_* attributes.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM = 26,
+
+ /* Unsigned 32-bit value; number of samples for averaging RSSI. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE
+ = 27,
+ /* Unsigned 32-bit value; number of samples to confirm AP loss. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE
+ = 28,
+ /* Unsigned 32-bit value; number of APs breaching threshold. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING = 29,
+ /* Unsigned 32-bit value; number of APs. Followed by an array of
+ * AP_THRESHOLD_PARAM attributes. Size of the array is NUM_AP.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP = 30,
+ /* Unsigned 32-bit value; number of samples to confirm AP loss. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE
+ = 31,
+ /* Unsigned 32-bit value. If max_period is non zero or different than
+ * period, then this bucket is an exponential backoff bucket.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_MAX_PERIOD = 32,
+ /* Unsigned 32-bit value. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BASE = 33,
+ /* Unsigned 32-bit value. For exponential back off bucket, number of
+ * scans to perform for a given period.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_STEP_COUNT = 34,
+ /* Unsigned 8-bit value; in number of scans, wake up AP after these
+ * many scans.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS
+ = 35,
+
+ /* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SSID_HOTLIST sub command.
+ */
+ /* Unsigned 3-2bit value; number of samples to confirm SSID loss. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE
+ = 36,
+ /* Number of hotlist SSIDs as unsigned 32-bit value, followed by a
+ * nested array of SSID_THRESHOLD_PARAM_* attributes and values. The
+ * size of the array is determined by NUM_SSID.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_NUM_SSID = 37,
+ /* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_*
+ * attributes.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_NUM_SSID
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM = 38,
+
+ /* An array of 33 x unsigned 8-bit value; NULL terminated SSID */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_SSID = 39,
+ /* Unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_BAND = 40,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW = 41,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH = 42,
+ /* Unsigned 32-bit value; a bitmask with additional gscan config flag.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CONFIGURATION_FLAGS = 43,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_gscan_results {
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_INVALID = 0,
+
+ /* Unsigned 32-bit value; must match the request Id supplied by
+ * Wi-Fi HAL in the corresponding subcmd NL msg.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID = 1,
+
+ /* Unsigned 32-bit value; used to indicate the status response from
+ * firmware/driver for the vendor sub-command.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS = 2,
+
+ /* GSCAN Valid Channels attributes */
+ /* Unsigned 32bit value; followed by a nested array of CHANNELS. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS = 3,
+ /* An array of NUM_CHANNELS x unsigned 32-bit value integers
+ * representing channel numbers.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS = 4,
+
+ /* GSCAN Capabilities attributes */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE = 5,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS = 6,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN
+ = 7,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE
+ = 8,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD
+ = 9,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS = 10,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS
+ = 11,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES
+ = 12,
+
+ /* GSCAN Attributes used with
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE sub-command.
+ */
+
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE = 13,
+
+ /* GSCAN attributes used with
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT sub-command.
+ */
+
+ /* An array of NUM_RESULTS_AVAILABLE x
+ * QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_*
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST = 14,
+
+ /* Unsigned 64-bit value; age of sample at the time of retrieval */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP = 15,
+ /* 33 x unsigned 8-bit value; NULL terminated SSID */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID = 16,
+ /* An array of 6 x unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID = 17,
+ /* Unsigned 32-bit value; channel frequency in MHz */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL = 18,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI = 19,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT = 20,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD = 21,
+ /* Unsigned 16-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD = 22,
+ /* Unsigned 16-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY = 23,
+ /* Unsigned 32-bit value; size of the IE DATA blob */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH = 24,
+ /* An array of IE_LENGTH x unsigned 8-bit value; blob of all the
+ * information elements found in the beacon; this data should be a
+ * packed list of wifi_information_element objects, one after the
+ * other.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA = 25,
+
+ /* Unsigned 8-bit value; set by driver to indicate more scan results are
+ * available.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA = 26,
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT sub-command.
+ */
+ /* Unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_TYPE = 27,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_STATUS = 28,
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND sub-command.
+ */
+ /* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+ * to indicate number of results.
+ * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the
+ * list of results.
+ */
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE sub-command.
+ */
+ /* An array of 6 x unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID = 29,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL
+ = 30,
+ /* Unsigned 32-bit value. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI
+ = 31,
+ /* A nested array of signed 32-bit RSSI values. Size of the array is
+ * determined by (NUM_RSSI of SIGNIFICANT_CHANGE_RESULT_NUM_RSSI.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST
+ = 32,
+
+ /* GSCAN attributes used with
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS sub-command.
+ */
+ /* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+ * to indicate number of gscan cached results returned.
+ * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST to indicate
+ * the list of gscan cached results.
+ */
+
+ /* An array of NUM_RESULTS_AVAILABLE x
+ * QCA_NL80211_VENDOR_ATTR_GSCAN_CACHED_RESULTS_*
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST = 33,
+ /* Unsigned 32-bit value; a unique identifier for the scan unit. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID = 34,
+ /* Unsigned 32-bit value; a bitmask w/additional information about scan.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_FLAGS = 35,
+ /* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+ * to indicate number of wifi scan results/bssids retrieved by the scan.
+ * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the
+ * list of wifi scan results returned for each cached result block.
+ */
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND sub-command.
+ */
+ /* Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE for
+ * number of results.
+ * Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the nested
+ * list of wifi scan results returned for each
+ * wifi_passpoint_match_result block.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE.
+ */
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND sub-command.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES
+ = 36,
+ /* A nested array of
+ * QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_*
+ * attributes. Array size =
+ * *_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST = 37,
+
+ /* Unsigned 32-bit value; network block id for the matched network */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID = 38,
+ /* Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the nested
+ * list of wifi scan results returned for each
+ * wifi_passpoint_match_result block.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN = 39,
+ /* An array size of PASSPOINT_MATCH_ANQP_LEN of unsigned 8-bit values;
+ * ANQP data in the information_element format.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP = 40,
+
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS = 41,
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS = 42,
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID
+ = 43,
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID
+ = 44,
+
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED = 45,
+
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute.
+ * This is used to limit the maximum number of BSSIDs while sending
+ * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with attributes
+ * QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID and
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX =
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_pno_config_params {
+ QCA_WLAN_VENDOR_ATTR_PNO_INVALID = 0,
+ /* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST sub command.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM = 1,
+ /* Array of nested QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_*
+ * attributes. Array size =
+ * QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY = 2,
+
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID = 3,
+ /* An array of 256 x unsigned 8-bit value; NULL terminated UTF-8 encoded
+ * realm, 0 if unspecified.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM = 4,
+ /* An array of 16 x unsigned 32-bit value; roaming consortium ids to
+ * match, 0 if unspecified.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID = 5,
+ /* An array of 6 x unsigned 8-bit value; MCC/MNC combination, 0s if
+ * unspecified.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN = 6,
+
+ /* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST sub command.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS = 7,
+ /* Array of nested
+ * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_*
+ * attributes. Array size =
+ * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST = 8,
+ /* An array of 33 x unsigned 8-bit value; NULL terminated SSID */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID = 9,
+ /* Signed 8-bit value; threshold for considering this SSID as found,
+ * required granularity for this threshold is 4 dBm to 8 dBm.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD
+ = 10,
+ /* Unsigned 8-bit value; WIFI_PNO_FLAG_XXX */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS = 11,
+ /* Unsigned 8-bit value; auth bit field for matching WPA IE */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT = 12,
+ /* Unsigned 8-bit to indicate ePNO type;
+ * It takes values from qca_wlan_epno_type
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_TYPE = 13,
+
+ /* Nested attribute to send the channel list */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_CHANNEL_LIST = 14,
+
+ /* Unsigned 32-bit value; indicates the interval between PNO scan
+ * cycles in msec.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_SCAN_INTERVAL = 15,
+ QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI = 16,
+ QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI = 17,
+ QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX = 18,
+ QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS = 19,
+ QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS = 20,
+ QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS = 21,
+ QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS = 22,
+ /* Unsigned 32-bit value, representing the PNO Request ID */
+ QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID = 23,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PNO_MAX =
+ QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_acs_select_reason: This represents the different reasons why
+ * the ACS has to be triggered. These values are used by
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_REASON and
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON
+ */
+enum qca_wlan_vendor_acs_select_reason {
+ /* Represents the reason that the ACS triggered during the AP start */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_INIT,
+ /* Represents the reason that DFS found with the current channel */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS,
+ /* Represents the reason that LTE co-exist in the current band. */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX,
+};
+
+/**
+ * qca_wlan_vendor_attr_external_acs_policy: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_POLICY to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This represents the
+ * external ACS policies to select the channels w.r.t. the PCL weights.
+ * (QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL represents the channels and
+ * their PCL weights.)
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_POLICY_PCL_MANDATORY: Mandatory to
+ * select a channel with non-zero PCL weight.
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_POLICY_PCL_PREFERRED: Prefer a
+ * channel with non-zero PCL weight.
+ *
+ */
+enum qca_wlan_vendor_attr_external_acs_policy {
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_POLICY_PCL_PREFERRED,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_POLICY_PCL_MANDATORY,
+};
+
+/**
+ * qca_wlan_vendor_channel_prop_flags: This represent the flags for a channel.
+ * This is used by QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS.
+ */
+enum qca_wlan_vendor_channel_prop_flags {
+ /* Bits 0, 1, 2, and 3 are reserved */
+
+ /* Turbo channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_TURBO = 1 << 4,
+ /* CCK channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_CCK = 1 << 5,
+ /* OFDM channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_OFDM = 1 << 6,
+ /* 2.4 GHz spectrum channel. */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_2GHZ = 1 << 7,
+ /* 5 GHz spectrum channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_5GHZ = 1 << 8,
+ /* Only passive scan allowed */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_PASSIVE = 1 << 9,
+ /* Dynamic CCK-OFDM channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_DYN = 1 << 10,
+ /* GFSK channel (FHSS PHY) */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_GFSK = 1 << 11,
+ /* Radar found on channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_RADAR = 1 << 12,
+ /* 11a static turbo channel only */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_STURBO = 1 << 13,
+ /* Half rate channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HALF = 1 << 14,
+ /* Quarter rate channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_QUARTER = 1 << 15,
+ /* HT 20 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT20 = 1 << 16,
+ /* HT 40 with extension channel above */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40PLUS = 1 << 17,
+ /* HT 40 with extension channel below */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40MINUS = 1 << 18,
+ /* HT 40 intolerant */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40INTOL = 1 << 19,
+ /* VHT 20 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT20 = 1 << 20,
+ /* VHT 40 with extension channel above */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40PLUS = 1 << 21,
+ /* VHT 40 with extension channel below */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40MINUS = 1 << 22,
+ /* VHT 80 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80 = 1 << 23,
+ /* HT 40 intolerant mark bit for ACS use */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40INTOLMARK = 1 << 24,
+ /* Channel temporarily blocked due to noise */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_BLOCKED = 1 << 25,
+ /* VHT 160 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT160 = 1 << 26,
+ /* VHT 80+80 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80_80 = 1 << 27,
+ /* HE 20 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE20 = 1 << 28,
+ /* HE 40 with extension channel above */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40PLUS = 1 << 29,
+ /* HE 40 with extension channel below */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40MINUS = 1 << 30,
+ /* HE 40 intolerant */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40INTOL = 1 << 31,
+};
+
+/**
+ * qca_wlan_vendor_channel_prop_flags_2: This represents the flags for a
+ * channel, and is a continuation of qca_wlan_vendor_channel_prop_flags. This is
+ * used by QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS_2.
+ */
+enum qca_wlan_vendor_channel_prop_flags_2 {
+ /* HE 40 intolerant mark bit for ACS use */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40INTOLMARK = 1 << 0,
+ /* HE 80 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE80 = 1 << 1,
+ /* HE 160 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE160 = 1 << 2,
+ /* HE 80+80 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE80_80 = 1 << 3,
+};
+
+/**
+ * qca_wlan_vendor_channel_prop_flags_ext: This represent the extended flags for
+ * each channel. This is used by
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAG_EXT.
+ */
+enum qca_wlan_vendor_channel_prop_flags_ext {
+ /* Radar found on channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_RADAR_FOUND = 1 << 0,
+ /* DFS required on channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DFS = 1 << 1,
+ /* DFS required on channel for 2nd band of 80+80 */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DFS_CFREQ2 = 1 << 2,
+ /* If channel has been checked for DFS */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DFS_CLEAR = 1 << 3,
+ /* Excluded in 802.11d */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_11D_EXCLUDED = 1 << 4,
+ /* Channel Switch Announcement received on this channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_CSA_RECEIVED = 1 << 5,
+ /* Ad-hoc is not allowed */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_ADHOC = 1 << 6,
+ /* Station only channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_HOSTAP = 1 << 7,
+ /* DFS radar history for slave device (STA mode) */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_HISTORY_RADAR = 1 << 8,
+ /* DFS CAC valid for slave device (STA mode) */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_CAC_VALID = 1 << 9,
+};
+
+/**
+ * qca_wlan_vendor_external_acs_event_chan_info_attr: Represents per channel
+ * information. These attributes are sent as part of
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO. Each set of the following
+ * attributes correspond to a single channel.
+ */
+enum qca_wlan_vendor_external_acs_event_chan_info_attr {
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_INVALID = 0,
+
+ /* A bitmask (u32) with flags specified in
+ * enum qca_wlan_vendor_channel_prop_flags.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS = 1,
+ /* A bitmask (u32) with flags specified in
+ * enum qca_wlan_vendor_channel_prop_flags_ext.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAG_EXT = 2,
+ /* frequency in MHz (u32) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ = 3,
+ /* maximum regulatory transmission power (u32) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_REG_POWER = 4,
+ /* maximum transmission power (u32) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_POWER = 5,
+ /* minimum transmission power (u32) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MIN_POWER = 6,
+ /* regulatory class id (u8) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_REG_CLASS_ID = 7,
+ /* maximum antenna gain in (u8) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_ANTENNA_GAIN = 8,
+ /* VHT segment 0 (u8) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0 = 9,
+ /* VHT segment 1 (u8) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1 = 10,
+ /* A bitmask (u32) with flags specified in
+ * enum qca_wlan_vendor_channel_prop_flags_2.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS_2 = 11,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_pcl: Represents attributes for
+ * preferred channel list (PCL). These attributes are sent as part of
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL and
+ * QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST.
+ */
+enum qca_wlan_vendor_attr_pcl {
+ QCA_WLAN_VENDOR_ATTR_PCL_INVALID = 0,
+
+ /* Channel number (u8) */
+ QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL = 1,
+ /* Channel weightage (u8) */
+ QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT = 2,
+ /* Channel frequency (u32) in MHz */
+ QCA_WLAN_VENDOR_ATTR_PCL_FREQ = 3,
+ /* Channel flags (u32)
+ * bit 0 set: channel to be used for GO role,
+ * bit 1 set: channel to be used on CLI role,
+ * bit 2 set: channel must be considered for operating channel
+ * selection & peer chosen operating channel should be
+ * one of the channels with this flag set,
+ * bit 3 set: channel should be excluded in GO negotiation
+ */
+ QCA_WLAN_VENDOR_ATTR_PCL_FLAG = 4,
+};
+
+/**
+ * qca_wlan_vendor_attr_external_acs_event: Attribute to vendor sub-command
+ * QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This attribute will be sent by
+ * host driver.
+ */
+enum qca_wlan_vendor_attr_external_acs_event {
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_INVALID = 0,
+
+ /* This reason (u8) refers to enum qca_wlan_vendor_acs_select_reason.
+ * This helps ACS module to understand why ACS needs to be started.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_REASON = 1,
+ /* Flag attribute to indicate if driver supports spectral scanning */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_SPECTRAL_SUPPORTED = 2,
+ /* Flag attribute to indicate if 11ac is offloaded to firmware */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_OFFLOAD_ENABLED = 3,
+ /* Flag attribute to indicate if driver provides additional channel
+ * capability as part of scan operation
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_ADD_CHAN_STATS_SUPPORT = 4,
+ /* Flag attribute to indicate interface status is UP */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AP_UP = 5,
+ /* Operating mode (u8) of interface. Takes one of enum nl80211_iftype
+ * values.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_SAP_MODE = 6,
+ /* Channel width (u8). It takes one of enum nl80211_chan_width values.
+ * This is the upper bound of channel width. ACS logic should try to get
+ * a channel with the specified width and if not found, look for lower
+ * values.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_WIDTH = 7,
+ /* This (u8) will hold values of one of enum nl80211_bands */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_BAND = 8,
+ /* PHY/HW mode (u8). Takes one of enum qca_wlan_vendor_acs_hw_mode
+ * values
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PHY_MODE = 9,
+ /* Array of (u32) supported frequency list among which ACS should choose
+ * best frequency.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_FREQ_LIST = 10,
+ /* Preferred channel list by the driver which will have array of nested
+ * values as per enum qca_wlan_vendor_attr_pcl attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL = 11,
+ /* Array of nested attribute for each channel. It takes attr as defined
+ * in enum qca_wlan_vendor_external_acs_event_chan_info_attr.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO = 12,
+ /* External ACS policy such as PCL mandatory, PCL preferred, etc.
+ * It uses values defined in enum
+ * qca_wlan_vendor_attr_external_acs_policy.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_POLICY = 13,
+ /* Reference RF Operating Parameter (RROP) availability information
+ * (u16). It uses values defined in enum
+ * qca_wlan_vendor_attr_rropavail_info.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_RROPAVAIL_INFO = 14,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_MAX =
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This carries a list of channels
+ * in priority order as decided after ACS operation in userspace.
+ */
+enum qca_wlan_vendor_attr_external_acs_channels {
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_INVALID = 0,
+
+ /* One of reason code (u8) from enum qca_wlan_vendor_acs_select_reason
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON = 1,
+
+ /* Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_BAND,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST = 2,
+ /* This (u8) will hold values of one of enum nl80211_bands */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_BAND = 3,
+ /* Primary channel (u8) */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY = 4,
+ /* Secondary channel (u8) used for HT 40 MHz channels */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY = 5,
+ /* VHT seg0 channel (u8) */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0 = 6,
+ /* VHT seg1 channel (u8) */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1 = 7,
+ /* Channel width (u8). Takes one of enum nl80211_chan_width values. */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH = 8,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX =
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST - 1
+};
+
+enum qca_chip_power_save_failure_reason {
+ /* Indicates if the reason for the failure is due to a protocol
+ * layer/module.
+ */
+ QCA_CHIP_POWER_SAVE_FAILURE_REASON_PROTOCOL = 0,
+ /* Indicates if the reason for the failure is due to a hardware issue.
+ */
+ QCA_CHIP_POWER_SAVE_FAILURE_REASON_HARDWARE = 1,
+};
+
+/**
+ * qca_attr_chip_power_save_failure: Attributes to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE. This carries the requisite
+ * information leading to the power save failure.
+ */
+enum qca_attr_chip_power_save_failure {
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_INVALID = 0,
+ /* Reason to cause the power save failure.
+ * These reasons are represented by
+ * enum qca_chip_power_save_failure_reason.
+ */
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON = 1,
+
+ /* keep last */
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST,
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_MAX =
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_nud_stats_data_pkt_flags: Flag representing the various
+ * data types for which the stats have to get collected.
+ */
+enum qca_wlan_vendor_nud_stats_data_pkt_flags {
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_ARP = 1 << 0,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_DNS = 1 << 1,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_HANDSHAKE = 1 << 2,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_ICMPV4 = 1 << 3,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_ICMPV6 = 1 << 4,
+ /* Used by QCA_ATTR_NUD_STATS_PKT_TYPE only in nud stats get
+ * to represent the stats of respective data type.
+ */
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_SYN = 1 << 5,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_SYN_ACK = 1 << 6,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_ACK = 1 << 7,
+};
+
+enum qca_wlan_vendor_nud_stats_set_data_pkt_info {
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_INVALID = 0,
+ /* Represents the data packet type to be monitored (u32).
+ * Host driver tracks the stats corresponding to each data frame
+ * represented by these flags.
+ * These data packets are represented by
+ * enum qca_wlan_vendor_nud_stats_data_pkt_flags
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_TYPE = 1,
+ /* Name corresponding to the DNS frame for which the respective DNS
+ * stats have to get monitored (string). Max string length 255.
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DNS_DOMAIN_NAME = 2,
+ /* source port on which the respective proto stats have to get
+ * collected (u32).
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_SRC_PORT = 3,
+ /* destination port on which the respective proto stats have to get
+ * collected (u32).
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_PORT = 4,
+ /* IPv4 address for which the destined data packets have to be
+ * monitored. (in network byte order), u32.
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV4 = 5,
+ /* IPv6 address for which the destined data packets have to be
+ * monitored. (in network byte order), 16 bytes array.
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV6 = 6,
+
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_LAST,
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_MAX =
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_nud_stats_set: Attributes to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET. This carries the requisite
+ * information to start/stop the NUD statistics collection.
+ */
+enum qca_attr_nud_stats_set {
+ QCA_ATTR_NUD_STATS_SET_INVALID = 0,
+
+ /* Flag to start/stop the NUD statistics collection.
+ * Start - If included, Stop - If not included
+ */
+ QCA_ATTR_NUD_STATS_SET_START = 1,
+ /* IPv4 address of the default gateway (in network byte order), u32 */
+ QCA_ATTR_NUD_STATS_GW_IPV4 = 2,
+ /* Represents the list of data packet types to be monitored.
+ * Host driver tracks the stats corresponding to each data frame
+ * represented by these flags.
+ * These data packets are represented by
+ * enum qca_wlan_vendor_nud_stats_set_data_pkt_info
+ */
+ QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO = 3,
+
+ /* keep last */
+ QCA_ATTR_NUD_STATS_SET_LAST,
+ QCA_ATTR_NUD_STATS_SET_MAX =
+ QCA_ATTR_NUD_STATS_SET_LAST - 1,
+};
+
+enum qca_attr_nud_data_stats {
+ QCA_ATTR_NUD_DATA_STATS_INVALID = 0,
+ /* Data packet type for which the stats are collected (u32).
+ * Represented by enum qca_wlan_vendor_nud_stats_data_pkt_flags
+ */
+ QCA_ATTR_NUD_STATS_PKT_TYPE = 1,
+ /* Name corresponding to the DNS frame for which the respective DNS
+ * stats are monitored (string). Max string length 255.
+ */
+ QCA_ATTR_NUD_STATS_PKT_DNS_DOMAIN_NAME = 2,
+ /* source port on which the respective proto stats are collected (u32).
+ */
+ QCA_ATTR_NUD_STATS_PKT_SRC_PORT = 3,
+ /* destination port on which the respective proto stats are collected
+ * (u32).
+ */
+ QCA_ATTR_NUD_STATS_PKT_DEST_PORT = 4,
+ /* IPv4 address for which the destined data packets have to be
+ * monitored. (in network byte order), u32.
+ */
+ QCA_ATTR_NUD_STATS_PKT_DEST_IPV4 = 5,
+ /* IPv6 address for which the destined data packets have to be
+ * monitored. (in network byte order), 16 bytes array.
+ */
+ QCA_ATTR_NUD_STATS_PKT_DEST_IPV6 = 6,
+ /* Data packet Request count received from netdev (u32). */
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_FROM_NETDEV = 7,
+ /* Data packet Request count sent to lower MAC from upper MAC (u32). */
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TO_LOWER_MAC = 8,
+ /* Data packet Request count received by lower MAC from upper MAC
+ * (u32)
+ */
+ QCA_ATTR_NUD_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC = 9,
+ /* Data packet Request count successfully transmitted by the device
+ * (u32)
+ */
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TX_SUCCESS = 10,
+ /* Data packet Response count received by lower MAC (u32) */
+ QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC = 11,
+ /* Data packet Response count received by upper MAC (u32) */
+ QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC = 12,
+ /* Data packet Response count delivered to netdev (u32) */
+ QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_TO_NETDEV = 13,
+ /* Data Packet Response count that are dropped out of order (u32) */
+ QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP = 14,
+
+ /* keep last */
+ QCA_ATTR_NUD_DATA_STATS_LAST,
+ QCA_ATTR_NUD_DATA_STATS_MAX =
+ QCA_ATTR_NUD_DATA_STATS_LAST - 1,
+};
+
+/**
+ * qca_attr_nud_stats_get: Attributes to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carries the requisite
+ * NUD statistics collected when queried.
+ */
+enum qca_attr_nud_stats_get {
+ QCA_ATTR_NUD_STATS_GET_INVALID = 0,
+ /* ARP Request count from netdev (u32) */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1,
+ /* ARP Request count sent to lower MAC from upper MAC (u32) */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2,
+ /* ARP Request count received by lower MAC from upper MAC (u32) */
+ QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3,
+ /* ARP Request count successfully transmitted by the device (u32) */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4,
+ /* ARP Response count received by lower MAC (u32) */
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5,
+ /* ARP Response count received by upper MAC (u32) */
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6,
+ /* ARP Response count delivered to netdev (u32) */
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7,
+ /* ARP Response count dropped due to out of order reception (u32) */
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8,
+ /* Flag indicating if the station's link to the AP is active.
+ * Active Link - If included, Inactive link - If not included
+ */
+ QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE = 9,
+ /* Flag indicating if there is any duplicate address detected (DAD).
+ * Yes - If detected, No - If not detected.
+ */
+ QCA_ATTR_NUD_STATS_IS_DAD = 10,
+ /* List of Data packet types for which the stats are requested.
+ * This list does not carry ARP stats as they are done by the
+ * above attributes. Represented by enum qca_attr_nud_data_stats.
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_STATS = 11,
+
+ /* keep last */
+ QCA_ATTR_NUD_STATS_GET_LAST,
+ QCA_ATTR_NUD_STATS_GET_MAX =
+ QCA_ATTR_NUD_STATS_GET_LAST - 1,
+};
+
+enum qca_wlan_btm_candidate_status {
+ QCA_STATUS_ACCEPT = 0,
+ QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED = 1,
+ QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED = 2,
+ QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY = 3,
+ QCA_STATUS_REJECT_LOW_RSSI = 4,
+ QCA_STATUS_REJECT_HIGH_INTERFERENCE = 5,
+ QCA_STATUS_REJECT_UNKNOWN = 6,
+};
+
+enum qca_wlan_vendor_attr_btm_candidate_info {
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_INVALID = 0,
+
+ /* 6-byte MAC address representing the BSSID of transition candidate */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID = 1,
+ /* Unsigned 32-bit value from enum qca_wlan_btm_candidate_status
+ * returned by the driver. It says whether the BSSID provided in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID is acceptable by
+ * the driver, if not it specifies the reason for rejection.
+ * Note that the user-space can overwrite the transition reject reason
+ * codes provided by driver based on more information.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST - 1,
+};
+
+enum qca_attr_trace_level {
+ QCA_ATTR_TRACE_LEVEL_INVALID = 0,
+ /*
+ * Nested array of the following attributes:
+ * QCA_ATTR_TRACE_LEVEL_MODULE,
+ * QCA_ATTR_TRACE_LEVEL_MASK.
+ */
+ QCA_ATTR_TRACE_LEVEL_PARAM = 1,
+ /*
+ * Specific QCA host driver module. Please refer to the QCA host
+ * driver implementation to get the specific module ID.
+ */
+ QCA_ATTR_TRACE_LEVEL_MODULE = 2,
+ /* Different trace level masks represented in the QCA host driver. */
+ QCA_ATTR_TRACE_LEVEL_MASK = 3,
+
+ /* keep last */
+ QCA_ATTR_TRACE_LEVEL_AFTER_LAST,
+ QCA_ATTR_TRACE_LEVEL_MAX =
+ QCA_ATTR_TRACE_LEVEL_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_he_capabilities - IEEE 802.11ax HE capabilities
+ */
+enum qca_wlan_vendor_attr_get_he_capabilities {
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID = 0,
+ /* Whether HE capabilities is supported
+ * (u8 attribute: 0 = not supported, 1 = supported)
+ */
+ QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED = 1,
+ /* HE PHY capabilities, array of 3 u32 values */
+ QCA_WLAN_VENDOR_ATTR_PHY_CAPAB = 2,
+ /* HE MAC capabilities (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_MAC_CAPAB = 3,
+ /* HE MCS map (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_HE_MCS = 4,
+ /* Number of SS (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_NUM_SS = 5,
+ /* RU count (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK = 6,
+ /* PPE threshold data, array of 8 u32 values */
+ QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX =
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_spectral_scan - Spectral scan config parameters
+ */
+enum qca_wlan_vendor_attr_spectral_scan {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INVALID = 0,
+ /* Number of times the chip enters spectral scan mode before
+ * deactivating spectral scans. When set to 0, chip will enter spectral
+ * scan mode continuously. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT = 1,
+ /* Spectral scan period. Period increment resolution is 256*Tclk,
+ * where Tclk = 1/44 MHz (Gmode), 1/40 MHz (Amode). u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD = 2,
+ /* Spectral scan priority. u32 attribute. */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY = 3,
+ /* Number of FFT data points to compute. u32 attribute. */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE = 4,
+ /* Enable targeted gain change before starting the spectral scan FFT.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA = 5,
+ /* Restart a queued spectral scan. u32 attribute. */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA = 6,
+ /* Noise floor reference number for the calculation of bin power.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF = 7,
+ /* Disallow spectral scan triggers after TX/RX packets by setting
+ * this delay value to roughly SIFS time period or greater.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY = 8,
+ /* Number of strong bins (inclusive) per sub-channel, below
+ * which a signal is declared a narrow band tone. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR = 9,
+ /* Specify the threshold over which a bin is declared strong (for
+ * scan bandwidth analysis). u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR = 10,
+ /* Spectral scan report mode. u32 attribute. */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE = 11,
+ /* RSSI report mode, if the ADC RSSI is below
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR,
+ * then FFTs will not trigger, but timestamps and summaries get
+ * reported. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE = 12,
+ /* ADC RSSI must be greater than or equal to this threshold (signed dB)
+ * to ensure spectral scan reporting with normal error code.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR = 13,
+ /* Format of frequency bin magnitude for spectral scan triggered FFTs:
+ * 0: linear magnitude, 1: log magnitude (20*log10(lin_mag)).
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT = 14,
+ /* Format of FFT report to software for spectral scan triggered FFTs.
+ * 0: No FFT report (only spectral scan summary report)
+ * 1: 2-dword summary of metrics for each completed FFT + spectral scan
+ * report
+ * 2: 2-dword summary of metrics for each completed FFT + 1x-oversampled
+ * bins (in-band) per FFT + spectral scan summary report
+ * 3: 2-dword summary of metrics for each completed FFT + 2x-oversampled
+ * bins (all) per FFT + spectral scan summary report
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE = 15,
+ /* Number of LSBs to shift out in order to scale the FFT bins.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE = 16,
+ /* Set to 1 (with spectral_scan_pwr_format=1), to report bin magnitudes
+ * in dBm power. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ = 17,
+ /* Per chain enable mask to select input ADC for search FFT.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK = 18,
+ /* An unsigned 64-bit integer provided by host driver to identify the
+ * spectral scan request. This attribute is included in the scan
+ * response message for @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START
+ * and used as an attribute in
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP to identify the
+ * specific scan to be stopped.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE = 19,
+ /* Skip interval for FFT reports. u32 attribute */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD = 20,
+ /* Set to report only one set of FFT results.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT = 21,
+ /* Debug level for spectral module in driver.
+ * 0 : Verbosity level 0
+ * 1 : Verbosity level 1
+ * 2 : Verbosity level 2
+ * 3 : Matched filterID display
+ * 4 : One time dump of FFT report
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL = 22,
+ /* Type of spectral scan request. u32 attribute.
+ * It uses values defined in enum
+ * qca_wlan_vendor_attr_spectral_scan_request_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE = 23,
+
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_spectral_diag_stats - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS.
+ */
+enum qca_wlan_vendor_attr_spectral_diag_stats {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_INVALID = 0,
+ /* Number of spectral TLV signature mismatches.
+ * u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SIG_MISMATCH = 1,
+ /* Number of spectral phyerror events with insufficient length when
+ * parsing for secondary 80 search FFT report. u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SEC80_SFFT_INSUFFLEN = 2,
+ /* Number of spectral phyerror events without secondary 80
+ * search FFT report. u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_NOSEC80_SFFT = 3,
+ /* Number of spectral phyerror events with vht operation segment 1 id
+ * mismatches in search fft report. u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG1ID_MISMATCH = 4,
+ /* Number of spectral phyerror events with vht operation segment 2 id
+ * mismatches in search fft report. u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG2ID_MISMATCH = 5,
+
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_MAX =
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_spectral_cap - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO.
+ */
+enum qca_wlan_vendor_attr_spectral_cap {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_INVALID = 0,
+ /* Flag attribute to indicate phydiag capability */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_PHYDIAG = 1,
+ /* Flag attribute to indicate radar detection capability */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RADAR = 2,
+ /* Flag attribute to indicate spectral capability */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_SPECTRAL = 3,
+ /* Flag attribute to indicate advanced spectral capability */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_ADVANCED_SPECTRAL = 4,
+ /* Spectral hardware generation. u32 attribute.
+ * It uses values defined in enum
+ * qca_wlan_vendor_spectral_scan_cap_hw_gen.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN = 5,
+ /* Spectral bin scaling formula ID. u16 attribute.
+ * It uses values defined in enum
+ * qca_wlan_vendor_spectral_scan_cap_formula_id.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID = 6,
+ /* Spectral bin scaling param - low level offset.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_LOW_LEVEL_OFFSET = 7,
+ /* Spectral bin scaling param - high level offset.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HIGH_LEVEL_OFFSET = 8,
+ /* Spectral bin scaling param - RSSI threshold.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RSSI_THR = 9,
+ /* Spectral bin scaling param - default AGC max gain.
+ * u8 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
+
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_spectral_scan_status - used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS.
+ */
+enum qca_wlan_vendor_attr_spectral_scan_status {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_INVALID = 0,
+ /* Flag attribute to indicate whether spectral scan is enabled */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ENABLED = 1,
+ /* Flag attribute to indicate whether spectral scan is in progress*/
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ACTIVE = 2,
+
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MAX =
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_spectral_scan_request_type: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START. This represents the
+ * spectral scan request types.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN_AND_CONFIG: Request to
+ * set the spectral parameters and start scan.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN: Request to
+ * only set the spectral parameters.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_CONFIG: Request to
+ * only start the spectral scan.
+ */
+enum qca_wlan_vendor_attr_spectral_scan_request_type {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN_AND_CONFIG,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_CONFIG,
+};
+
+/**
+ * qca_wlan_vendor_spectral_scan_cap_hw_gen: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO. This represents the
+ * spectral hardware generation.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_1: generation 1
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_2: generation 2
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_3: generation 3
+ */
+enum qca_wlan_vendor_spectral_scan_cap_hw_gen {
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_1 = 0,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_2 = 1,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_3 = 2,
+};
+
+enum qca_wlan_vendor_tos {
+ QCA_WLAN_VENDOR_TOS_BK = 0,
+ QCA_WLAN_VENDOR_TOS_BE = 1,
+ QCA_WLAN_VENDOR_TOS_VI = 2,
+ QCA_WLAN_VENDOR_TOS_VO = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_active_tos - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ACTIVE_TOS.
+ */
+enum qca_wlan_vendor_attr_active_tos {
+ QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_INVALID = 0,
+ /* Type Of Service - Represented by qca_wlan_vendor_tos */
+ QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS = 1,
+ /* Flag attribute representing the start (attribute included) or stop
+ * (attribute not included) of the respective TOS.
+ */
+ QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START = 2,
+};
+
+enum qca_wlan_vendor_hang_reason {
+ /* Unspecified reason */
+ QCA_WLAN_HANG_REASON_UNSPECIFIED = 0,
+ /* No Map for the MAC entry for the received frame */
+ QCA_WLAN_HANG_RX_HASH_NO_ENTRY_FOUND = 1,
+ /* Peer deletion timeout happened */
+ QCA_WLAN_HANG_PEER_DELETION_TIMEDOUT = 2,
+ /* Peer unmap timeout */
+ QCA_WLAN_HANG_PEER_UNMAP_TIMEDOUT = 3,
+ /* Scan request timed out */
+ QCA_WLAN_HANG_SCAN_REQ_EXPIRED = 4,
+ /* Consecutive Scan attempt failures */
+ QCA_WLAN_HANG_SCAN_ATTEMPT_FAILURES = 5,
+ /* Unable to get the message buffer */
+ QCA_WLAN_HANG_GET_MSG_BUFF_FAILURE = 6,
+ /* Current command processing is timedout */
+ QCA_WLAN_HANG_ACTIVE_LIST_TIMEOUT = 7,
+ /* Timeout for an ACK from FW for suspend request */
+ QCA_WLAN_HANG_SUSPEND_TIMEOUT = 8,
+ /* Timeout for an ACK from FW for resume request */
+ QCA_WLAN_HANG_RESUME_TIMEOUT = 9,
+ /* Transmission timeout for consecutive data frames */
+ QCA_WLAN_HANG_TRANSMISSIONS_TIMEOUT = 10,
+ /* Timeout for the TX completion status of data frame */
+ QCA_WLAN_HANG_TX_COMPLETE_TIMEOUT = 11,
+ /* DXE failure for TX/RX, DXE resource unavailability */
+ QCA_WLAN_HANG_DXE_FAILURE = 12,
+ /* WMI pending commands exceed the maximum count */
+ QCA_WLAN_HANG_WMI_EXCEED_MAX_PENDING_CMDS = 13,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_hang - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_HANG.
+ */
+enum qca_wlan_vendor_attr_hang {
+ QCA_WLAN_VENDOR_ATTR_HANG_INVALID = 0,
+ /* Reason for the hang - u32 attribute with a value from enum
+ * qca_wlan_vendor_hang_reason.
+ */
+ QCA_WLAN_VENDOR_ATTR_HANG_REASON = 1,
+
+ QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HANG_MAX =
+ QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_flush_pending - Attributes for
+ * flushing pending traffic in firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_ADDR: Configure peer MAC address.
+ * @QCA_WLAN_VENDOR_ATTR_AC: Configure access category of the pending
+ * packets. It is u8 value with bit 0~3 represent AC_BE, AC_BK,
+ * AC_VI, AC_VO respectively. Set the corresponding bit to 1 to
+ * flush packets with access category.
+ */
+enum qca_wlan_vendor_attr_flush_pending {
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_PEER_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_AC = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX =
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_spectral_scan_cap_formula_id: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID in the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO. This represents the
+ * Spectral bin scaling formula ID.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_NO_SCALING: No scaling
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_AGC_GAIN_RSSI_CORR_BASED: AGC gain
+ * and RSSI threshold based formula.
+ */
+enum qca_wlan_vendor_spectral_scan_cap_formula_id {
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_NO_SCALING = 0,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_AGC_GAIN_RSSI_CORR_BASED = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rropavail_info - Specifies whether Representative
+ * RF Operating Parameter (RROP) information is available, and if so, at which
+ * point in the application-driver interaction sequence it can be retrieved by
+ * the application from the driver. This point may vary by architecture and
+ * other factors. This is a u16 value.
+ */
+enum qca_wlan_vendor_attr_rropavail_info {
+ /* RROP information is unavailable. */
+ QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_UNAVAILABLE,
+ /* RROP information is available and the application can retrieve the
+ * information after receiving an QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS
+ * event from the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_EXTERNAL_ACS_START,
+ /* RROP information is available only after a vendor specific scan
+ * (requested using QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN) has
+ * successfully completed. The application can retrieve the information
+ * after receiving the QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE event from
+ * the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_VSCAN_END,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rrop_info - Specifies vendor specific
+ * Representative RF Operating Parameter (RROP) information. It is sent for the
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO. This information is
+ * intended for use by external Auto Channel Selection applications. It provides
+ * guidance values for some RF parameters that are used by the system during
+ * operation. These values could vary by channel, band, radio, and so on.
+ */
+enum qca_wlan_vendor_attr_rrop_info {
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_INVALID = 0,
+
+ /* Representative Tx Power List (RTPL) which has an array of nested
+ * values as per attributes in enum qca_wlan_vendor_attr_rtplinst.
+ */
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_RTPL = 1,
+
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rtplinst - Specifies attributes for individual list
+ * entry instances in the Representative Tx Power List (RTPL). It provides
+ * simplified power values intended for helping external Auto channel Selection
+ * applications compare potential Tx power performance between channels, other
+ * operating conditions remaining identical. These values are not necessarily
+ * the actual Tx power values that will be used by the system. They are also not
+ * necessarily the max or average values that will be used. Instead, they are
+ * relative, summarized keys for algorithmic use computed by the driver or
+ * underlying firmware considering a number of vendor specific factors.
+ */
+enum qca_wlan_vendor_attr_rtplinst {
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_INVALID = 0,
+
+ /* Primary channel number (u8) */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY = 1,
+ /* Representative Tx power in dBm (s32) with emphasis on throughput. */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_THROUGHPUT = 2,
+ /* Representative Tx power in dBm (s32) with emphasis on range. */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_RANGE = 3,
+
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_MAX =
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_latency_level - Level for
+ * wlan latency module.
+ *
+ * There will be various of Wi-Fi functionality like scan/roaming/adaptive
+ * power saving which would causing data exchange out of service, this
+ * would be a big impact on latency. For latency sensitive applications over
+ * Wi-Fi are intolerant to such operations and thus would configure them
+ * to meet their respective needs. It is well understood by such applications
+ * that altering the default behavior would degrade the Wi-Fi functionality
+ * w.r.t the above pointed WLAN operations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL:
+ * Default WLAN operation level which throughput orientated.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE:
+ * Use moderate level to improve latency by limit scan duration.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW:
+ * Use low latency level to benifit application like concurrent
+ * downloading or video streaming via constraint scan/adaptive PS.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW:
+ * Use ultra low latency level to benefit for gaming/voice
+ * application via constraint scan/roaming/adaptive PS.
+ */
+enum qca_wlan_vendor_attr_config_latency_level {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL = 1,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE = 2,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW = 3,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_wlan_mac - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO.
+ */
+enum qca_wlan_vendor_attr_mac {
+ QCA_WLAN_VENDOR_ATTR_MAC_INVALID = 0,
+
+ /* MAC mode info list which has an array of nested values as
+ * per attributes in enum qca_wlan_vendor_attr_mac_mode_info.
+ */
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MAC_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MAC_MAX =
+ QCA_WLAN_VENDOR_ATTR_MAC_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mac_iface_info - Information of the connected
+ * Wi-Fi netdev interface on a respective MAC.
+ * Used by the attribute QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO.
+ */
+enum qca_wlan_vendor_attr_mac_iface_info {
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_INVALID = 0,
+ /* Wi-Fi netdev's interface index (u32) */
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX = 1,
+ /* Associated frequency in MHz of the connected Wi-Fi interface (u32) */
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mac_info - Points to MAC the information.
+ * Used by the attribute QCA_WLAN_VENDOR_ATTR_MAC_INFO of the
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO.
+ */
+enum qca_wlan_vendor_attr_mac_info {
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_INVALID = 0,
+ /* Hardware MAC ID associated for the MAC (u32) */
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID = 1,
+ /* Band supported by the MAC at a given point.
+ * This is a u32 bitmask of BIT(NL80211_BAND_*) as described in %enum
+ * nl80211_band.
+ */
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND = 2,
+ /* Refers to list of WLAN netdev interfaces associated with this MAC.
+ * Represented by enum qca_wlan_vendor_attr_mac_iface_info.
+ */
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_logger_features - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET.
+ */
+enum qca_wlan_vendor_attr_get_logger_features {
+ QCA_WLAN_VENDOR_ATTR_LOGGER_INVALID = 0,
+ /* Unsigned 32-bit enum value of wifi_logger_supported_features */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED = 1,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LOGGER_MAX =
+ QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST - 1,
+};
+
+/**
+ * enum wifi_logger_supported_features - Values for supported logger features
+ */
+enum wifi_logger_supported_features {
+ WIFI_LOGGER_MEMORY_DUMP_FEATURE = (1 << (0)),
+ WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_FEATURE = (1 << (1)),
+ WIFI_LOGGER_CONNECT_EVENT_FEATURE = (1 << (2)),
+ WIFI_LOGGER_POWER_EVENT_FEATURE = (1 << (3)),
+ WIFI_LOGGER_WAKE_LOCK_FEATURE = (1 << (4)),
+ WIFI_LOGGER_VERBOSE_FEATURE = (1 << (5)),
+ WIFI_LOGGER_WATCHDOG_TIMER_FEATURE = (1 << (6)),
+ WIFI_LOGGER_DRIVER_DUMP_FEATURE = (1 << (7)),
+ WIFI_LOGGER_PACKET_FATE_FEATURE = (1 << (8)),
+};
+
+/**
+ * enum qca_wlan_tdls_caps_features_supported - Values for TDLS get
+ * capabilities features
+ */
+enum qca_wlan_tdls_caps_features_supported {
+ WIFI_TDLS_SUPPORT = (1 << (0)),
+ WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT = (1 << (1)),
+ WIFI_TDLS_OFFCHANNEL_SUPPORT = (1 << (2))
+};
+
+/**
+ * enum qca_wlan_vendor_attr_tdls_get_capabilities - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES.
+ */
+enum qca_wlan_vendor_attr_tdls_get_capabilities {
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_INVALID = 0,
+ /* Indicates the max concurrent sessions */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS,
+ /* Indicates the support for features */
+ /* Unsigned 32-bit bitmap qca_wlan_tdls_caps_features_supported
+ */
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX =
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_offloaded_packets_sending_control - Offload packets control
+ * command used as value for the attribute
+ * QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL.
+ */
+enum qca_wlan_offloaded_packets_sending_control {
+ QCA_WLAN_OFFLOADED_PACKETS_SENDING_CONTROL_INVALID = 0,
+ QCA_WLAN_OFFLOADED_PACKETS_SENDING_START,
+ QCA_WLAN_OFFLOADED_PACKETS_SENDING_STOP
+};
+
+/**
+ * enum qca_wlan_vendor_attr_offloaded_packets - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS.
+ */
+enum qca_wlan_vendor_attr_offloaded_packets {
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_INVALID = 0,
+ /* Takes valid value from the enum
+ * qca_wlan_offloaded_packets_sending_control
+ * Unsigned 32-bit value
+ */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID,
+ /* array of u8 len: Max packet size */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA,
+ /* 6-byte MAC address used to represent source MAC address */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR,
+ /* 6-byte MAC address used to represent destination MAC address */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR,
+ /* Unsigned 32-bit value, in milli seconds */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD,
+ /* This optional unsigned 16-bit attribute is used for specifying
+ * ethernet protocol type. If not specified ethertype defaults to IPv4.
+ */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_ETHER_PROTO_TYPE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX =
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_rssi_monitoring_control - RSSI control commands used as values
+ * by the attribute QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL.
+ */
+enum qca_wlan_rssi_monitoring_control {
+ QCA_WLAN_RSSI_MONITORING_CONTROL_INVALID = 0,
+ QCA_WLAN_RSSI_MONITORING_START,
+ QCA_WLAN_RSSI_MONITORING_STOP,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rssi_monitoring - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI.
+ */
+enum qca_wlan_vendor_attr_rssi_monitoring {
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_INVALID = 0,
+ /* Takes valid value from the enum
+ * qca_wlan_rssi_monitoring_control
+ * Unsigned 32-bit value enum qca_wlan_rssi_monitoring_control
+ */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
+ /* Signed 8-bit value in dBm */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
+ /* Signed 8-bit value in dBm */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
+ /* attributes to be used/received in callback */
+ /* 6-byte MAC address used to represent current BSSID MAC address */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
+ /* Signed 8-bit value indicating the current RSSI */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX =
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ndp_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NDP.
+ */
+enum qca_wlan_vendor_attr_ndp_params {
+ QCA_WLAN_VENDOR_ATTR_NDP_PARAM_INVALID = 0,
+ /* Unsigned 32-bit value
+ * enum of sub commands values in qca_wlan_ndp_sub_cmd
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
+ /* Unsigned 16-bit value */
+ QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
+ /* NL attributes for data used NDP SUB cmds */
+ /* Unsigned 32-bit value indicating a service info */
+ QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID,
+ /* Unsigned 32-bit value; channel frequency in MHz */
+ QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL,
+ /* Interface Discovery MAC address. An array of 6 Unsigned int8 */
+ QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR,
+ /* Interface name on which NDP is being created */
+ QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR,
+ /* Unsigned 32-bit value for security */
+ /* CONFIG_SECURITY is deprecated, use NCS_SK_TYPE/PMK/SCID instead */
+ QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY,
+ /* Unsigned 32-bit value for QoS */
+ QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS,
+ /* Array of u8: len = QCA_WLAN_VENDOR_ATTR_NAN_DP_APP_INFO_LEN */
+ QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO,
+ /* Unsigned 32-bit value for NDP instance Id */
+ QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID,
+ /* Array of instance Ids */
+ QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY,
+ /* Unsigned 32-bit value for initiator/responder NDP response code
+ * accept/reject
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE,
+ /* NDI MAC address. An array of 6 Unsigned int8 */
+ QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR,
+ /* Unsigned 32-bit value errors types returned by driver
+ * The wifi_nan.h in AOSP project platform/hardware/libhardware_legacy
+ * NanStatusType includes these values.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE,
+ /* Unsigned 32-bit value error values returned by driver
+ * The nan_i.h in AOSP project platform/hardware/qcom/wlan
+ * NanInternalStatusType includes these values.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE,
+ /* Unsigned 32-bit value for Channel setup configuration
+ * The wifi_nan.h in AOSP project platform/hardware/libhardware_legacy
+ * NanDataPathChannelCfg includes these values.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG,
+ /* Unsigned 32-bit value for Cipher Suite Shared Key Type */
+ QCA_WLAN_VENDOR_ATTR_NDP_CSID,
+ /* Array of u8: len = NAN_PMK_INFO_LEN 32 bytes */
+ QCA_WLAN_VENDOR_ATTR_NDP_PMK,
+ /* Security Context Identifier that contains the PMKID
+ * Array of u8: len = NAN_SCID_BUF_LEN 1024 bytes
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_SCID,
+ /* Array of u8: len = NAN_SECURITY_MAX_PASSPHRASE_LEN 63 bytes */
+ QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE,
+ /* Array of u8: len = NAN_MAX_SERVICE_NAME_LEN 255 bytes */
+ QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME,
+ /* Unsigned 32-bit bitmap indicating schedule update
+ * BIT_0: NSS Update
+ * BIT_1: Channel list update
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON,
+ /* Unsigned 32-bit value for NSS */
+ QCA_WLAN_VENDOR_ATTR_NDP_NSS,
+ /* Unsigned 32-bit value for NUMBER NDP CHANNEL */
+ QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS,
+ /* Unsigned 32-bit value for CHANNEL BANDWIDTH
+ * 0:20 MHz, 1:40 MHz, 2:80 MHz, 3:160 MHz
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH,
+ /* Array of channel/band width */
+ QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO,
+ /* IPv6 address used by NDP (in network byte order), 16 bytes array.
+ * This attribute is used and optional for ndp request, ndp response,
+ * ndp indication, and ndp confirm.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR = 27,
+ /* Unsigned 16-bit value indicating transport port used by NDP.
+ * This attribute is used and optional for ndp response, ndp indication,
+ * and ndp confirm.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT = 28,
+ /* Unsigned 8-bit value indicating protocol used by NDP and assigned by
+ * the Internet Assigned Numbers Authority (IANA) as per:
+ * https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
+ * This attribute is used and optional for ndp response, ndp indication,
+ * and ndp confirm.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL = 29,
+ /* Unsigned 8-bit value indicating if NDP remote peer supports NAN NDPE.
+ * 1:support 0:not support
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_NDPE_SUPPORT = 30,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX =
+ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_ndp_sub_cmd {
+ QCA_WLAN_VENDOR_ATTR_NDP_INVALID = 0,
+ /* Command to create a NAN data path interface */
+ QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE = 1,
+ /* Command to delete a NAN data path interface */
+ QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE = 2,
+ /* Command to initiate a NAN data path session */
+ QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST = 3,
+ /* Command to notify if the NAN data path session was sent */
+ QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE = 4,
+ /* Command to respond to NAN data path session */
+ QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST = 5,
+ /* Command to notify on the responder about the response */
+ QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE = 6,
+ /* Command to initiate a NAN data path end */
+ QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST = 7,
+ /* Command to notify the if end request was sent */
+ QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE = 8,
+ /* Command to notify the peer about the end request */
+ QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND = 9,
+ /* Command to confirm the NAN data path session is complete */
+ QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND = 10,
+ /* Command to indicate the peer about the end request being received */
+ QCA_WLAN_VENDOR_ATTR_NDP_END_IND = 11,
+ /* Command to indicate the peer of schedule update */
+ QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_IND = 12
+};
+
+/**
+ * enum qca_wlan_vendor_attr_nd_offload - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD.
+ */
+enum qca_wlan_vendor_attr_nd_offload {
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_INVALID = 0,
+ /* Flag to set Neighbour Discovery offload */
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG,
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX =
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST - 1,
+};
+
+/**
+ * enum packet_filter_sub_cmd - Packet filter sub commands
+ */
+enum packet_filter_sub_cmd {
+ /**
+ * Write packet filter program and/or data. The driver/firmware should
+ * disable APF before writing into local buffer and re-enable APF after
+ * writing is done.
+ */
+ QCA_WLAN_SET_PACKET_FILTER = 1,
+ /* Get packet filter feature capabilities from driver */
+ QCA_WLAN_GET_PACKET_FILTER = 2,
+ /**
+ * Write packet filter program and/or data. User space will send the
+ * %QCA_WLAN_DISABLE_PACKET_FILTER command before issuing this command
+ * and will send the %QCA_WLAN_ENABLE_PACKET_FILTER afterwards. The key
+ * difference from that %QCA_WLAN_SET_PACKET_FILTER is the control over
+ * enable/disable is given to user space with this command. Also,
+ * user space sends the length of program portion in the buffer within
+ * %QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH.
+ */
+ QCA_WLAN_WRITE_PACKET_FILTER = 3,
+ /* Read packet filter program and/or data */
+ QCA_WLAN_READ_PACKET_FILTER = 4,
+ /* Enable APF feature */
+ QCA_WLAN_ENABLE_PACKET_FILTER = 5,
+ /* Disable APF feature */
+ QCA_WLAN_DISABLE_PACKET_FILTER = 6,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_packet_filter - BPF control commands used by
+ * vendor QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER.
+ */
+enum qca_wlan_vendor_attr_packet_filter {
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID = 0,
+ /* Unsigned 32-bit enum passed using packet_filter_sub_cmd */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
+ /* Unsigned 32-bit value indicating the packet filter version */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION,
+ /* Unsigned 32-bit value indicating the packet filter id */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID,
+ /**
+ * Unsigned 32-bit value indicating the packet filter size including
+ * program + data.
+ */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE,
+ /* Unsigned 32-bit value indicating the packet filter current offset */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET,
+ /* Program and/or data in bytes */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM,
+ /* Unsigned 32-bit value of the length of the program section in packet
+ * filter buffer.
+ */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX =
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_drv_info - WLAN driver info used by vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE.
+ */
+enum qca_wlan_vendor_drv_info {
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_INVALID = 0,
+ /* Maximum Message size info between firmware & HOST
+ * Unsigned 32-bit value
+ */
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_wake_stats - Wake lock stats used by vendor
+ * command QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS.
+ */
+enum qca_wlan_vendor_attr_wake_stats {
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_INVALID = 0,
+ /* Unsigned 32-bit value indicating the total count of wake event */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_CMD_EVENT_WAKE,
+ /* Array of individual wake count, each index representing wake reason
+ */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_CMD_EVENT_WAKE_CNT_PTR,
+ /* Unsigned 32-bit value representing wake count array */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_CMD_EVENT_WAKE_CNT_SZ,
+ /* Unsigned 32-bit total wake count value of driver/fw */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_DRIVER_FW_LOCAL_WAKE,
+ /* Array of wake stats of driver/fw */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_PTR,
+ /* Unsigned 32-bit total wake count value of driver/fw */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_SZ,
+ /* Unsigned 32-bit total wake count value of packets received */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_RX_DATA_WAKE,
+ /* Unsigned 32-bit wake count value unicast packets received */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_UNICAST_CNT,
+ /* Unsigned 32-bit wake count value multicast packets received */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_MULTICAST_CNT,
+ /* Unsigned 32-bit wake count value broadcast packets received */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_BROADCAST_CNT,
+ /* Unsigned 32-bit wake count value of ICMP packets */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP_PKT,
+ /* Unsigned 32-bit wake count value of ICMP6 packets */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_PKT,
+ /* Unsigned 32-bit value ICMP6 router advertisement */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RA,
+ /* Unsigned 32-bit value ICMP6 neighbor advertisement */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NA,
+ /* Unsigned 32-bit value ICMP6 neighbor solicitation */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NS,
+ /* Unsigned 32-bit wake count value of receive side ICMP4 multicast */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP4_RX_MULTICAST_CNT,
+ /* Unsigned 32-bit wake count value of receive side ICMP6 multicast */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RX_MULTICAST_CNT,
+ /* Unsigned 32-bit wake count value of receive side multicast */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_OTHER_RX_MULTICAST_CNT,
+ /* Unsigned 32-bit wake count value of a given RSSI breach */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RSSI_BREACH_CNT,
+ /* Unsigned 32-bit wake count value of low RSSI */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_LOW_RSSI_CNT,
+ /* Unsigned 32-bit value GSCAN count */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_GSCAN_CNT,
+ /* Unsigned 32-bit value PNO complete count */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_PNO_COMPLETE_CNT,
+ /* Unsigned 32-bit value PNO match count */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_PNO_MATCH_CNT,
+ /* keep last */
+ QCA_WLAN_VENDOR_GET_WAKE_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX =
+ QCA_WLAN_VENDOR_GET_WAKE_STATS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_thermal_cmd - Vendor subcmd attributes to set
+ * cmd value. Used for NL attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
+ */
+enum qca_wlan_vendor_attr_thermal_cmd {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_INVALID = 0,
+ /* The value of command, driver will implement different operations
+ * according to this value. It uses values defined in
+ * enum qca_wlan_vendor_attr_thermal_cmd_type.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX =
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST - 1
+};
+
+/**
+ * qca_wlan_vendor_attr_thermal_cmd_type: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD. This represents the
+ * thermal command types sent to driver.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS: Request to
+ * get thermal shutdown configuration parameters for display. Parameters
+ * responded from driver are defined in
+ * enum qca_wlan_vendor_attr_get_thermal_params_rsp.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE: Request to
+ * get temperature. Host should respond with a temperature data. It is defined
+ * in enum qca_wlan_vendor_attr_thermal_get_temperature.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND: Request to execute thermal
+ * suspend action.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME: Request to execute thermal
+ * resume action.
+ */
+enum qca_wlan_vendor_attr_thermal_cmd_type {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_thermal_get_temperature - vendor subcmd attributes
+ * to get chip temperature by user.
+ * enum values are used for NL attributes for data used by
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE command for data used
+ * by QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
+ */
+enum qca_wlan_vendor_attr_thermal_get_temperature {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_INVALID = 0,
+ /* Temperature value (degree Celsius) from driver.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_DATA,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_MAX =
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_thermal_params_rsp - vendor subcmd attributes
+ * to get configuration parameters of thermal shutdown feature. Enum values are
+ * used by QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS command for data
+ * used by QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
+ */
+enum qca_wlan_vendor_attr_get_thermal_params_rsp {
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_INVALID = 0,
+ /* Indicate if the thermal shutdown feature is enabled.
+ * NLA_FLAG attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SHUTDOWN_EN,
+ /* Indicate if the auto mode is enabled.
+ * Enable: Driver triggers the suspend/resume action.
+ * Disable: User space triggers the suspend/resume action.
+ * NLA_FLAG attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SHUTDOWN_AUTO_EN,
+ /* Thermal resume threshold (degree Celsius). Issue the resume command
+ * if the temperature value is lower than this threshold.
+ * u16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_RESUME_THRESH,
+ /* Thermal warning threshold (degree Celsius). FW reports temperature
+ * to driver if it's higher than this threshold.
+ * u16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_WARNING_THRESH,
+ /* Thermal suspend threshold (degree Celsius). Issue the suspend command
+ * if the temperature value is higher than this threshold.
+ * u16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SUSPEND_THRESH,
+ /* FW reports temperature data periodically at this interval (ms).
+ * u16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SAMPLE_RATE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_MAX =
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_thermal_event - vendor subcmd attributes to
+ * report thermal events from driver to user space.
+ * enum values are used for NL attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_thermal_event {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_INVALID = 0,
+ /* Temperature value (degree Celsius) from driver.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_TEMPERATURE,
+ /* Indication of resume completion from power save mode.
+ * NLA_FLAG attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_RESUME_COMPLETE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_MAX =
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST - 1,
+};
+
+/**
+ * enum he_fragmentation_val - HE fragmentation support values
+ * Indicates level of dynamic fragmentation that is supported by
+ * a STA as a recipient.
+ * HE fragmentation values are defined in IEEE P802.11ax/D2.0, 9.4.2.237.2
+ * (HE MAC Capabilities Information field) and are used in HE Capabilities
+ * element to advertise the support. These values are validated in the driver
+ * to check the device capability and advertised in the HE Capabilities
+ * element. These values are used to configure testbed device to allow the
+ * advertised hardware capabilities to be downgraded for testing purposes.
+ *
+ * @HE_FRAG_DISABLE: no support for dynamic fragmentation
+ * @HE_FRAG_LEVEL1: support for dynamic fragments that are
+ * contained within an MPDU or S-MPDU, no support for dynamic fragments
+ * within an A-MPDU that is not an S-MPDU.
+ * @HE_FRAG_LEVEL2: support for dynamic fragments that are
+ * contained within an MPDU or S-MPDU and support for up to one dynamic
+ * fragment for each MSDU, each A-MSDU if supported by the recipient, and
+ * each MMPDU within an A-MPDU or multi-TID A-MPDU that is not an
+ * MPDU or S-MPDU.
+ * @HE_FRAG_LEVEL3: support for dynamic fragments that are
+ * contained within an MPDU or S-MPDU and support for multiple dynamic
+ * fragments for each MSDU and for each A-MSDU if supported by the
+ * recipient within an A-MPDU or multi-TID AMPDU and up to one dynamic
+ * fragment for each MMPDU in a multi-TID A-MPDU that is not an S-MPDU.
+ */
+enum he_fragmentation_val {
+ HE_FRAG_DISABLE,
+ HE_FRAG_LEVEL1,
+ HE_FRAG_LEVEL2,
+ HE_FRAG_LEVEL3,
+};
+
+/**
+ * enum he_mcs_config - HE MCS support configuration
+ *
+ * Configures the HE Tx/Rx MCS map in HE capability IE for given bandwidth.
+ * These values are used in driver to configure the HE MCS map to advertise
+ * Tx/Rx MCS map in HE capability and these values are applied for all the
+ * streams supported by the device. To configure MCS for different bandwidths,
+ * vendor command needs to be sent using this attribute with appropriate value.
+ * For example, to configure HE_80_MCS_0_7, send vendor command using HE MCS
+ * attribute with HE_80_MCS0_7. And to configure HE MCS for HE_160_MCS0_11
+ * send this command using HE MCS config attribute with value HE_160_MCS0_11.
+ * These values are used to configure testbed device to allow the advertised
+ * hardware capabilities to be downgraded for testing purposes. The enum values
+ * are defined such that BIT[1:0] indicates the MCS map value. Values 3,7 and
+ * 11 are not used as BIT[1:0] value is 3 which is used to disable MCS map.
+ * These values are validated in the driver before setting the MCS map and
+ * driver returns error if the input is other than these enum values.
+ *
+ * @HE_80_MCS0_7: support for HE 80/40/20 MHz MCS 0 to 7
+ * @HE_80_MCS0_9: support for HE 80/40/20 MHz MCS 0 to 9
+ * @HE_80_MCS0_11: support for HE 80/40/20 MHz MCS 0 to 11
+ * @HE_160_MCS0_7: support for HE 160 MHz MCS 0 to 7
+ * @HE_160_MCS0_9: support for HE 160 MHz MCS 0 to 9
+ * @HE_160_MCS0_11: support for HE 160 MHz MCS 0 to 11
+ * @HE_80P80_MCS0_7: support for HE 80p80 MHz MCS 0 to 7
+ * @HE_80P80_MCS0_9: support for HE 80p80 MHz MCS 0 to 9
+ * @HE_80P80_MCS0_11: support for HE 80p80 MHz MCS 0 to 11
+ */
+enum he_mcs_config {
+ HE_80_MCS0_7 = 0,
+ HE_80_MCS0_9 = 1,
+ HE_80_MCS0_11 = 2,
+ HE_160_MCS0_7 = 4,
+ HE_160_MCS0_9 = 5,
+ HE_160_MCS0_11 = 6,
+ HE_80P80_MCS0_7 = 8,
+ HE_80P80_MCS0_9 = 9,
+ HE_80P80_MCS0_11 = 10,
+};
+
+/**
+ * enum qca_wlan_ba_session_config - BA session configuration
+ *
+ * Indicates the configuration values for BA session configuration attribute.
+ *
+ * @QCA_WLAN_ADD_BA: Establish a new BA session with given configuration.
+ * @QCA_WLAN_DELETE_BA: Delete the existing BA session for given TID.
+ */
+enum qca_wlan_ba_session_config {
+ QCA_WLAN_ADD_BA = 1,
+ QCA_WLAN_DELETE_BA = 2,
+};
+
+/**
+ * enum qca_wlan_ac_type - Access category type
+ *
+ * Indicates the access category type value.
+ *
+ * @QCA_WLAN_AC_BE: BE access category
+ * @QCA_WLAN_AC_BK: BK access category
+ * @QCA_WLAN_AC_VI: VI access category
+ * @QCA_WLAN_AC_VO: VO access category
+ * @QCA_WLAN_AC_ALL: All ACs
+ */
+enum qca_wlan_ac_type {
+ QCA_WLAN_AC_BE = 0,
+ QCA_WLAN_AC_BK = 1,
+ QCA_WLAN_AC_VI = 2,
+ QCA_WLAN_AC_VO = 3,
+ QCA_WLAN_AC_ALL = 4,
+};
+
+/**
+ * enum qca_wlan_he_ltf_cfg - HE LTF configuration
+ *
+ * Indicates the HE LTF configuration value.
+ *
+ * @QCA_WLAN_HE_LTF_AUTO: HE-LTF is automatically set to the mandatory HE-LTF,
+ * based on the GI setting
+ * @QCA_WLAN_HE_LTF_1X: 1X HE LTF is 3.2us LTF
+ * @QCA_WLAN_HE_LTF_2X: 2X HE LTF is 6.4us LTF
+ * @QCA_WLAN_HE_LTF_4X: 4X HE LTF is 12.8us LTF
+ */
+enum qca_wlan_he_ltf_cfg {
+ QCA_WLAN_HE_LTF_AUTO = 0,
+ QCA_WLAN_HE_LTF_1X = 1,
+ QCA_WLAN_HE_LTF_2X = 2,
+ QCA_WLAN_HE_LTF_4X = 3,
+};
+
+/**
+ * enum qca_wlan_he_mac_padding_dur - HE trigger frame MAC padding duration
+ *
+ * Indicates the HE trigger frame MAC padding duration value.
+ *
+ * @QCA_WLAN_HE_NO_ADDITIONAL_PROCESS_TIME: no additional time required to
+ * process the trigger frame.
+ * @QCA_WLAN_HE_8US_OF_PROCESS_TIME: indicates the 8us of processing time for
+ * trigger frame.
+ * @QCA_WLAN_HE_16US_OF_PROCESS_TIME: indicates the 16us of processing time for
+ * trigger frame.
+ */
+enum qca_wlan_he_mac_padding_dur {
+ QCA_WLAN_HE_NO_ADDITIONAL_PROCESS_TIME = 0,
+ QCA_WLAN_HE_8US_OF_PROCESS_TIME = 1,
+ QCA_WLAN_HE_16US_OF_PROCESS_TIME = 2,
+};
+
+/**
+ * enum qca_wlan_he_om_ctrl_ch_bw - HE OM control field BW configuration
+ *
+ * Indicates the HE Operating mode control channel width setting value.
+ *
+ * @QCA_WLAN_HE_OM_CTRL_BW_20M: Primary 20 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_40M: Primary 40 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_80M: Primary 80 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_160M: 160 MHz and 80+80 MHz
+ */
+enum qca_wlan_he_om_ctrl_ch_bw {
+ QCA_WLAN_HE_OM_CTRL_BW_20M = 0,
+ QCA_WLAN_HE_OM_CTRL_BW_40M = 1,
+ QCA_WLAN_HE_OM_CTRL_BW_80M = 2,
+ QCA_WLAN_HE_OM_CTRL_BW_160M = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_he_omi_tx: Represents attributes for
+ * HE operating mode control transmit request. These attributes are
+ * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX and
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS: Mandatory 8-bit unsigned value
+ * indicates the maximum number of spatial streams, NSS, that the STA
+ * supports in reception for PPDU bandwidths less than or equal to 80 MHz
+ * and is set to NSS - 1.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW: Mandatory 8-bit unsigned value
+ * indicates the operating channel width supported by the STA for both
+ * reception and transmission. Uses enum qca_wlan_he_om_ctrl_ch_bw values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE: Mandatory 8-bit unsigned value
+ * indicates the all trigger based UL MU operations by the STA.
+ * 0 - UL MU operations are enabled by the STA.
+ * 1 - All triggered UL MU transmissions are suspended by the STA.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS: Mandatory 8-bit unsigned value
+ * indicates the maximum number of space-time streams, NSTS, that
+ * the STA supports in transmission and is set to NSTS - 1.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE: 8-bit unsigned value
+ * combined with the UL MU Disable subfield and the recipient's setting
+ * of the OM Control UL MU Data Disable RX Support subfield in the HE MAC
+ * capabilities to determine which HE TB PPDUs are possible by the
+ * STA to transmit.
+ * 0 - UL MU data operations are enabled by the STA.
+ * 1 - Determine which HE TB PPDU types are allowed by the STA if UL MU disable
+ * bit is not set, else UL MU Tx is suspended.
+ *
+ */
+enum qca_wlan_vendor_attr_he_omi_tx {
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS = 1,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW = 2,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE = 3,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS = 4,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX =
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1,
+};
+
+/* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
+ */
+enum qca_wlan_vendor_attr_wifi_test_config {
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_INVALID = 0,
+ /* 8-bit unsigned value to configure the driver to enable/disable
+ * WMM feature. This attribute is used to configure testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WMM_ENABLE = 1,
+
+ /* 8-bit unsigned value to configure the driver to accept/reject
+ * the addba request from peer. This attribute is used to configure
+ * the testbed device.
+ * 1-accept addba, 0-reject addba
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ACCEPT_ADDBA_REQ = 2,
+
+ /* 8-bit unsigned value to configure the driver to send or not to
+ * send the addba request to peer.
+ * This attribute is used to configure the testbed device.
+ * 1-send addba, 0-do not send addba
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SEND_ADDBA_REQ = 3,
+
+ /* 8-bit unsigned value to indicate the HE fragmentation support.
+ * Uses enum he_fragmentation_val values.
+ * This attribute is used to configure the testbed device to
+ * allow the advertised hardware capabilities to be downgraded
+ * for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_FRAGMENTATION = 4,
+
+ /* 8-bit unsigned value to indicate the HE MCS support.
+ * Uses enum he_mcs_config values.
+ * This attribute is used to configure the testbed device to
+ * allow the advertised hardware capabilities to be downgraded
+ * for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MCS = 5,
+
+ /* 8-bit unsigned value to configure the driver to allow or not to
+ * allow the connection with WEP/TKIP in HT/VHT/HE modes.
+ * This attribute is used to configure the testbed device.
+ * 1-allow WEP/TKIP in HT/VHT/HE, 0-do not allow WEP/TKIP.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WEP_TKIP_IN_HE = 6,
+
+ /* 8-bit unsigned value to configure the driver to add a
+ * new BA session or delete the existing BA session for
+ * given TID. ADDBA command uses the buffer size and TID
+ * configuration if user specifies the values else default
+ * value for buffer size is used for all TIDs if the TID
+ * also not specified. For DEL_BA command TID value is
+ * required to process the command.
+ * Uses enum qca_wlan_ba_session_config values.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADD_DEL_BA_SESSION = 7,
+
+ /* 16-bit unsigned value to configure the buffer size in addba
+ * request and response frames.
+ * This attribute is used to configure the testbed device.
+ * The range of the value is 0 to 256.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE = 8,
+
+ /* 8-bit unsigned value to configure the buffer size in addba
+ * request and response frames.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BA_TID = 9,
+
+ /* 8-bit unsigned value to configure the no ack policy.
+ * To configure no ack policy, access category value is
+ * required to process the command.
+ * This attribute is used to configure the testbed device.
+ * 1 - enable no ack, 0 - disable no ack.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_NO_ACK = 10,
+
+ /* 8-bit unsigned value to configure the AC for no ack policy
+ * This attribute is used to configure the testbed device.
+ * Uses the enum qca_wlan_ac_type values.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_NO_ACK_AC = 11,
+
+ /* 8-bit unsigned value to configure the HE LTF
+ * This attribute is used to configure the testbed device.
+ * Uses the enum qca_wlan_he_ltf_cfg values.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_LTF = 12,
+
+ /* 8-bit unsigned value to configure the tx beamformee.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_TX_BEAMFORMEE = 13,
+
+ /* 8-bit unsigned value to configure the tx beamformee number
+ * of space-time streams.
+ * This attribute is used to configure the testbed device.
+ * The range of the value is 0 to 8.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_BEAMFORMEE_NSTS = 14,
+
+ /* 8-bit unsigned value to configure the MU EDCA params for given AC
+ * This attribute is used to configure the testbed device.
+ * Uses the enum qca_wlan_ac_type values.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_AC = 15,
+
+ /* 8-bit unsigned value to configure the MU EDCA AIFSN for given AC
+ * To configure MU EDCA AIFSN value, MU EDCA access category value
+ * is required to process the command.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_AIFSN = 16,
+
+ /* 8-bit unsigned value to configure the MU EDCA ECW min value for
+ * given AC.
+ * To configure MU EDCA ECW min value, MU EDCA access category value
+ * is required to process the command.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_ECWMIN = 17,
+
+ /* 8-bit unsigned value to configure the MU EDCA ECW max value for
+ * given AC.
+ * To configure MU EDCA ECW max value, MU EDCA access category value
+ * is required to process the command.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_ECWMAX = 18,
+
+ /* 8-bit unsigned value to configure the MU EDCA timer for given AC
+ * To configure MU EDCA timer value, MU EDCA access category value
+ * is required to process the command.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_TIMER = 19,
+
+ /* 8-bit unsigned value to configure the HE trigger frame MAC padding
+ * duration.
+ * This attribute is used to configure the testbed device.
+ * Uses the enum qca_wlan_he_mac_padding_dur values.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MAC_PADDING_DUR = 20,
+
+ /* 8-bit unsigned value to override the MU EDCA params to defaults
+ * regardless of the AP beacon MU EDCA params. If it is enabled use
+ * the default values else use the MU EDCA params from AP beacon.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OVERRIDE_MU_EDCA = 21,
+
+ /* 8-bit unsigned value to configure the support for receiving
+ * an MPDU that contains an operating mode control subfield.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_SUPP = 22,
+
+ /* Nested attribute values required to setup the TWT session.
+ * enum qca_wlan_vendor_attr_twt_setup provides the necessary
+ * information to set up the session. It contains broadcast flags,
+ * set_up flags, trigger value, flow type, flow ID, wake interval
+ * exponent, protection, target wake time, wake duration, wake interval
+ * mantissa. These nested attributes are used to setup a host triggered
+ * TWT session.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP = 23,
+
+ /* This nested attribute is used to terminate the current TWT session.
+ * It does not currently carry any attributes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_TERMINATE = 24,
+
+ /* This nested attribute is used to suspend the current TWT session.
+ * It does not currently carry any attributes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SUSPEND = 25,
+
+ /* Nested attribute values to indicate the request for resume.
+ * This attribute is used to resume the TWT session.
+ * enum qca_wlan_vendor_attr_twt_resume provides the necessary
+ * parameters required to resume the TWT session.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME = 26,
+
+ /* 8-bit unsigned value to set the HE operating mode control
+ * (OM CTRL) Channel Width subfield.
+ * The Channel Width subfield indicates the operating channel width
+ * supported by the STA for both reception and transmission.
+ * Uses the enum qca_wlan_he_om_ctrl_ch_bw values.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_BW = 27,
+
+ /* 8-bit unsigned value to configure the number of spatial
+ * streams in HE operating mode control field.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_NSS = 28,
+
+ /* Flag attribute to configure the UL MU disable bit in
+ * HE operating mode control field.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_UL_MU_DISABLE = 29,
+
+ /* Flag attribute to clear the previously set HE operating mode
+ * control field configuration.
+ * This attribute is used to configure the testbed device to reset
+ * defaults to clear any previously set HE operating mode control
+ * field configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG = 30,
+
+ /* 8-bit unsigned value to configure HE single user PPDU
+ * transmission. By default this setting is disabled and it
+ * is disabled in the reset defaults of the device configuration.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_SUPPDU = 31,
+
+ /* 8-bit unsigned value to configure action frame transmission
+ * in HE trigger based PPDU transmission.
+ * By default this setting is disabled and it is disabled in
+ * the reset defaults of the device configuration.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_ACTION_TX_TB_PPDU = 32,
+
+ /* Nested attribute to indicate HE operating mode control field
+ * transmission. It contains operating mode control field Nss,
+ * channel bandwidth, Tx Nsts and UL MU disable attributes.
+ * These nested attributes are used to send HE operating mode control
+ * with configured values.
+ * Uses the enum qca_wlan_vendor_attr_he_omi_tx attributes.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX = 33,
+
+ /* 8-bit unsigned value to configure +HTC_HE support to indicate the
+ * support for the reception of a frame that carries an HE variant
+ * HT Control field.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_HTC_HE_SUPP = 34,
+
+ /* 8-bit unsigned value to configure VHT support in 2.4G band.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_2G_VHT = 35,
+
+ /* 8-bit unsigned value to configure HE testbed defaults.
+ * This attribute is used to configure the testbed device.
+ * 1-set the device HE capabilities to testbed defaults.
+ * 0-reset the device HE capabilities to supported config.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SET_HE_TESTBED_DEFAULTS = 36,
+
+ /* 8-bit unsigned value to configure TWT request support.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TWT_REQ_SUPPORT = 37,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_bss_filter - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ * The user can add/delete the filter by specifying the BSSID/STA MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, filter type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, add/delete action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user can get the
+ * statistics of an unassociated station by specifying the MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, station type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, GET action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user also can get
+ * the statistics of all unassociated stations by specifying the Broadcast MAC
+ * address (ff:ff:ff:ff:ff:ff) in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR with
+ * above procedure. In the response, driver shall specify statistics
+ * information nested in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS.
+ */
+enum qca_wlan_vendor_attr_bss_filter {
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR = 1,
+ /* Other BSS filter type, unsigned 8 bit value. One of the values
+ * in enum qca_wlan_vendor_bss_filter_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE = 2,
+ /* Other BSS filter action, unsigned 8 bit value. One of the values
+ * in enum qca_wlan_vendor_bss_filter_action.
+ */
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION = 3,
+ /* Array of nested attributes where each entry is the statistics
+ * information of the specified station that belong to another BSS.
+ * Attributes for each entry are taken from enum
+ * qca_wlan_vendor_bss_filter_sta_stats.
+ * Other BSS station configured in
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER with filter type
+ * QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA.
+ * Statistics returned by QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER
+ * with filter action QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET.
+ */
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX =
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_type - Type of
+ * filter used in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID: BSSID filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA: Station MAC address filter
+ */
+enum qca_wlan_vendor_bss_filter_type {
+ QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID,
+ QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_action - Type of
+ * action in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD: Add filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL: Delete filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET: Get the statistics
+ */
+enum qca_wlan_vendor_bss_filter_action {
+ QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD,
+ QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL,
+ QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_sta_stats - Attributes for
+ * the statistics of a specific unassociated station belonging to another BSS.
+ * The statistics provides information of the unassociated station
+ * filtered by other BSS operation - such as MAC, signal value.
+ * Used by the vendor command QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAC: MAC address of the station.
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI: Last received signal strength
+ * of the station. Unsigned 8 bit number containing RSSI.
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS: Time stamp of the host
+ * driver for the last received RSSI. Unsigned 64 bit number containing
+ * nanoseconds from the boottime.
+ */
+enum qca_wlan_vendor_bss_filter_sta_stats {
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_INVALID = 0,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAC = 1,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI = 2,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAX =
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_AFTER_LAST - 1
+};
+
+/* enum qca_wlan_nan_subcmd_type - Type of NAN command used by attribute
+ * QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE as a part of vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT.
+ */
+enum qca_wlan_nan_ext_subcmd_type {
+ /* Subcmd of type NAN Enable Request */
+ QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ = 1,
+ /* Subcmd of type NAN Disable Request */
+ QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_nan_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT.
+ */
+enum qca_wlan_vendor_attr_nan_params {
+ QCA_WLAN_VENDOR_ATTR_NAN_INVALID = 0,
+ /* Carries NAN command for firmware component. Every vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT must contain this attribute with a
+ * payload containing the NAN command. NLA_BINARY attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA = 1,
+ /* Indicates the type of NAN command sent with
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT. enum qca_wlan_nan_ext_subcmd_type
+ * describes the possible range of values. This attribute is mandatory
+ * if the command being issued is either
+ * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ or
+ * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ. NLA_U32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE = 2,
+ /* Frequency (in MHz) of primary NAN discovery social channel in 2.4 GHz
+ * band. This attribute is mandatory when command type is
+ * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ. NLA_U32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_NAN_DISC_24GHZ_BAND_FREQ = 3,
+ /* Frequency (in MHz) of secondary NAN discovery social channel in 5 GHz
+ * band. This attribute is optional and should be included when command
+ * type is QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ and NAN discovery
+ * has to be started on 5GHz along with 2.4GHz. NLA_U32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_NAN_DISC_5GHZ_BAND_FREQ = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_MAX =
+ QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_setup: Represents attributes for
+ * TWT (Target Wake Time) setup request. These attributes are sent as part of
+ * %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP and
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST: Flag attribute.
+ * Disable (flag attribute not present) - Individual TWT
+ * Enable (flag attribute present) - Broadcast TWT.
+ * Individual means the session is between the STA and the AP.
+ * This session is established using a separate negotiation between
+ * STA and AP.
+ * Broadcast means the session is across multiple STAs and an AP. The
+ * configuration parameters are announced in Beacon frames by the AP.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE: Required (u8).
+ * Unsigned 8-bit qca_wlan_vendor_twt_setup_req_type to
+ * specify the TWT request type
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER: Flag attribute
+ * Enable (flag attribute present) - TWT with trigger support.
+ * Disable (flag attribute not present) - TWT without trigger support.
+ * Trigger means the AP will send the trigger frame to allow STA to send data.
+ * Without trigger, the STA will wait for the MU EDCA timer before
+ * transmitting the data.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE: Required (u8)
+ * 0 - Announced TWT - In this mode, STA may skip few service periods to
+ * save more power. If STA wants to wake up, it will send a PS-POLL/QoS
+ * NULL frame to AP.
+ * 1 - Unannounced TWT - The STA will wakeup during every SP.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID: Optional (u8)
+ * Flow ID is the unique identifier for each TWT session.
+ * Currently this is not required and dialog ID will be set to zero.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP: Required (u8)
+ * This attribute (exp) is used along with the mantissa to derive the
+ * wake interval using the following formula:
+ * pow(2,exp) = wake_intvl_us/wake_intvl_mantis
+ * Wake interval is the interval between 2 successive SP.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION: Flag attribute
+ * Enable (flag attribute present) - Protection required.
+ * Disable (flag attribute not present) - Protection not required.
+ * If protection is enabled, then the AP will use protection
+ * mechanism using RTS/CTS to self to reserve the airtime.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME: Optional (u32)
+ * This attribute is used as the SP offset which is the offset from
+ * TSF after which the wake happens. The units are in microseconds. If
+ * this attribute is not provided, then the value will be set to zero.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION: Required (u32)
+ * This is the duration of the service period. The units are in TU.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA: Required (u32)
+ * This attribute is used to configure wake interval mantissa.
+ * The units are in TU.
+ */
+enum qca_wlan_vendor_attr_twt_setup {
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID = 5,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP = 6,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION = 7,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME = 8,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION = 9,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA = 10,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_resume: Represents attributes for
+ * TWT (Target Wake Time) resume request. These attributes are sent as part of
+ * %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME and
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT: Optional (u8)
+ * This attribute is used as the SP offset which is the offset from
+ * TSF after which the wake happens. The units are in microseconds.
+ * If this attribute is not provided, then the value will be set to
+ * zero.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE: Required (u32)
+ * This attribute represents the next TWT subfield size.
+ */
+enum qca_wlan_vendor_attr_twt_resume {
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_twt_setup_req_type - Required (u8)
+ * Represents the setup type being requested for TWT.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_REQUEST: STA is not specifying all the TWT
+ * parameters but relying on AP to fill the parameters during the negotiation.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST: STA will provide all the suggested
+ * values which the AP may accept or AP may provide alternative parameters
+ * which the STA may accept.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_DEMAND: STA is not willing to accept any
+ * alternate parameters than the requested ones.
+ */
+enum qca_wlan_vendor_twt_setup_req_type {
+ QCA_WLAN_VENDOR_TWT_SETUP_REQUEST = 1,
+ QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST = 2,
+ QCA_WLAN_VENDOR_TWT_SETUP_DEMAND = 3,
+};
+
+/**
+ * enum qca_wlan_roam_scan_event_type - Type of roam scan event
+ *
+ * Indicates the type of roam scan event sent by firmware/driver.
+ *
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_EVENT: Roam scan trigger event type.
+ * @QCA_WLAN_ROAM_SCAN_STOP_EVENT: Roam scan stopped event type.
+ */
+enum qca_wlan_roam_scan_event_type {
+ QCA_WLAN_ROAM_SCAN_TRIGGER_EVENT = 0,
+ QCA_WLAN_ROAM_SCAN_STOP_EVENT = 1,
+};
+
+/**
+ * enum qca_wlan_roam_scan_trigger_reason - Roam scan trigger reason
+ *
+ * Indicates the reason for triggering roam scan by firmware/driver.
+ *
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_LOW_RSSI: Due to low RSSI of current AP.
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_HIGH_PER: Due to high packet error rate.
+ */
+enum qca_wlan_roam_scan_trigger_reason {
+ QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_LOW_RSSI = 0,
+ QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_HIGH_PER = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_roam_scan - Vendor subcmd attributes to report
+ * roam scan related details from driver/firmware to user space. enum values
+ * are used for NL attributes sent with
+ * %QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_roam_scan {
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_INVALID = 0,
+ /* Encapsulates type of roam scan event being reported. enum
+ * qca_wlan_roam_scan_event_type describes the possible range of
+ * values. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_EVENT_TYPE = 1,
+ /* Encapsulates reason for triggering roam scan. enum
+ * qca_wlan_roam_scan_trigger_reason describes the possible range of
+ * values. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_TRIGGER_REASON = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_cfr_method - QCA vendor CFR methods used by
+ * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD as part of vendor
+ * command QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG.
+ */
+enum qca_wlan_vendor_cfr_method {
+ /* CFR method using QOS Null frame */
+ QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0,
+};
+
+/**
+ * enum qca_wlan_vendor_peer_cfr_capture_attr - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer
+ * Channel Frequency Response capture parameters and enable periodic CFR
+ * capture.
+ */
+enum qca_wlan_vendor_peer_cfr_capture_attr {
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0,
+ /* 6-byte MAC address of the peer.
+ * This attribute is mandatory.
+ */
+ QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR = 1,
+ /* Enable peer CFR Capture, flag attribute.
+ * This attribute is mandatory to enable peer CFR capture.
+ * If this attribute is not present, peer CFR capture is disabled.
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE = 2,
+ /* BW of measurement, attribute uses the values in enum nl80211_chan_width
+ * Supported values: 20, 40, 80, 80+80, 160.
+ * Note that all targets may not support all bandwidths.
+ * u8 attribute. This attribute is mandatory if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH = 3,
+ /* Periodicity of CFR measurement in msec.
+ * Periodicity should be a multiple of Base timer.
+ * Current Base timer value supported is 10 msecs (default).
+ * 0 for one shot capture. u32 attribute.
+ * This attribute is mandatory if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY = 4,
+ /* Method used to capture Channel Frequency Response.
+ * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
+ * u8 attribute. This attribute is mandatory if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD = 5,
+ /* Enable periodic CFR capture, flag attribute.
+ * This attribute is mandatory to enable Periodic CFR capture.
+ * If this attribute is not present, periodic CFR capture is disabled.
+ */
+ QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE = 6,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX =
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_throughput_level - Current throughput level
+ *
+ * Indicates the current level of throughput calculated by the driver. The
+ * driver may choose different thresholds to decide whether the throughput level
+ * is low or medium or high based on variety of parameters like physical link
+ * capacity of the current connection, the number of packets being dispatched
+ * per second, etc. The throughput level events might not be consistent with the
+ * actual current throughput value being observed.
+ *
+ * @QCA_WLAN_THROUGHPUT_LEVEL_LOW: Low level of throughput
+ * @QCA_WLAN_THROUGHPUT_LEVEL_MEDIUM: Medium level of throughput
+ * @QCA_WLAN_THROUGHPUT_LEVEL_HIGH: High level of throughput
+ */
+enum qca_wlan_throughput_level {
+ QCA_WLAN_THROUGHPUT_LEVEL_LOW = 0,
+ QCA_WLAN_THROUGHPUT_LEVEL_MEDIUM = 1,
+ QCA_WLAN_THROUGHPUT_LEVEL_HIGH = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_throughput_change - Vendor subcmd attributes to
+ * report throughput changes from the driver to user space. enum values are used
+ * for netlink attributes sent with
+ * %QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_throughput_change {
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_INVALID = 0,
+ /* Indicates the direction of throughput in which the change is being
+ * reported. u8 attribute. Value is 0 for TX and 1 for RX.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_DIRECTION = 1,
+ /* Indicates the newly observed throughput level. enum
+ * qca_wlan_throughput_level describes the possible range of values.
+ * u8 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_THROUGHPUT_LEVEL = 2,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_limit_output_bytes. u32 attribute. The
+ * driver may optionally include this attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_LIMIT_OUTPUT_BYTES = 3,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_adv_win_scale. s8 attribute. Possible
+ * values are from -31 to 31. The driver may optionally include this
+ * attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_ADV_WIN_SCALE = 4,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_delack_seg. u32 attribute. The driver may
+ * optionally include this attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_DELACK_SEG = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_MAX =
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_coex_config_profiles - This enum defines different types of
+ * traffic streams that can be prioritized one over the other during coex
+ * scenarios.
+ * The types defined in this enum are categorized in the below manner.
+ * 0 - 31 values corresponds to WLAN
+ * 32 - 63 values corresponds to BT
+ * 64 - 95 values corresponds to Zigbee
+ * @QCA_WIFI_STA_DISCOVERY: Prioritize discovery frames for WLAN STA
+ * @QCA_WIFI_STA_CONNECTION: Prioritize connection frames for WLAN STA
+ * @QCA_WIFI_STA_CLASS_3_MGMT: Prioritize class 3 mgmt frames for WLAN STA
+ * @QCA_WIFI_STA_DATA : Prioritize data frames for WLAN STA
+ * @QCA_WIFI_STA_ALL: Priritize all frames for WLAN STA
+ * @QCA_WIFI_SAP_DISCOVERY: Prioritize discovery frames for WLAN SAP
+ * @QCA_WIFI_SAP_CONNECTION: Prioritize connection frames for WLAN SAP
+ * @QCA_WIFI_SAP_CLASS_3_MGMT: Prioritize class 3 mgmt frames for WLAN SAP
+ * @QCA_WIFI_SAP_DATA: Prioritize data frames for WLAN SAP
+ * @QCA_WIFI_SAP_ALL: Prioritize all frames for WLAN SAP
+ * @QCA_BT_A2DP: Prioritize BT A2DP
+ * @QCA_BT_BLE: Prioritize BT BLE
+ * @QCA_BT_SCO: Prioritize BT SCO
+ * @QCA_ZB_LOW: Prioritize Zigbee Low
+ * @QCA_ZB_HIGH: Prioritize Zigbee High
+ */
+enum qca_coex_config_profiles {
+ /* 0 - 31 corresponds to WLAN */
+ QCA_WIFI_STA_DISCOVERY = 0,
+ QCA_WIFI_STA_CONNECTION = 1,
+ QCA_WIFI_STA_CLASS_3_MGMT = 2,
+ QCA_WIFI_STA_DATA = 3,
+ QCA_WIFI_STA_ALL = 4,
+ QCA_WIFI_SAP_DISCOVERY = 5,
+ QCA_WIFI_SAP_CONNECTION = 6,
+ QCA_WIFI_SAP_CLASS_3_MGMT = 7,
+ QCA_WIFI_SAP_DATA = 8,
+ QCA_WIFI_SAP_ALL = 9,
+ QCA_WIFI_CASE_MAX = 31,
+ /* 32 - 63 corresponds to BT */
+ QCA_BT_A2DP = 32,
+ QCA_BT_BLE = 33,
+ QCA_BT_SCO = 34,
+ QCA_BT_CASE_MAX = 63,
+ /* 64 - 95 corresponds to Zigbee */
+ QCA_ZB_LOW = 64,
+ QCA_ZB_HIGH = 65,
+ QCA_ZB_CASE_MAX = 95,
+ /* 0xff is default value if the u8 profile value is not set. */
+ QCA_COEX_CONFIG_PROFILE_DEFAULT_VALUE = 255
+};
+
+/**
+ * enum qca_vendor_attr_coex_config_types - Coex configurations types.
+ * This enum defines the valid set of values of coex configuration types. These
+ * values may used by attribute
+ * %QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET: Reset all the
+ * weights to default values.
+ * @QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START: Start to config
+ * weights with configurability value.
+ */
+enum qca_vendor_attr_coex_config_types {
+ QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET = 1,
+ QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START = 2,
+};
+
+/**
+ * enum qca_vendor_attr_coex_config - Specifies vendor coex config attributes
+ *
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_PROFILES: This attribute contains variable
+ * length array of 8-bit values from enum qca_coex_config_profiles.
+ * FW will prioritize the profiles in the order given in the array encapsulated
+ * in this attribute.
+ * For example:
+ * -----------------------------------------------------------------------
+ * | 1 | 34 | 32 | 65 |
+ * -----------------------------------------------------------------------
+ * If the attribute contains the values defined in above array then it means
+ * 1) Wifi STA connection has priority over BT_SCO, BT_A2DP and ZIGBEE HIGH.
+ * 2) BT_SCO has priority over BT_A2DP.
+ * 3) BT_A2DP has priority over ZIGBEE HIGH.
+ * Profiles which are not listed in this array shall not be preferred over the
+ * profiles which are listed in the array as a part of this attribute.
+ */
+enum qca_vendor_attr_coex_config {
+ QCA_VENDOR_ATTR_COEX_CONFIG_INVALID = 0,
+ QCA_VENDOR_ATTR_COEX_CONFIG_PROFILES = 1,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST,
+ QCA_VENDOR_ATTR_COEX_CONFIG_MAX =
+ QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_coex_config_three_way - Specifies vendor coex config
+ * attributes
+ * Attributes for data used by QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG
+ *
+ * QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE: u32 attribute.
+ * Indicate config type.
+ * The config types are 32-bit values from qca_vendor_attr_coex_config_types
+ *
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1: u32 attribute.
+ * Indicate the Priority 1 profiles.
+ * The profiles are 8-bit values from enum qca_coex_config_profiles.
+ * In same priority level, maximum to 4 profiles can be set here.
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2: u32 attribute.
+ * Indicate the Priority 2 profiles.
+ * The profiles are 8-bit values from enum qca_coex_config_profiles.
+ * In same priority level, maximum to 4 profiles can be set here.
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3: u32 attribute.
+ * Indicate the Priority 3 profiles.
+ * The profiles are 8-bit values from enum qca_coex_config_profiles.
+ * In same priority level, maximum to 4 profiles can be set here.
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4: u32 attribute.
+ * Indicate the Priority 4 profiles.
+ * The profiles are 8-bit values from enum qca_coex_config_profiles.
+ * In same priority level, maximum to 4 profiles can be set here.
+ * NOTE:
+ * Limitations for QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_x priority
+ * arrangement:
+ * 1: In the same u32 attribute (priority x), the profiles enum values own
+ * same priority level.
+ * 2: 0xff is default value if the u8 profile value is not set.
+ * 3: max to 4 rules/profiles in same priority level.
+ * 4: max to 4 priority level (priority 1 - priority 4)
+ * 5: one priority level only supports one scenario from WLAN/BT/ZB,
+ * hybrid rules not support.
+ * 6: if WMI_COEX_CONFIG_THREE_WAY_COEX_RESET called, priority x will
+ * remain blank to reset all parameters.
+ * For example:
+ *
+ * If the attributes as follow:
+ * priority 1:
+ * ------------------------------------
+ * | 0xff | 0 | 1 | 2 |
+ * ------------------------------------
+ * priority 2:
+ * -------------------------------------
+ * | 0xff | 0xff | 0xff | 32 |
+ * -------------------------------------
+ * priority 3:
+ * -------------------------------------
+ * | 0xff | 0xff | 0xff | 65 |
+ * -------------------------------------
+ * then it means:
+ * 1: WIFI_STA_DISCOVERY, WIFI_STA_CLASS_3_MGMT and WIFI_STA_CONNECTION
+ * owns same priority level.
+ * 2: WIFI_STA_DISCOVERY, WIFI_STA_CLASS_3_MGMT and WIFI_STA_CONNECTION
+ * has priority over BT_A2DP and ZB_HIGH.
+ * 3: BT_A2DP has priority over ZB_HIGH.
+ */
+
+enum qca_vendor_attr_coex_config_three_way {
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_INVALID = 0,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE = 1,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1 = 2,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2 = 3,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3 = 4,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4 = 5,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_AFTER_LAST,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX =
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_link_properties - Represent the link properties.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR: MAC address of the peer
+ * (STA/AP) for the connected link.
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS: Attribute containing a
+ * &struct nl80211_sta_flag_update for the respective connected link. MAC
+ * address of the peer represented by
+ * QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR.
+ */
+enum qca_wlan_vendor_attr_link_properties {
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_INVALID = 0,
+ /* 1 - 3 are reserved */
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR = 4,
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS = 5,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST,
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_MAX =
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_peer_stats_cache_type - Represents peer stats cache type
+ * This enum defines the valid set of values of peer stats cache types. These
+ * values are used by attribute
+ * %QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_TX_RATE_STATS: Represents peer TX rate statistics
+ * @QCA_WLAN_VENDOR_ATTR_PEER_RX_RATE_STATS: Represents peer RX rate statistics
+ * @QCA_WLAN_VENDOR_ATTR_PEER_TX_SOJOURN_STATS: Represents peer TX sojourn
+ * statistics
+ */
+enum qca_vendor_attr_peer_stats_cache_type {
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE_INVALID = 0,
+
+ QCA_WLAN_VENDOR_ATTR_PEER_TX_RATE_STATS,
+ QCA_WLAN_VENDOR_ATTR_PEER_RX_RATE_STATS,
+ QCA_WLAN_VENDOR_ATTR_PEER_TX_SOJOURN_STATS,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_peer_stats_cache_params - This enum defines
+ * attributes required for QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH
+ * Information in these attributes is used to flush peer rate statistics from
+ * the driver to user application.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE: Unsigned 32-bit attribute
+ * Indicate peer statistics cache type.
+ * The statistics types are 32-bit values from
+ * enum qca_vendor_attr_peer_stats_cache_type.
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_MAC: Unsigned 8-bit array
+ * of size 6 octets, representing the peer MAC address.
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA: Opaque data attribute
+ * containing buffer of statistics to send to application layer entity.
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE: Unsigned 64-bit attribute
+ * representing a cookie for peer unique session.
+ */
+enum qca_wlan_vendor_attr_peer_stats_cache_params {
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_INVALID = 0,
+
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_MAC = 2,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA = 3,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE = 4,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_LAST,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_MAX =
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_LAST - 1
+};
+
+/**
+ * enum qca_mpta_helper_attr_zigbee_state - Current Zigbee state
+ * This enum defines all the possible states of Zigbee, which can be
+ * delivered in the QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE attribute.
+ *
+ * @ZIGBEE_IDLE: Zigbee in idle state
+ * @ZIGBEE_FORM_NETWORK: Zigbee forming network
+ * @ZIGBEE_WAIT_JOIN: Zigbee waiting for joining network
+ * @ZIGBEE_JOIN: Zigbee joining network
+ * @ZIGBEE_NETWORK_UP: Zigbee network is up
+ * @ZIGBEE_HMI: Zigbee in HMI mode
+ */
+enum qca_mpta_helper_attr_zigbee_state {
+ ZIGBEE_IDLE = 0,
+ ZIGBEE_FORM_NETWORK = 1,
+ ZIGBEE_WAIT_JOIN = 2,
+ ZIGBEE_JOIN = 3,
+ ZIGBEE_NETWORK_UP = 4,
+ ZIGBEE_HMI = 5,
+};
+
+/*
+ * enum qca_mpta_helper_vendor_attr - Attributes used in vendor sub-command
+ * QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG.
+ */
+enum qca_mpta_helper_vendor_attr {
+ QCA_MPTA_HELPER_VENDOR_ATTR_INVALID = 0,
+ /* Optional attribute used to update Zigbee state.
+ * enum qca_mpta_helper_attr_zigbee_state.
+ * NLA_U32 attribute.
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE = 1,
+ /* Optional attribute used to configure WLAN duration for Shape-OCS
+ * during interrupt.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION.
+ * Value range 0 ~ 300 (ms).
+ * NLA_U32 attribute.
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION = 2,
+ /* Optional attribute used to configure non-WLAN duration for Shape-OCS
+ * during interrupt.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION.
+ * Value range 0 ~ 300 (ms).
+ * NLA_U32 attribute.
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION = 3,
+ /* Optional attribute used to configure WLAN duration for Shape-OCS
+ * monitor period.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION.
+ * Value range 0 ~ 300 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION = 4,
+ /* Optional attribute used to configure non-WLAN duration for Shape-OCS
+ * monitor period.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION.
+ * Value range 0 ~ 300 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION = 5,
+ /* Optional attribute used to configure OCS interrupt duration.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION.
+ * Value range 1000 ~ 20000 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION = 6,
+ /* Optional attribute used to configure OCS monitor duration.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION.
+ * Value range 1000 ~ 20000 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION = 7,
+ /* Optional attribute used to notify WLAN firmware the current Zigbee
+ * channel.
+ * Value range 11 ~ 26
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN = 8,
+ /* Optional attribute used to configure WLAN mute duration.
+ * Value range 0 ~ 400 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION = 9,
+
+ /* keep last */
+ QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST,
+ QCA_MPTA_HELPER_VENDOR_ATTR_MAX =
+ QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST - 1
};
#endif /* QCA_VENDOR_H */
diff --git a/contrib/wpa/src/common/sae.c b/contrib/wpa/src/common/sae.c
index 503fa1d..5a50294 100644
--- a/contrib/wpa/src/common/sae.c
+++ b/contrib/wpa/src/common/sae.c
@@ -1,6 +1,6 @@
/*
* Simultaneous authentication of equals
- * Copyright (c) 2012-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/const_time.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
#include "crypto/random.h"
@@ -17,10 +18,33 @@
#include "sae.h"
+static int sae_suitable_group(int group)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ /* Allow all groups for testing purposes in non-production builds. */
+ return 1;
+#else /* CONFIG_TESTING_OPTIONS */
+ /* Enforce REVmd rules on which SAE groups are suitable for production
+ * purposes: FFC groups whose prime is >= 3072 bits and ECC groups
+ * defined over a prime field whose prime is >= 256 bits. Furthermore,
+ * ECC groups defined over a characteristic 2 finite field and ECC
+ * groups with a co-factor greater than 1 are not suitable. */
+ return group == 19 || group == 20 || group == 21 ||
+ group == 28 || group == 29 || group == 30 ||
+ group == 15 || group == 16 || group == 17 || group == 18;
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
int sae_set_group(struct sae_data *sae, int group)
{
struct sae_temporary_data *tmp;
+ if (!sae_suitable_group(group)) {
+ wpa_printf(MSG_DEBUG, "SAE: Reject unsuitable group %d", group);
+ return -1;
+ }
+
sae_clear_data(sae);
tmp = sae->tmp = os_zalloc(sizeof(*tmp));
if (tmp == NULL)
@@ -29,6 +53,8 @@ int sae_set_group(struct sae_data *sae, int group)
/* First, check if this is an ECC group */
tmp->ec = crypto_ec_init(group);
if (tmp->ec) {
+ wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d",
+ group);
sae->group = group;
tmp->prime_len = crypto_ec_prime_len(tmp->ec);
tmp->prime = crypto_ec_get_prime(tmp->ec);
@@ -39,6 +65,8 @@ int sae_set_group(struct sae_data *sae, int group)
/* Not an ECC group, check FFC */
tmp->dh = dh_groups_get(group);
if (tmp->dh) {
+ wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d",
+ group);
sae->group = group;
tmp->prime_len = tmp->dh->prime_len;
if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
@@ -66,6 +94,8 @@ int sae_set_group(struct sae_data *sae, int group)
}
/* Unsupported group */
+ wpa_printf(MSG_DEBUG,
+ "SAE: Group %d not supported by the crypto library", group);
return -1;
}
@@ -88,6 +118,7 @@ void sae_clear_temp_data(struct sae_data *sae)
crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
wpabuf_free(tmp->anti_clogging_token);
+ os_free(tmp->pw_id);
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
}
@@ -201,12 +232,14 @@ get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
static int is_quadratic_residue_blind(struct sae_data *sae,
const u8 *prime, size_t bits,
- const struct crypto_bignum *qr,
- const struct crypto_bignum *qnr,
+ const u8 *qr, const u8 *qnr,
const struct crypto_bignum *y_sqr)
{
- struct crypto_bignum *r, *num;
+ struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
int r_odd, check, res = -1;
+ u8 qr_or_qnr_bin[SAE_MAX_ECC_PRIME_LEN];
+ size_t prime_len = sae->tmp->prime_len;
+ unsigned int mask;
/*
* Use the blinding technique to mask y_sqr while determining
@@ -217,7 +250,7 @@ static int is_quadratic_residue_blind(struct sae_data *sae,
* r = a random number between 1 and p-1, inclusive
* num = (v * r * r) modulo p
*/
- r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
+ r = get_rand_1_to_p_1(prime, prime_len, bits, &r_odd);
if (!r)
return -1;
@@ -227,58 +260,60 @@ static int is_quadratic_residue_blind(struct sae_data *sae,
crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
goto fail;
- if (r_odd) {
- /*
- * num = (num * qr) module p
- * LGR(num, p) = 1 ==> quadratic residue
- */
- if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
- goto fail;
- check = 1;
- } else {
- /*
- * num = (num * qnr) module p
- * LGR(num, p) = -1 ==> quadratic residue
- */
- if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
- goto fail;
- check = -1;
- }
+ /*
+ * Need to minimize differences in handling different cases, so try to
+ * avoid branches and timing differences.
+ *
+ * If r_odd:
+ * num = (num * qr) module p
+ * LGR(num, p) = 1 ==> quadratic residue
+ * else:
+ * num = (num * qnr) module p
+ * LGR(num, p) = -1 ==> quadratic residue
+ */
+ mask = const_time_is_zero(r_odd);
+ const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin);
+ qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len);
+ if (!qr_or_qnr ||
+ crypto_bignum_mulmod(num, qr_or_qnr, sae->tmp->prime, num) < 0)
+ goto fail;
+ /* r_odd is 0 or 1; branchless version of check = r_odd ? 1 : -1, */
+ check = const_time_select_int(mask, -1, 1);
res = crypto_bignum_legendre(num, sae->tmp->prime);
if (res == -2) {
res = -1;
goto fail;
}
- res = res == check;
+ /* branchless version of res = res == check
+ * (res is -1, 0, or 1; check is -1 or 1) */
+ mask = const_time_eq(res, check);
+ res = const_time_select_int(mask, 1, 0);
fail:
crypto_bignum_deinit(num, 1);
crypto_bignum_deinit(r, 1);
+ crypto_bignum_deinit(qr_or_qnr, 1);
return res;
}
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
- const u8 *prime,
- const struct crypto_bignum *qr,
- const struct crypto_bignum *qnr,
- struct crypto_bignum **ret_x_cand)
+ const u8 *prime, const u8 *qr, const u8 *qnr,
+ u8 *pwd_value)
{
- u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
struct crypto_bignum *y_sqr, *x_cand;
int res;
size_t bits;
- *ret_x_cand = NULL;
-
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
- sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
- prime, sae->tmp->prime_len, pwd_value, bits);
+ if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+ prime, sae->tmp->prime_len, pwd_value, bits) < 0)
+ return -1;
if (bits % 8)
- buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+ buf_shift_right(pwd_value, sae->tmp->prime_len, 8 - bits % 8);
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
pwd_value, sae->tmp->prime_len);
@@ -289,53 +324,61 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
if (!x_cand)
return -1;
y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
- if (!y_sqr) {
- crypto_bignum_deinit(x_cand, 1);
+ crypto_bignum_deinit(x_cand, 1);
+ if (!y_sqr)
return -1;
- }
res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
crypto_bignum_deinit(y_sqr, 1);
- if (res <= 0) {
- crypto_bignum_deinit(x_cand, 1);
- return res;
- }
-
- *ret_x_cand = x_cand;
- return 1;
+ return res;
}
+/* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided
+ * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */
static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
struct crypto_bignum *pwe)
{
u8 pwd_value[SAE_MAX_PRIME_LEN];
size_t bits = sae->tmp->prime_len * 8;
u8 exp[1];
- struct crypto_bignum *a, *b;
- int res;
+ struct crypto_bignum *a, *b = NULL;
+ int res, is_val;
+ u8 pwd_value_valid;
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
- sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
- sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
- bits);
- if (bits % 8)
- buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+ if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+ sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
+ bits) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
sae->tmp->prime_len);
- if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
- {
- wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
- return 0;
- }
+ /* Check whether pwd-value < p */
+ res = const_time_memcmp(pwd_value, sae->tmp->dh->prime,
+ sae->tmp->prime_len);
+ /* pwd-value >= p is invalid, so res is < 0 for the valid cases and
+ * the negative sign can be used to fill the mask for constant time
+ * selection */
+ pwd_value_valid = const_time_fill_msb(res);
+
+ /* If pwd-value >= p, force pwd-value to be < p and perform the
+ * calculations anyway to hide timing difference. The derived PWE will
+ * be ignored in that case. */
+ pwd_value[0] = const_time_select_u8(pwd_value_valid, pwd_value[0], 0);
/* PWE = pwd-value^((p-1)/r) modulo p */
+ res = -1;
a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+ if (!a)
+ goto fail;
+ /* This is an optimization based on the used group that does not depend
+ * on the password in any way, so it is fine to use separate branches
+ * for this step without constant time operations. */
if (sae->tmp->dh->safe_prime) {
/*
* r = (p-1)/2 for the group used here, so this becomes:
@@ -349,33 +392,34 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
b = crypto_bignum_init_set(exp, sizeof(exp));
if (b == NULL ||
crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
- crypto_bignum_div(b, sae->tmp->order, b) < 0) {
- crypto_bignum_deinit(b, 0);
- b = NULL;
- }
+ crypto_bignum_div(b, sae->tmp->order, b) < 0)
+ goto fail;
}
- if (a == NULL || b == NULL)
- res = -1;
- else
- res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
-
- crypto_bignum_deinit(a, 0);
- crypto_bignum_deinit(b, 0);
+ if (!b)
+ goto fail;
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
- return -1;
- }
+ res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
+ if (res < 0)
+ goto fail;
- /* if (PWE > 1) --> found */
- if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
- wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
- return 0;
- }
+ /* There were no fatal errors in calculations, so determine the return
+ * value using constant time operations. We get here for number of
+ * invalid cases which are cleared here after having performed all the
+ * computation. PWE is valid if pwd-value was less than prime and
+ * PWE > 1. Start with pwd-value check first and then use constant time
+ * operations to clear res to 0 if PWE is 0 or 1.
+ */
+ res = const_time_select_u8(pwd_value_valid, 1, 0);
+ is_val = crypto_bignum_is_zero(pwe);
+ res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
+ is_val = crypto_bignum_is_one(pwe);
+ res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
- wpa_printf(MSG_DEBUG, "SAE: PWE found");
- return 1;
+fail:
+ crypto_bignum_deinit(a, 1);
+ crypto_bignum_deinit(b, 1);
+ return res;
}
@@ -417,31 +461,39 @@ static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
- size_t password_len)
+ size_t password_len, const char *identifier)
{
u8 counter, k = 40;
u8 addrs[2 * ETH_ALEN];
- const u8 *addr[2];
- size_t len[2];
- u8 dummy_password[32];
- size_t dummy_password_len;
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem;
+ u8 *dummy_password, *tmp_password;
int pwd_seed_odd = 0;
u8 prime[SAE_MAX_ECC_PRIME_LEN];
size_t prime_len;
- struct crypto_bignum *x = NULL, *qr, *qnr;
+ struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL;
+ u8 x_bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 qr_bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 qnr_bin[SAE_MAX_ECC_PRIME_LEN];
size_t bits;
- int res;
+ int res = -1;
+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+ * mask */
- dummy_password_len = password_len;
- if (dummy_password_len > sizeof(dummy_password))
- dummy_password_len = sizeof(dummy_password);
- if (random_get_bytes(dummy_password, dummy_password_len) < 0)
- return -1;
+ os_memset(x_bin, 0, sizeof(x_bin));
+
+ dummy_password = os_malloc(password_len);
+ tmp_password = os_malloc(password_len);
+ if (!dummy_password || !tmp_password ||
+ random_get_bytes(dummy_password, password_len) < 0)
+ goto fail;
prime_len = sae->tmp->prime_len;
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
prime_len) < 0)
- return -1;
+ goto fail;
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
/*
@@ -449,33 +501,44 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
* (qnr) modulo p for blinding purposes during the loop.
*/
if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
- &qr, &qnr) < 0)
- return -1;
+ &qr, &qnr) < 0 ||
+ crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), prime_len) < 0 ||
+ crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), prime_len) < 0)
+ goto fail;
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
password, password_len);
+ if (identifier)
+ wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
+ identifier);
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
- * base = password
+ * base = password [|| identifier]
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
* base || counter)
*/
sae_pwd_seed_key(addr1, addr2, addrs);
- addr[0] = password;
+ addr[0] = tmp_password;
len[0] = password_len;
- addr[1] = &counter;
- len[1] = sizeof(counter);
+ num_elem = 1;
+ if (identifier) {
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ addr[num_elem] = &counter;
+ len[num_elem] = sizeof(counter);
+ num_elem++;
/*
* Continue for at least k iterations to protect against side-channel
* attacks that attempt to determine the number of iterations required
* in the loop.
*/
- for (counter = 1; counter <= k || !x; counter++) {
+ for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
- struct crypto_bignum *x_cand;
if (counter > 200) {
/* This should not happen in practice */
@@ -483,36 +546,45 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
break;
}
- wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
- if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
- pwd_seed) < 0)
+ wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter);
+ const_time_select_bin(found, dummy_password, password,
+ password_len, tmp_password);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ addr, len, pwd_seed) < 0)
break;
res = sae_test_pwd_seed_ecc(sae, pwd_seed,
- prime, qr, qnr, &x_cand);
+ prime, qr_bin, qnr_bin, x_cand_bin);
+ const_time_select_bin(found, x_bin, x_cand_bin, prime_len,
+ x_bin);
+ pwd_seed_odd = const_time_select_u8(
+ found, pwd_seed_odd,
+ pwd_seed[SHA256_MAC_LEN - 1] & 0x01);
+ os_memset(pwd_seed, 0, sizeof(pwd_seed));
if (res < 0)
goto fail;
- if (res > 0 && !x) {
- wpa_printf(MSG_DEBUG,
- "SAE: Selected pwd-seed with counter %u",
- counter);
- x = x_cand;
- pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
- os_memset(pwd_seed, 0, sizeof(pwd_seed));
+ /* Need to minimize differences in handling res == 0 and 1 here
+ * to avoid differences in timing and instruction cache access,
+ * so use const_time_select_*() to make local copies of the
+ * values based on whether this loop iteration was the one that
+ * found the pwd-seed/x. */
+
+ /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
+ * (with res converted to 0/0xff) handles this in constant time.
+ */
+ found |= res * 0xff;
+ wpa_printf(MSG_DEBUG, "SAE: pwd-seed result %d found=0x%02x",
+ res, found);
+ }
- /*
- * Use a dummy password for the following rounds, if
- * any.
- */
- addr[0] = dummy_password;
- len[0] = dummy_password_len;
- } else if (res > 0) {
- crypto_bignum_deinit(x_cand, 1);
- }
+ if (!found) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
+ res = -1;
+ goto fail;
}
+ x = crypto_bignum_init_set(x_bin, prime_len);
if (!x) {
- wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
res = -1;
goto fail;
}
@@ -525,7 +597,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
sae->tmp->pwe_ecc, x,
pwd_seed_odd);
- crypto_bignum_deinit(x, 1);
if (res < 0) {
/*
* This should not happen since we already checked that there
@@ -537,26 +608,48 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
fail:
crypto_bignum_deinit(qr, 0);
crypto_bignum_deinit(qnr, 0);
+ os_free(dummy_password);
+ bin_clear_free(tmp_password, password_len);
+ crypto_bignum_deinit(x, 1);
+ os_memset(x_bin, 0, sizeof(x_bin));
+ os_memset(x_cand_bin, 0, sizeof(x_cand_bin));
return res;
}
+static int sae_modp_group_require_masking(int group)
+{
+ /* Groups for which pwd-value is likely to be >= p frequently */
+ return group == 22 || group == 23 || group == 24;
+}
+
+
static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
- size_t password_len)
+ size_t password_len, const char *identifier)
{
- u8 counter;
+ u8 counter, k, sel_counter = 0;
u8 addrs[2 * ETH_ALEN];
- const u8 *addr[2];
- size_t len[2];
- int found = 0;
-
- if (sae->tmp->pwe_ffc == NULL) {
- sae->tmp->pwe_ffc = crypto_bignum_init();
- if (sae->tmp->pwe_ffc == NULL)
- return -1;
- }
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem;
+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+ * mask */
+ u8 mask;
+ struct crypto_bignum *pwe;
+ size_t prime_len = sae->tmp->prime_len * 8;
+ u8 *pwe_buf;
+
+ crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
+ sae->tmp->pwe_ffc = NULL;
+
+ /* Allocate a buffer to maintain selected and candidate PWE for constant
+ * time selection. */
+ pwe_buf = os_zalloc(prime_len * 2);
+ pwe = crypto_bignum_init();
+ if (!pwe_buf || !pwe)
+ goto fail;
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
password, password_len);
@@ -564,16 +657,25 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
- * password || counter)
+ * password [|| identifier] || counter)
*/
sae_pwd_seed_key(addr1, addr2, addrs);
addr[0] = password;
len[0] = password_len;
- addr[1] = &counter;
- len[1] = sizeof(counter);
+ num_elem = 1;
+ if (identifier) {
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ addr[num_elem] = &counter;
+ len[num_elem] = sizeof(counter);
+ num_elem++;
- for (counter = 1; !found; counter++) {
+ k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
+
+ for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
int res;
@@ -583,20 +685,37 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
break;
}
- wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
- if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
- pwd_seed) < 0)
+ wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ addr, len, pwd_seed) < 0)
break;
- res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
+ res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
+ /* res is -1 for fatal failure, 0 if a valid PWE was not found,
+ * or 1 if a valid PWE was found. */
if (res < 0)
break;
- if (res > 0) {
- wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
- found = 1;
- }
+ /* Store the candidate PWE into the second half of pwe_buf and
+ * the selected PWE in the beginning of pwe_buf using constant
+ * time selection. */
+ if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len,
+ prime_len) < 0)
+ break;
+ const_time_select_bin(found, pwe_buf, pwe_buf + prime_len,
+ prime_len, pwe_buf);
+ sel_counter = const_time_select_u8(found, sel_counter, counter);
+ mask = const_time_eq_u8(res, 1);
+ found = const_time_select_u8(found, found, mask);
}
- return found ? 0 : -1;
+ if (!found)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter);
+ sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len);
+fail:
+ crypto_bignum_deinit(pwe, 1);
+ bin_clear_free(pwe_buf, prime_len * 2);
+ return sae->tmp->pwe_ffc ? 0 : -1;
}
@@ -696,13 +815,15 @@ fail:
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
- struct sae_data *sae)
+ const char *identifier, struct sae_data *sae)
{
if (sae->tmp == NULL ||
(sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
- password_len) < 0) ||
+ password_len,
+ identifier) < 0) ||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
- password_len) < 0) ||
+ password_len,
+ identifier) < 0) ||
sae_derive_commit(sae) < 0)
return -1;
return 0;
@@ -811,11 +932,13 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
crypto_bignum_mod(tmp, sae->tmp->order, tmp);
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
- sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
- val, sae->tmp->prime_len, keys, sizeof(keys));
+ if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
+ val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
+ goto fail;
os_memset(keyseed, 0, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+ os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
os_memset(keys, 0, sizeof(keys));
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
@@ -840,7 +963,7 @@ int sae_process_commit(struct sae_data *sae)
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
- const struct wpabuf *token)
+ const struct wpabuf *token, const char *identifier)
{
u8 *pos;
@@ -874,6 +997,16 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
pos, sae->tmp->prime_len);
}
+
+ if (identifier) {
+ /* Password Identifier element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + os_strlen(identifier));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER);
+ wpabuf_put_str(buf, identifier);
+ wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
+ identifier);
+ }
}
@@ -919,25 +1052,70 @@ u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
}
+static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 3 &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER;
+}
+
+
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
size_t *token_len)
{
- if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
- size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
- sae->tmp->prime_len);
- wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
- if (token)
- *token = *pos;
- if (token_len)
- *token_len = tlen;
- *pos += tlen;
- } else {
- if (token)
- *token = NULL;
- if (token_len)
- *token_len = 0;
+ size_t scalar_elem_len, tlen;
+ const u8 *elem;
+
+ if (token)
+ *token = NULL;
+ if (token_len)
+ *token_len = 0;
+
+ scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
+ if (scalar_elem_len >= (size_t) (end - *pos))
+ return; /* No extra data beyond peer scalar and element */
+
+ /* It is a bit difficult to parse this now that there is an
+ * optional variable length Anti-Clogging Token field and
+ * optional variable length Password Identifier element in the
+ * frame. We are sending out fixed length Anti-Clogging Token
+ * fields, so use that length as a requirement for the received
+ * token and check for the presence of possible Password
+ * Identifier element based on the element header information.
+ */
+ tlen = end - (*pos + scalar_elem_len);
+
+ if (tlen < SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
+ (unsigned int) tlen);
+ return;
+ }
+
+ elem = *pos + scalar_elem_len;
+ if (sae_is_password_id_elem(elem, end)) {
+ /* Password Identifier element takes out all available
+ * extra octets, so there can be no Anti-Clogging token in
+ * this frame. */
+ return;
+ }
+
+ elem += SHA256_MAC_LEN;
+ if (sae_is_password_id_elem(elem, end)) {
+ /* Password Identifier element is included in the end, so
+ * remove its length from the Anti-Clogging token field. */
+ tlen -= 2 + elem[1];
}
+
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
+ if (token)
+ *token = *pos;
+ if (token_len)
+ *token_len = tlen;
+ *pos += tlen;
}
@@ -946,7 +1124,7 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
{
struct crypto_bignum *peer_scalar;
- if (*pos + sae->tmp->prime_len > end) {
+ if (sae->tmp->prime_len > end - *pos) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
@@ -989,12 +1167,12 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
}
-static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
u8 prime[SAE_MAX_ECC_PRIME_LEN];
- if (pos + 2 * sae->tmp->prime_len > end) {
+ if (2 * sae->tmp->prime_len > end - *pos) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
"commit-element");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1005,8 +1183,8 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/* element x and y coordinates < p */
- if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
- os_memcmp(pos + sae->tmp->prime_len, prime,
+ if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 ||
+ os_memcmp(*pos + sae->tmp->prime_len, prime,
sae->tmp->prime_len) >= 0) {
wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
"element");
@@ -1014,13 +1192,13 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
}
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
- pos, sae->tmp->prime_len);
+ *pos, sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
- pos + sae->tmp->prime_len, sae->tmp->prime_len);
+ *pos + sae->tmp->prime_len, sae->tmp->prime_len);
crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
sae->tmp->peer_commit_element_ecc =
- crypto_ec_point_from_bin(sae->tmp->ec, pos);
+ crypto_ec_point_from_bin(sae->tmp->ec, *pos);
if (sae->tmp->peer_commit_element_ecc == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1030,27 +1208,29 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+ *pos += 2 * sae->tmp->prime_len;
+
return WLAN_STATUS_SUCCESS;
}
-static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
struct crypto_bignum *res, *one;
const u8 one_bin[1] = { 0x01 };
- if (pos + sae->tmp->prime_len > end) {
+ if (sae->tmp->prime_len > end - *pos) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
"commit-element");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos,
sae->tmp->prime_len);
crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
sae->tmp->peer_commit_element_ffc =
- crypto_bignum_init_set(pos, sae->tmp->prime_len);
+ crypto_bignum_init_set(*pos, sae->tmp->prime_len);
if (sae->tmp->peer_commit_element_ffc == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/* 1 < element < p - 1 */
@@ -1078,11 +1258,13 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
}
crypto_bignum_deinit(res, 0);
+ *pos += sae->tmp->prime_len;
+
return WLAN_STATUS_SUCCESS;
}
-static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
if (sae->tmp->dh)
@@ -1091,6 +1273,44 @@ static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
}
+static int sae_parse_password_identifier(struct sae_data *sae,
+ const u8 *pos, const u8 *end)
+{
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ pos, end - pos);
+ if (!sae_is_password_id_elem(pos, end)) {
+ if (sae->tmp->pw_id) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No Password Identifier included, but expected one (%s)",
+ sae->tmp->pw_id);
+ return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+ }
+ os_free(sae->tmp->pw_id);
+ sae->tmp->pw_id = NULL;
+ return WLAN_STATUS_SUCCESS; /* No Password Identifier */
+ }
+
+ if (sae->tmp->pw_id &&
+ (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
+ os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: The included Password Identifier does not match the expected one (%s)",
+ sae->tmp->pw_id);
+ return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+ }
+
+ os_free(sae->tmp->pw_id);
+ sae->tmp->pw_id = os_malloc(pos[1]);
+ if (!sae->tmp->pw_id)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
+ sae->tmp->pw_id[pos[1] - 1] = '\0';
+ wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
+ sae->tmp->pw_id, pos[1] - 1);
+ return WLAN_STATUS_SUCCESS;
+}
+
+
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
const u8 **token, size_t *token_len, int *allowed_groups)
{
@@ -1098,7 +1318,7 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
u16 res;
/* Check Finite Cyclic Group */
- if (pos + 2 > end)
+ if (end - pos < 2)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
if (res != WLAN_STATUS_SUCCESS)
@@ -1114,7 +1334,12 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
return res;
/* commit-element */
- res = sae_parse_commit_element(sae, pos, end);
+ res = sae_parse_commit_element(sae, &pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+
+ /* Optional Password Identifier element */
+ res = sae_parse_password_identifier(sae, pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
@@ -1233,7 +1458,8 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
/* Send-Confirm */
sc = wpabuf_put(buf, 0);
wpabuf_put_le16(buf, sae->send_confirm);
- sae->send_confirm++;
+ if (sae->send_confirm < 0xffff)
+ sae->send_confirm++;
if (sae->tmp->ec)
sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
@@ -1261,23 +1487,31 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
- if (sae->tmp == NULL) {
+ if (!sae->tmp || !sae->peer_commit_scalar ||
+ !sae->tmp->own_commit_scalar) {
wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
return -1;
}
- if (sae->tmp->ec)
+ if (sae->tmp->ec) {
+ if (!sae->tmp->peer_commit_element_ecc ||
+ !sae->tmp->own_commit_element_ecc)
+ return -1;
sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ecc,
sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ecc,
verifier);
- else
+ } else {
+ if (!sae->tmp->peer_commit_element_ffc ||
+ !sae->tmp->own_commit_element_ffc)
+ return -1;
sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ffc,
sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ffc,
verifier);
+ }
if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
@@ -1290,3 +1524,19 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
return 0;
}
+
+
+const char * sae_state_txt(enum sae_state state)
+{
+ switch (state) {
+ case SAE_NOTHING:
+ return "Nothing";
+ case SAE_COMMITTED:
+ return "Committed";
+ case SAE_CONFIRMED:
+ return "Confirmed";
+ case SAE_ACCEPTED:
+ return "Accepted";
+ }
+ return "?";
+}
diff --git a/contrib/wpa/src/common/sae.h b/contrib/wpa/src/common/sae.h
index c07026c..3eb6e32 100644
--- a/contrib/wpa/src/common/sae.h
+++ b/contrib/wpa/src/common/sae.h
@@ -39,15 +39,24 @@ struct sae_temporary_data {
struct crypto_bignum *prime_buf;
struct crypto_bignum *order_buf;
struct wpabuf *anti_clogging_token;
+ char *pw_id;
+ int vlan_id;
+ u8 bssid[ETH_ALEN];
+};
+
+enum sae_state {
+ SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED
};
struct sae_data {
- enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
+ enum sae_state state;
u16 send_confirm;
u8 pmk[SAE_PMK_LEN];
+ u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
int group;
- int sync;
+ unsigned int sync; /* protocol instance variable: Sync */
+ u16 rc; /* protocol instance variable: Rc (received send-confirm) */
struct sae_temporary_data *tmp;
};
@@ -57,14 +66,15 @@ void sae_clear_data(struct sae_data *sae);
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
- struct sae_data *sae);
+ const char *identifier, struct sae_data *sae);
int sae_process_commit(struct sae_data *sae);
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
- const struct wpabuf *token);
+ const struct wpabuf *token, const char *identifier);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
const u8 **token, size_t *token_len, int *allowed_groups);
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
+const char * sae_state_txt(enum sae_state state);
#endif /* SAE_H */
diff --git a/contrib/wpa/src/common/version.h b/contrib/wpa/src/common/version.h
index a5cc5b7..06fc5e4 100644
--- a/contrib/wpa/src/common/version.h
+++ b/contrib/wpa/src/common/version.h
@@ -5,6 +5,10 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
-#define VERSION_STR "2.5" VERSION_STR_POSTFIX
+#ifndef GIT_VERSION_STR_POSTFIX
+#define GIT_VERSION_STR_POSTFIX ""
+#endif /* GIT_VERSION_STR_POSTFIX */
+
+#define VERSION_STR "2.8" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/contrib/wpa/src/common/wpa_common.c b/contrib/wpa/src/common/wpa_common.c
index e9d4248..ed2d1c2 100644
--- a/contrib/wpa/src/common/wpa_common.c
+++ b/contrib/wpa/src/common/wpa_common.c
@@ -1,6 +1,6 @@
/*
* WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,6 +13,7 @@
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "crypto/sha384.h"
+#include "crypto/sha512.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "ieee802_11_defs.h"
@@ -20,27 +21,151 @@
#include "wpa_common.h"
-static unsigned int wpa_kck_len(int akmp)
+static unsigned int wpa_kck_len(int akmp, size_t pmk_len)
{
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ switch (akmp) {
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
return 24;
- return 16;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 0;
+ case WPA_KEY_MGMT_DPP:
+ return pmk_len / 2;
+ case WPA_KEY_MGMT_OWE:
+ return pmk_len / 2;
+ default:
+ return 16;
+ }
}
-static unsigned int wpa_kek_len(int akmp)
+#ifdef CONFIG_IEEE80211R
+static unsigned int wpa_kck2_len(int akmp)
{
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ switch (akmp) {
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ return 16;
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 24;
+ default:
+ return 0;
+ }
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static unsigned int wpa_kek_len(int akmp, size_t pmk_len)
+{
+ switch (akmp) {
+ case WPA_KEY_MGMT_FILS_SHA384:
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 64;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
return 32;
- return 16;
+ case WPA_KEY_MGMT_DPP:
+ return pmk_len <= 32 ? 16 : 32;
+ case WPA_KEY_MGMT_OWE:
+ return pmk_len <= 32 ? 16 : 32;
+ default:
+ return 16;
+ }
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static unsigned int wpa_kek2_len(int akmp)
+{
+ switch (akmp) {
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ return 16;
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 32;
+ default:
+ return 0;
+ }
}
+#endif /* CONFIG_IEEE80211R */
-unsigned int wpa_mic_len(int akmp)
+unsigned int wpa_mic_len(int akmp, size_t pmk_len)
{
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ switch (akmp) {
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
return 24;
- return 16;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 0;
+ case WPA_KEY_MGMT_DPP:
+ return pmk_len / 2;
+ case WPA_KEY_MGMT_OWE:
+ return pmk_len / 2;
+ default:
+ return 16;
+ }
+}
+
+
+/**
+ * wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise
+ */
+int wpa_use_akm_defined(int akmp)
+{
+ return akmp == WPA_KEY_MGMT_OSEN ||
+ akmp == WPA_KEY_MGMT_OWE ||
+ akmp == WPA_KEY_MGMT_DPP ||
+ akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
+ wpa_key_mgmt_sae(akmp) ||
+ wpa_key_mgmt_suite_b(akmp) ||
+ wpa_key_mgmt_fils(akmp);
+}
+
+
+/**
+ * wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if CMAC is used; 0 otherwise
+ */
+int wpa_use_cmac(int akmp)
+{
+ return akmp == WPA_KEY_MGMT_OSEN ||
+ akmp == WPA_KEY_MGMT_OWE ||
+ akmp == WPA_KEY_MGMT_DPP ||
+ wpa_key_mgmt_ft(akmp) ||
+ wpa_key_mgmt_sha256(akmp) ||
+ wpa_key_mgmt_sae(akmp) ||
+ wpa_key_mgmt_suite_b(akmp);
+}
+
+
+/**
+ * wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if AES Keywrap is used; 0 otherwise
+ *
+ * Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether
+ * to use AES Keywrap based on the negotiated pairwise cipher. This function
+ * does not cover those special cases.
+ */
+int wpa_use_aes_key_wrap(int akmp)
+{
+ return akmp == WPA_KEY_MGMT_OSEN ||
+ akmp == WPA_KEY_MGMT_OWE ||
+ akmp == WPA_KEY_MGMT_DPP ||
+ wpa_key_mgmt_ft(akmp) ||
+ wpa_key_mgmt_sha256(akmp) ||
+ wpa_key_mgmt_sae(akmp) ||
+ wpa_key_mgmt_suite_b(akmp);
}
@@ -67,30 +192,50 @@ unsigned int wpa_mic_len(int akmp)
int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
const u8 *buf, size_t len, u8 *mic)
{
- u8 hash[SHA384_MAC_LEN];
+ u8 hash[SHA512_MAC_LEN];
+
+ if (key_len == 0) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: KCK not set - cannot calculate MIC");
+ return -1;
+ }
switch (ver) {
#ifndef CONFIG_FIPS
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
+ wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-MD5");
return hmac_md5(key, key_len, buf, len, mic);
#endif /* CONFIG_FIPS */
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
+ wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-SHA1");
if (hmac_sha1(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
+ wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
switch (akmp) {
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ case WPA_KEY_MGMT_FT_SAE:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
+ return omac1_aes_128(key, buf, len, mic);
+#endif /* CONFIG_SAE */
#ifdef CONFIG_HS20
case WPA_KEY_MGMT_OSEN:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - OSEN)");
return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_SUITEB
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using HMAC-SHA256 (AKM-defined - Suite B)");
if (hmac_sha256(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
@@ -98,16 +243,79 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
#endif /* CONFIG_SUITEB */
#ifdef CONFIG_SUITEB192
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - Suite B 192-bit)");
if (hmac_sha384(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, 24);
break;
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_OWE
+ case WPA_KEY_MGMT_OWE:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - OWE)",
+ (unsigned int) key_len * 8 * 2);
+ if (key_len == 128 / 8) {
+ if (hmac_sha256(key, key_len, buf, len, hash))
+ return -1;
+ } else if (key_len == 192 / 8) {
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+ } else if (key_len == 256 / 8) {
+ if (hmac_sha512(key, key_len, buf, len, hash))
+ return -1;
+ } else {
+ wpa_printf(MSG_INFO,
+ "OWE: Unsupported KCK length: %u",
+ (unsigned int) key_len);
+ return -1;
+ }
+ os_memcpy(mic, hash, key_len);
+ break;
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ case WPA_KEY_MGMT_DPP:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - DPP)",
+ (unsigned int) key_len * 8 * 2);
+ if (key_len == 128 / 8) {
+ if (hmac_sha256(key, key_len, buf, len, hash))
+ return -1;
+ } else if (key_len == 192 / 8) {
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+ } else if (key_len == 256 / 8) {
+ if (hmac_sha512(key, key_len, buf, len, hash))
+ return -1;
+ } else {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported KCK length: %u",
+ (unsigned int) key_len);
+ return -1;
+ }
+ os_memcpy(mic, hash, key_len);
+ break;
+#endif /* CONFIG_DPP */
+#if defined(CONFIG_IEEE80211R) && defined(CONFIG_SHA384)
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - FT 802.1X SHA384)");
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 24);
+ break;
+#endif /* CONFIG_IEEE80211R && CONFIG_SHA384 */
default:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)",
+ akmp);
return -1;
}
break;
default:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC algorithm not known (ver=%d)",
+ ver);
return -1;
}
@@ -132,21 +340,32 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PTK = PRF-X(PMK, "Pairwise key expansion",
* Min(AA, SA) || Max(AA, SA) ||
- * Min(ANonce, SNonce) || Max(ANonce, SNonce))
+ * Min(ANonce, SNonce) || Max(ANonce, SNonce)
+ * [ || Z.x ])
*
- * STK = PRF-X(SMK, "Peer key expansion",
- * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
- * Min(INonce, PNonce) || Max(INonce, PNonce))
+ * The optional Z.x component is used only with DPP and that part is not defined
+ * in IEEE 802.11.
*/
int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
- struct wpa_ptk *ptk, int akmp, int cipher)
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ const u8 *z, size_t z_len)
{
- u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+#define MAX_Z_LEN 66 /* with NIST P-521 */
+ u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
+ size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
size_t ptk_len;
+ if (pmk_len == 0) {
+ wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
+ return -1;
+ }
+
+ if (z_len > MAX_Z_LEN)
+ return -1;
+
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
os_memcpy(data, addr1, ETH_ALEN);
os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
@@ -165,29 +384,74 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
WPA_NONCE_LEN);
}
- ptk->kck_len = wpa_kck_len(akmp);
- ptk->kek_len = wpa_kek_len(akmp);
+ if (z && z_len) {
+ os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len);
+ data_len += z_len;
+ }
+
+ ptk->kck_len = wpa_kck_len(akmp, pmk_len);
+ ptk->kek_len = wpa_kek_len(akmp, pmk_len);
ptk->tk_len = wpa_cipher_key_len(cipher);
+ if (ptk->tk_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "WPA: Unsupported cipher (0x%x) used in PTK derivation",
+ cipher);
+ return -1;
+ }
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
-#ifdef CONFIG_SUITEB192
- if (wpa_key_mgmt_sha384(akmp))
- sha384_prf(pmk, pmk_len, label, data, sizeof(data),
- tmp, ptk_len);
- else
-#endif /* CONFIG_SUITEB192 */
-#ifdef CONFIG_IEEE80211W
- if (wpa_key_mgmt_sha256(akmp))
- sha256_prf(pmk, pmk_len, label, data, sizeof(data),
- tmp, ptk_len);
- else
-#endif /* CONFIG_IEEE80211W */
- sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len);
+ if (wpa_key_mgmt_sha384(akmp)) {
+#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+#else /* CONFIG_SUITEB192 || CONFIG_FILS */
+ return -1;
+#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
+ } else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
+ return -1;
+#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
+#ifdef CONFIG_DPP
+ } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
+ if (sha512_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_DPP) {
+ wpa_printf(MSG_INFO, "DPP: Unknown PMK length %u",
+ (unsigned int) pmk_len);
+ return -1;
+#endif /* CONFIG_DPP */
+ } else {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
+ if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
+ ptk_len) < 0)
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
MAC2STR(addr1), MAC2STR(addr2));
wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
+ if (z && z_len)
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
@@ -200,10 +464,291 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+ ptk->kek2_len = 0;
+ ptk->kck2_len = 0;
+
+ os_memset(tmp, 0, sizeof(tmp));
+ os_memset(data, 0, data_len);
+ return 0;
+}
+
+#ifdef CONFIG_FILS
+
+int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
+ const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
+ size_t dh_ss_len, u8 *pmk, size_t *pmk_len)
+{
+ u8 nonces[2 * FILS_NONCE_LEN];
+ const u8 *addr[2];
+ size_t len[2];
+ size_t num_elem;
+ int res;
+
+ /* PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) */
+ wpa_printf(MSG_DEBUG, "FILS: rMSK to PMK derivation");
+
+ if (wpa_key_mgmt_sha384(akmp))
+ *pmk_len = SHA384_MAC_LEN;
+ else if (wpa_key_mgmt_sha256(akmp))
+ *pmk_len = SHA256_MAC_LEN;
+ else
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "FILS: rMSK", rmsk, rmsk_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: DHss", dh_ss, dh_ss_len);
+
+ os_memcpy(nonces, snonce, FILS_NONCE_LEN);
+ os_memcpy(&nonces[FILS_NONCE_LEN], anonce, FILS_NONCE_LEN);
+ addr[0] = rmsk;
+ len[0] = rmsk_len;
+ num_elem = 1;
+ if (dh_ss) {
+ addr[1] = dh_ss;
+ len[1] = dh_ss_len;
+ num_elem++;
+ }
+ if (wpa_key_mgmt_sha384(akmp))
+ res = hmac_sha384_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
+ addr, len, pmk);
+ else
+ res = hmac_sha256_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
+ addr, len, pmk);
+ if (res == 0)
+ wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len);
+ else
+ *pmk_len = 0;
+ return res;
+}
+
+
+int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
+ u8 *pmkid)
+{
+ const u8 *addr[1];
+ size_t len[1];
+ u8 hash[SHA384_MAC_LEN];
+ int res;
+
+ /* PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) */
+ addr[0] = reauth;
+ len[0] = reauth_len;
+ if (wpa_key_mgmt_sha384(akmp))
+ res = sha384_vector(1, addr, len, hash);
+ else if (wpa_key_mgmt_sha256(akmp))
+ res = sha256_vector(1, addr, len, hash);
+ else
+ return -1;
+ if (res)
+ return res;
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
+ return 0;
+}
+
+
+int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
+ const u8 *snonce, const u8 *anonce, const u8 *dhss,
+ size_t dhss_len, struct wpa_ptk *ptk,
+ u8 *ick, size_t *ick_len, int akmp, int cipher,
+ u8 *fils_ft, size_t *fils_ft_len)
+{
+ u8 *data, *pos;
+ size_t data_len;
+ u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+ FILS_FT_MAX_LEN];
+ size_t key_data_len;
+ const char *label = "FILS PTK Derivation";
+ int ret = -1;
+
+ /*
+ * FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation",
+ * SPA || AA || SNonce || ANonce [ || DHss ])
+ * ICK = L(FILS-Key-Data, 0, ICK_bits)
+ * KEK = L(FILS-Key-Data, ICK_bits, KEK_bits)
+ * TK = L(FILS-Key-Data, ICK_bits + KEK_bits, TK_bits)
+ * If doing FT initial mobility domain association:
+ * FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits,
+ * FILS-FT_bits)
+ */
+ data_len = 2 * ETH_ALEN + 2 * FILS_NONCE_LEN + dhss_len;
+ data = os_malloc(data_len);
+ if (!data)
+ goto err;
+ pos = data;
+ os_memcpy(pos, spa, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, aa, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, snonce, FILS_NONCE_LEN);
+ pos += FILS_NONCE_LEN;
+ os_memcpy(pos, anonce, FILS_NONCE_LEN);
+ pos += FILS_NONCE_LEN;
+ if (dhss)
+ os_memcpy(pos, dhss, dhss_len);
+
+ ptk->kck_len = 0;
+ ptk->kek_len = wpa_kek_len(akmp, pmk_len);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ if (wpa_key_mgmt_sha384(akmp))
+ *ick_len = 48;
+ else if (wpa_key_mgmt_sha256(akmp))
+ *ick_len = 32;
+ else
+ goto err;
+ key_data_len = *ick_len + ptk->kek_len + ptk->tk_len;
+
+ if (fils_ft && fils_ft_len) {
+ if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) {
+ *fils_ft_len = 32;
+ } else if (akmp == WPA_KEY_MGMT_FT_FILS_SHA384) {
+ *fils_ft_len = 48;
+ } else {
+ *fils_ft_len = 0;
+ fils_ft = NULL;
+ }
+ key_data_len += *fils_ft_len;
+ }
+
+ if (wpa_key_mgmt_sha384(akmp)) {
+ wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA384)");
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
+ tmp, key_data_len) < 0)
+ goto err;
+ } else {
+ wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA256)");
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
+ tmp, key_data_len) < 0)
+ goto err;
+ }
+
+ wpa_printf(MSG_DEBUG, "FILS: PTK derivation - SPA=" MACSTR
+ " AA=" MACSTR, MAC2STR(spa), MAC2STR(aa));
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
+ if (dhss)
+ wpa_hexdump_key(MSG_DEBUG, "FILS: DHss", dhss, dhss_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, pmk_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len);
+
+ os_memcpy(ick, tmp, *ick_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len);
+
+ os_memcpy(ptk->kek, tmp + *ick_len, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len);
+
+ os_memcpy(ptk->tk, tmp + *ick_len + ptk->kek_len, ptk->tk_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len);
+
+ if (fils_ft && fils_ft_len) {
+ os_memcpy(fils_ft, tmp + *ick_len + ptk->kek_len + ptk->tk_len,
+ *fils_ft_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT",
+ fils_ft, *fils_ft_len);
+ }
+
+ ptk->kek2_len = 0;
+ ptk->kck2_len = 0;
+
os_memset(tmp, 0, sizeof(tmp));
+ ret = 0;
+err:
+ bin_clear_free(data, data_len);
+ return ret;
+}
+
+
+int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
+ const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
+ const u8 *g_sta, size_t g_sta_len,
+ const u8 *g_ap, size_t g_ap_len,
+ int akmp, u8 *key_auth_sta, u8 *key_auth_ap,
+ size_t *key_auth_len)
+{
+ const u8 *addr[6];
+ size_t len[6];
+ size_t num_elem = 4;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "FILS: Key-Auth derivation: STA-MAC=" MACSTR
+ " AP-BSSID=" MACSTR, MAC2STR(sta_addr), MAC2STR(bssid));
+ wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, ick_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: gSTA", g_sta, g_sta_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: gAP", g_ap, g_ap_len);
+
+ /*
+ * For (Re)Association Request frame (STA->AP):
+ * Key-Auth = HMAC-Hash(ICK, SNonce || ANonce || STA-MAC || AP-BSSID
+ * [ || gSTA || gAP ])
+ */
+ addr[0] = snonce;
+ len[0] = FILS_NONCE_LEN;
+ addr[1] = anonce;
+ len[1] = FILS_NONCE_LEN;
+ addr[2] = sta_addr;
+ len[2] = ETH_ALEN;
+ addr[3] = bssid;
+ len[3] = ETH_ALEN;
+ if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ addr[4] = g_sta;
+ len[4] = g_sta_len;
+ addr[5] = g_ap;
+ len[5] = g_ap_len;
+ num_elem = 6;
+ }
+
+ if (wpa_key_mgmt_sha384(akmp)) {
+ *key_auth_len = 48;
+ res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
+ key_auth_sta);
+ } else if (wpa_key_mgmt_sha256(akmp)) {
+ *key_auth_len = 32;
+ res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
+ key_auth_sta);
+ } else {
+ return -1;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * For (Re)Association Response frame (AP->STA):
+ * Key-Auth = HMAC-Hash(ICK, ANonce || SNonce || AP-BSSID || STA-MAC
+ * [ || gAP || gSTA ])
+ */
+ addr[0] = anonce;
+ addr[1] = snonce;
+ addr[2] = bssid;
+ addr[3] = sta_addr;
+ if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ addr[4] = g_ap;
+ len[4] = g_ap_len;
+ addr[5] = g_sta;
+ len[5] = g_sta_len;
+ }
+
+ if (wpa_key_mgmt_sha384(akmp))
+ res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
+ key_auth_ap);
+ else if (wpa_key_mgmt_sha256(akmp))
+ res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
+ key_auth_ap);
+ if (res < 0)
+ return res;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (STA)",
+ key_auth_sta, *key_auth_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (AP)",
+ key_auth_ap, *key_auth_len);
+
return 0;
}
+#endif /* CONFIG_FILS */
+
#ifdef CONFIG_IEEE80211R
int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
@@ -216,14 +761,23 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *addr[9];
size_t len[9];
size_t i, num_elem = 0;
- u8 zero_mic[16];
-
- if (kck_len != 16) {
+ u8 zero_mic[24];
+ size_t mic_len, fte_fixed_len;
+
+ if (kck_len == 16) {
+ mic_len = 16;
+#ifdef CONFIG_SHA384
+ } else if (kck_len == 24) {
+ mic_len = 24;
+#endif /* CONFIG_SHA384 */
+ } else {
wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
(unsigned int) kck_len);
return -1;
}
+ fte_fixed_len = sizeof(struct rsn_ftie) - 16 + mic_len;
+
addr[num_elem] = sta_addr;
len[num_elem] = ETH_ALEN;
num_elem++;
@@ -247,7 +801,7 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
num_elem++;
}
if (ftie) {
- if (ftie_len < 2 + sizeof(struct rsn_ftie))
+ if (ftie_len < 2 + fte_fixed_len)
return -1;
/* IE hdr and mic_control */
@@ -256,14 +810,14 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
num_elem++;
/* MIC field with all zeros */
- os_memset(zero_mic, 0, sizeof(zero_mic));
+ os_memset(zero_mic, 0, mic_len);
addr[num_elem] = zero_mic;
- len[num_elem] = sizeof(zero_mic);
+ len[num_elem] = mic_len;
num_elem++;
/* Rest of FTIE */
- addr[num_elem] = ftie + 2 + 2 + 16;
- len[num_elem] = ftie_len - (2 + 2 + 16);
+ addr[num_elem] = ftie + 2 + 2 + mic_len;
+ len[num_elem] = ftie_len - (2 + 2 + mic_len);
num_elem++;
}
if (ric) {
@@ -274,7 +828,17 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
for (i = 0; i < num_elem; i++)
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
- if (omac1_aes_128_vector(kck, num_elem, addr, len, mic))
+#ifdef CONFIG_SHA384
+ if (kck_len == 24) {
+ u8 hash[SHA384_MAC_LEN];
+
+ if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 24);
+ }
+#endif /* CONFIG_SHA384 */
+ if (kck_len == 16 &&
+ omac1_aes_128_vector(kck, num_elem, addr, len, mic))
return -1;
return 0;
@@ -282,48 +846,70 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
- struct wpa_ft_ies *parse)
+ struct wpa_ft_ies *parse, int use_sha384)
{
const u8 *end, *pos;
parse->ftie = ie;
parse->ftie_len = ie_len;
- pos = ie + sizeof(struct rsn_ftie);
+ pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) :
+ sizeof(struct rsn_ftie));
end = ie + ie_len;
+ wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
+
+ while (end - pos >= 2) {
+ u8 id, len;
+
+ id = *pos++;
+ len = *pos++;
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
+ break;
+ }
- while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
- switch (pos[0]) {
+ switch (id) {
case FTIE_SUBELEM_R1KH_ID:
- if (pos[1] != FT_R1KH_ID_LEN) {
- wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
- "length in FTIE: %d", pos[1]);
+ if (len != FT_R1KH_ID_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid R1KH-ID length in FTIE: %d",
+ len);
return -1;
}
- parse->r1kh_id = pos + 2;
+ parse->r1kh_id = pos;
break;
case FTIE_SUBELEM_GTK:
- parse->gtk = pos + 2;
- parse->gtk_len = pos[1];
+ parse->gtk = pos;
+ parse->gtk_len = len;
break;
case FTIE_SUBELEM_R0KH_ID:
- if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
- wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
- "length in FTIE: %d", pos[1]);
+ if (len < 1 || len > FT_R0KH_ID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid R0KH-ID length in FTIE: %d",
+ len);
return -1;
}
- parse->r0kh_id = pos + 2;
- parse->r0kh_id_len = pos[1];
+ parse->r0kh_id = pos;
+ parse->r0kh_id_len = len;
break;
#ifdef CONFIG_IEEE80211W
case FTIE_SUBELEM_IGTK:
- parse->igtk = pos + 2;
- parse->igtk_len = pos[1];
+ parse->igtk = pos;
+ parse->igtk_len = len;
break;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ case FTIE_SUBELEM_OCI:
+ parse->oci = pos;
+ parse->oci_len = len;
+ break;
+#endif /* CONFIG_OCV */
+ default:
+ wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
+ break;
}
- pos += 2 + pos[1];
+ pos += len;
}
return 0;
@@ -331,13 +917,19 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
- struct wpa_ft_ies *parse)
+ struct wpa_ft_ies *parse, int use_sha384)
{
const u8 *end, *pos;
struct wpa_ie_data data;
int ret;
const struct rsn_ftie *ftie;
int prot_ie_count = 0;
+ int update_use_sha384 = 0;
+
+ if (use_sha384 < 0) {
+ use_sha384 = 0;
+ update_use_sha384 = 1;
+ }
os_memset(parse, 0, sizeof(*parse));
if (ies == NULL)
@@ -345,11 +937,19 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
pos = ies;
end = ies + ies_len;
- while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
- switch (pos[0]) {
+ while (end - pos >= 2) {
+ u8 id, len;
+
+ id = *pos++;
+ len = *pos++;
+ if (len > end - pos)
+ break;
+
+ switch (id) {
case WLAN_EID_RSN:
- parse->rsn = pos + 2;
- parse->rsn_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len);
+ parse->rsn = pos;
+ parse->rsn_len = len;
ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
parse->rsn_len + 2,
&data);
@@ -360,34 +960,77 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
}
if (data.num_pmkid == 1 && data.pmkid)
parse->rsn_pmkid = data.pmkid;
+ parse->key_mgmt = data.key_mgmt;
+ parse->pairwise_cipher = data.pairwise_cipher;
+ if (update_use_sha384) {
+ use_sha384 =
+ wpa_key_mgmt_sha384(parse->key_mgmt);
+ update_use_sha384 = 0;
+ }
break;
case WLAN_EID_MOBILITY_DOMAIN:
- if (pos[1] < sizeof(struct rsn_mdie))
+ wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
+ if (len < sizeof(struct rsn_mdie))
return -1;
- parse->mdie = pos + 2;
- parse->mdie_len = pos[1];
+ parse->mdie = pos;
+ parse->mdie_len = len;
break;
case WLAN_EID_FAST_BSS_TRANSITION:
- if (pos[1] < sizeof(*ftie))
+ wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len);
+ if (use_sha384) {
+ const struct rsn_ftie_sha384 *ftie_sha384;
+
+ if (len < sizeof(*ftie_sha384))
+ return -1;
+ ftie_sha384 =
+ (const struct rsn_ftie_sha384 *) pos;
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
+ ftie_sha384->mic_control, 2);
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
+ ftie_sha384->mic,
+ sizeof(ftie_sha384->mic));
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
+ ftie_sha384->anonce,
+ WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
+ ftie_sha384->snonce,
+ WPA_NONCE_LEN);
+ prot_ie_count = ftie_sha384->mic_control[1];
+ if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0)
+ return -1;
+ break;
+ }
+
+ if (len < sizeof(*ftie))
return -1;
- ftie = (const struct rsn_ftie *) (pos + 2);
+ ftie = (const struct rsn_ftie *) pos;
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
+ ftie->mic_control, 2);
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
+ ftie->mic, sizeof(ftie->mic));
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
+ ftie->anonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
+ ftie->snonce, WPA_NONCE_LEN);
prot_ie_count = ftie->mic_control[1];
- if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+ if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0)
return -1;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
- if (pos[1] != 5)
+ wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval",
+ pos, len);
+ if (len != 5)
break;
- parse->tie = pos + 2;
- parse->tie_len = pos[1];
+ parse->tie = pos;
+ parse->tie_len = len;
break;
case WLAN_EID_RIC_DATA:
if (parse->ric == NULL)
- parse->ric = pos;
+ parse->ric = pos - 2;
break;
}
- pos += 2 + pos[1];
+ pos += len;
}
if (prot_ie_count == 0)
@@ -416,13 +1059,15 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
}
/* Determine the end of the RIC IE(s) */
- pos = parse->ric;
- while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
- prot_ie_count) {
- prot_ie_count--;
- pos += 2 + pos[1];
+ if (parse->ric) {
+ pos = parse->ric;
+ while (end - pos >= 2 && 2 + pos[1] <= end - pos &&
+ prot_ie_count) {
+ prot_ie_count--;
+ pos += 2 + pos[1];
+ }
+ parse->ric_len = pos - parse->ric;
}
- parse->ric_len = pos - parse->ric;
if (prot_ie_count) {
wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
"frame", (int) prot_ie_count);
@@ -475,6 +1120,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
return WPA_KEY_MGMT_FT_IEEE8021X;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
return WPA_KEY_MGMT_FT_PSK;
+#ifdef CONFIG_SHA384
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384)
+ return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
@@ -492,6 +1141,22 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA256)
+ return WPA_KEY_MGMT_FILS_SHA256;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA384)
+ return WPA_KEY_MGMT_FILS_SHA384;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA256)
+ return WPA_KEY_MGMT_FT_FILS_SHA256;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA384)
+ return WPA_KEY_MGMT_FT_FILS_SHA384;
+#ifdef CONFIG_OWE
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OWE)
+ return WPA_KEY_MGMT_OWE;
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_DPP)
+ return WPA_KEY_MGMT_DPP;
+#endif /* CONFIG_DPP */
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
return WPA_KEY_MGMT_OSEN;
return 0;
@@ -561,6 +1226,9 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
pos = rsn_ie + 6;
left = rsn_ie_len - 6;
+ data->group_cipher = WPA_CIPHER_GTK_NOT_USED;
+ data->has_group = 1;
+ data->key_mgmt = WPA_KEY_MGMT_OSEN;
data->proto = WPA_PROTO_OSEN;
} else {
const struct rsn_ie_hdr *hdr;
@@ -581,9 +1249,12 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos);
+ data->has_group = 1;
if (!wpa_cipher_valid_group(data->group_cipher)) {
- wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x",
- __func__, data->group_cipher);
+ wpa_printf(MSG_DEBUG,
+ "%s: invalid group cipher 0x%x (%08x)",
+ __func__, data->group_cipher,
+ WPA_GET_BE32(pos));
return -1;
}
pos += RSN_SELECTOR_LEN;
@@ -604,6 +1275,8 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
"count %u left %u", __func__, count, left);
return -4;
}
+ if (count)
+ data->has_pairwise = 1;
for (i = 0; i < count; i++) {
data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
pos += RSN_SELECTOR_LEN;
@@ -671,9 +1344,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
- wpa_printf(MSG_DEBUG, "%s: Unsupported management "
- "group cipher 0x%x", __func__,
- data->mgmt_group_cipher);
+ wpa_printf(MSG_DEBUG,
+ "%s: Unsupported management group cipher 0x%x (%08x)",
+ __func__, data->mgmt_group_cipher,
+ WPA_GET_BE32(pos));
return -10;
}
pos += RSN_SELECTOR_LEN;
@@ -821,6 +1495,15 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
}
+int wpa_default_rsn_cipher(int freq)
+{
+ if (freq > 56160)
+ return WPA_CIPHER_GCMP; /* DMG */
+
+ return WPA_CIPHER_CCMP;
+}
+
+
#ifdef CONFIG_IEEE80211R
/**
@@ -828,27 +1511,39 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
*
* IEEE Std 802.11r-2008 - 8.5.1.5.3
*/
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
- const u8 *ssid, size_t ssid_len,
- const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
- const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
+ int use_sha384)
{
u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
- u8 *pos, r0_key_data[48], hash[32];
+ u8 *pos, r0_key_data[64], hash[48];
const u8 *addr[2];
size_t len[2];
+ size_t q = use_sha384 ? 48 : 32;
+ size_t r0_key_data_len = q + 16;
/*
* R0-Key-Data = KDF-384(XXKey, "FT-R0",
* SSIDlength || SSID || MDID || R0KHlength ||
* R0KH-ID || S0KH-ID)
- * XXKey is either the second 256 bits of MSK or PSK.
- * PMK-R0 = L(R0-Key-Data, 0, 256)
- * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
+ * XXKey is either the second 256 bits of MSK or PSK; or the first
+ * 384 bits of MSK for FT-EAP-SHA384.
+ * PMK-R0 = L(R0-Key-Data, 0, Q)
+ * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128)
+ * Q = 384 for FT-EAP-SHA384; otherwise, 256
*/
if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
- return;
+ return -1;
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s",
+ use_sha384 ? "SHA384" : "SHA256");
+ wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len);
+ wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN);
+ wpa_hexdump_ascii(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len);
+ wpa_printf(MSG_DEBUG, "FT: S0KH-ID: " MACSTR, MAC2STR(s0kh_id));
pos = buf;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
@@ -861,20 +1556,51 @@ void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
os_memcpy(pos, s0kh_id, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
- r0_key_data, sizeof(r0_key_data));
- os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
+#ifdef CONFIG_SHA384
+ if (use_sha384) {
+ if (xxkey_len != SHA384_MAC_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected XXKey length %d (expected %d)",
+ (int) xxkey_len, SHA384_MAC_LEN);
+ return -1;
+ }
+ if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, r0_key_data_len) < 0)
+ return -1;
+ }
+#endif /* CONFIG_SHA384 */
+ if (!use_sha384) {
+ if (xxkey_len != PMK_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected XXKey length %d (expected %d)",
+ (int) xxkey_len, PMK_LEN);
+ return -1;
+ }
+ if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, r0_key_data_len) < 0)
+ return -1;
+ }
+ os_memcpy(pmk_r0, r0_key_data, q);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16);
/*
- * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
+ * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt)
*/
addr[0] = (const u8 *) "FT-R0N";
len[0] = 6;
- addr[1] = r0_key_data + PMK_LEN;
+ addr[1] = &r0_key_data[q];
len[1] = 16;
- sha256_vector(2, addr, len, hash);
+#ifdef CONFIG_SHA384
+ if (use_sha384 && sha384_vector(2, addr, len, hash) < 0)
+ return -1;
+#endif /* CONFIG_SHA384 */
+ if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0)
+ return -1;
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+ os_memset(r0_key_data, 0, sizeof(r0_key_data));
+ return 0;
}
@@ -883,16 +1609,16 @@ void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name)
+int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+ const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384)
{
- u8 hash[32];
+ u8 hash[48];
const u8 *addr[4];
size_t len[4];
/*
- * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
- * R1KH-ID || S1KH-ID))
+ * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name ||
+ * R1KH-ID || S1KH-ID))
*/
addr[0] = (const u8 *) "FT-R1N";
len[0] = 6;
@@ -903,8 +1629,14 @@ void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
addr[3] = s1kh_id;
len[3] = ETH_ALEN;
- sha256_vector(4, addr, len, hash);
+#ifdef CONFIG_SHA384
+ if (use_sha384 && sha384_vector(4, addr, len, hash) < 0)
+ return -1;
+#endif /* CONFIG_SHA384 */
+ if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
+ return -1;
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+ return 0;
}
@@ -913,23 +1645,46 @@ void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
- const u8 *r1kh_id, const u8 *s1kh_id,
- u8 *pmk_r1, u8 *pmk_r1_name)
+int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
+ const u8 *pmk_r0_name,
+ const u8 *r1kh_id, const u8 *s1kh_id,
+ u8 *pmk_r1, u8 *pmk_r1_name)
{
u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
u8 *pos;
/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-%s",
+ pmk_r0_len == SHA384_MAC_LEN ? "SHA384" : "SHA256");
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN);
+ wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id));
pos = buf;
os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
pos += FT_R1KH_ID_LEN;
os_memcpy(pos, s1kh_id, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
+#ifdef CONFIG_SHA384
+ if (pmk_r0_len == SHA384_MAC_LEN &&
+ sha384_prf(pmk_r0, pmk_r0_len, "FT-R1",
+ buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
+ return -1;
+#endif /* CONFIG_SHA384 */
+ if (pmk_r0_len == PMK_LEN &&
+ sha256_prf(pmk_r0, pmk_r0_len, "FT-R1",
+ buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
+ return -1;
+ if (pmk_r0_len != SHA384_MAC_LEN && pmk_r0_len != PMK_LEN) {
+ wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R0 length %d",
+ (int) pmk_r0_len);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len);
- wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
+ return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
+ pmk_r1_name,
+ pmk_r0_len == SHA384_MAC_LEN);
}
@@ -938,7 +1693,8 @@ void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
*
* IEEE Std 802.11r-2008 - 8.5.1.5.5
*/
-int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
+ const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
@@ -947,13 +1703,21 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
- u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
- size_t ptk_len;
+ u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t ptk_len, offset;
+ int use_sha384 = wpa_key_mgmt_sha384(akmp);
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
*/
+ wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-%s",
+ use_sha384 ? "SHA384" : "SHA256");
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
+ wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
+ wpa_printf(MSG_DEBUG, "FT: BSSID=" MACSTR " STA-ADDR=" MACSTR,
+ MAC2STR(bssid), MAC2STR(sta_addr));
pos = buf;
os_memcpy(pos, snonce, WPA_NONCE_LEN);
pos += WPA_NONCE_LEN;
@@ -964,17 +1728,45 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
- ptk->kck_len = wpa_kck_len(akmp);
- ptk->kek_len = wpa_kek_len(akmp);
+ ptk->kck_len = wpa_kck_len(akmp, PMK_LEN);
+ ptk->kck2_len = wpa_kck2_len(akmp);
+ ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
+ ptk->kek2_len = wpa_kek2_len(akmp);
ptk->tk_len = wpa_cipher_key_len(cipher);
- ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
-
- sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
+ ptk->kck2_len + ptk->kek2_len;
+
+#ifdef CONFIG_SHA384
+ if (use_sha384) {
+ if (pmk_r1_len != SHA384_MAC_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected PMK-R1 length %d (expected %d)",
+ (int) pmk_r1_len, SHA384_MAC_LEN);
+ return -1;
+ }
+ if (sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+ buf, pos - buf, tmp, ptk_len) < 0)
+ return -1;
+ }
+#endif /* CONFIG_SHA384 */
+ if (!use_sha384) {
+ if (pmk_r1_len != PMK_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected PMK-R1 length %d (expected %d)",
+ (int) pmk_r1_len, PMK_LEN);
+ return -1;
+ }
+ if (sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+ buf, pos - buf, tmp, ptk_len) < 0)
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len);
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
* ANonce || BSSID || STA-ADDR))
*/
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
addr[0] = pmk_r1_name;
len[0] = WPA_PMK_NAME_LEN;
addr[1] = (const u8 *) "FT-PTKN";
@@ -988,15 +1780,28 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
addr[5] = sta_addr;
len[5] = ETH_ALEN;
- sha256_vector(6, addr, len, hash);
+ if (sha256_vector(6, addr, len, hash) < 0)
+ return -1;
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
os_memcpy(ptk->kck, tmp, ptk->kck_len);
- os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
- os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+ offset = ptk->kck_len;
+ os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
+ offset += ptk->kek_len;
+ os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
+ offset += ptk->tk_len;
+ os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
+ offset += ptk->kck2_len;
+ os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
+ if (ptk->kck2_len)
+ wpa_hexdump_key(MSG_DEBUG, "FT: KCK2",
+ ptk->kck2, ptk->kck2_len);
+ if (ptk->kek2_len)
+ wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
+ ptk->kek2, ptk->kek2_len);
wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
@@ -1015,29 +1820,48 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
* @aa: Authenticator address
* @spa: Supplicant address
* @pmkid: Buffer for PMKID
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated key management protocol
*
- * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
- * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
+ * IEEE Std 802.11-2016 - 12.7.1.3 Pairwise key hierarchy
+ * AKM: 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16
+ * PMKID = Truncate-128(HMAC-SHA-256(PMK, "PMK Name" || AA || SPA))
+ * AKM: 00-0F-AC:11
+ * See rsn_pmkid_suite_b()
+ * AKM: 00-0F-AC:12
+ * See rsn_pmkid_suite_b_192()
+ * AKM: 00-0F-AC:13, 00-0F-AC:15, 00-0F-AC:17
+ * PMKID = Truncate-128(HMAC-SHA-384(PMK, "PMK Name" || AA || SPA))
+ * Otherwise:
+ * PMKID = Truncate-128(HMAC-SHA-1(PMK, "PMK Name" || AA || SPA))
*/
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
- u8 *pmkid, int use_sha256)
+ u8 *pmkid, int akmp)
{
char *title = "PMK Name";
const u8 *addr[3];
const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
- unsigned char hash[SHA256_MAC_LEN];
+ unsigned char hash[SHA384_MAC_LEN];
addr[0] = (u8 *) title;
addr[1] = aa;
addr[2] = spa;
-#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (0) {
+#if defined(CONFIG_FILS) || defined(CONFIG_SHA384)
+ } else if (wpa_key_mgmt_sha384(akmp)) {
+ wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
+ hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
+#endif /* CONFIG_FILS || CONFIG_SHA384 */
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
+ } else if (wpa_key_mgmt_sha256(akmp)) {
+ wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
- else
-#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211W || CONFIG_FILS */
+ } else {
+ wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
+ }
+ wpa_hexdump(MSG_DEBUG, "RSN: Derived PMKID", hash, PMKID_LEN);
os_memcpy(pmkid, hash, PMKID_LEN);
}
@@ -1134,6 +1958,14 @@ const char * wpa_cipher_txt(int cipher)
return "GCMP-256";
case WPA_CIPHER_CCMP_256:
return "CCMP-256";
+ case WPA_CIPHER_AES_128_CMAC:
+ return "BIP";
+ case WPA_CIPHER_BIP_GMAC_128:
+ return "BIP-GMAC-128";
+ case WPA_CIPHER_BIP_GMAC_256:
+ return "BIP-GMAC-256";
+ case WPA_CIPHER_BIP_CMAC_256:
+ return "BIP-CMAC-256";
case WPA_CIPHER_GTK_NOT_USED:
return "GTK_NOT_USED";
default:
@@ -1163,11 +1995,15 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
"WPA2-PSK" : "WPA-PSK";
case WPA_KEY_MGMT_NONE:
return "NONE";
+ case WPA_KEY_MGMT_WPA_NONE:
+ return "WPA-NONE";
case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
return "IEEE 802.1X (no WPA)";
#ifdef CONFIG_IEEE80211R
case WPA_KEY_MGMT_FT_IEEE8021X:
return "FT-EAP";
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ return "FT-EAP-SHA384";
case WPA_KEY_MGMT_FT_PSK:
return "FT-PSK";
#endif /* CONFIG_IEEE80211R */
@@ -1189,6 +2025,18 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
return "WPA2-EAP-SUITE-B";
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
return "WPA2-EAP-SUITE-B-192";
+ case WPA_KEY_MGMT_FILS_SHA256:
+ return "FILS-SHA256";
+ case WPA_KEY_MGMT_FILS_SHA384:
+ return "FILS-SHA384";
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ return "FT-FILS-SHA256";
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return "FT-FILS-SHA384";
+ case WPA_KEY_MGMT_OWE:
+ return "OWE";
+ case WPA_KEY_MGMT_DPP:
+ return "DPP";
default:
return "UNKNOWN";
}
@@ -1197,28 +2045,36 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
u32 wpa_akm_to_suite(int akm)
{
+ if (akm & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ return RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
- return WLAN_AKM_SUITE_FT_8021X;
+ return RSN_AUTH_KEY_MGMT_FT_802_1X;
if (akm & WPA_KEY_MGMT_FT_PSK)
- return WLAN_AKM_SUITE_FT_PSK;
- if (akm & WPA_KEY_MGMT_IEEE8021X)
- return WLAN_AKM_SUITE_8021X;
+ return RSN_AUTH_KEY_MGMT_FT_PSK;
if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
- return WLAN_AKM_SUITE_8021X_SHA256;
+ return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
if (akm & WPA_KEY_MGMT_IEEE8021X)
- return WLAN_AKM_SUITE_8021X;
+ return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (akm & WPA_KEY_MGMT_PSK_SHA256)
- return WLAN_AKM_SUITE_PSK_SHA256;
+ return RSN_AUTH_KEY_MGMT_PSK_SHA256;
if (akm & WPA_KEY_MGMT_PSK)
- return WLAN_AKM_SUITE_PSK;
+ return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
if (akm & WPA_KEY_MGMT_CCKM)
- return WLAN_AKM_SUITE_CCKM;
+ return RSN_AUTH_KEY_MGMT_CCKM;
if (akm & WPA_KEY_MGMT_OSEN)
- return WLAN_AKM_SUITE_OSEN;
+ return RSN_AUTH_KEY_MGMT_OSEN;
if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
- return WLAN_AKM_SUITE_8021X_SUITE_B;
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
- return WLAN_AKM_SUITE_8021X_SUITE_B_192;
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
+ if (akm & WPA_KEY_MGMT_FILS_SHA256)
+ return RSN_AUTH_KEY_MGMT_FILS_SHA256;
+ if (akm & WPA_KEY_MGMT_FILS_SHA384)
+ return RSN_AUTH_KEY_MGMT_FILS_SHA384;
+ if (akm & WPA_KEY_MGMT_FT_FILS_SHA256)
+ return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
+ if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
+ return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
return 0;
}
@@ -1260,14 +2116,14 @@ int wpa_compare_rsn_ie(int ft_initial_assoc,
}
-#ifdef CONFIG_IEEE80211R
-int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
+int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
int added = 0;
start = ies;
- end = ies + ies_len;
+ end = ies + *ies_len;
while (start < end) {
if (*start == WLAN_EID_RSN)
@@ -1320,11 +2176,29 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
added += 2 + PMKID_LEN;
start[1] += 2 + PMKID_LEN;
} else {
- /* PMKID-Count was included; use it */
- if (WPA_GET_LE16(rpos) != 0) {
- wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
- "in RSN IE in EAPOL-Key data");
+ u16 num_pmkid;
+
+ if (rend - rpos < 2)
return -1;
+ num_pmkid = WPA_GET_LE16(rpos);
+ /* PMKID-Count was included; use it */
+ if (num_pmkid != 0) {
+ u8 *after;
+
+ if (num_pmkid * PMKID_LEN > rend - rpos - 2)
+ return -1;
+ /*
+ * PMKID may have been included in RSN IE in
+ * (Re)Association Request frame, so remove the old
+ * PMKID(s) first before adding the new one.
+ */
+ wpa_printf(MSG_DEBUG,
+ "FT: Remove %u old PMKID(s) from RSN IE",
+ num_pmkid);
+ after = rpos + 2 + num_pmkid * PMKID_LEN;
+ os_memmove(rpos + 2, after, rend - after);
+ start[1] -= num_pmkid * PMKID_LEN;
+ added -= num_pmkid * PMKID_LEN;
}
WPA_PUT_LE16(rpos, 1);
rpos += 2;
@@ -1337,9 +2211,11 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
"(PMKID inserted)", start, 2 + start[1]);
- return added;
+ *ies_len += added;
+
+ return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
int wpa_cipher_key_len(int cipher)
@@ -1378,7 +2254,7 @@ int wpa_cipher_rsc_len(int cipher)
}
-int wpa_cipher_to_alg(int cipher)
+enum wpa_alg wpa_cipher_to_alg(int cipher)
{
switch (cipher) {
case WPA_CIPHER_CCMP_256:
@@ -1573,6 +2449,14 @@ int wpa_parse_cipher(const char *value)
val |= WPA_CIPHER_NONE;
else if (os_strcmp(start, "GTK_NOT_USED") == 0)
val |= WPA_CIPHER_GTK_NOT_USED;
+ else if (os_strcmp(start, "AES-128-CMAC") == 0)
+ val |= WPA_CIPHER_AES_128_CMAC;
+ else if (os_strcmp(start, "BIP-GMAC-128") == 0)
+ val |= WPA_CIPHER_BIP_GMAC_128;
+ else if (os_strcmp(start, "BIP-GMAC-256") == 0)
+ val |= WPA_CIPHER_BIP_GMAC_256;
+ else if (os_strcmp(start, "BIP-CMAC-256") == 0)
+ val |= WPA_CIPHER_BIP_CMAC_256;
else {
os_free(buf);
return -1;
@@ -1628,6 +2512,34 @@ int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
return -1;
pos += ret;
}
+ if (ciphers & WPA_CIPHER_AES_128_CMAC) {
+ ret = os_snprintf(pos, end - pos, "%sAES-128-CMAC",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_BIP_GMAC_128) {
+ ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-128",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_BIP_GMAC_256) {
+ ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-256",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_BIP_CMAC_256) {
+ ret = os_snprintf(pos, end - pos, "%sBIP-CMAC-256",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
if (ciphers & WPA_CIPHER_NONE) {
ret = os_snprintf(pos, end - pos, "%sNONE",
pos == start ? "" : delim);
@@ -1662,3 +2574,29 @@ int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
return WPA_CIPHER_CCMP_256;
return WPA_CIPHER_CCMP;
}
+
+
+#ifdef CONFIG_FILS
+int fils_domain_name_hash(const char *domain, u8 *hash)
+{
+ char buf[255], *wpos = buf;
+ const char *pos = domain;
+ size_t len;
+ const u8 *addr[1];
+ u8 mac[SHA256_MAC_LEN];
+
+ for (len = 0; len < sizeof(buf) && *pos; len++) {
+ if (isalpha(*pos) && isupper(*pos))
+ *wpos++ = tolower(*pos);
+ else
+ *wpos++ = *pos;
+ pos++;
+ }
+
+ addr[0] = (const u8 *) buf;
+ if (sha256_vector(1, addr, &len, mac) < 0)
+ return -1;
+ os_memcpy(hash, mac, 2);
+ return 0;
+}
+#endif /* CONFIG_FILS */
diff --git a/contrib/wpa/src/common/wpa_common.h b/contrib/wpa/src/common/wpa_common.h
index a04e759..e83d688 100644
--- a/contrib/wpa/src/common/wpa_common.h
+++ b/contrib/wpa/src/common/wpa_common.h
@@ -1,6 +1,6 @@
/*
* WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,12 +12,16 @@
/* IEEE 802.11i */
#define PMKID_LEN 16
#define PMK_LEN 32
+#define PMK_LEN_SUITE_B_192 48
+#define PMK_LEN_MAX 64
#define WPA_REPLAY_COUNTER_LEN 8
#define WPA_NONCE_LEN 32
#define WPA_KEY_RSC_LEN 8
#define WPA_GMK_LEN 32
#define WPA_GTK_MAX_LEN 32
+#define OWE_DH_GROUP 19
+
#define WPA_ALLOWED_PAIRWISE_CIPHERS \
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
@@ -25,6 +29,9 @@ WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
WPA_CIPHER_GTK_NOT_USED)
+#define WPA_ALLOWED_GROUP_MGMT_CIPHERS \
+(WPA_CIPHER_AES_128_CMAC | WPA_CIPHER_BIP_GMAC_128 | WPA_CIPHER_BIP_GMAC_256 | \
+WPA_CIPHER_BIP_CMAC_256)
#define WPA_SELECTOR_LEN 4
#define WPA_VERSION 1
@@ -46,10 +53,8 @@ WPA_CIPHER_GTK_NOT_USED)
#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
-#ifdef CONFIG_IEEE80211R
#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#endif /* CONFIG_IEEE80211R */
#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
@@ -57,17 +62,24 @@ WPA_CIPHER_GTK_NOT_USED)
#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
-#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
-RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_AUTH_KEY_MGMT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
+#define RSN_AUTH_KEY_MGMT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 15)
+#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
+#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 17)
+#define RSN_AUTH_KEY_MGMT_OWE RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
+#define RSN_AUTH_KEY_MGMT_DPP RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x02)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
+#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#if 0
#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#endif
#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
@@ -76,6 +88,12 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define RSN_CIPHER_SUITE_BIP_GMAC_128 RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_CIPHER_SUITE_BIP_GMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
#define RSN_CIPHER_SUITE_BIP_CMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_CIPHER_SUITE_SMS4 RSN_SELECTOR(0x00, 0x14, 0x72, 1)
+#define RSN_CIPHER_SUITE_CKIP RSN_SELECTOR(0x00, 0x40, 0x96, 0)
+#define RSN_CIPHER_SUITE_CKIP_CMIC RSN_SELECTOR(0x00, 0x40, 0x96, 1)
+#define RSN_CIPHER_SUITE_CMIC RSN_SELECTOR(0x00, 0x40, 0x96, 2)
+/* KRK is defined for nl80211 use only */
+#define RSN_CIPHER_SUITE_KRK RSN_SELECTOR(0x00, 0x40, 0x96, 255)
/* EAPOL-Key Key Data Encapsulation
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.
@@ -86,18 +104,13 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#endif
#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#ifdef CONFIG_PEERKEY
-#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
-#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
-#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
-#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
-#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#endif /* CONFIG_IEEE80211W */
#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
@@ -136,7 +149,8 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
#define WPA_CAPABILITY_PBAC BIT(12)
#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
-/* B14-B15: Reserved */
+#define WPA_CAPABILITY_OCVC BIT(14)
+/* B15: Reserved */
/* IEEE 802.11r */
@@ -177,30 +191,17 @@ struct wpa_eapol_key {
u8 key_iv[16];
u8 key_rsc[WPA_KEY_RSC_LEN];
u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
- u8 key_mic[16];
- u8 key_data_length[2]; /* big endian */
- /* followed by key_data_length bytes of key_data */
-} STRUCT_PACKED;
-
-struct wpa_eapol_key_192 {
- u8 type;
- /* Note: key_info, key_length, and key_data_length are unaligned */
- u8 key_info[2]; /* big endian */
- u8 key_length[2]; /* big endian */
- u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
- u8 key_nonce[WPA_NONCE_LEN];
- u8 key_iv[16];
- u8 key_rsc[WPA_KEY_RSC_LEN];
- u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
- u8 key_mic[24];
- u8 key_data_length[2]; /* big endian */
- /* followed by key_data_length bytes of key_data */
+ /* variable length Key MIC field */
+ /* big endian 2-octet Key Data Length field */
+ /* followed by Key Data Length bytes of Key Data */
} STRUCT_PACKED;
-#define WPA_EAPOL_KEY_MIC_MAX_LEN 24
-#define WPA_KCK_MAX_LEN 24
-#define WPA_KEK_MAX_LEN 32
+#define WPA_EAPOL_KEY_MIC_MAX_LEN 32
+#define WPA_KCK_MAX_LEN 32
+#define WPA_KEK_MAX_LEN 64
#define WPA_TK_MAX_LEN 32
+#define FILS_ICK_MAX_LEN 48
+#define FILS_FT_MAX_LEN 48
/**
* struct wpa_ptk - WPA Pairwise Transient Key
@@ -210,9 +211,13 @@ struct wpa_ptk {
u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */
u8 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */
u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
+ u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */
+ u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */
size_t kck_len;
size_t kek_len;
size_t tk_len;
+ size_t kck2_len;
+ size_t kek2_len;
int installed; /* 1 if key has already been installed to driver */
};
@@ -281,22 +286,6 @@ struct rsn_ie_hdr {
} STRUCT_PACKED;
-#ifdef CONFIG_PEERKEY
-enum {
- STK_MUI_4WAY_STA_AP = 1,
- STK_MUI_4WAY_STAT_STA = 2,
- STK_MUI_GTK = 3,
- STK_MUI_SMK = 4
-};
-
-enum {
- STK_ERR_STA_NR = 1,
- STK_ERR_STA_NRSN = 2,
- STK_ERR_CPHR_NS = 3,
- STK_ERR_NO_STSL = 4
-};
-#endif /* CONFIG_PEERKEY */
-
struct rsn_error_kde {
be16 mui;
be16 error_type;
@@ -327,10 +316,19 @@ struct rsn_ftie {
/* followed by optional parameters */
} STRUCT_PACKED;
+struct rsn_ftie_sha384 {
+ u8 mic_control[2];
+ u8 mic[24];
+ u8 anonce[WPA_NONCE_LEN];
+ u8 snonce[WPA_NONCE_LEN];
+ /* followed by optional parameters */
+} STRUCT_PACKED;
+
#define FTIE_SUBELEM_R1KH_ID 1
#define FTIE_SUBELEM_GTK 2
#define FTIE_SUBELEM_R0KH_ID 3
#define FTIE_SUBELEM_IGTK 4
+#define FTIE_SUBELEM_OCI 5
struct rsn_rdie {
u8 id;
@@ -349,7 +347,24 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
- struct wpa_ptk *ptk, int akmp, int cipher);
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ const u8 *z, size_t z_len);
+int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
+ const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
+ size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
+int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
+ u8 *pmkid);
+int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
+ const u8 *snonce, const u8 *anonce, const u8 *dhss,
+ size_t dhss_len, struct wpa_ptk *ptk,
+ u8 *ick, size_t *ick_len, int akmp, int cipher,
+ u8 *fils_ft, size_t *fils_ft_len);
+int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
+ const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
+ const u8 *g_sta, size_t g_sta_len,
+ const u8 *g_ap, size_t g_ap_len,
+ int akmp, u8 *key_auth_sta, u8 *key_auth_ap,
+ size_t *key_auth_len);
#ifdef CONFIG_IEEE80211R
int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
@@ -358,17 +373,19 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic);
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
- const u8 *ssid, size_t ssid_len,
- const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
- const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name);
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
- const u8 *r1kh_id, const u8 *s1kh_id,
- u8 *pmk_r1, u8 *pmk_r1_name);
-int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
- const u8 *sta_addr, const u8 *bssid,
+int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
+ int use_sha384);
+int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+ const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384);
+int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
+ const u8 *pmk_r0_name,
+ const u8 *r1kh_id, const u8 *s1kh_id,
+ u8 *pmk_r1, u8 *pmk_r1_name);
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, const u8 *snonce,
+ const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
#endif /* CONFIG_IEEE80211R */
@@ -376,7 +393,9 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
struct wpa_ie_data {
int proto;
int pairwise_cipher;
+ int has_pairwise;
int group_cipher;
+ int has_group;
int key_mgmt;
int capabilities;
size_t num_pmkid;
@@ -389,9 +408,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data);
int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data);
+int wpa_default_rsn_cipher(int freq);
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
- u8 *pmkid, int use_sha256);
+ u8 *pmkid, int akmp);
#ifdef CONFIG_SUITEB
int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
const u8 *spa, u8 *pmkid);
@@ -419,7 +439,7 @@ u32 wpa_akm_to_suite(int akm);
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len);
-int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
+int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid);
struct wpa_ft_ies {
const u8 *mdie;
@@ -438,15 +458,22 @@ struct wpa_ft_ies {
size_t tie_len;
const u8 *igtk;
size_t igtk_len;
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
const u8 *ric;
size_t ric_len;
+ int key_mgmt;
+ int pairwise_cipher;
};
-int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
+ int use_sha384);
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
-int wpa_cipher_to_alg(int cipher);
+enum wpa_alg wpa_cipher_to_alg(int cipher);
int wpa_cipher_valid_group(int cipher);
int wpa_cipher_valid_pairwise(int cipher);
int wpa_cipher_valid_mgmt_group(int cipher);
@@ -458,6 +485,10 @@ int wpa_pick_group_cipher(int ciphers);
int wpa_parse_cipher(const char *value);
int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
-unsigned int wpa_mic_len(int akmp);
+unsigned int wpa_mic_len(int akmp, size_t pmk_len);
+int wpa_use_akm_defined(int akmp);
+int wpa_use_cmac(int akmp);
+int wpa_use_aes_key_wrap(int akmp);
+int fils_domain_name_hash(const char *domain, u8 *hash);
#endif /* WPA_COMMON_H */
diff --git a/contrib/wpa/src/common/wpa_ctrl.c b/contrib/wpa/src/common/wpa_ctrl.c
index 5733aa6..c9890a0 100644
--- a/contrib/wpa/src/common/wpa_ctrl.c
+++ b/contrib/wpa/src/common/wpa_ctrl.c
@@ -11,6 +11,8 @@
#ifdef CONFIG_CTRL_IFACE
#ifdef CONFIG_CTRL_IFACE_UNIX
+#include <sys/stat.h>
+#include <fcntl.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
@@ -133,6 +135,19 @@ try_again:
return NULL;
}
tries++;
+#ifdef ANDROID
+ /* Set client socket file permissions so that bind() creates the client
+ * socket with these permissions and there is no need to try to change
+ * them with chmod() after bind() which would have potential issues with
+ * race conditions. These permissions are needed to make sure the server
+ * side (wpa_supplicant or hostapd) can reply to the control interface
+ * messages.
+ *
+ * The lchown() calls below after bind() are also part of the needed
+ * operations to allow the response to go through. Those are using the
+ * no-deference-symlinks version to avoid races. */
+ fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+#endif /* ANDROID */
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
@@ -151,10 +166,9 @@ try_again:
}
#ifdef ANDROID
- chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
/* Set group even if we do not have privileges to change owner */
- chown(ctrl->local.sun_path, -1, AID_WIFI);
- chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
+ lchown(ctrl->local.sun_path, -1, AID_WIFI);
+ lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
if (socket_local_client_connect(
@@ -532,13 +546,16 @@ retry_send:
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ if (res < 0 && errno == EINTR)
+ continue;
if (res < 0)
return res;
if (FD_ISSET(ctrl->s, &rfds)) {
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
- if (res > 0 && reply[0] == '<') {
+ if ((res > 0 && reply[0] == '<') ||
+ (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
diff --git a/contrib/wpa/src/common/wpa_ctrl.h b/contrib/wpa/src/common/wpa_ctrl.h
index 3de4682..f65077e 100644
--- a/contrib/wpa/src/common/wpa_ctrl.h
+++ b/contrib/wpa/src/common/wpa_ctrl.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -50,10 +50,19 @@ extern "C" {
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
/** EAP status */
#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS "
+/** Retransmit the previous request packet */
+#define WPA_EVENT_EAP_RETRANSMIT "CTRL-EVENT-EAP-RETRANSMIT "
+#define WPA_EVENT_EAP_RETRANSMIT2 "CTRL-EVENT-EAP-RETRANSMIT2 "
/** EAP authentication completed successfully */
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+#define WPA_EVENT_EAP_SUCCESS2 "CTRL-EVENT-EAP-SUCCESS2 "
/** EAP authentication failed (EAP-Failure received) */
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+#define WPA_EVENT_EAP_FAILURE2 "CTRL-EVENT-EAP-FAILURE2 "
+/** EAP authentication failed due to no response received */
+#define WPA_EVENT_EAP_TIMEOUT_FAILURE "CTRL-EVENT-EAP-TIMEOUT-FAILURE "
+#define WPA_EVENT_EAP_TIMEOUT_FAILURE2 "CTRL-EVENT-EAP-TIMEOUT-FAILURE2 "
+#define WPA_EVENT_EAP_ERROR_CODE "EAP-ERROR-CODE "
/** Network block temporarily disabled (e.g., due to authentication failure) */
#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
/** Temporarily disabled network block re-enabled */
@@ -74,8 +83,28 @@ extern "C" {
#define WPA_EVENT_NETWORK_NOT_FOUND "CTRL-EVENT-NETWORK-NOT-FOUND "
/** Change in the signal level was reported by the driver */
#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
+/** Beacon loss reported by the driver */
+#define WPA_EVENT_BEACON_LOSS "CTRL-EVENT-BEACON-LOSS "
/** Regulatory domain channel */
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
+/** Channel switch (followed by freq=<MHz> and other channel parameters) */
+#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
+/** SAE authentication failed due to unknown password identifier */
+#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
+ "CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
+
+/** IP subnet status change notification
+ *
+ * When using an offloaded roaming mechanism where driver/firmware takes care
+ * of roaming and IP subnet validation checks post-roaming, this event can
+ * indicate whether IP subnet has changed.
+ *
+ * The event has a status=<0/1/2> parameter where
+ * 0 = unknown
+ * 1 = IP subnet unchanged (can continue to use the old IP address)
+ * 2 = IP subnet changed (need to get a new IP address)
+ */
+#define WPA_EVENT_SUBNET_STATUS_UPDATE "CTRL-EVENT-SUBNET-STATUS-UPDATE "
/** RSN IBSS 4-way handshakes completed with specified peer */
#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
@@ -126,6 +155,33 @@ extern "C" {
#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
+/* DPP events */
+#define DPP_EVENT_AUTH_SUCCESS "DPP-AUTH-SUCCESS "
+#define DPP_EVENT_AUTH_INIT_FAILED "DPP-AUTH-INIT-FAILED "
+#define DPP_EVENT_NOT_COMPATIBLE "DPP-NOT-COMPATIBLE "
+#define DPP_EVENT_RESPONSE_PENDING "DPP-RESPONSE-PENDING "
+#define DPP_EVENT_SCAN_PEER_QR_CODE "DPP-SCAN-PEER-QR-CODE "
+#define DPP_EVENT_AUTH_DIRECTION "DPP-AUTH-DIRECTION "
+#define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
+#define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
+#define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
+#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
+#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
+#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
+#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
+#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
+#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
+#define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
+#define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
+#define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
+#define DPP_EVENT_RX "DPP-RX "
+#define DPP_EVENT_TX "DPP-TX "
+#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
+#define DPP_EVENT_FAIL "DPP-FAIL "
+#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
+#define DPP_EVENT_INTRO "DPP-INTRO "
+#define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX "
+
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
@@ -174,6 +230,7 @@ extern "C" {
#define P2P_EVENT_SERV_ASP_RESP "P2P-SERV-ASP-RESP "
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_INVITATION_ACCEPTED "P2P-INVITATION-ACCEPTED "
#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
#define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id="
#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE "
@@ -212,8 +269,18 @@ extern "C" {
/* parameters: <addr> <result> */
#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
+#define RX_ANQP "RX-ANQP "
+#define RX_HS20_ANQP "RX-HS20-ANQP "
+#define RX_HS20_ANQP_ICON "RX-HS20-ANQP-ICON "
+#define RX_HS20_ICON "RX-HS20-ICON "
+#define RX_MBO_ANQP "RX-MBO-ANQP "
+
+/* parameters: <Venue Number> <Venue URL> */
+#define RX_VENUE_URL "RX-VENUE-URL "
+
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
+#define HS20_T_C_ACCEPTANCE "HS20-T-C-ACCEPTANCE "
#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
@@ -232,10 +299,14 @@ extern "C" {
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
+#define AP_STA_POLL_OK "AP-STA-POLL-OK "
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
+#define HS20_T_C_FILTERING_ADD "HS20-T-C-FILTERING-ADD "
+#define HS20_T_C_FILTERING_REMOVE "HS20-T-C-FILTERING-REMOVE "
+
#define AP_EVENT_ENABLED "AP-ENABLED "
#define AP_EVENT_DISABLED "AP-DISABLED "
@@ -251,12 +322,56 @@ extern "C" {
#define DFS_EVENT_CAC_START "DFS-CAC-START "
#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED "
#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED "
+#define DFS_EVENT_PRE_CAC_EXPIRED "DFS-PRE-CAC-EXPIRED "
#define AP_CSA_FINISHED "AP-CSA-FINISHED "
+#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED "
+#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON "
+
/* BSS Transition Management Response frame received */
#define BSS_TM_RESP "BSS-TM-RESP "
+/* Collocated Interference Request frame received;
+ * parameters: <dialog token> <automatic report enabled> <report timeout> */
+#define COLOC_INTF_REQ "COLOC-INTF-REQ "
+/* Collocated Interference Report frame received;
+ * parameters: <STA address> <dialog token> <hexdump of report elements> */
+#define COLOC_INTF_REPORT "COLOC-INTF-REPORT "
+
+/* MBO IE with cellular data connection preference received */
+#define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE "
+
+/* BSS Transition Management Request received with MBO transition reason */
+#define MBO_TRANSITION_REASON "MBO-TRANSITION-REASON "
+
+/* parameters: <STA address> <dialog token> <ack=0/1> */
+#define BEACON_REQ_TX_STATUS "BEACON-REQ-TX-STATUS "
+/* parameters: <STA address> <dialog token> <report mode> <beacon report> */
+#define BEACON_RESP_RX "BEACON-RESP-RX "
+
+/* PMKSA cache entry added; parameters: <BSSID> <network_id> */
+#define PMKSA_CACHE_ADDED "PMKSA-CACHE-ADDED "
+/* PMKSA cache entry removed; parameters: <BSSID> <network_id> */
+#define PMKSA_CACHE_REMOVED "PMKSA-CACHE-REMOVED "
+
+/* FILS HLP Container receive; parameters: dst=<addr> src=<addr> frame=<hexdump>
+ */
+#define FILS_HLP_RX "FILS-HLP-RX "
+
+/* Event to indicate Probe Request frame;
+ * parameters: sa=<STA MAC address> signal=<signal> */
+#define RX_PROBE_REQUEST "RX-PROBE-REQUEST "
+
+/* Event to indicate station's HT/VHT operation mode change information */
+#define STA_OPMODE_MAX_BW_CHANGED "STA-OPMODE-MAX-BW-CHANGED "
+#define STA_OPMODE_SMPS_MODE_CHANGED "STA-OPMODE-SMPS-MODE-CHANGED "
+#define STA_OPMODE_N_SS_CHANGED "STA-OPMODE-N_SS-CHANGED "
+
+/* New interface addition or removal for 4addr WDS SDA */
+#define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED "
+#define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
@@ -282,6 +397,9 @@ extern "C" {
#define WPA_BSS_MASK_SNR BIT(19)
#define WPA_BSS_MASK_EST_THROUGHPUT BIT(20)
#define WPA_BSS_MASK_FST BIT(21)
+#define WPA_BSS_MASK_UPDATE_IDX BIT(22)
+#define WPA_BSS_MASK_BEACON_IE BIT(23)
+#define WPA_BSS_MASK_FILS_INDICATION BIT(24)
/* VENDOR_ELEM_* frame id values */
@@ -300,6 +418,7 @@ enum wpa_vendor_elem_frame {
VENDOR_ELEM_P2P_ASSOC_REQ = 11,
VENDOR_ELEM_P2P_ASSOC_RESP = 12,
VENDOR_ELEM_ASSOC_REQ = 13,
+ VENDOR_ELEM_PROBE_REQ = 14,
NUM_VENDOR_ELEM_FRAMES
};
@@ -354,7 +473,7 @@ void wpa_ctrl_close(struct wpa_ctrl *ctrl);
*
* This function is used to send commands to wpa_supplicant/hostapd. Received
* response will be written to reply and reply_len is set to the actual length
- * of the reply. This function will block for up to two seconds while waiting
+ * of the reply. This function will block for up to 10 seconds while waiting
* for the reply. If unsolicited messages are received, the blocking time may
* be longer.
*
diff --git a/contrib/wpa/src/common/wpa_helpers.c b/contrib/wpa/src/common/wpa_helpers.c
index 28913b9..8e1c09e 100644
--- a/contrib/wpa/src/common/wpa_helpers.c
+++ b/contrib/wpa/src/common/wpa_helpers.c
@@ -172,7 +172,8 @@ int get_wpa_status(const char *ifname, const char *field, char *obuf,
if (ctrl == NULL)
return -1;
len = sizeof(buf);
- if (wpa_ctrl_request(ctrl, "STATUS", 6, buf, &len, NULL) < 0) {
+ if (wpa_ctrl_request(ctrl, "STATUS-NO_EVENTS", 16, buf, &len,
+ NULL) < 0) {
wpa_ctrl_close(ctrl);
return -1;
}
@@ -221,7 +222,8 @@ int wait_ip_addr(const char *ifname, int timeout)
if (get_wpa_status(ifname, "ip_address", ip, sizeof(ip)) == 0
&& strlen(ip) > 0) {
printf("IP address found: '%s'\n", ip);
- return 0;
+ if (strncmp(ip, "169.254.", 8) != 0)
+ return 0;
}
ctrl = wpa_open_ctrl(ifname);
if (ctrl == NULL)
diff --git a/contrib/wpa/src/crypto/aes-cbc.c b/contrib/wpa/src/crypto/aes-cbc.c
index 2833cfcc..0835f2c 100644
--- a/contrib/wpa/src/crypto/aes-cbc.c
+++ b/contrib/wpa/src/crypto/aes-cbc.c
@@ -28,6 +28,9 @@ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
u8 *pos = data;
int i, j, blocks;
+ if (TEST_FAIL())
+ return -1;
+
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
@@ -61,6 +64,9 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
u8 *pos = data;
int i, j, blocks;
+ if (TEST_FAIL())
+ return -1;
+
ctx = aes_decrypt_init(key, 16);
if (ctx == NULL)
return -1;
diff --git a/contrib/wpa/src/crypto/aes-ctr.c b/contrib/wpa/src/crypto/aes-ctr.c
index d4d874d..e27f3bb 100644
--- a/contrib/wpa/src/crypto/aes-ctr.c
+++ b/contrib/wpa/src/crypto/aes-ctr.c
@@ -1,5 +1,5 @@
/*
- * AES-128 CTR
+ * AES-128/192/256 CTR
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -14,15 +14,16 @@
#include "aes_wrap.h"
/**
- * aes_128_ctr_encrypt - AES-128 CTR mode encryption
- * @key: Key for encryption (16 bytes)
+ * aes_ctr_encrypt - AES-128/192/256 CTR mode encryption
+ * @key: Key for encryption (key_len bytes)
+ * @key_len: Length of the key (16, 24, or 32 bytes)
* @nonce: Nonce for counter mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* Returns: 0 on success, -1 on failure
*/
-int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
- u8 *data, size_t data_len)
+int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
+ u8 *data, size_t data_len)
{
void *ctx;
size_t j, len, left = data_len;
@@ -30,7 +31,7 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *pos = data;
u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
- ctx = aes_encrypt_init(key, 16);
+ ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
os_memcpy(counter, nonce, AES_BLOCK_SIZE);
@@ -53,3 +54,18 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
aes_encrypt_deinit(ctx);
return 0;
}
+
+
+/**
+ * aes_128_ctr_encrypt - AES-128 CTR mode encryption
+ * @key: Key for encryption (key_len bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len)
+{
+ return aes_ctr_encrypt(key, 16, nonce, data, data_len);
+}
diff --git a/contrib/wpa/src/crypto/aes-internal-dec.c b/contrib/wpa/src/crypto/aes-internal-dec.c
index 720c703..7482295 100644
--- a/contrib/wpa/src/crypto/aes-internal-dec.c
+++ b/contrib/wpa/src/crypto/aes-internal-dec.c
@@ -147,10 +147,12 @@ d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
PUTU32(pt + 12, s3);
}
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
u32 *rk = ctx;
rijndaelDecrypt(ctx, rk[AES_PRIV_NR_POS], crypt, plain);
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/aes-internal-enc.c b/contrib/wpa/src/crypto/aes-internal-enc.c
index f3c61b8..baeffca 100644
--- a/contrib/wpa/src/crypto/aes-internal-enc.c
+++ b/contrib/wpa/src/crypto/aes-internal-enc.c
@@ -99,6 +99,10 @@ void * aes_encrypt_init(const u8 *key, size_t len)
{
u32 *rk;
int res;
+
+ if (TEST_FAIL())
+ return NULL;
+
rk = os_malloc(AES_PRIV_SIZE);
if (rk == NULL)
return NULL;
@@ -112,10 +116,11 @@ void * aes_encrypt_init(const u8 *key, size_t len)
}
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
u32 *rk = ctx;
rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt);
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/aes-omac1.c b/contrib/wpa/src/crypto/aes-omac1.c
index 375db57..8642516 100644
--- a/contrib/wpa/src/crypto/aes-omac1.c
+++ b/contrib/wpa/src/crypto/aes-omac1.c
@@ -48,6 +48,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *pos, *end;
size_t i, e, left, total_len;
+ if (TEST_FAIL())
+ return -1;
+
ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
diff --git a/contrib/wpa/src/crypto/aes-siv.c b/contrib/wpa/src/crypto/aes-siv.c
index 5ac82c2..b682f3a 100644
--- a/contrib/wpa/src/crypto/aes-siv.c
+++ b/contrib/wpa/src/crypto/aes-siv.c
@@ -61,26 +61,33 @@ static void pad_block(u8 *pad, const u8 *addr, size_t len)
}
-static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
- size_t *len, u8 *mac)
+static int aes_s2v(const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
{
u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
u8 *buf = NULL;
int ret;
size_t i;
+ const u8 *data[1];
+ size_t data_len[1];
if (!num_elem) {
os_memcpy(tmp, zero, sizeof(zero));
tmp[AES_BLOCK_SIZE - 1] = 1;
- return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ data[0] = tmp;
+ data_len[0] = sizeof(tmp);
+ return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
}
- ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+ data[0] = zero;
+ data_len[0] = sizeof(zero);
+ ret = omac1_aes_vector(key, key_len, 1, data, data_len, tmp);
if (ret)
return ret;
for (i = 0; i < num_elem - 1; i++) {
- ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+ ret = omac1_aes_vector(key, key_len, 1, &addr[i], &len[i],
+ tmp2);
if (ret)
return ret;
@@ -88,13 +95,13 @@ static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
xor(tmp, tmp2);
}
if (len[i] >= AES_BLOCK_SIZE) {
- buf = os_malloc(len[i]);
+ buf = os_memdup(addr[i], len[i]);
if (!buf)
return -ENOMEM;
- os_memcpy(buf, addr[i], len[i]);
xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
- ret = omac1_aes_128(key, buf, len[i], mac);
+ data[0] = buf;
+ ret = omac1_aes_vector(key, key_len, 1, data, &len[i], mac);
bin_clear_free(buf, len[i]);
return ret;
}
@@ -103,24 +110,32 @@ static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
pad_block(tmp2, addr[i], len[i]);
xor(tmp, tmp2);
- return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ data[0] = tmp;
+ data_len[0] = sizeof(tmp);
+ return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
}
-int aes_siv_encrypt(const u8 *key, const u8 *pw,
- size_t pwlen, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *out)
+int aes_siv_encrypt(const u8 *key, size_t key_len,
+ const u8 *pw, size_t pwlen,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out)
{
const u8 *_addr[6];
size_t _len[6];
- const u8 *k1 = key, *k2 = key + 16;
+ const u8 *k1, *k2;
u8 v[AES_BLOCK_SIZE];
size_t i;
u8 *iv, *crypt_pw;
- if (num_elem > ARRAY_SIZE(_addr) - 1)
+ if (num_elem > ARRAY_SIZE(_addr) - 1 ||
+ (key_len != 32 && key_len != 48 && key_len != 64))
return -1;
+ key_len /= 2;
+ k1 = key;
+ k2 = key + key_len;
+
for (i = 0; i < num_elem; i++) {
_addr[i] = addr[i];
_len[i] = len[i];
@@ -128,7 +143,7 @@ int aes_siv_encrypt(const u8 *key, const u8 *pw,
_addr[num_elem] = pw;
_len[num_elem] = pwlen;
- if (aes_s2v(k1, num_elem + 1, _addr, _len, v))
+ if (aes_s2v(k1, key_len, num_elem + 1, _addr, _len, v))
return -1;
iv = out;
@@ -140,26 +155,31 @@ int aes_siv_encrypt(const u8 *key, const u8 *pw,
/* zero out 63rd and 31st bits of ctr (from right) */
v[8] &= 0x7f;
v[12] &= 0x7f;
- return aes_128_ctr_encrypt(k2, v, crypt_pw, pwlen);
+ return aes_ctr_encrypt(k2, key_len, v, crypt_pw, pwlen);
}
-int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+int aes_siv_decrypt(const u8 *key, size_t key_len,
+ const u8 *iv_crypt, size_t iv_c_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *out)
{
const u8 *_addr[6];
size_t _len[6];
- const u8 *k1 = key, *k2 = key + 16;
+ const u8 *k1, *k2;
size_t crypt_len;
size_t i;
int ret;
u8 iv[AES_BLOCK_SIZE];
u8 check[AES_BLOCK_SIZE];
- if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1)
+ if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1 ||
+ (key_len != 32 && key_len != 48 && key_len != 64))
return -1;
crypt_len = iv_c_len - AES_BLOCK_SIZE;
+ key_len /= 2;
+ k1 = key;
+ k2 = key + key_len;
for (i = 0; i < num_elem; i++) {
_addr[i] = addr[i];
@@ -174,11 +194,11 @@ int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
iv[8] &= 0x7f;
iv[12] &= 0x7f;
- ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+ ret = aes_ctr_encrypt(k2, key_len, iv, out, crypt_len);
if (ret)
return ret;
- ret = aes_s2v(k1, num_elem + 1, _addr, _len, check);
+ ret = aes_s2v(k1, key_len, num_elem + 1, _addr, _len, check);
if (ret)
return ret;
if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
diff --git a/contrib/wpa/src/crypto/aes.h b/contrib/wpa/src/crypto/aes.h
index 2de59e0..8ab3de2 100644
--- a/contrib/wpa/src/crypto/aes.h
+++ b/contrib/wpa/src/crypto/aes.h
@@ -12,10 +12,10 @@
#define AES_BLOCK_SIZE 16
void * aes_encrypt_init(const u8 *key, size_t len);
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
void aes_encrypt_deinit(void *ctx);
void * aes_decrypt_init(const u8 *key, size_t len);
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
void aes_decrypt_deinit(void *ctx);
#endif /* AES_H */
diff --git a/contrib/wpa/src/crypto/aes_siv.h b/contrib/wpa/src/crypto/aes_siv.h
index 463cf65..fb05d80 100644
--- a/contrib/wpa/src/crypto/aes_siv.h
+++ b/contrib/wpa/src/crypto/aes_siv.h
@@ -9,10 +9,12 @@
#ifndef AES_SIV_H
#define AES_SIV_H
-int aes_siv_encrypt(const u8 *key, const u8 *pw,
- size_t pwlen, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *out);
-int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+int aes_siv_encrypt(const u8 *key, size_t key_len,
+ const u8 *pw, size_t pwlen,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out);
+int aes_siv_decrypt(const u8 *key, size_t key_len,
+ const u8 *iv_crypt, size_t iv_c_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *out);
diff --git a/contrib/wpa/src/crypto/aes_wrap.h b/contrib/wpa/src/crypto/aes_wrap.h
index 4a14209..b70b1d2 100644
--- a/contrib/wpa/src/crypto/aes_wrap.h
+++ b/contrib/wpa/src/crypto/aes_wrap.h
@@ -3,7 +3,7 @@
*
* - AES Key Wrap Algorithm (RFC3394)
* - One-Key CBC MAC (OMAC1) hash with AES-128 and AES-256
- * - AES-128 CTR mode encryption
+ * - AES-128/192/256 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
* - AES-GCM
@@ -33,6 +33,8 @@ int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len,
u8 *mac);
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+int __must_check aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
+ u8 *data, size_t data_len);
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
int __must_check aes_128_eax_encrypt(const u8 *key,
diff --git a/contrib/wpa/src/crypto/crypto.h b/contrib/wpa/src/crypto/crypto.h
index 534c4bd..12109ce 100644
--- a/contrib/wpa/src/crypto/crypto.h
+++ b/contrib/wpa/src/crypto/crypto.h
@@ -1,6 +1,6 @@
/*
* Wrapper functions for crypto libraries
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -80,12 +80,35 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
+ * sha384_vector - SHA384 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
+
+/**
+ * sha512_vector - SHA512 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
+
+/**
* des_encrypt - Encrypt one block with DES
* @clear: 8 octets (in)
* @key: 7 octets (in) (no parity bits included)
* @cypher: 8 octets (out)
+ * Returns: 0 on success, -1 on failure
*/
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
/**
* aes_encrypt_init - Initialize AES for encryption
@@ -100,8 +123,9 @@ void * aes_encrypt_init(const u8 *key, size_t len);
* @ctx: Context pointer from aes_encrypt_init()
* @plain: Plaintext data to be encrypted (16 bytes)
* @crypt: Buffer for the encrypted data (16 bytes)
+ * Returns: 0 on success, -1 on failure
*/
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
/**
* aes_encrypt_deinit - Deinitialize AES encryption
@@ -122,8 +146,9 @@ void * aes_decrypt_init(const u8 *key, size_t len);
* @ctx: Context pointer from aes_encrypt_init()
* @crypt: Encrypted data (16 bytes)
* @plain: Buffer for the decrypted data (16 bytes)
+ * Returns: 0 on success, -1 on failure
*/
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
/**
* aes_decrypt_deinit - Deinitialize AES decryption
@@ -135,7 +160,8 @@ void aes_decrypt_deinit(void *ctx);
enum crypto_hash_alg {
CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
- CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
+ CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256,
+ CRYPTO_HASH_ALG_SHA384, CRYPTO_HASH_ALG_SHA512
};
struct crypto_hash;
@@ -391,6 +417,14 @@ int __must_check crypto_public_key_decrypt_pkcs1(
struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey);
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len);
+
/**
* crypto_global_init - Initialize crypto wrapper
*
@@ -503,6 +537,14 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
u8 *buf, size_t buflen, size_t padlen);
/**
+ * crypto_bignum_rand - Create a random number in range of modulus
+ * @r: Bignum; set to a random value
+ * @m: Bignum; modulus
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m);
+
+/**
* crypto_bignum_add - c = a + b
* @a: Bignum
* @b: Bignum
@@ -584,6 +626,16 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
struct crypto_bignum *d);
/**
+ * crypto_bignum_rshift - r = a >> n
+ * @a: Bignum
+ * @n: Number of bits
+ * @r: Bignum; used to store the result of a >> n
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r);
+
+/**
* crypto_bignum_cmp - Compare two bignums
* @a: Bignum
* @b: Bignum
@@ -614,6 +666,13 @@ int crypto_bignum_is_zero(const struct crypto_bignum *a);
int crypto_bignum_is_one(const struct crypto_bignum *a);
/**
+ * crypto_bignum_is_odd - Is the given bignum odd
+ * @a: Bignum
+ * Returns: 1 if @a is odd or 0 if not
+ */
+int crypto_bignum_is_odd(const struct crypto_bignum *a);
+
+/**
* crypto_bignum_legendre - Compute the Legendre symbol (a/p)
* @a: Bignum
* @p: Bignum
@@ -659,6 +718,13 @@ size_t crypto_ec_prime_len(struct crypto_ec *e);
size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
/**
+ * crypto_ec_order_len - Get length of the order in octets
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the order defining the group
+ */
+size_t crypto_ec_order_len(struct crypto_ec *e);
+
+/**
* crypto_ec_get_prime - Get prime defining an EC group
* @e: EC context from crypto_ec_init()
* Returns: Prime (bignum) defining the group
@@ -695,6 +761,16 @@ struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e);
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
/**
+ * crypto_ec_point_x - Copies the x-ordinate point into big number
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point data
+ * @x: Big number to set to the copy of x-ordinate
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x);
+
+/**
* crypto_ec_point_to_bin - Write EC point value as binary data
* @e: EC context from crypto_ec_init()
* @p: EC point data from crypto_ec_point_init()
@@ -723,7 +799,7 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
const u8 *val);
/**
- * crypto_bignum_add - c = a + b
+ * crypto_ec_point_add - c = a + b
* @e: EC context from crypto_ec_init()
* @a: Bignum
* @b: Bignum
@@ -735,7 +811,7 @@ int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
struct crypto_ec_point *c);
/**
- * crypto_bignum_mul - res = b * p
+ * crypto_ec_point_mul - res = b * p
* @e: EC context from crypto_ec_init()
* @p: EC point
* @b: Bignum
@@ -806,4 +882,12 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
const struct crypto_ec_point *a,
const struct crypto_ec_point *b);
+struct crypto_ecdh;
+
+struct crypto_ecdh * crypto_ecdh_init(int group);
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y);
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+ const u8 *key, size_t len);
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
+
#endif /* CRYPTO_H */
diff --git a/contrib/wpa/src/crypto/crypto_gnutls.c b/contrib/wpa/src/crypto/crypto_gnutls.c
index 0dfd54d..4ef1146 100644
--- a/contrib/wpa/src/crypto/crypto_gnutls.c
+++ b/contrib/wpa/src/crypto/crypto_gnutls.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for libgcrypt
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,27 +10,42 @@
#include <gcrypt.h>
#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
#include "crypto.h"
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+static int gnutls_digest_vector(int algo, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
- if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
+ if (TEST_FAIL())
+ return -1;
+
+ if (gcry_md_open(&hd, algo, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_MD4);
+ p = gcry_md_read(hd, algo);
if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
+ memcpy(mac, p, gcry_md_get_algo_dlen(algo));
gcry_md_close(hd);
return 0;
}
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_MD4, num_elem, addr, len, mac);
+}
+
+
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
gcry_cipher_hd_t hd;
u8 pkey[8], next, tmp;
@@ -49,49 +64,161 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
gcry_cipher_close(hd);
+ return 0;
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- gcry_md_hd_t hd;
- unsigned char *p;
- size_t i;
-
- if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
- return -1;
- for (i = 0; i < num_elem; i++)
- gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_MD5);
- if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
- gcry_md_close(hd);
- return 0;
+ return gnutls_digest_vector(GCRY_MD_MD5, num_elem, addr, len, mac);
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
+ return gnutls_digest_vector(GCRY_MD_SHA1, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA256, num_elem, addr, len, mac);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA384, num_elem, addr, len, mac);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA512, num_elem, addr, len, mac);
+}
+
+
+static int gnutls_hmac_vector(int algo, const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac)
+{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
- if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
+ if (TEST_FAIL())
+ return -1;
+
+ if (gcry_md_open(&hd, algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR)
+ return -1;
+ if (gcry_md_setkey(hd, key, key_len) != GPG_ERR_NO_ERROR) {
+ gcry_md_close(hd);
return -1;
+ }
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_SHA1);
+ p = gcry_md_read(hd, algo);
if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
+ memcpy(mac, p, gcry_md_get_algo_dlen(algo));
gcry_md_close(hd);
return 0;
}
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_MD5, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA1, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA256, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA384, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA512, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
void * aes_encrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
+ if (TEST_FAIL())
+ return NULL;
+
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR) {
printf("cipher open failed\n");
@@ -107,10 +234,11 @@ void * aes_encrypt_init(const u8 *key, size_t len)
}
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
+ return 0;
}
@@ -125,6 +253,9 @@ void * aes_decrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
+ if (TEST_FAIL())
+ return NULL;
+
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR)
return NULL;
@@ -137,10 +268,11 @@ void * aes_decrypt_init(const u8 *key, size_t len)
}
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
+ return 0;
}
@@ -151,6 +283,81 @@ void aes_decrypt_deinit(void *ctx)
}
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ gcry_mpi_t pub = NULL;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ if (gcry_mpi_scan(&pub, GCRYMPI_FMT_USG, pubkey, pubkey_len, NULL) !=
+ GPG_ERR_NO_ERROR ||
+ gcry_mpi_cmp_ui(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ gcry_mpi_t p = NULL, q = NULL, tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ tmp = gcry_mpi_new(prime_len * 8);
+ failed = !tmp ||
+ gcry_mpi_scan(&p, GCRYMPI_FMT_USG, prime, prime_len,
+ NULL) != GPG_ERR_NO_ERROR ||
+ gcry_mpi_scan(&q, GCRYMPI_FMT_USG, order, order_len,
+ NULL) != GPG_ERR_NO_ERROR;
+ if (!failed) {
+ gcry_mpi_powm(tmp, pub, q, p);
+ failed = gcry_mpi_cmp_ui(tmp, 1) != 0;
+ }
+ gcry_mpi_release(p);
+ gcry_mpi_release(q);
+ gcry_mpi_release(tmp);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ gcry_mpi_release(pub);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/contrib/wpa/src/crypto/crypto_internal-modexp.c b/contrib/wpa/src/crypto/crypto_internal-modexp.c
index 9dcabb9..6819f1a 100644
--- a/contrib/wpa/src/crypto/crypto_internal-modexp.c
+++ b/contrib/wpa/src/crypto/crypto_internal-modexp.c
@@ -13,6 +13,79 @@
#include "crypto.h"
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ struct bignum *pub;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ pub = bignum_init();
+ if (!pub || bignum_set_unsigned_bin(pub, pubkey, pubkey_len) < 0 ||
+ bignum_cmp_d(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ struct bignum *p, *q, *tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ p = bignum_init();
+ q = bignum_init();
+ tmp = bignum_init();
+ failed = !p || !q || !tmp ||
+ bignum_set_unsigned_bin(p, prime, prime_len) < 0 ||
+ bignum_set_unsigned_bin(q, order, order_len) < 0 ||
+ bignum_exptmod(pub, q, p, tmp) < 0 ||
+ bignum_cmp_d(tmp, 1) != 0;
+ bignum_deinit(p);
+ bignum_deinit(q);
+ bignum_deinit(tmp);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ bignum_deinit(pub);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/contrib/wpa/src/crypto/crypto_internal.c b/contrib/wpa/src/crypto/crypto_internal.c
index f3602da..aad40af 100644
--- a/contrib/wpa/src/crypto/crypto_internal.c
+++ b/contrib/wpa/src/crypto/crypto_internal.c
@@ -11,6 +11,8 @@
#include "common.h"
#include "crypto.h"
#include "sha256_i.h"
+#include "sha384_i.h"
+#include "sha512_i.h"
#include "sha1_i.h"
#include "md5_i.h"
@@ -22,6 +24,12 @@ struct crypto_hash {
#ifdef CONFIG_SHA256
struct sha256_state sha256;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ struct sha384_state sha384;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ struct sha512_state sha512;
+#endif /* CONFIG_INTERNAL_SHA512 */
} u;
u8 key[64];
size_t key_len;
@@ -54,6 +62,16 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
sha256_init(&ctx->u.sha256);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ sha384_init(&ctx->u.sha384);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ sha512_init(&ctx->u.sha512);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (key_len > sizeof(k_pad)) {
MD5Init(&ctx->u.md5);
@@ -142,6 +160,16 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
sha256_process(&ctx->u.sha256, data, len);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ sha384_process(&ctx->u.sha384, data, len);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ sha512_process(&ctx->u.sha512, data, len);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
default:
break;
}
@@ -191,6 +219,28 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
sha256_done(&ctx->u.sha256, mac);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ if (*len < 48) {
+ *len = 48;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 48;
+ sha384_done(&ctx->u.sha384, mac);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ if (*len < 64) {
+ *len = 64;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 64;
+ sha512_done(&ctx->u.sha512, mac);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (*len < 16) {
*len = 16;
@@ -260,6 +310,9 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
os_free(ctx);
+ if (TEST_FAIL())
+ return -1;
+
return 0;
}
diff --git a/contrib/wpa/src/crypto/crypto_libtomcrypt.c b/contrib/wpa/src/crypto/crypto_libtomcrypt.c
index a55edd1..ed30efa 100644
--- a/contrib/wpa/src/crypto/crypto_libtomcrypt.c
+++ b/contrib/wpa/src/crypto/crypto_libtomcrypt.c
@@ -35,7 +35,7 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
}
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
@@ -53,6 +53,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
des_setup(pkey, 8, 0, &skey);
des_ecb_encrypt(clear, cypher, &skey);
des_done(&skey);
+ return 0;
}
@@ -96,10 +97,10 @@ void * aes_encrypt_init(const u8 *key, size_t len)
}
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
symmetric_key *skey = ctx;
- aes_ecb_encrypt(plain, crypt, skey);
+ return aes_ecb_encrypt(plain, crypt, skey) == CRYPT_OK ? 0 : -1;
}
@@ -125,10 +126,10 @@ void * aes_decrypt_init(const u8 *key, size_t len)
}
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
symmetric_key *skey = ctx;
- aes_ecb_encrypt(plain, (u8 *) crypt, skey);
+ return aes_ecb_encrypt(plain, (u8 *) crypt, skey) == CRYPT_OK ? 0 : -1;
}
@@ -277,6 +278,9 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
os_free(ctx);
+ if (TEST_FAIL())
+ return -1;
+
return ret;
}
@@ -297,7 +301,7 @@ struct crypto_cipher {
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
-{
+{
struct crypto_cipher *ctx;
int idx, res, rc4 = 0;
@@ -693,6 +697,44 @@ void crypto_global_deinit(void)
#ifdef CONFIG_MODEXP
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ /* TODO: check pubkey */
+ return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/contrib/wpa/src/crypto/crypto_linux.c b/contrib/wpa/src/crypto/crypto_linux.c
new file mode 100644
index 0000000..1724456
--- /dev/null
+++ b/contrib/wpa/src/crypto/crypto_linux.c
@@ -0,0 +1,1009 @@
+/*
+ * Crypto wrapper for Linux kernel AF_ALG
+ * Copyright (c) 2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <linux/if_alg.h>
+
+#include "common.h"
+#include "crypto.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "aes.h"
+
+
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif /* SOL_ALG */
+
+
+static int linux_af_alg_socket(const char *type, const char *name)
+{
+ struct sockaddr_alg sa;
+ int s;
+
+ if (TEST_FAIL())
+ return -1;
+
+ s = socket(AF_ALG, SOCK_SEQPACKET, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "%s: Failed to open AF_ALG socket: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&sa, 0, sizeof(sa));
+ sa.salg_family = AF_ALG;
+ os_strlcpy((char *) sa.salg_type, type, sizeof(sa.salg_type));
+ os_strlcpy((char *) sa.salg_name, name, sizeof(sa.salg_type));
+ if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: Failed to bind AF_ALG socket(%s,%s): %s",
+ __func__, type, name, strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+
+static int linux_af_alg_hash_vector(const char *alg, const u8 *key,
+ size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len,
+ u8 *mac, size_t mac_len)
+{
+ int s, t;
+ size_t i;
+ ssize_t res;
+ int ret = -1;
+
+ s = linux_af_alg_socket("hash", alg);
+ if (s < 0)
+ return -1;
+
+ if (key && setsockopt(s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
+ wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
+ __func__, strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ t = accept(s, NULL, NULL);
+ if (t < 0) {
+ wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ for (i = 0; i < num_elem; i++) {
+ res = send(t, addr[i], len[i], i + 1 < num_elem ? MSG_MORE : 0);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: send on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if ((size_t) res < len[i]) {
+ wpa_printf(MSG_ERROR,
+ "%s: send on AF_ALG socket did not accept full buffer (%d/%d)",
+ __func__, (int) res, (int) len[i]);
+ goto fail;
+ }
+ }
+
+ res = recv(t, mac, mac_len, 0);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: recv on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if ((size_t) res < mac_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: recv on AF_ALG socket did not return full buffer (%d/%d)",
+ __func__, (int) res, (int) mac_len);
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ close(t);
+ close(s);
+
+ return ret;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("md4", NULL, 0, num_elem, addr, len,
+ mac, 16);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("md5", NULL, 0, num_elem, addr, len,
+ mac, MD5_MAC_LEN);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return linux_af_alg_hash_vector("sha1", NULL, 0, num_elem, addr, len,
+ mac, SHA1_MAC_LEN);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return linux_af_alg_hash_vector("sha256", NULL, 0, num_elem, addr, len,
+ mac, SHA256_MAC_LEN);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return linux_af_alg_hash_vector("sha384", NULL, 0, num_elem, addr, len,
+ mac, SHA384_MAC_LEN);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return linux_af_alg_hash_vector("sha512", NULL, 0, num_elem, addr, len,
+ mac, 64);
+}
+
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("hmac(md5)", key, key_len, num_elem,
+ addr, len, mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("hmac(sha1)", key, key_len, num_elem,
+ addr, len, mac, SHA1_MAC_LEN);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("hmac(sha256)", key, key_len, num_elem,
+ addr, len, mac, SHA256_MAC_LEN);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("hmac(sha384)", key, key_len, num_elem,
+ addr, len, mac, SHA384_MAC_LEN);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+struct crypto_hash {
+ int s;
+ int t;
+ size_t mac_len;
+ int failed;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ctx;
+ const char *name;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ switch (alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ name = "md5";
+ ctx->mac_len = MD5_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ name = "sha1";
+ ctx->mac_len = SHA1_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ name = "hmac(md5)";
+ ctx->mac_len = MD5_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ name = "hmac(sha1)";
+ ctx->mac_len = SHA1_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_SHA256:
+ name = "sha256";
+ ctx->mac_len = SHA256_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ name = "hmac(sha256)";
+ ctx->mac_len = SHA256_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_SHA384:
+ name = "sha384";
+ ctx->mac_len = SHA384_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_SHA512:
+ name = "sha512";
+ ctx->mac_len = 64;
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->s = linux_af_alg_socket("hash", name);
+ if (ctx->s < 0) {
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (key && key_len &&
+ setsockopt(ctx->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
+ wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
+ __func__, strerror(errno));
+ close(ctx->s);
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->t = accept(ctx->s, NULL, NULL);
+ if (ctx->t < 0) {
+ wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ close(ctx->s);
+ os_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ ssize_t res;
+
+ if (!ctx)
+ return;
+
+ res = send(ctx->t, data, len, MSG_MORE);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: send on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ ctx->failed = 1;
+ return;
+ }
+ if ((size_t) res < len) {
+ wpa_printf(MSG_ERROR,
+ "%s: send on AF_ALG socket did not accept full buffer (%d/%d)",
+ __func__, (int) res, (int) len);
+ ctx->failed = 1;
+ return;
+ }
+}
+
+
+static void crypto_hash_deinit(struct crypto_hash *ctx)
+{
+ close(ctx->s);
+ close(ctx->t);
+ os_free(ctx);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ ssize_t res;
+
+ if (!ctx)
+ return -2;
+
+ if (!mac || !len) {
+ crypto_hash_deinit(ctx);
+ return 0;
+ }
+
+ if (ctx->failed) {
+ crypto_hash_deinit(ctx);
+ return -2;
+ }
+
+ if (*len < ctx->mac_len) {
+ crypto_hash_deinit(ctx);
+ *len = ctx->mac_len;
+ return -1;
+ }
+ *len = ctx->mac_len;
+
+ res = recv(ctx->t, mac, ctx->mac_len, 0);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: recv on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ crypto_hash_deinit(ctx);
+ return -2;
+ }
+ if ((size_t) res < ctx->mac_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: recv on AF_ALG socket did not return full buffer (%d/%d)",
+ __func__, (int) res, (int) ctx->mac_len);
+ crypto_hash_deinit(ctx);
+ return -2;
+ }
+
+ crypto_hash_deinit(ctx);
+
+ if (TEST_FAIL())
+ return -1;
+ return 0;
+}
+
+
+struct linux_af_alg_skcipher {
+ int s;
+ int t;
+};
+
+
+static void linux_af_alg_skcipher_deinit(struct linux_af_alg_skcipher *skcipher)
+{
+ if (!skcipher)
+ return;
+ if (skcipher->s >= 0)
+ close(skcipher->s);
+ if (skcipher->t >= 0)
+ close(skcipher->t);
+ os_free(skcipher);
+}
+
+
+static struct linux_af_alg_skcipher *
+linux_af_alg_skcipher(const char *alg, const u8 *key, size_t key_len)
+{
+ struct linux_af_alg_skcipher *skcipher;
+
+ skcipher = os_zalloc(sizeof(*skcipher));
+ if (!skcipher)
+ goto fail;
+ skcipher->t = -1;
+
+ skcipher->s = linux_af_alg_socket("skcipher", alg);
+ if (skcipher->s < 0)
+ goto fail;
+
+ if (setsockopt(skcipher->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
+ wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+
+ skcipher->t = accept(skcipher->s, NULL, NULL);
+ if (skcipher->t < 0) {
+ wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+
+ return skcipher;
+fail:
+ linux_af_alg_skcipher_deinit(skcipher);
+ return NULL;
+}
+
+
+static int linux_af_alg_skcipher_oper(struct linux_af_alg_skcipher *skcipher,
+ int enc, const u8 *in, u8 *out)
+{
+ char buf[CMSG_SPACE(sizeof(u32))];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+
+ io[0].iov_base = (void *) in;
+ io[0].iov_len = AES_BLOCK_SIZE;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ ret = read(skcipher->t, out, AES_BLOCK_SIZE);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: read failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ if (ret < AES_BLOCK_SIZE) {
+ wpa_printf(MSG_ERROR,
+ "%s: read did not return full data (%d/%d)",
+ __func__, (int) ret, AES_BLOCK_SIZE);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ return linux_af_alg_skcipher("ecb(aes)", key, len);
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ struct linux_af_alg_skcipher *skcipher = ctx;
+
+ return linux_af_alg_skcipher_oper(skcipher, 1, plain, crypt);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ linux_af_alg_skcipher_deinit(ctx);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ return linux_af_alg_skcipher("ecb(aes)", key, len);
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ struct linux_af_alg_skcipher *skcipher = ctx;
+
+ return linux_af_alg_skcipher_oper(skcipher, 0, crypt, plain);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ linux_af_alg_skcipher_deinit(ctx);
+}
+
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+ u8 *data, size_t data_len)
+{
+ struct linux_af_alg_skcipher *skcipher;
+ u8 *skip_buf;
+ char buf[CMSG_SPACE(sizeof(u32))];
+ struct iovec io[2];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+
+ skip_buf = os_zalloc(skip + 1);
+ if (!skip_buf)
+ return -1;
+ skcipher = linux_af_alg_skcipher("ecb(arc4)", key, keylen);
+ if (!skcipher) {
+ os_free(skip_buf);
+ return -1;
+ }
+
+ io[0].iov_base = skip_buf;
+ io[0].iov_len = skip;
+ io[1].iov_base = data;
+ io[1].iov_len = data_len;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = ALG_OP_ENCRYPT;
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ os_free(skip_buf);
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+ os_free(skip_buf);
+
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ ret = recvmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: recvmsg failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+ linux_af_alg_skcipher_deinit(skcipher);
+
+ if ((size_t) ret < skip + data_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: recvmsg did not return full data (%d/%d)",
+ __func__, (int) ret, (int) (skip + data_len));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ u8 pkey[8], next, tmp;
+ int i;
+ struct linux_af_alg_skcipher *skcipher;
+ char buf[CMSG_SPACE(sizeof(u32))];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+ int res = -1;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ skcipher = linux_af_alg_skcipher("ecb(des)", pkey, sizeof(pkey));
+ if (!skcipher)
+ goto fail;
+
+ io[0].iov_base = (void *) clear;
+ io[0].iov_len = 8;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = ALG_OP_ENCRYPT;
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+
+ ret = read(skcipher->t, cypher, 8);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: read failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if (ret < 8) {
+ wpa_printf(MSG_ERROR,
+ "%s: read did not return full data (%d/8)",
+ __func__, (int) ret);
+ goto fail;
+ }
+
+ res = 0;
+fail:
+ linux_af_alg_skcipher_deinit(skcipher);
+ return res;
+}
+
+
+static int aes_128_cbc_oper(const u8 *key, int enc, const u8 *iv,
+ u8 *data, size_t data_len)
+{
+ struct linux_af_alg_skcipher *skcipher;
+ char buf[100];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+ struct af_alg_iv *alg_iv;
+ size_t iv_len = AES_BLOCK_SIZE;
+
+ skcipher = linux_af_alg_skcipher("cbc(aes)", key, 16);
+ if (!skcipher)
+ return -1;
+
+ io[0].iov_base = (void *) data;
+ io[0].iov_len = data_len;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32)) +
+ CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+
+ hdr = CMSG_NXTHDR(&msg, hdr);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_IV;
+ hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
+ alg_iv->ivlen = iv_len;
+ os_memcpy(alg_iv->iv, iv, iv_len);
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+
+ ret = recvmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: recvmsg failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+ if ((size_t) ret < data_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: recvmsg not return full data (%d/%d)",
+ __func__, (int) ret, (int) data_len);
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+
+ linux_af_alg_skcipher_deinit(skcipher);
+ return 0;
+}
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ return aes_128_cbc_oper(key, 1, iv, data, data_len);
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ return aes_128_cbc_oper(key, 0, iv, data, data_len);
+}
+
+
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("cmac(aes)", key, key_len, num_elem,
+ addr, len, mac, AES_BLOCK_SIZE);
+}
+
+
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
+{
+ struct linux_af_alg_skcipher *skcipher;
+ char buf[100];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+ struct af_alg_iv *alg_iv;
+ size_t iv_len = 8;
+
+ skcipher = linux_af_alg_skcipher("kw(aes)", kek, kek_len);
+ if (!skcipher)
+ return -1;
+
+ io[0].iov_base = (void *) (cipher + iv_len);
+ io[0].iov_len = n * 8;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32)) +
+ CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = ALG_OP_DECRYPT;
+
+ hdr = CMSG_NXTHDR(&msg, hdr);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_IV;
+ hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
+ alg_iv->ivlen = iv_len;
+ os_memcpy(alg_iv->iv, cipher, iv_len);
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ ret = read(skcipher->t, plain, n * 8);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: read failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+ if (ret < n * 8) {
+ wpa_printf(MSG_ERROR,
+ "%s: read not return full data (%d/%d)",
+ __func__, (int) ret, n * 8);
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+
+ linux_af_alg_skcipher_deinit(skcipher);
+ return 0;
+}
+
+
+struct crypto_cipher {
+ struct linux_af_alg_skcipher *skcipher;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+ const char *name;
+ struct af_alg_iv *alg_iv;
+ size_t iv_len = 0;
+ char buf[100];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ name = "ecb(arc4)";
+ break;
+ case CRYPTO_CIPHER_ALG_AES:
+ name = "cbc(aes)";
+ iv_len = AES_BLOCK_SIZE;
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ name = "cbc(des3_ede)";
+ iv_len = 8;
+ break;
+ case CRYPTO_CIPHER_ALG_DES:
+ name = "cbc(des)";
+ iv_len = 8;
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->skcipher = linux_af_alg_skcipher(name, key, key_len);
+ if (!ctx->skcipher) {
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (iv && iv_len) {
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_IV;
+ hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
+ alg_iv->ivlen = iv_len;
+ os_memcpy(alg_iv->iv, iv, iv_len);
+
+ ret = sendmsg(ctx->skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(ctx->skcipher);
+ os_free(ctx);
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+
+static int crypto_cipher_oper(struct crypto_cipher *ctx, u32 type, const u8 *in,
+ u8 *out, size_t len)
+{
+ char buf[CMSG_SPACE(sizeof(u32))];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+
+ io[0].iov_base = (void *) in;
+ io[0].iov_len = len;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = type;
+
+ ret = sendmsg(ctx->skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ ret = read(ctx->skcipher->t, out, len);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: read failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ if (ret < (ssize_t) len) {
+ wpa_printf(MSG_ERROR,
+ "%s: read did not return full data (%d/%d)",
+ __func__, (int) ret, (int) len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ return crypto_cipher_oper(ctx, ALG_OP_ENCRYPT, plain, crypt, len);
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ return crypto_cipher_oper(ctx, ALG_OP_DECRYPT, crypt, plain, len);
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ if (ctx) {
+ linux_af_alg_skcipher_deinit(ctx->skcipher);
+ os_free(ctx);
+ }
+}
+
+
+int crypto_global_init(void)
+{
+ return 0;
+}
+
+
+void crypto_global_deinit(void)
+{
+}
diff --git a/contrib/wpa/src/crypto/crypto_module_tests.c b/contrib/wpa/src/crypto/crypto_module_tests.c
index 581005d..1cc73d8 100644
--- a/contrib/wpa/src/crypto/crypto_module_tests.c
+++ b/contrib/wpa/src/crypto/crypto_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "crypto/aes_siv.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes.h"
@@ -16,6 +17,7 @@
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
static int test_siv(void)
@@ -91,7 +93,7 @@ static int test_siv(void)
addr[0] = ad;
len[0] = sizeof(ad);
- if (aes_siv_encrypt(key, plaintext, sizeof(plaintext),
+ if (aes_siv_encrypt(key, sizeof(key), plaintext, sizeof(plaintext),
1, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
return 1;
@@ -102,7 +104,8 @@ static int test_siv(void)
return 1;
}
- if (aes_siv_decrypt(key, iv_c, sizeof(iv_c), 1, addr, len, out)) {
+ if (aes_siv_decrypt(key, sizeof(key), iv_c, sizeof(iv_c),
+ 1, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
return 1;
}
@@ -120,7 +123,8 @@ static int test_siv(void)
addr[2] = nonce_2;
len[2] = sizeof(nonce_2);
- if (aes_siv_encrypt(key_2, plaintext_2, sizeof(plaintext_2),
+ if (aes_siv_encrypt(key_2, sizeof(key_2),
+ plaintext_2, sizeof(plaintext_2),
3, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
return 1;
@@ -131,7 +135,8 @@ static int test_siv(void)
return 1;
}
- if (aes_siv_decrypt(key_2, iv_c_2, sizeof(iv_c_2), 3, addr, len, out)) {
+ if (aes_siv_decrypt(key_2, sizeof(key_2), iv_c_2, sizeof(iv_c_2),
+ 3, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
return 1;
}
@@ -1266,7 +1271,7 @@ static int test_sha1(void)
}
-const struct {
+static const struct {
char *data;
u8 hash[32];
} tests[] = {
@@ -1290,14 +1295,15 @@ const struct {
}
};
-const struct hmac_test {
- u8 key[80];
+static const struct hmac_test {
+ u8 key[150];
size_t key_len;
- u8 data[128];
+ u8 data[160];
size_t data_len;
- u8 hash[32];
+ u8 hash[32]; /* HMAC-SHA-256 */
+ u8 hash384[48]; /* HMAC-SHA-384 */
} hmac_tests[] = {
- /* draft-ietf-ipsec-ciph-sha-256-01.txt */
+ /* draft-ietf-ipsec-ciph-sha-256-01.txt; RFC 4231 */
{
{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
@@ -1312,7 +1318,8 @@ const struct hmac_test {
0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
- }
+ },
+ { }
},
{
{
@@ -1329,7 +1336,8 @@ const struct hmac_test {
0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
- }
+ },
+ { }
},
{
{
@@ -1347,7 +1355,8 @@ const struct hmac_test {
0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
- }
+ },
+ { }
},
{
{
@@ -1364,9 +1373,34 @@ const struct hmac_test {
0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 1 */
+ {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+ },
+ 20,
+ "Hi There",
+ 8,
+ {
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
+ 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
+ 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+ 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7
+ },
+ {
+ 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+ 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f,
+ 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+ 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+ 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+ 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6
}
},
- {
+ { /* RFC 4231 - Test Case 2 */
"Jefe",
4,
"what do ya want for nothing?",
@@ -1376,6 +1410,14 @@ const struct hmac_test {
0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+ },
+ {
+ 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+ 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+ 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+ 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+ 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+ 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49
}
},
{
@@ -1401,6 +1443,39 @@ const struct hmac_test {
0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 3 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 20,
+ {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+ },
+ 50,
+ {
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
+ 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
+ 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+ 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe
+ },
+ {
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a,
+ 0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f,
+ 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b,
+ 0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9,
+ 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27
}
},
{
@@ -1427,6 +1502,40 @@ const struct hmac_test {
0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 4 */
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19,
+ },
+ 25,
+ {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+ },
+ 50,
+ {
+ 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
+ 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
+ 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+ 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b
+ },
+ {
+ 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85,
+ 0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7,
+ 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+ 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e,
+ 0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79,
+ 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb
}
},
{
@@ -1444,7 +1553,8 @@ const struct hmac_test {
0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
- }
+ },
+ { }
},
{
{
@@ -1467,6 +1577,45 @@ const struct hmac_test {
0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 6 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa
+ },
+ 131,
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ 54,
+ {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+ 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+ 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+ 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+ },
+ {
+ 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+ 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+ 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+ 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+ 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52
}
},
{
@@ -1491,6 +1640,45 @@ const struct hmac_test {
0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 7 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa
+ },
+ 131,
+ "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ 152,
+ {
+ 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
+ 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
+ 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+ 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2
+ },
+ {
+ 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+ 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+ 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+ 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+ 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e
}
}
};
@@ -1503,6 +1691,7 @@ static int test_sha256(void)
const u8 *addr[2];
size_t len[2];
int errors = 0;
+ u8 *key;
for (i = 0; i < ARRAY_SIZE(tests); i++) {
wpa_printf(MSG_INFO, "SHA256 test case %d:", i + 1);
@@ -1573,12 +1762,285 @@ static int test_sha256(void)
hash, sizeof(hash));
/* TODO: add proper test case for this */
+ key = os_malloc(8161);
+ if (key) {
+#ifdef CONFIG_HMAC_SHA256_KDF
+ int res;
+
+ res = hmac_sha256_kdf((u8 *) "secret", 6, "label",
+ (u8 *) "seed", 4, key, 8160);
+ if (res) {
+ wpa_printf(MSG_INFO,
+ "Unexpected hmac_sha256_kdf(outlen=8160) failure");
+ errors++;
+ }
+
+ res = hmac_sha256_kdf((u8 *) "secret", 6, "label",
+ (u8 *) "seed", 4, key, 8161);
+ if (res == 0) {
+ wpa_printf(MSG_INFO,
+ "Unexpected hmac_sha256_kdf(outlen=8161) success");
+ errors++;
+ }
+#endif /* CONFIG_HMAC_SHA256_KDF */
+
+ os_free(key);
+ }
+
if (!errors)
wpa_printf(MSG_INFO, "SHA256 test cases passed");
return errors;
}
+static int test_sha384(void)
+{
+#ifdef CONFIG_SHA384
+ unsigned int i;
+ u8 hash[48];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+ const char *data = "hello";
+ const u8 hash_res[] = {
+ 0x59, 0xe1, 0x74, 0x87, 0x77, 0x44, 0x8c, 0x69,
+ 0xde, 0x6b, 0x80, 0x0d, 0x7a, 0x33, 0xbb, 0xfb,
+ 0x9f, 0xf1, 0xb4, 0x63, 0xe4, 0x43, 0x54, 0xc3,
+ 0x55, 0x3b, 0xcd, 0xb9, 0xc6, 0x66, 0xfa, 0x90,
+ 0x12, 0x5a, 0x3c, 0x79, 0xf9, 0x03, 0x97, 0xbd,
+ 0xf5, 0xf6, 0xa1, 0x3d, 0xe8, 0x28, 0x68, 0x4f
+ };
+
+ addr[0] = (const u8 *) data;
+ len[0] = 5;
+ if (sha384_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, hash_res, 48) != 0) {
+ wpa_printf(MSG_INFO, "SHA384 test case 1: FAIL");
+ errors++;
+ } else {
+ wpa_printf(MSG_INFO, "SHA384 test case 1: OK");
+ }
+
+ addr[0] = (const u8 *) data;
+ len[0] = 4;
+ addr[1] = (const u8 *) data + 4;
+ len[1] = 1;
+ if (sha384_vector(2, addr, len, hash) < 0 ||
+ os_memcmp(hash, hash_res, 48) != 0) {
+ wpa_printf(MSG_INFO, "SHA384 test case 2: FAIL");
+ errors++;
+ } else {
+ wpa_printf(MSG_INFO, "SHA384 test case 2: OK");
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+ const struct hmac_test *t = &hmac_tests[i];
+
+ if (t->hash384[0] == 0 && t->hash384[1] == 0 &&
+ t->hash384[2] == 0 && t->hash384[3] == 0)
+ continue;
+ wpa_printf(MSG_INFO, "HMAC-SHA384 test case %d:", i + 1);
+
+ if (hmac_sha384(t->key, t->key_len, t->data, t->data_len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ addr[0] = t->data;
+ len[0] = t->data_len;
+ if (hmac_sha384_vector(t->key, t->key_len, 1, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = t->data;
+ len[0] = 1;
+ addr[1] = t->data + 1;
+ len[1] = t->data_len - 1;
+ if (hmac_sha384_vector(t->key, t->key_len, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "SHA384 test cases passed");
+ return errors;
+#else /* CONFIG_SHA384 */
+ return 0;
+#endif /* CONFIG_SHA384 */
+}
+
+
+static int test_fips186_2_prf(void)
+{
+ /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
+ u8 xkey[] = {
+ 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+ 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+ 0xeb, 0x5a, 0x38, 0xb6
+ };
+ u8 w[] = {
+ 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
+ 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
+ 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
+ 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
+ 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
+ };
+ u8 buf[40];
+
+ wpa_printf(MSG_INFO,
+ "Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)");
+ if (fips186_2_prf(xkey, sizeof(xkey), buf, sizeof(buf)) < 0 ||
+ os_memcmp(w, buf, sizeof(w)) != 0) {
+ wpa_printf(MSG_INFO, "fips186_2_prf failed");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int test_extract_expand_hkdf(void)
+{
+ u8 prk[SHA256_MAC_LEN];
+ u8 okm[82];
+
+ /* RFC 5869, A.1 */
+ u8 ikm1[22] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ };
+ u8 salt1[13] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c
+ };
+ u8 info1[10] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9
+ };
+ u8 prk1[32] = {
+ 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
+ 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
+ 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
+ 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5
+ };
+ u8 okm1[42] = {
+ 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
+ 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
+ 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
+ 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
+ 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+ 0x58, 0x65
+ };
+
+ /* RFC 5869, A.2 */
+ u8 ikm2[80] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+ };
+ u8 salt2[80] = {
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf
+ };
+ u8 info2[80] = {
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ u8 prk2[32] = {
+ 0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a,
+ 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c,
+ 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01,
+ 0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44
+ };
+ u8 okm2[82] = {
+ 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1,
+ 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34,
+ 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
+ 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c,
+ 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72,
+ 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
+ 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
+ 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71,
+ 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87,
+ 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f,
+ 0x1d, 0x87
+ };
+
+ wpa_printf(MSG_INFO, "Testing Extract-and-Expand HKDF (RFC 5869)");
+
+ wpa_printf(MSG_INFO, "RFC 5869 - Test Case 1");
+ if (hmac_sha256(salt1, sizeof(salt1), ikm1, sizeof(ikm1), prk) < 0)
+ return -1;
+ if (os_memcmp(prk, prk1, SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "HKDF-Extract mismatch in PRK");
+ return -1;
+ }
+ if (hmac_sha256_kdf(prk1, sizeof(prk1), NULL, info1, sizeof(info1),
+ okm, sizeof(okm1)) < 0)
+ return -1;
+ if (os_memcmp(okm, okm1, sizeof(okm1)) != 0) {
+ wpa_printf(MSG_INFO, "HKDF-Expand mismatch in OKM");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 5869 - Test Case 2");
+ if (hmac_sha256(salt2, sizeof(salt2), ikm2, sizeof(ikm2), prk) < 0)
+ return -1;
+ if (os_memcmp(prk, prk2, SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "HKDF-Extract mismatch in PRK");
+ return -1;
+ }
+ if (hmac_sha256_kdf(prk2, sizeof(prk2), NULL, info2, sizeof(info2),
+ okm, sizeof(okm2)) < 0)
+ return -1;
+ if (os_memcmp(okm, okm2, sizeof(okm2)) != 0) {
+ wpa_printf(MSG_INFO, "HKDF-Expand mismatch in OKM");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "Extract-and-Expand HKDF test cases passed");
+
+ return 0;
+}
+
+
static int test_ms_funcs(void)
{
#ifndef CONFIG_FIPS
@@ -1695,6 +2157,9 @@ int crypto_module_tests(void)
test_md5() ||
test_sha1() ||
test_sha256() ||
+ test_sha384() ||
+ test_fips186_2_prf() ||
+ test_extract_expand_hkdf() ||
test_ms_funcs())
ret = -1;
diff --git a/contrib/wpa/src/crypto/crypto_nettle.c b/contrib/wpa/src/crypto/crypto_nettle.c
new file mode 100644
index 0000000..f85d365
--- /dev/null
+++ b/contrib/wpa/src/crypto/crypto_nettle.c
@@ -0,0 +1,469 @@
+/*
+ * Wrapper functions for libnettle and libgmp
+ * Copyright (c) 2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <nettle/nettle-meta.h>
+#include <nettle/des.h>
+#undef des_encrypt
+#include <nettle/hmac.h>
+#include <nettle/aes.h>
+#undef aes_encrypt
+#undef aes_decrypt
+#include <nettle/arcfour.h>
+#include <nettle/bignum.h>
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
+#include "crypto.h"
+
+
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ struct des_ctx ctx;
+ u8 pkey[8], next, tmp;
+ int i;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ nettle_des_set_key(&ctx, pkey);
+ nettle_des_encrypt(&ctx, DES_BLOCK_SIZE, cypher, clear);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+static int nettle_digest_vector(const struct nettle_hash *alg, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ void *ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = os_malloc(alg->context_size);
+ if (!ctx)
+ return -1;
+ alg->init(ctx);
+ for (i = 0; i < num_elem; i++)
+ alg->update(ctx, len[i], addr[i]);
+ alg->digest(ctx, alg->digest_size, mac);
+ bin_clear_free(ctx, alg->context_size);
+ return 0;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_md4, num_elem, addr, len, mac);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_md5, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha1, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha256, num_elem, addr, len, mac);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha384, num_elem, addr, len, mac);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha512, num_elem, addr, len, mac);
+}
+
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_md5_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_md5_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_md5_update(&ctx, len[i], addr[i]);
+ hmac_md5_digest(&ctx, MD5_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha1_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha1_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha1_update(&ctx, len[i], addr[i]);
+ hmac_sha1_digest(&ctx, SHA1_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha256_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha256_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha256_update(&ctx, len[i], addr[i]);
+ hmac_sha256_digest(&ctx, SHA256_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha384_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha384_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha384_update(&ctx, len[i], addr[i]);
+ hmac_sha384_digest(&ctx, SHA384_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha512_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha512_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha512_update(&ctx, len[i], addr[i]);
+ hmac_sha512_digest(&ctx, SHA512_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ struct aes_ctx *ctx;
+
+ if (TEST_FAIL())
+ return NULL;
+ ctx = os_malloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ nettle_aes_set_encrypt_key(ctx, len, key);
+
+ return ctx;
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ struct aes_ctx *actx = ctx;
+ nettle_aes_encrypt(actx, AES_BLOCK_SIZE, crypt, plain);
+ return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ struct aes_ctx *actx = ctx;
+ bin_clear_free(actx, sizeof(*actx));
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ struct aes_ctx *ctx;
+
+ if (TEST_FAIL())
+ return NULL;
+ ctx = os_malloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ nettle_aes_set_decrypt_key(ctx, len, key);
+
+ return ctx;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ struct aes_ctx *actx = ctx;
+ nettle_aes_decrypt(actx, AES_BLOCK_SIZE, plain, crypt);
+ return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ struct aes_ctx *actx = ctx;
+ bin_clear_free(actx, sizeof(*actx));
+}
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ mpz_t pub;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ mpz_init(pub);
+ mpz_import(pub, pubkey_len, 1, 1, 1, 0, pubkey);
+ if (mpz_cmp_d(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ mpz_t p, q, tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ mpz_inits(p, q, tmp, NULL);
+ mpz_import(p, prime_len, 1, 1, 1, 0, prime);
+ mpz_import(q, order_len, 1, 1, 1, 0, order);
+ mpz_powm(tmp, pub, q, p);
+ failed = mpz_cmp_d(tmp, 1) != 0;
+ mpz_clears(p, q, tmp, NULL);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ mpz_clear(pub);
+ return res;
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+ const u8 *power, size_t power_len,
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len)
+{
+ mpz_t bn_base, bn_exp, bn_modulus, bn_result;
+ int ret = -1;
+ size_t len;
+
+ mpz_inits(bn_base, bn_exp, bn_modulus, bn_result, NULL);
+ mpz_import(bn_base, base_len, 1, 1, 1, 0, base);
+ mpz_import(bn_exp, power_len, 1, 1, 1, 0, power);
+ mpz_import(bn_modulus, modulus_len, 1, 1, 1, 0, modulus);
+
+ mpz_powm(bn_result, bn_base, bn_exp, bn_modulus);
+ len = mpz_sizeinbase(bn_result, 2);
+ len = (len + 7) / 8;
+ if (*result_len < len)
+ goto error;
+ mpz_export(result, result_len, 1, 1, 1, 0, bn_result);
+ ret = 0;
+
+error:
+ mpz_clears(bn_base, bn_exp, bn_modulus, bn_result, NULL);
+ return ret;
+}
+
+
+struct crypto_cipher {
+ enum crypto_cipher_alg alg;
+ union {
+ struct arcfour_ctx arcfour_ctx;
+ } u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ ctx->alg = alg;
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_set_key(&ctx->u.arcfour_ctx, key_len, key);
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_crypt(&ctx->u.arcfour_ctx, len, crypt, plain);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_crypt(&ctx->u.arcfour_ctx, len, plain, crypt);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ bin_clear_free(ctx, sizeof(*ctx));
+}
diff --git a/contrib/wpa/src/crypto/crypto_none.c b/contrib/wpa/src/crypto/crypto_none.c
index 011f3f3..5479194 100644
--- a/contrib/wpa/src/crypto/crypto_none.c
+++ b/contrib/wpa/src/crypto/crypto_none.c
@@ -18,6 +18,7 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
}
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/crypto_openssl.c b/contrib/wpa/src/crypto/crypto_openssl.c
index 6cff75c..1b0c1ec 100644
--- a/contrib/wpa/src/crypto/crypto_openssl.c
+++ b/contrib/wpa/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
* Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -24,16 +24,72 @@
#endif /* CONFIG_ECC */
#include "common.h"
+#include "utils/const_time.h"
#include "wpabuf.h"
#include "dh_group5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha384.h"
+#include "sha512.h"
+#include "md5.h"
+#include "aes_wrap.h"
#include "crypto.h"
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+/* Compatibility wrappers for older versions. */
+
+static HMAC_CTX * HMAC_CTX_new(void)
+{
+ HMAC_CTX *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx)
+ HMAC_CTX_init(ctx);
+ return ctx;
+}
+
+
+static void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+ if (!ctx)
+ return;
+ HMAC_CTX_cleanup(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+}
+
+
+static EVP_MD_CTX * EVP_MD_CTX_new(void)
+{
+ EVP_MD_CTX *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx)
+ EVP_MD_CTX_init(ctx);
+ return ctx;
+}
+
+
+static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+ if (!ctx)
+ return;
+ EVP_MD_CTX_cleanup(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+}
+
+#endif /* OpenSSL version < 1.1.0 */
+
static BIGNUM * get_group5_prime(void)
{
-#ifdef OPENSSL_IS_BORINGSSL
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !(defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+ return BN_get_rfc3526_prime_1536(NULL);
+#elif !defined(OPENSSL_IS_BORINGSSL)
+ return get_rfc3526_prime_1536(NULL);
+#else
static const unsigned char RFC3526_PRIME_1536[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
@@ -53,41 +109,76 @@ static BIGNUM * get_group5_prime(void)
0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
-#else /* OPENSSL_IS_BORINGSSL */
- return get_rfc3526_prime_1536(NULL);
-#endif /* OPENSSL_IS_BORINGSSL */
+#endif
+}
+
+
+static BIGNUM * get_group5_order(void)
+{
+ static const unsigned char RFC3526_ORDER_1536[] = {
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE4,0x87,0xED,0x51,
+ 0x10,0xB4,0x61,0x1A,0x62,0x63,0x31,0x45,0xC0,0x6E,0x0E,0x68,
+ 0x94,0x81,0x27,0x04,0x45,0x33,0xE6,0x3A,0x01,0x05,0xDF,0x53,
+ 0x1D,0x89,0xCD,0x91,0x28,0xA5,0x04,0x3C,0xC7,0x1A,0x02,0x6E,
+ 0xF7,0xCA,0x8C,0xD9,0xE6,0x9D,0x21,0x8D,0x98,0x15,0x85,0x36,
+ 0xF9,0x2F,0x8A,0x1B,0xA7,0xF0,0x9A,0xB6,0xB6,0xA8,0xE1,0x22,
+ 0xF2,0x42,0xDA,0xBB,0x31,0x2F,0x3F,0x63,0x7A,0x26,0x21,0x74,
+ 0xD3,0x1B,0xF6,0xB5,0x85,0xFF,0xAE,0x5B,0x7A,0x03,0x5B,0xF6,
+ 0xF7,0x1C,0x35,0xFD,0xAD,0x44,0xCF,0xD2,0xD7,0x4F,0x92,0x08,
+ 0xBE,0x25,0x8F,0xF3,0x24,0x94,0x33,0x28,0xF6,0x72,0x2D,0x9E,
+ 0xE1,0x00,0x3E,0x5C,0x50,0xB1,0xDF,0x82,0xCC,0x6D,0x24,0x1B,
+ 0x0E,0x2A,0xE9,0xCD,0x34,0x8B,0x1F,0xD4,0x7E,0x92,0x67,0xAF,
+ 0xC1,0xB2,0xAE,0x91,0xEE,0x51,0xD6,0xCB,0x0E,0x31,0x79,0xAB,
+ 0x10,0x42,0xA9,0x5D,0xCF,0x6A,0x94,0x83,0xB8,0x4B,0x4B,0x36,
+ 0xB3,0x86,0x1A,0xA7,0x25,0x5E,0x4C,0x02,0x78,0xBA,0x36,0x04,
+ 0x65,0x11,0xB9,0x93,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+ };
+ return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL);
}
+
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
#endif
+#ifdef OPENSSL_NO_SHA512
+#define NO_SHA384_WRAPPER
+#endif
static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
- EVP_MD_CTX ctx;
+ EVP_MD_CTX *ctx;
size_t i;
unsigned int mac_len;
- EVP_MD_CTX_init(&ctx);
- if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ return -1;
+ if (!EVP_DigestInit_ex(ctx, type, NULL)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
return -1;
}
for (i = 0; i < num_elem; i++) {
- if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
+ if (!EVP_DigestUpdate(ctx, addr[i], len[i])) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
"failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
return -1;
}
}
- if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
+ if (!EVP_DigestFinal(ctx, mac, &mac_len)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
return -1;
}
+ EVP_MD_CTX_free(ctx);
return 0;
}
@@ -101,7 +192,7 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
#endif /* CONFIG_FIPS */
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
@@ -119,6 +210,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
DES_set_key((DES_cblock *) &pkey, &ks);
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
DES_ENCRYPT);
+ return 0;
}
@@ -129,32 +221,34 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
#ifdef OPENSSL_NO_RC4
return -1;
#else /* OPENSSL_NO_RC4 */
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx;
int outl;
int res = -1;
unsigned char skip_buf[16];
- EVP_CIPHER_CTX_init(&ctx);
- if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
- !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
- !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
- !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx ||
+ !EVP_CIPHER_CTX_set_padding(ctx, 0) ||
+ !EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
+ !EVP_CIPHER_CTX_set_key_length(ctx, keylen) ||
+ !EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, 1))
goto out;
while (skip >= sizeof(skip_buf)) {
size_t len = skip;
if (len > sizeof(skip_buf))
len = sizeof(skip_buf);
- if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
+ if (!EVP_CipherUpdate(ctx, skip_buf, &outl, skip_buf, len))
goto out;
skip -= len;
}
- if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
+ if (EVP_CipherUpdate(ctx, data, &outl, data, data_len))
res = 0;
out:
- EVP_CIPHER_CTX_cleanup(&ctx);
+ if (ctx)
+ EVP_CIPHER_CTX_free(ctx);
return res;
#endif /* OPENSSL_NO_RC4 */
}
@@ -184,15 +278,31 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
#endif /* NO_SHA256_WRAPPER */
+#ifndef NO_SHA384_WRAPPER
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return openssl_digest_vector(EVP_sha384(), num_elem, addr, len, mac);
+}
+#endif /* NO_SHA384_WRAPPER */
+
+
+#ifndef NO_SHA512_WRAPPER
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return openssl_digest_vector(EVP_sha512(), num_elem, addr, len, mac);
+}
+#endif /* NO_SHA512_WRAPPER */
+
+
static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
{
switch (keylen) {
case 16:
return EVP_aes_128_ecb();
-#ifndef OPENSSL_IS_BORINGSSL
case 24:
return EVP_aes_192_ecb();
-#endif /* OPENSSL_IS_BORINGSSL */
case 32:
return EVP_aes_256_ecb();
}
@@ -206,14 +316,19 @@ void * aes_encrypt_init(const u8 *key, size_t len)
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *type;
+ if (TEST_FAIL())
+ return NULL;
+
type = aes_get_evp_cipher(len);
- if (type == NULL)
+ if (!type) {
+ wpa_printf(MSG_INFO, "%s: Unsupported len=%u",
+ __func__, (unsigned int) len);
return NULL;
+ }
- ctx = os_malloc(sizeof(*ctx));
+ ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
return NULL;
- EVP_CIPHER_CTX_init(ctx);
if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
os_free(ctx);
return NULL;
@@ -223,14 +338,16 @@ void * aes_encrypt_init(const u8 *key, size_t len)
}
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
EVP_CIPHER_CTX *c = ctx;
int clen = 16;
if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ return -1;
}
+ return 0;
}
@@ -247,8 +364,7 @@ void aes_encrypt_deinit(void *ctx)
wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
"in AES encrypt", len);
}
- EVP_CIPHER_CTX_cleanup(c);
- bin_clear_free(c, sizeof(*c));
+ EVP_CIPHER_CTX_free(c);
}
@@ -257,16 +373,21 @@ void * aes_decrypt_init(const u8 *key, size_t len)
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *type;
+ if (TEST_FAIL())
+ return NULL;
+
type = aes_get_evp_cipher(len);
- if (type == NULL)
+ if (!type) {
+ wpa_printf(MSG_INFO, "%s: Unsupported len=%u",
+ __func__, (unsigned int) len);
return NULL;
+ }
- ctx = os_malloc(sizeof(*ctx));
+ ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
return NULL;
- EVP_CIPHER_CTX_init(ctx);
if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
- os_free(ctx);
+ EVP_CIPHER_CTX_free(ctx);
return NULL;
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
@@ -274,14 +395,16 @@ void * aes_decrypt_init(const u8 *key, size_t len)
}
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
EVP_CIPHER_CTX *c = ctx;
int plen = 16;
if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ return -1;
}
+ return 0;
}
@@ -298,8 +421,7 @@ void aes_decrypt_deinit(void *ctx)
wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
"in AES decrypt", len);
}
- EVP_CIPHER_CTX_cleanup(c);
- bin_clear_free(c, sizeof(*c));
+ EVP_CIPHER_CTX_free(c);
}
@@ -311,6 +433,8 @@ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
AES_KEY actx;
int res;
+ if (TEST_FAIL())
+ return -1;
if (AES_set_encrypt_key(kek, kek_len << 3, &actx))
return -1;
res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
@@ -325,6 +449,8 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
AES_KEY actx;
int res;
+ if (TEST_FAIL())
+ return -1;
if (AES_set_decrypt_key(kek, kek_len << 3, &actx))
return -1;
res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
@@ -338,54 +464,128 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx;
int clen, len;
u8 buf[16];
+ int res = -1;
- EVP_CIPHER_CTX_init(&ctx);
- if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ if (TEST_FAIL())
return -1;
- EVP_CIPHER_CTX_set_padding(&ctx, 0);
- clen = data_len;
- if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 ||
- clen != (int) data_len)
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
return -1;
-
+ clen = data_len;
len = sizeof(buf);
- if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
- return -1;
- EVP_CIPHER_CTX_cleanup(&ctx);
+ if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_EncryptUpdate(ctx, data, &clen, data, data_len) == 1 &&
+ clen == (int) data_len &&
+ EVP_EncryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+ res = 0;
+ EVP_CIPHER_CTX_free(ctx);
- return 0;
+ return res;
}
int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx;
int plen, len;
u8 buf[16];
+ int res = -1;
- EVP_CIPHER_CTX_init(&ctx);
- if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ if (TEST_FAIL())
return -1;
- EVP_CIPHER_CTX_set_padding(&ctx, 0);
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return -1;
plen = data_len;
- if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
- plen != (int) data_len)
+ len = sizeof(buf);
+ if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_DecryptUpdate(ctx, data, &plen, data, data_len) == 1 &&
+ plen == (int) data_len &&
+ EVP_DecryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+ res = 0;
+ EVP_CIPHER_CTX_free(ctx);
+
+ return res;
+
+}
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
- len = sizeof(buf);
- if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
return -1;
- EVP_CIPHER_CTX_cleanup(&ctx);
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
return 0;
}
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ BIGNUM *pub, *p;
+ int res = -1;
+
+ pub = BN_bin2bn(pubkey, pubkey_len, NULL);
+ p = BN_bin2bn(prime, prime_len, NULL);
+ if (!pub || !p || BN_is_zero(pub) || BN_is_one(pub) ||
+ BN_cmp(pub, p) >= 0)
+ goto fail;
+
+ if (order) {
+ BN_CTX *ctx;
+ BIGNUM *q, *tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ q = BN_bin2bn(order, order_len, NULL);
+ ctx = BN_CTX_new();
+ tmp = BN_new();
+ failed = !q || !ctx || !tmp ||
+ !BN_mod_exp(tmp, pub, q, p, ctx) ||
+ !BN_is_one(tmp);
+ BN_clear(q);
+ BN_clear(tmp);
+ BN_CTX_free(ctx);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ BN_clear(pub);
+ BN_clear(p);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
@@ -408,7 +608,8 @@ int crypto_mod_exp(const u8 *base, size_t base_len,
bn_result == NULL)
goto error;
- if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
+ if (BN_mod_exp_mont_consttime(bn_result, bn_base, bn_exp, bn_modulus,
+ ctx, NULL) != 1)
goto error;
*result_len = BN_bn2bin(bn_result, result);
@@ -425,8 +626,8 @@ error:
struct crypto_cipher {
- EVP_CIPHER_CTX enc;
- EVP_CIPHER_CTX dec;
+ EVP_CIPHER_CTX *enc;
+ EVP_CIPHER_CTX *dec;
};
@@ -487,23 +688,25 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
return NULL;
}
- EVP_CIPHER_CTX_init(&ctx->enc);
- EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
- if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
- !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
- !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
- EVP_CIPHER_CTX_cleanup(&ctx->enc);
+ if (!(ctx->enc = EVP_CIPHER_CTX_new()) ||
+ !EVP_CIPHER_CTX_set_padding(ctx->enc, 0) ||
+ !EVP_EncryptInit_ex(ctx->enc, cipher, NULL, NULL, NULL) ||
+ !EVP_CIPHER_CTX_set_key_length(ctx->enc, key_len) ||
+ !EVP_EncryptInit_ex(ctx->enc, NULL, NULL, key, iv)) {
+ if (ctx->enc)
+ EVP_CIPHER_CTX_free(ctx->enc);
os_free(ctx);
return NULL;
}
- EVP_CIPHER_CTX_init(&ctx->dec);
- EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
- if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
- !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
- !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
- EVP_CIPHER_CTX_cleanup(&ctx->enc);
- EVP_CIPHER_CTX_cleanup(&ctx->dec);
+ if (!(ctx->dec = EVP_CIPHER_CTX_new()) ||
+ !EVP_CIPHER_CTX_set_padding(ctx->dec, 0) ||
+ !EVP_DecryptInit_ex(ctx->dec, cipher, NULL, NULL, NULL) ||
+ !EVP_CIPHER_CTX_set_key_length(ctx->dec, key_len) ||
+ !EVP_DecryptInit_ex(ctx->dec, NULL, NULL, key, iv)) {
+ EVP_CIPHER_CTX_free(ctx->enc);
+ if (ctx->dec)
+ EVP_CIPHER_CTX_free(ctx->dec);
os_free(ctx);
return NULL;
}
@@ -516,7 +719,7 @@ int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
int outl;
- if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
+ if (!EVP_EncryptUpdate(ctx->enc, crypt, &outl, plain, len))
return -1;
return 0;
}
@@ -527,7 +730,7 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
{
int outl;
outl = len;
- if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
+ if (!EVP_DecryptUpdate(ctx->dec, plain, &outl, crypt, len))
return -1;
return 0;
}
@@ -535,19 +738,23 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
- EVP_CIPHER_CTX_cleanup(&ctx->enc);
- EVP_CIPHER_CTX_cleanup(&ctx->dec);
+ EVP_CIPHER_CTX_free(ctx->enc);
+ EVP_CIPHER_CTX_free(ctx->dec);
os_free(ctx);
}
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
*priv = NULL;
+ wpabuf_free(*publ);
*publ = NULL;
dh = DH_new();
@@ -562,6 +769,10 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
if (dh->p == NULL)
goto err;
+ dh->q = get_group5_order();
+ if (!dh->q)
+ goto err;
+
if (DH_generate_key(dh) != 1)
goto err;
@@ -586,11 +797,68 @@ err:
wpabuf_clear_free(privkey);
DH_free(dh);
return NULL;
+#else
+ DH *dh;
+ struct wpabuf *pubkey = NULL, *privkey = NULL;
+ size_t publen, privlen;
+ BIGNUM *p, *g, *q;
+ const BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+ *priv = NULL;
+ wpabuf_free(*publ);
+ *publ = NULL;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+
+ g = BN_new();
+ p = get_group5_prime();
+ q = get_group5_order();
+ if (!g || BN_set_word(g, 2) != 1 || !p || !q ||
+ DH_set0_pqg(dh, p, q, g) != 1)
+ goto err;
+ p = NULL;
+ q = NULL;
+ g = NULL;
+
+ if (DH_generate_key(dh) != 1)
+ goto err;
+
+ DH_get0_key(dh, &pub_key, &priv_key);
+ publen = BN_num_bytes(pub_key);
+ pubkey = wpabuf_alloc(publen);
+ if (!pubkey)
+ goto err;
+ privlen = BN_num_bytes(priv_key);
+ privkey = wpabuf_alloc(privlen);
+ if (!privkey)
+ goto err;
+
+ BN_bn2bin(pub_key, wpabuf_put(pubkey, publen));
+ BN_bn2bin(priv_key, wpabuf_put(privkey, privlen));
+
+ *priv = privkey;
+ *publ = pubkey;
+ return dh;
+
+err:
+ BN_free(p);
+ BN_free(q);
+ BN_free(g);
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
+ DH_free(dh);
+ return NULL;
+#endif
}
void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
DH *dh;
dh = DH_new();
@@ -621,6 +889,42 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
err:
DH_free(dh);
return NULL;
+#else
+ DH *dh;
+ BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+
+ g = BN_new();
+ p = get_group5_prime();
+ if (!g || BN_set_word(g, 2) != 1 || !p ||
+ DH_set0_pqg(dh, p, NULL, g) != 1)
+ goto err;
+ p = NULL;
+ g = NULL;
+
+ priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+ pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+ if (!priv_key || !pub_key || DH_set0_key(dh, pub_key, priv_key) != 1)
+ goto err;
+ pub_key = NULL;
+ priv_key = NULL;
+
+ if (DH_generate_key(dh) != 1)
+ goto err;
+
+ return dh;
+
+err:
+ BN_free(p);
+ BN_free(g);
+ BN_free(pub_key);
+ BN_clear_free(priv_key);
+ DH_free(dh);
+ return NULL;
+#endif
}
@@ -672,7 +976,7 @@ void dh5_free(void *ctx)
struct crypto_hash {
- HMAC_CTX ctx;
+ HMAC_CTX *ctx;
};
@@ -707,16 +1011,17 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
- HMAC_CTX_init(&ctx->ctx);
+ ctx->ctx = HMAC_CTX_new();
+ if (!ctx->ctx) {
+ os_free(ctx);
+ return NULL;
+ }
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
-#else /* openssl < 0.9.9 */
- if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
+ if (HMAC_Init_ex(ctx->ctx, key, key_len, md, NULL) != 1) {
+ HMAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
return NULL;
}
-#endif /* openssl < 0.9.9 */
return ctx;
}
@@ -726,7 +1031,7 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL)
return;
- HMAC_Update(&ctx->ctx, data, len);
+ HMAC_Update(ctx->ctx, data, len);
}
@@ -739,20 +1044,19 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
return -2;
if (mac == NULL || len == NULL) {
+ HMAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
return 0;
}
mdlen = *len;
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Final(&ctx->ctx, mac, &mdlen);
- res = 1;
-#else /* openssl < 0.9.9 */
- res = HMAC_Final(&ctx->ctx, mac, &mdlen);
-#endif /* openssl < 0.9.9 */
- HMAC_CTX_cleanup(&ctx->ctx);
+ res = HMAC_Final(ctx->ctx, mac, &mdlen);
+ HMAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
+ if (TEST_FAIL())
+ return -1;
+
if (res == 1) {
*len = mdlen;
return 0;
@@ -767,28 +1071,26 @@ static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
const u8 *addr[], const size_t *len, u8 *mac,
unsigned int mdlen)
{
- HMAC_CTX ctx;
+ HMAC_CTX *ctx;
size_t i;
int res;
- HMAC_CTX_init(&ctx);
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Init_ex(&ctx, key, key_len, type, NULL);
-#else /* openssl < 0.9.9 */
- if (HMAC_Init_ex(&ctx, key, key_len, type, NULL) != 1)
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = HMAC_CTX_new();
+ if (!ctx)
return -1;
-#endif /* openssl < 0.9.9 */
+ res = HMAC_Init_ex(ctx, key, key_len, type, NULL);
+ if (res != 1)
+ goto done;
for (i = 0; i < num_elem; i++)
- HMAC_Update(&ctx, addr[i], len[i]);
+ HMAC_Update(ctx, addr[i], len[i]);
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Final(&ctx, mac, &mdlen);
- res = 1;
-#else /* openssl < 0.9.9 */
- res = HMAC_Final(&ctx, mac, &mdlen);
-#endif /* openssl < 0.9.9 */
- HMAC_CTX_cleanup(&ctx);
+ res = HMAC_Final(ctx, mac, &mdlen);
+done:
+ HMAC_CTX_free(ctx);
return res == 1 ? 0 : -1;
}
@@ -863,7 +1165,7 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_hmac_vector(EVP_sha384(), key, key_len, num_elem, addr,
- len, mac, 32);
+ len, mac, 48);
}
@@ -876,6 +1178,25 @@ int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector(EVP_sha512(), key, key_len, num_elem, addr,
+ len, mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
int crypto_get_random(void *buf, size_t len)
{
if (RAND_bytes(buf, len) != 1)
@@ -892,6 +1213,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
int ret = -1;
size_t outlen, i;
+ if (TEST_FAIL())
+ return -1;
+
ctx = CMAC_CTX_new();
if (ctx == NULL)
return -1;
@@ -941,13 +1265,20 @@ int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
struct crypto_bignum * crypto_bignum_init(void)
{
+ if (TEST_FAIL())
+ return NULL;
return (struct crypto_bignum *) BN_new();
}
struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
{
- BIGNUM *bn = BN_bin2bn(buf, len, NULL);
+ BIGNUM *bn;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ bn = BN_bin2bn(buf, len, NULL);
return (struct crypto_bignum *) bn;
}
@@ -966,6 +1297,9 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
{
int num_bytes, offset;
+ if (TEST_FAIL())
+ return -1;
+
if (padlen > buflen)
return -1;
@@ -984,6 +1318,14 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
}
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+ if (TEST_FAIL())
+ return -1;
+ return BN_rand_range((BIGNUM *) r, (const BIGNUM *) m) == 1 ? 0 : -1;
+}
+
+
int crypto_bignum_add(const struct crypto_bignum *a,
const struct crypto_bignum *b,
struct crypto_bignum *c)
@@ -1019,11 +1361,15 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a,
int res;
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
- res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
- (const BIGNUM *) c, bnctx);
+ res = BN_mod_exp_mont_consttime((BIGNUM *) d, (const BIGNUM *) a,
+ (const BIGNUM *) b, (const BIGNUM *) c,
+ bnctx, NULL);
BN_CTX_free(bnctx);
return res ? 0 : -1;
@@ -1037,9 +1383,16 @@ int crypto_bignum_inverse(const struct crypto_bignum *a,
BIGNUM *res;
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
+#ifdef OPENSSL_IS_BORINGSSL
+ /* TODO: use BN_mod_inverse_blinded() ? */
+#else /* OPENSSL_IS_BORINGSSL */
+ BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
+#endif /* OPENSSL_IS_BORINGSSL */
res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a,
(const BIGNUM *) b, bnctx);
BN_CTX_free(bnctx);
@@ -1052,6 +1405,8 @@ int crypto_bignum_sub(const struct crypto_bignum *a,
const struct crypto_bignum *b,
struct crypto_bignum *c)
{
+ if (TEST_FAIL())
+ return -1;
return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
0 : -1;
}
@@ -1065,9 +1420,15 @@ int crypto_bignum_div(const struct crypto_bignum *a,
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
+#ifndef OPENSSL_IS_BORINGSSL
+ BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
+#endif /* OPENSSL_IS_BORINGSSL */
res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a,
(const BIGNUM *) b, bnctx);
BN_CTX_free(bnctx);
@@ -1085,6 +1446,9 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
@@ -1096,6 +1460,15 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
}
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r)
+{
+ /* Note: BN_rshift() does not modify the first argument even though it
+ * has not been marked const. */
+ return BN_rshift((BIGNUM *) a, (BIGNUM *) r, n) == 1 ? 0 : -1;
+}
+
+
int crypto_bignum_cmp(const struct crypto_bignum *a,
const struct crypto_bignum *b)
{
@@ -1121,12 +1494,22 @@ int crypto_bignum_is_one(const struct crypto_bignum *a)
}
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+ return BN_is_odd((const BIGNUM *) a);
+}
+
+
int crypto_bignum_legendre(const struct crypto_bignum *a,
const struct crypto_bignum *p)
{
BN_CTX *bnctx;
BIGNUM *exp = NULL, *tmp = NULL;
int res = -2;
+ unsigned int mask;
+
+ if (TEST_FAIL())
+ return -2;
bnctx = BN_CTX_new();
if (bnctx == NULL)
@@ -1138,16 +1521,17 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
/* exp = (p-1) / 2 */
!BN_sub(exp, (const BIGNUM *) p, BN_value_one()) ||
!BN_rshift1(exp, exp) ||
- !BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p,
- bnctx))
+ !BN_mod_exp_mont_consttime(tmp, (const BIGNUM *) a, exp,
+ (const BIGNUM *) p, bnctx, NULL))
goto fail;
- if (BN_is_word(tmp, 1))
- res = 1;
- else if (BN_is_zero(tmp))
- res = 0;
- else
- res = -1;
+ /* Return 1 if tmp == 1, 0 if tmp == 0, or -1 otherwise. Need to use
+ * constant time selection to avoid branches here. */
+ res = -1;
+ mask = const_time_eq(BN_is_word(tmp, 1), 1);
+ res = const_time_select_int(mask, 1, res);
+ mask = const_time_eq(BN_is_zero(tmp), 1);
+ res = const_time_select_int(mask, 0, res);
fail:
BN_clear_free(tmp);
@@ -1161,6 +1545,7 @@ fail:
struct crypto_ec {
EC_GROUP *group;
+ int nid;
BN_CTX *bnctx;
BIGNUM *prime;
BIGNUM *order;
@@ -1218,6 +1603,7 @@ struct crypto_ec * crypto_ec_init(int group)
if (e == NULL)
return NULL;
+ e->nid = nid;
e->bnctx = BN_CTX_new();
e->group = EC_GROUP_new_by_curve_name(nid);
e->prime = BN_new();
@@ -1252,6 +1638,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
{
+ if (TEST_FAIL())
+ return NULL;
if (e == NULL)
return NULL;
return (struct crypto_ec_point *) EC_POINT_new(e->group);
@@ -1270,6 +1658,12 @@ size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
}
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+ return BN_num_bytes(e->order);
+}
+
+
const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
{
return (const struct crypto_bignum *) e->prime;
@@ -1291,6 +1685,16 @@ void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
}
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x)
+{
+ return EC_POINT_get_affine_coordinates_GFp(e->group,
+ (const EC_POINT *) p,
+ (BIGNUM *) x, NULL,
+ e->bnctx) == 1 ? 0 : -1;
+}
+
+
int crypto_ec_point_to_bin(struct crypto_ec *e,
const struct crypto_ec_point *point, u8 *x, u8 *y)
{
@@ -1298,6 +1702,9 @@ int crypto_ec_point_to_bin(struct crypto_ec *e,
int ret = -1;
int len = BN_num_bytes(e->prime);
+ if (TEST_FAIL())
+ return -1;
+
x_bn = BN_new();
y_bn = BN_new();
@@ -1328,6 +1735,9 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
EC_POINT *elem;
int len = BN_num_bytes(e->prime);
+ if (TEST_FAIL())
+ return NULL;
+
x = BN_bin2bn(val, len, NULL);
y = BN_bin2bn(val + len, len, NULL);
elem = EC_POINT_new(e->group);
@@ -1355,6 +1765,8 @@ int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
const struct crypto_ec_point *b,
struct crypto_ec_point *c)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a,
(const EC_POINT *) b, e->bnctx) ? 0 : -1;
}
@@ -1364,6 +1776,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
const struct crypto_bignum *b,
struct crypto_ec_point *res)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_mul(e->group, (EC_POINT *) res, NULL,
(const EC_POINT *) p, (const BIGNUM *) b, e->bnctx)
? 0 : -1;
@@ -1372,6 +1786,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1;
}
@@ -1380,6 +1796,8 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
struct crypto_ec_point *p,
const struct crypto_bignum *x, int y_bit)
{
+ if (TEST_FAIL())
+ return -1;
if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p,
(const BIGNUM *) x, y_bit,
e->bnctx) ||
@@ -1395,6 +1813,9 @@ crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
{
BIGNUM *tmp, *tmp2, *y_sqr = NULL;
+ if (TEST_FAIL())
+ return NULL;
+
tmp = BN_new();
tmp2 = BN_new();
@@ -1439,4 +1860,228 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
(const EC_POINT *) b, e->bnctx);
}
+
+struct crypto_ecdh {
+ struct crypto_ec *ec;
+ EVP_PKEY *pkey;
+};
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+ struct crypto_ecdh *ecdh;
+ EVP_PKEY *params = NULL;
+ EC_KEY *ec_params;
+ EVP_PKEY_CTX *kctx = NULL;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ ec_params = EC_KEY_new_by_curve_name(ecdh->ec->nid);
+ if (!ec_params) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to generate EC_KEY parameters");
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
+ params = EVP_PKEY_new();
+ if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to generate EVP_PKEY parameters");
+ goto fail;
+ }
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (!kctx)
+ goto fail;
+
+ if (EVP_PKEY_keygen_init(kctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EVP_PKEY_keygen_init failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_keygen(kctx, &ecdh->pkey) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_PKEY_keygen failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+done:
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ ecdh = NULL;
+ goto done;
+}
+
+
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
+{
+ struct wpabuf *buf = NULL;
+ EC_KEY *eckey;
+ const EC_POINT *pubkey;
+ BIGNUM *x, *y = NULL;
+ int len = BN_num_bytes(ecdh->ec->prime);
+ int res;
+
+ eckey = EVP_PKEY_get1_EC_KEY(ecdh->pkey);
+ if (!eckey)
+ return NULL;
+
+ pubkey = EC_KEY_get0_public_key(eckey);
+ if (!pubkey)
+ return NULL;
+
+ x = BN_new();
+ if (inc_y) {
+ y = BN_new();
+ if (!y)
+ goto fail;
+ }
+ buf = wpabuf_alloc(inc_y ? 2 * len : len);
+ if (!x || !buf)
+ goto fail;
+
+ if (EC_POINT_get_affine_coordinates_GFp(ecdh->ec->group, pubkey,
+ x, y, ecdh->ec->bnctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_POINT_get_affine_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ res = crypto_bignum_to_bin((struct crypto_bignum *) x,
+ wpabuf_put(buf, len), len, len);
+ if (res < 0)
+ goto fail;
+
+ if (inc_y) {
+ res = crypto_bignum_to_bin((struct crypto_bignum *) y,
+ wpabuf_put(buf, len), len, len);
+ if (res < 0)
+ goto fail;
+ }
+
+done:
+ BN_clear_free(x);
+ BN_clear_free(y);
+ EC_KEY_free(eckey);
+
+ return buf;
+fail:
+ wpabuf_free(buf);
+ buf = NULL;
+ goto done;
+}
+
+
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+ const u8 *key, size_t len)
+{
+ BIGNUM *x, *y = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *peerkey = NULL;
+ struct wpabuf *secret = NULL;
+ size_t secret_len;
+ EC_POINT *pub;
+ EC_KEY *eckey = NULL;
+
+ x = BN_bin2bn(key, inc_y ? len / 2 : len, NULL);
+ pub = EC_POINT_new(ecdh->ec->group);
+ if (!x || !pub)
+ goto fail;
+
+ if (inc_y) {
+ y = BN_bin2bn(key + len / 2, len / 2, NULL);
+ if (!y)
+ goto fail;
+ if (!EC_POINT_set_affine_coordinates_GFp(ecdh->ec->group, pub,
+ x, y,
+ ecdh->ec->bnctx)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ } else if (!EC_POINT_set_compressed_coordinates_GFp(ecdh->ec->group,
+ pub, x, 0,
+ ecdh->ec->bnctx)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_POINT_set_compressed_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (!EC_POINT_is_on_curve(ecdh->ec->group, pub, ecdh->ec->bnctx)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: ECDH peer public key is not on curve");
+ goto fail;
+ }
+
+ eckey = EC_KEY_new_by_curve_name(ecdh->ec->nid);
+ if (!eckey || EC_KEY_set_public_key(eckey, pub) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_KEY_set_public_key failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ peerkey = EVP_PKEY_new();
+ if (!peerkey || EVP_PKEY_set1_EC_KEY(peerkey, eckey) != 1)
+ goto fail;
+
+ ctx = EVP_PKEY_CTX_new(ecdh->pkey, NULL);
+ if (!ctx || EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, peerkey) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &secret_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EVP_PKEY_derive(1) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ secret = wpabuf_alloc(secret_len);
+ if (!secret)
+ goto fail;
+ if (EVP_PKEY_derive(ctx, wpabuf_put(secret, secret_len),
+ &secret_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EVP_PKEY_derive(2) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+done:
+ BN_free(x);
+ BN_free(y);
+ EC_KEY_free(eckey);
+ EC_POINT_free(pub);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return secret;
+fail:
+ wpabuf_free(secret);
+ secret = NULL;
+ goto done;
+}
+
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
+{
+ if (ecdh) {
+ crypto_ec_deinit(ecdh->ec);
+ EVP_PKEY_free(ecdh->pkey);
+ os_free(ecdh);
+ }
+}
+
#endif /* CONFIG_ECC */
diff --git a/contrib/wpa/src/crypto/crypto_wolfssl.c b/contrib/wpa/src/crypto/crypto_wolfssl.c
new file mode 100644
index 0000000..976a008
--- /dev/null
+++ b/contrib/wpa/src/crypto/crypto_wolfssl.c
@@ -0,0 +1,1786 @@
+/*
+ * Wrapper functions for libwolfssl
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+/* wolfSSL headers */
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/md4.h>
+#include <wolfssl/wolfcrypt/md5.h>
+#include <wolfssl/wolfcrypt/sha.h>
+#include <wolfssl/wolfcrypt/sha256.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#include <wolfssl/wolfcrypt/hmac.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/arc4.h>
+#include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/dh.h>
+#include <wolfssl/wolfcrypt/cmac.h>
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/openssl/bn.h>
+
+
+#ifndef CONFIG_FIPS
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ Md4 md4;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitMd4(&md4);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Md4Update(&md4, addr[i], len[i]);
+
+ wc_Md4Final(&md4, mac);
+
+ return 0;
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ wc_Md5 md5;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitMd5(&md5);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Md5Update(&md5, addr[i], len[i]);
+
+ wc_Md5Final(&md5, mac);
+
+ return 0;
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ wc_Sha sha;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha(&sha);
+
+ for (i = 0; i < num_elem; i++)
+ wc_ShaUpdate(&sha, addr[i], len[i]);
+
+ wc_ShaFinal(&sha, mac);
+
+ return 0;
+}
+
+
+#ifndef NO_SHA256_WRAPPER
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha256 sha256;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha256(&sha256);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha256Update(&sha256, addr[i], len[i]);
+
+ wc_Sha256Final(&sha256, mac);
+
+ return 0;
+}
+#endif /* NO_SHA256_WRAPPER */
+
+
+#ifdef CONFIG_SHA384
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha384 sha384;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha384(&sha384);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha384Update(&sha384, addr[i], len[i]);
+
+ wc_Sha384Final(&sha384, mac);
+
+ return 0;
+}
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha512 sha512;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha512(&sha512);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha512Update(&sha512, addr[i], len[i]);
+
+ wc_Sha512Final(&sha512, mac);
+
+ return 0;
+}
+#endif /* CONFIG_SHA512 */
+
+
+static int wolfssl_hmac_vector(int type, const u8 *key,
+ size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac,
+ unsigned int mdlen)
+{
+ Hmac hmac;
+ size_t i;
+
+ (void) mdlen;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
+ return -1;
+ for (i = 0; i < num_elem; i++)
+ if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0)
+ return -1;
+ if (wc_HmacFinal(&hmac, mac) != 0)
+ return -1;
+ return 0;
+}
+
+
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_MD5, key, key_len, num_elem, addr, len,
+ mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA, key, key_len, num_elem, addr, len,
+ mac, 20);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA256, key, key_len, num_elem, addr, len,
+ mac, 32);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA384, key, key_len, num_elem, addr, len,
+ mac, 48);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA512, key, key_len, num_elem, addr, len,
+ mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+ if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
+ ssid_len, iterations, buflen, WC_SHA) != 0)
+ return -1;
+ return 0;
+}
+
+
+#ifdef CONFIG_DES
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ Des des;
+ u8 pkey[8], next, tmp;
+ int i;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ wc_Des_SetKey(&des, pkey, NULL, DES_ENCRYPTION);
+ wc_Des_EcbEncrypt(&des, cypher, clear, DES_BLOCK_SIZE);
+
+ return 0;
+}
+#endif /* CONFIG_DES */
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ Aes *aes;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ aes = os_malloc(sizeof(Aes));
+ if (!aes)
+ return NULL;
+
+ if (wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION) < 0) {
+ os_free(aes);
+ return NULL;
+ }
+
+ return aes;
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ wc_AesEncryptDirect(ctx, crypt, plain);
+ return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ os_free(ctx);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ Aes *aes;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ aes = os_malloc(sizeof(Aes));
+ if (!aes)
+ return NULL;
+
+ if (wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION) < 0) {
+ os_free(aes);
+ return NULL;
+ }
+
+ return aes;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ wc_AesDecryptDirect(ctx, plain, crypt);
+ return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ os_free(ctx);
+}
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ Aes aes;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesSetKey(&aes, key, 16, iv, AES_ENCRYPTION);
+ if (ret != 0)
+ return -1;
+
+ ret = wc_AesCbcEncrypt(&aes, data, data, data_len);
+ if (ret != 0)
+ return -1;
+ return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ Aes aes;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesSetKey(&aes, key, 16, iv, AES_DECRYPTION);
+ if (ret != 0)
+ return -1;
+
+ ret = wc_AesCbcDecrypt(&aes, data, data, data_len);
+ if (ret != 0)
+ return -1;
+ return 0;
+}
+
+
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
+ NULL);
+ return ret != (n + 1) * 8 ? -1 : 0;
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
+ NULL);
+ return ret != n * 8 ? -1 : 0;
+}
+
+
+#ifndef CONFIG_NO_RC4
+int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data,
+ size_t data_len)
+{
+#ifndef NO_RC4
+ Arc4 arc4;
+ unsigned char skip_buf[16];
+
+ wc_Arc4SetKey(&arc4, key, keylen);
+
+ while (skip >= sizeof(skip_buf)) {
+ size_t len = skip;
+
+ if (len > sizeof(skip_buf))
+ len = sizeof(skip_buf);
+ wc_Arc4Process(&arc4, skip_buf, skip_buf, len);
+ skip -= len;
+ }
+
+ wc_Arc4Process(&arc4, data, data, data_len);
+
+ return 0;
+#else /* NO_RC4 */
+ return -1;
+#endif /* NO_RC4 */
+}
+#endif /* CONFIG_NO_RC4 */
+
+
+#if defined(EAP_IKEV2) || defined(EAP_IKEV2_DYNAMIC) \
+ || defined(EAP_SERVER_IKEV2)
+union wolfssl_cipher {
+ Aes aes;
+ Des3 des3;
+ Arc4 arc4;
+};
+
+struct crypto_cipher {
+ enum crypto_cipher_alg alg;
+ union wolfssl_cipher enc;
+ union wolfssl_cipher dec;
+};
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ switch (alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4SetKey(&ctx->enc.arc4, key, key_len);
+ wc_Arc4SetKey(&ctx->dec.arc4, key, key_len);
+ break;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ switch (key_len) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+ if (wc_AesSetKey(&ctx->enc.aes, key, key_len, iv,
+ AES_ENCRYPTION) ||
+ wc_AesSetKey(&ctx->dec.aes, key, key_len, iv,
+ AES_DECRYPTION)) {
+ os_free(ctx);
+ return NULL;
+ }
+ break;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (key_len != DES3_KEYLEN ||
+ wc_Des3_SetKey(&ctx->enc.des3, key, iv, DES_ENCRYPTION) ||
+ wc_Des3_SetKey(&ctx->dec.des3, key, iv, DES_DECRYPTION)) {
+ os_free(ctx);
+ return NULL;
+ }
+ break;
+#endif /* NO_DES3 */
+ case CRYPTO_CIPHER_ALG_RC2:
+ case CRYPTO_CIPHER_ALG_DES:
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->alg = alg;
+
+ return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4Process(&ctx->enc.arc4, crypt, plain, len);
+ return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ if (wc_AesCbcEncrypt(&ctx->enc.aes, crypt, plain, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (wc_Des3_CbcEncrypt(&ctx->enc.des3, crypt, plain, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_DES3 */
+ default:
+ return -1;
+ }
+ return -1;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4Process(&ctx->dec.arc4, plain, crypt, len);
+ return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ if (wc_AesCbcDecrypt(&ctx->dec.aes, plain, crypt, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (wc_Des3_CbcDecrypt(&ctx->dec.des3, plain, crypt, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_DES3 */
+ default:
+ return -1;
+ }
+ return -1;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ os_free(ctx);
+}
+
+#endif
+
+
+#ifdef CONFIG_WPS_NFC
+
+static const unsigned char RFC3526_PRIME_1536[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
+ 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
+ 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
+ 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static const unsigned char RFC3526_GENERATOR_1536[] = {
+ 0x02
+};
+
+#define RFC3526_LEN sizeof(RFC3526_PRIME_1536)
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+ WC_RNG rng;
+ DhKey *ret = NULL;
+ DhKey *dh = NULL;
+ struct wpabuf *privkey = NULL;
+ struct wpabuf *pubkey = NULL;
+ word32 priv_sz, pub_sz;
+
+ *priv = NULL;
+ wpabuf_free(*publ);
+ *publ = NULL;
+
+ dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!dh)
+ return NULL;
+ wc_InitDhKey(dh);
+
+ if (wc_InitRng(&rng) != 0) {
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ return NULL;
+ }
+
+ privkey = wpabuf_alloc(RFC3526_LEN);
+ pubkey = wpabuf_alloc(RFC3526_LEN);
+ if (!privkey || !pubkey)
+ goto done;
+
+ if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+ RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+ != 0)
+ goto done;
+
+ if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz,
+ wpabuf_mhead(pubkey), &pub_sz) != 0)
+ goto done;
+
+ wpabuf_put(privkey, priv_sz);
+ wpabuf_put(pubkey, pub_sz);
+
+ ret = dh;
+ *priv = privkey;
+ *publ = pubkey;
+ dh = NULL;
+ privkey = NULL;
+ pubkey = NULL;
+done:
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
+ if (dh) {
+ wc_FreeDhKey(dh);
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+ DhKey *ret = NULL;
+ DhKey *dh;
+ byte *secret;
+ word32 secret_sz;
+
+ dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!dh)
+ return NULL;
+ wc_InitDhKey(dh);
+
+ secret = XMALLOC(RFC3526_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!secret)
+ goto done;
+
+ if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+ RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+ != 0)
+ goto done;
+
+ if (wc_DhAgree(dh, secret, &secret_sz, wpabuf_head(priv),
+ wpabuf_len(priv), RFC3526_GENERATOR_1536,
+ sizeof(RFC3526_GENERATOR_1536)) != 0)
+ goto done;
+
+ if (secret_sz != wpabuf_len(publ) ||
+ os_memcmp(secret, wpabuf_head(publ), secret_sz) != 0)
+ goto done;
+
+ ret = dh;
+ dh = NULL;
+done:
+ if (dh) {
+ wc_FreeDhKey(dh);
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ return ret;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+ const struct wpabuf *own_private)
+{
+ struct wpabuf *ret = NULL;
+ struct wpabuf *secret;
+ word32 secret_sz;
+
+ secret = wpabuf_alloc(RFC3526_LEN);
+ if (!secret)
+ goto done;
+
+ if (wc_DhAgree(ctx, wpabuf_mhead(secret), &secret_sz,
+ wpabuf_head(own_private), wpabuf_len(own_private),
+ wpabuf_head(peer_public), wpabuf_len(peer_public)) != 0)
+ goto done;
+
+ wpabuf_put(secret, secret_sz);
+
+ ret = secret;
+ secret = NULL;
+done:
+ wpabuf_clear_free(secret);
+ return ret;
+}
+
+
+void dh5_free(void *ctx)
+{
+ if (!ctx)
+ return;
+
+ wc_FreeDhKey(ctx);
+ XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ int ret = -1;
+ WC_RNG rng;
+ DhKey *dh = NULL;
+ word32 priv_sz, pub_sz;
+
+ if (TEST_FAIL())
+ return -1;
+
+ dh = os_malloc(sizeof(DhKey));
+ if (!dh)
+ return -1;
+ wc_InitDhKey(dh);
+
+ if (wc_InitRng(&rng) != 0) {
+ os_free(dh);
+ return -1;
+ }
+
+ if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+ goto done;
+
+ if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz)
+ != 0)
+ goto done;
+
+ if (priv_sz < prime_len) {
+ size_t pad_sz = prime_len - priv_sz;
+
+ os_memmove(privkey + pad_sz, privkey, priv_sz);
+ os_memset(privkey, 0, pad_sz);
+ }
+
+ if (pub_sz < prime_len) {
+ size_t pad_sz = prime_len - pub_sz;
+
+ os_memmove(pubkey + pad_sz, pubkey, pub_sz);
+ os_memset(pubkey, 0, pad_sz);
+ }
+ ret = 0;
+done:
+ wc_FreeDhKey(dh);
+ os_free(dh);
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ int ret = -1;
+ DhKey *dh;
+ word32 secret_sz;
+
+ dh = os_malloc(sizeof(DhKey));
+ if (!dh)
+ return -1;
+ wc_InitDhKey(dh);
+
+ if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+ goto done;
+
+ if (wc_DhAgree(dh, secret, &secret_sz, privkey, privkey_len, pubkey,
+ pubkey_len) != 0)
+ goto done;
+
+ *len = secret_sz;
+ ret = 0;
+done:
+ wc_FreeDhKey(dh);
+ os_free(dh);
+ return ret;
+}
+
+
+#ifdef CONFIG_FIPS
+int crypto_get_random(void *buf, size_t len)
+{
+ int ret = 0;
+ WC_RNG rng;
+
+ if (wc_InitRng(&rng) != 0)
+ return -1;
+ if (wc_RNG_GenerateBlock(&rng, buf, len) != 0)
+ ret = -1;
+ wc_FreeRng(&rng);
+ return ret;
+}
+#endif /* CONFIG_FIPS */
+
+
+#if defined(EAP_PWD) || defined(EAP_SERVER_PWD)
+struct crypto_hash {
+ Hmac hmac;
+ int size;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ret = NULL;
+ struct crypto_hash *hash;
+ int type;
+
+ hash = os_zalloc(sizeof(*hash));
+ if (!hash)
+ goto done;
+
+ switch (alg) {
+#ifndef NO_MD5
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ hash->size = 16;
+ type = WC_MD5;
+ break;
+#endif /* NO_MD5 */
+#ifndef NO_SHA
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ type = WC_SHA;
+ hash->size = 20;
+ break;
+#endif /* NO_SHA */
+#ifdef CONFIG_SHA256
+#ifndef NO_SHA256
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ type = WC_SHA256;
+ hash->size = 32;
+ break;
+#endif /* NO_SHA256 */
+#endif /* CONFIG_SHA256 */
+ default:
+ goto done;
+ }
+
+ if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+ goto done;
+
+ ret = hash;
+ hash = NULL;
+done:
+ os_free(hash);
+ return ret;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ if (!ctx)
+ return;
+ wc_HmacUpdate(&ctx->hmac, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ int ret = 0;
+
+ if (!ctx)
+ return -2;
+
+ if (!mac || !len)
+ goto done;
+
+ if (wc_HmacFinal(&ctx->hmac, mac) != 0) {
+ ret = -1;
+ goto done;
+ }
+
+ *len = ctx->size;
+ ret = 0;
+done:
+ bin_clear_free(ctx, sizeof(*ctx));
+ if (TEST_FAIL())
+ return -1;
+ return ret;
+}
+
+#endif
+
+
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ Cmac cmac;
+ size_t i;
+ word32 sz;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (wc_InitCmac(&cmac, key, key_len, WC_CMAC_AES, NULL) != 0)
+ return -1;
+
+ for (i = 0; i < num_elem; i++)
+ if (wc_CmacUpdate(&cmac, addr[i], len[i]) != 0)
+ return -1;
+
+ sz = AES_BLOCK_SIZE;
+ if (wc_CmacFinal(&cmac, mac, &sz) != 0 || sz != AES_BLOCK_SIZE)
+ return -1;
+
+ return 0;
+}
+
+
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
+
+
+struct crypto_bignum * crypto_bignum_init(void)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = os_malloc(sizeof(*a));
+ if (!a || mp_init(a) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = (mp_int *) crypto_bignum_init();
+ if (!a)
+ return NULL;
+
+ if (mp_read_unsigned_bin(a, buf, len) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+ if (!n)
+ return;
+
+ if (clear)
+ mp_forcezero((mp_int *) n);
+ mp_clear((mp_int *) n);
+ os_free((mp_int *) n);
+}
+
+
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen)
+{
+ int num_bytes, offset;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (padlen > buflen)
+ return -1;
+
+ num_bytes = (mp_count_bits((mp_int *) a) + 7) / 8;
+ if ((size_t) num_bytes > buflen)
+ return -1;
+ if (padlen > (size_t) num_bytes)
+ offset = padlen - num_bytes;
+ else
+ offset = 0;
+
+ os_memset(buf, 0, offset);
+ mp_to_unsigned_bin((mp_int *) a, buf + offset);
+
+ return num_bytes + offset;
+}
+
+
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+ int ret = 0;
+ WC_RNG rng;
+
+ if (TEST_FAIL())
+ return -1;
+ if (wc_InitRng(&rng) != 0)
+ return -1;
+ if (mp_rand_prime((mp_int *) r,
+ (mp_count_bits((mp_int *) m) + 7) / 8 * 2,
+ &rng, NULL) != 0)
+ ret = -1;
+ if (ret == 0 &&
+ mp_mod((mp_int *) r, (mp_int *) m, (mp_int *) r) != 0)
+ ret = -1;
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+int crypto_bignum_add(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *r)
+{
+ return mp_add((mp_int *) a, (mp_int *) b,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mod(const struct crypto_bignum *a,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ return mp_mod((mp_int *) a, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_exptmod(const struct crypto_bignum *b,
+ const struct crypto_bignum *e,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_exptmod((mp_int *) b, (mp_int *) e, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_invmod((mp_int *) a, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_sub(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_add((mp_int *) a, (mp_int *) b,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_div(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_div((mp_int *) a, (mp_int *) b, (mp_int *) d,
+ NULL) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) m,
+ (mp_int *) d) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r)
+{
+ if (mp_copy((mp_int *) a, (mp_int *) r) != MP_OKAY)
+ return -1;
+ mp_rshb((mp_int *) r, n);
+ return 0;
+}
+
+
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+ const struct crypto_bignum *b)
+{
+ return mp_cmp((mp_int *) a, (mp_int *) b);
+}
+
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+ return mp_count_bits((mp_int *) a);
+}
+
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+ return mp_iszero((mp_int *) a);
+}
+
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+ return mp_isone((const mp_int *) a);
+}
+
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+ return mp_isodd((mp_int *) a);
+}
+
+
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+ const struct crypto_bignum *p)
+{
+ mp_int t;
+ int ret;
+ int res = -2;
+
+ if (TEST_FAIL())
+ return -2;
+
+ if (mp_init(&t) != MP_OKAY)
+ return -2;
+
+ /* t = (p-1) / 2 */
+ ret = mp_sub_d((mp_int *) p, 1, &t);
+ if (ret == MP_OKAY)
+ mp_rshb(&t, 1);
+ if (ret == MP_OKAY)
+ ret = mp_exptmod((mp_int *) a, &t, (mp_int *) p, &t);
+ if (ret == MP_OKAY) {
+ if (mp_isone(&t))
+ res = 1;
+ else if (mp_iszero(&t))
+ res = 0;
+ else
+ res = -1;
+ }
+
+ mp_clear(&t);
+ return res;
+}
+
+
+#ifdef CONFIG_ECC
+
+int ecc_map(ecc_point *, mp_int *, mp_digit);
+int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R,
+ mp_int *a, mp_int *modulus, mp_digit mp);
+
+struct crypto_ec {
+ ecc_key key;
+ mp_int a;
+ mp_int prime;
+ mp_int order;
+ mp_digit mont_b;
+ mp_int b;
+};
+
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+ int built = 0;
+ struct crypto_ec *e;
+ int curve_id;
+
+ /* Map from IANA registry for IKE D-H groups to OpenSSL NID */
+ switch (group) {
+ case 19:
+ curve_id = ECC_SECP256R1;
+ break;
+ case 20:
+ curve_id = ECC_SECP384R1;
+ break;
+ case 21:
+ curve_id = ECC_SECP521R1;
+ break;
+ case 25:
+ curve_id = ECC_SECP192R1;
+ break;
+ case 26:
+ curve_id = ECC_SECP224R1;
+ break;
+#ifdef HAVE_ECC_BRAINPOOL
+ case 27:
+ curve_id = ECC_BRAINPOOLP224R1;
+ break;
+ case 28:
+ curve_id = ECC_BRAINPOOLP256R1;
+ break;
+ case 29:
+ curve_id = ECC_BRAINPOOLP384R1;
+ break;
+ case 30:
+ curve_id = ECC_BRAINPOOLP512R1;
+ break;
+#endif /* HAVE_ECC_BRAINPOOL */
+ default:
+ return NULL;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (!e)
+ return NULL;
+
+ if (wc_ecc_init(&e->key) != 0 ||
+ wc_ecc_set_curve(&e->key, 0, curve_id) != 0 ||
+ mp_init(&e->a) != MP_OKAY ||
+ mp_init(&e->prime) != MP_OKAY ||
+ mp_init(&e->order) != MP_OKAY ||
+ mp_init(&e->b) != MP_OKAY ||
+ mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY ||
+ mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY ||
+ mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY ||
+ mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY ||
+ mp_montgomery_setup(&e->prime, &e->mont_b) != MP_OKAY)
+ goto done;
+
+ built = 1;
+done:
+ if (!built) {
+ crypto_ec_deinit(e);
+ e = NULL;
+ }
+ return e;
+}
+
+
+void crypto_ec_deinit(struct crypto_ec* e)
+{
+ if (!e)
+ return;
+
+ mp_clear(&e->b);
+ mp_clear(&e->order);
+ mp_clear(&e->prime);
+ mp_clear(&e->a);
+ wc_ecc_free(&e->key);
+ os_free(e);
+}
+
+
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
+{
+ if (TEST_FAIL())
+ return NULL;
+ if (!e)
+ return NULL;
+ return (struct crypto_ec_point *) wc_ecc_new_point();
+}
+
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+ return (mp_count_bits(&e->prime) + 7) / 8;
+}
+
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+ return mp_count_bits(&e->prime);
+}
+
+
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+ return (mp_count_bits(&e->order) + 7) / 8;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->prime;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->order;
+}
+
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+ ecc_point *point = (ecc_point *) p;
+
+ if (!p)
+ return;
+
+ if (clear) {
+ mp_forcezero(point->x);
+ mp_forcezero(point->y);
+ mp_forcezero(point->z);
+ }
+ wc_ecc_del_point(point);
+}
+
+
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x)
+{
+ return mp_copy(((ecc_point *) p)->x, (mp_int *) x) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+ const struct crypto_ec_point *point, u8 *x, u8 *y)
+{
+ ecc_point *p = (ecc_point *) point;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (!mp_isone(p->z)) {
+ if (ecc_map(p, &e->prime, e->mont_b) != MP_OKAY)
+ return -1;
+ }
+
+ if (x) {
+ if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x,
+ e->key.dp->size,
+ e->key.dp->size) <= 0)
+ return -1;
+ }
+
+ if (y) {
+ if (crypto_bignum_to_bin((struct crypto_bignum *) p->y, y,
+ e->key.dp->size,
+ e->key.dp->size) <= 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+ const u8 *val)
+{
+ ecc_point *point = NULL;
+ int loaded = 0;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ point = wc_ecc_new_point();
+ if (!point)
+ goto done;
+
+ if (mp_read_unsigned_bin(point->x, val, e->key.dp->size) != MP_OKAY)
+ goto done;
+ val += e->key.dp->size;
+ if (mp_read_unsigned_bin(point->y, val, e->key.dp->size) != MP_OKAY)
+ goto done;
+ mp_set(point->z, 1);
+
+ loaded = 1;
+done:
+ if (!loaded) {
+ wc_ecc_del_point(point);
+ point = NULL;
+ }
+ return (struct crypto_ec_point *) point;
+}
+
+
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b,
+ struct crypto_ec_point *c)
+{
+ mp_int mu;
+ ecc_point *ta = NULL, *tb = NULL;
+ ecc_point *pa = (ecc_point *) a, *pb = (ecc_point *) b;
+ mp_int *modulus = &e->prime;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = mp_init(&mu);
+ if (ret != MP_OKAY)
+ return -1;
+
+ ret = mp_montgomery_calc_normalization(&mu, modulus);
+ if (ret != MP_OKAY) {
+ mp_clear(&mu);
+ return -1;
+ }
+
+ if (!mp_isone(&mu)) {
+ ta = wc_ecc_new_point();
+ if (!ta) {
+ mp_clear(&mu);
+ return -1;
+ }
+ tb = wc_ecc_new_point();
+ if (!tb) {
+ wc_ecc_del_point(ta);
+ mp_clear(&mu);
+ return -1;
+ }
+
+ if (mp_mulmod(pa->x, &mu, modulus, ta->x) != MP_OKAY ||
+ mp_mulmod(pa->y, &mu, modulus, ta->y) != MP_OKAY ||
+ mp_mulmod(pa->z, &mu, modulus, ta->z) != MP_OKAY ||
+ mp_mulmod(pb->x, &mu, modulus, tb->x) != MP_OKAY ||
+ mp_mulmod(pb->y, &mu, modulus, tb->y) != MP_OKAY ||
+ mp_mulmod(pb->z, &mu, modulus, tb->z) != MP_OKAY) {
+ ret = -1;
+ goto end;
+ }
+ pa = ta;
+ pb = tb;
+ }
+
+ ret = ecc_projective_add_point(pa, pb, (ecc_point *) c, &e->a,
+ &e->prime, e->mont_b);
+ if (ret != 0) {
+ ret = -1;
+ goto end;
+ }
+
+ if (ecc_map((ecc_point *) c, &e->prime, e->mont_b) != MP_OKAY)
+ ret = -1;
+ else
+ ret = 0;
+end:
+ wc_ecc_del_point(tb);
+ wc_ecc_del_point(ta);
+ mp_clear(&mu);
+ return ret;
+}
+
+
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+ const struct crypto_bignum *b,
+ struct crypto_ec_point *res)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_ecc_mulmod((mp_int *) b, (ecc_point *) p, (ecc_point *) res,
+ &e->a, &e->prime, 1);
+ return ret == 0 ? 0 : -1;
+}
+
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+ ecc_point *point = (ecc_point *) p;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (mp_sub(&e->prime, point->y, point->y) != MP_OKAY)
+ return -1;
+
+ return 0;
+}
+
+
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+ struct crypto_ec_point *p,
+ const struct crypto_bignum *x, int y_bit)
+{
+ byte buf[1 + 2 * MAX_ECC_BYTES];
+ int ret;
+ int prime_len = crypto_ec_prime_len(e);
+
+ if (TEST_FAIL())
+ return -1;
+
+ buf[0] = y_bit ? ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN;
+ ret = crypto_bignum_to_bin(x, buf + 1, prime_len, prime_len);
+ if (ret <= 0)
+ return -1;
+ ret = wc_ecc_import_point_der(buf, 1 + 2 * ret, e->key.idx,
+ (ecc_point *) p);
+ if (ret != 0)
+ return -1;
+
+ return 0;
+}
+
+
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+ const struct crypto_bignum *x)
+{
+ mp_int *y2 = NULL;
+ mp_int t;
+ int calced = 0;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ if (mp_init(&t) != MP_OKAY)
+ return NULL;
+
+ y2 = (mp_int *) crypto_bignum_init();
+ if (!y2)
+ goto done;
+
+ if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+ mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
+ mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
+ mp_addmod(y2, &t, &e->prime, y2) != 0 ||
+ mp_addmod(y2, &e->b, &e->prime, y2) != 0)
+ goto done;
+
+ calced = 1;
+done:
+ if (!calced) {
+ if (y2) {
+ mp_clear(y2);
+ os_free(y2);
+ }
+ mp_clear(&t);
+ }
+
+ return (struct crypto_bignum *) y2;
+}
+
+
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return wc_ecc_point_is_at_infinity((ecc_point *) p);
+}
+
+
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return wc_ecc_is_point((ecc_point *) p, &e->a, &e->b, &e->prime) ==
+ MP_OKAY;
+}
+
+
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+ const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b)
+{
+ return wc_ecc_cmp_point((ecc_point *) a, (ecc_point *) b);
+}
+
+
+struct crypto_ecdh {
+ struct crypto_ec *ec;
+};
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+ struct crypto_ecdh *ecdh = NULL;
+ WC_RNG rng;
+ int ret;
+
+ if (wc_InitRng(&rng) != 0)
+ goto fail;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
+ ecdh->ec->key.dp->id);
+ if (ret < 0)
+ goto fail;
+
+done:
+ wc_FreeRng(&rng);
+
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ ecdh = NULL;
+ goto done;
+}
+
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
+{
+ if (ecdh) {
+ crypto_ec_deinit(ecdh->ec);
+ os_free(ecdh);
+ }
+}
+
+
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
+{
+ struct wpabuf *buf = NULL;
+ int ret;
+ int len = ecdh->ec->key.dp->size;
+
+ buf = wpabuf_alloc(inc_y ? 2 * len : len);
+ if (!buf)
+ goto fail;
+
+ ret = crypto_bignum_to_bin((struct crypto_bignum *)
+ ecdh->ec->key.pubkey.x, wpabuf_put(buf, len),
+ len, len);
+ if (ret < 0)
+ goto fail;
+ if (inc_y) {
+ ret = crypto_bignum_to_bin((struct crypto_bignum *)
+ ecdh->ec->key.pubkey.y,
+ wpabuf_put(buf, len), len, len);
+ if (ret < 0)
+ goto fail;
+ }
+
+done:
+ return buf;
+fail:
+ wpabuf_free(buf);
+ buf = NULL;
+ goto done;
+}
+
+
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+ const u8 *key, size_t len)
+{
+ int ret;
+ struct wpabuf *pubkey = NULL;
+ struct wpabuf *secret = NULL;
+ word32 key_len = ecdh->ec->key.dp->size;
+ ecc_point *point = NULL;
+ size_t need_key_len = inc_y ? 2 * key_len : key_len;
+
+ if (len < need_key_len)
+ goto fail;
+ pubkey = wpabuf_alloc(1 + 2 * key_len);
+ if (!pubkey)
+ goto fail;
+ wpabuf_put_u8(pubkey, inc_y ? ECC_POINT_UNCOMP : ECC_POINT_COMP_EVEN);
+ wpabuf_put_data(pubkey, key, need_key_len);
+
+ point = wc_ecc_new_point();
+ if (!point)
+ goto fail;
+
+ ret = wc_ecc_import_point_der(wpabuf_mhead(pubkey), 1 + 2 * key_len,
+ ecdh->ec->key.idx, point);
+ if (ret != MP_OKAY)
+ goto fail;
+
+ secret = wpabuf_alloc(key_len);
+ if (!secret)
+ goto fail;
+
+ ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point,
+ wpabuf_put(secret, key_len), &key_len);
+ if (ret != MP_OKAY)
+ goto fail;
+
+done:
+ wc_ecc_del_point(point);
+ wpabuf_free(pubkey);
+ return secret;
+fail:
+ wpabuf_free(secret);
+ secret = NULL;
+ goto done;
+}
+
+#endif /* CONFIG_ECC */
diff --git a/contrib/wpa/src/crypto/des-internal.c b/contrib/wpa/src/crypto/des-internal.c
index dec39ef..4ed6957 100644
--- a/contrib/wpa/src/crypto/des-internal.c
+++ b/contrib/wpa/src/crypto/des-internal.c
@@ -48,7 +48,7 @@
static const u32 bytebit[8] =
{
- 0200, 0100, 040, 020, 010, 04, 02, 01
+ 0200, 0100, 040, 020, 010, 04, 02, 01
};
static const u32 bigbyte[24] =
@@ -58,22 +58,22 @@ static const u32 bigbyte[24] =
0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL,
0x800UL, 0x400UL, 0x200UL, 0x100UL,
0x80UL, 0x40UL, 0x20UL, 0x10UL,
- 0x8UL, 0x4UL, 0x2UL, 0x1L
+ 0x8UL, 0x4UL, 0x2UL, 0x1L
};
/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
static const u8 pc1[56] = {
- 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
- 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
- 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
};
static const u8 totrot[16] = {
1, 2, 4, 6,
- 8, 10, 12, 14,
- 15, 17, 19, 21,
+ 8, 10, 12, 14,
+ 15, 17, 19, 21,
23, 25, 27, 28
};
@@ -396,7 +396,7 @@ static void desfunc(u32 *block, const u32 *keys)
/* wpa_supplicant/hostapd specific wrapper */
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
@@ -421,6 +421,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
os_memset(pkey, 0, sizeof(pkey));
os_memset(ek, 0, sizeof(ek));
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/dh_group5.c b/contrib/wpa/src/crypto/dh_group5.c
index ccdbfc8..425c848 100644
--- a/contrib/wpa/src/crypto/dh_group5.c
+++ b/contrib/wpa/src/crypto/dh_group5.c
@@ -15,6 +15,7 @@
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
+ wpabuf_free(*publ);
*publ = dh_init(dh_groups_get(5), priv);
if (*publ == NULL)
return NULL;
diff --git a/contrib/wpa/src/crypto/dh_groups.c b/contrib/wpa/src/crypto/dh_groups.c
index 3aeb2bb..5e421b2 100644
--- a/contrib/wpa/src/crypto/dh_groups.c
+++ b/contrib/wpa/src/crypto/dh_groups.c
@@ -1151,7 +1151,7 @@ static const u8 dh_group24_order[] = {
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
-
+
static const struct dh_group dh_groups[] = {
DH_GROUP(5, 1),
@@ -1203,32 +1203,24 @@ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
if (*priv == NULL)
return NULL;
- if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
- {
+ pv_len = dh->prime_len;
+ pv = wpabuf_alloc(pv_len);
+ if (pv == NULL) {
wpabuf_clear_free(*priv);
*priv = NULL;
return NULL;
}
-
- if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
- /* Make sure private value is smaller than prime */
- *(wpabuf_mhead_u8(*priv)) = 0;
- }
- wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
-
- pv_len = dh->prime_len;
- pv = wpabuf_alloc(pv_len);
- if (pv == NULL)
- return NULL;
- if (crypto_mod_exp(dh->generator, dh->generator_len,
- wpabuf_head(*priv), wpabuf_len(*priv),
- dh->prime, dh->prime_len, wpabuf_mhead(pv),
- &pv_len) < 0) {
+ if (crypto_dh_init(*dh->generator, dh->prime, dh->prime_len,
+ wpabuf_mhead(*priv), wpabuf_mhead(pv)) < 0) {
wpabuf_clear_free(pv);
- wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+ wpa_printf(MSG_INFO, "DH: crypto_dh_init failed");
+ wpabuf_clear_free(*priv);
+ *priv = NULL;
return NULL;
}
- wpabuf_put(pv, pv_len);
+ wpabuf_put(*priv, dh->prime_len);
+ wpabuf_put(pv, dh->prime_len);
+ wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
return pv;
@@ -1256,12 +1248,15 @@ struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
shared = wpabuf_alloc(shared_len);
if (shared == NULL)
return NULL;
- if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
- wpabuf_head(own_private), wpabuf_len(own_private),
- dh->prime, dh->prime_len,
- wpabuf_mhead(shared), &shared_len) < 0) {
+ if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+ dh->order, dh->order_len,
+ wpabuf_head(own_private),
+ wpabuf_len(own_private),
+ wpabuf_head(peer_public),
+ wpabuf_len(peer_public),
+ wpabuf_mhead(shared), &shared_len) < 0) {
wpabuf_clear_free(shared);
- wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+ wpa_printf(MSG_INFO, "DH: crypto_dh_derive_secret failed");
return NULL;
}
wpabuf_put(shared, shared_len);
diff --git a/contrib/wpa/src/crypto/fips_prf_openssl.c b/contrib/wpa/src/crypto/fips_prf_openssl.c
index fb03efc..4697e04 100644
--- a/contrib/wpa/src/crypto/fips_prf_openssl.c
+++ b/contrib/wpa/src/crypto/fips_prf_openssl.c
@@ -17,6 +17,19 @@ static void sha1_transform(u32 *state, const u8 data[64])
{
SHA_CTX context;
os_memset(&context, 0, sizeof(context));
+#if defined(OPENSSL_IS_BORINGSSL) && !defined(ANDROID)
+ context.h[0] = state[0];
+ context.h[1] = state[1];
+ context.h[2] = state[2];
+ context.h[3] = state[3];
+ context.h[4] = state[4];
+ SHA1_Transform(&context, data);
+ state[0] = context.h[0];
+ state[1] = context.h[1];
+ state[2] = context.h[2];
+ state[3] = context.h[3];
+ state[4] = context.h[4];
+#else
context.h0 = state[0];
context.h1 = state[1];
context.h2 = state[2];
@@ -28,6 +41,7 @@ static void sha1_transform(u32 *state, const u8 data[64])
state[2] = context.h2;
state[3] = context.h3;
state[4] = context.h4;
+#endif
}
@@ -62,12 +76,11 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
/* w_i = G(t, XVAL) */
os_memcpy(_t, t, 20);
sha1_transform(_t, xkey);
- _t[0] = host_to_be32(_t[0]);
- _t[1] = host_to_be32(_t[1]);
- _t[2] = host_to_be32(_t[2]);
- _t[3] = host_to_be32(_t[3]);
- _t[4] = host_to_be32(_t[4]);
- os_memcpy(xpos, _t, 20);
+ WPA_PUT_BE32(xpos, _t[0]);
+ WPA_PUT_BE32(xpos + 4, _t[1]);
+ WPA_PUT_BE32(xpos + 8, _t[2]);
+ WPA_PUT_BE32(xpos + 12, _t[3]);
+ WPA_PUT_BE32(xpos + 16, _t[4]);
/* XKEY = (1 + XKEY + w_i) mod 2^b */
carry = 1;
diff --git a/contrib/wpa/src/crypto/fips_prf_wolfssl.c b/contrib/wpa/src/crypto/fips_prf_wolfssl.c
new file mode 100644
index 0000000..feb39db
--- /dev/null
+++ b/contrib/wpa/src/crypto/fips_prf_wolfssl.c
@@ -0,0 +1,87 @@
+/*
+ * FIPS 186-2 PRF for libcrypto
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static void sha1_transform(u32 *state, const u8 data[64])
+{
+ wc_Sha sha;
+
+ os_memset(&sha, 0, sizeof(sha));
+ sha.digest[0] = state[0];
+ sha.digest[1] = state[1];
+ sha.digest[2] = state[2];
+ sha.digest[3] = state[3];
+ sha.digest[4] = state[4];
+ wc_ShaUpdate(&sha, data, 64);
+ state[0] = sha.digest[0];
+ state[1] = sha.digest[1];
+ state[2] = sha.digest[2];
+ state[3] = sha.digest[3];
+ state[4] = sha.digest[4];
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+ u8 xkey[64];
+ u32 t[5], _t[5];
+ int i, j, m, k;
+ u8 *xpos = x;
+ u32 carry;
+
+ if (seed_len < sizeof(xkey))
+ os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+ else
+ seed_len = sizeof(xkey);
+
+ /* FIPS 186-2 + change notice 1 */
+
+ os_memcpy(xkey, seed, seed_len);
+ t[0] = 0x67452301;
+ t[1] = 0xEFCDAB89;
+ t[2] = 0x98BADCFE;
+ t[3] = 0x10325476;
+ t[4] = 0xC3D2E1F0;
+
+ m = xlen / 40;
+ for (j = 0; j < m; j++) {
+ /* XSEED_j = 0 */
+ for (i = 0; i < 2; i++) {
+ /* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+ /* w_i = G(t, XVAL) */
+ os_memcpy(_t, t, 20);
+ sha1_transform(_t, xkey);
+ WPA_PUT_BE32(xpos, _t[0]);
+ WPA_PUT_BE32(xpos + 4, _t[1]);
+ WPA_PUT_BE32(xpos + 8, _t[2]);
+ WPA_PUT_BE32(xpos + 12, _t[3]);
+ WPA_PUT_BE32(xpos + 16, _t[4]);
+
+ /* XKEY = (1 + XKEY + w_i) mod 2^b */
+ carry = 1;
+ for (k = 19; k >= 0; k--) {
+ carry += xkey[k] + xpos[k];
+ xkey[k] = carry & 0xff;
+ carry >>= 8;
+ }
+
+ xpos += 20;
+ }
+ /* x_j = w_0|w_1 */
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/md4-internal.c b/contrib/wpa/src/crypto/md4-internal.c
index cd5e6ca..cf408e8 100644
--- a/contrib/wpa/src/crypto/md4-internal.c
+++ b/contrib/wpa/src/crypto/md4-internal.c
@@ -31,6 +31,9 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
MD4_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
MD4Init(&ctx);
for (i = 0; i < num_elem; i++)
MD4Update(&ctx, addr[i], len[i]);
@@ -82,7 +85,7 @@ MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
(cp)[1] = (value) >> 8; \
(cp)[0] = (value); } while (0)
-static u8 PADDING[MD4_BLOCK_LENGTH] = {
+static const u8 PADDING[MD4_BLOCK_LENGTH] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
diff --git a/contrib/wpa/src/crypto/md5-internal.c b/contrib/wpa/src/crypto/md5-internal.c
index f0a2a5d..944698a 100644
--- a/contrib/wpa/src/crypto/md5-internal.c
+++ b/contrib/wpa/src/crypto/md5-internal.c
@@ -33,6 +33,9 @@ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
MD5_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
MD5Init(&ctx);
for (i = 0; i < num_elem; i++)
MD5Update(&ctx, addr[i], len[i]);
diff --git a/contrib/wpa/src/crypto/ms_funcs.c b/contrib/wpa/src/crypto/ms_funcs.c
index 053d203..aff7d33 100644
--- a/contrib/wpa/src/crypto/ms_funcs.c
+++ b/contrib/wpa/src/crypto/ms_funcs.c
@@ -48,7 +48,7 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
WPA_PUT_LE16(ucs2_buffer + j,
((c & 0x1F) << 6) | (c2 & 0x3F));
j += 2;
- } else if (i == utf8_string_len ||
+ } else if (i == utf8_string_len - 1 ||
j >= ucs2_buffer_size - 1) {
/* incomplete surrogate */
return -1;
@@ -140,17 +140,20 @@ int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
* @challenge: 8-octet Challenge (IN)
* @password_hash: 16-octet PasswordHash (IN)
* @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
*/
-void challenge_response(const u8 *challenge, const u8 *password_hash,
- u8 *response)
+int challenge_response(const u8 *challenge, const u8 *password_hash,
+ u8 *response)
{
u8 zpwd[7];
- des_encrypt(challenge, password_hash, response);
- des_encrypt(challenge, password_hash + 7, response + 8);
+
+ if (des_encrypt(challenge, password_hash, response) < 0 ||
+ des_encrypt(challenge, password_hash + 7, response + 8) < 0)
+ return -1;
zpwd[0] = password_hash[14];
zpwd[1] = password_hash[15];
os_memset(zpwd + 2, 0, 5);
- des_encrypt(challenge, zpwd, response + 16);
+ return des_encrypt(challenge, zpwd, response + 16);
}
@@ -175,9 +178,9 @@ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
if (challenge_hash(peer_challenge, auth_challenge, username,
username_len, challenge) ||
- nt_password_hash(password, password_len, password_hash))
+ nt_password_hash(password, password_len, password_hash) ||
+ challenge_response(challenge, password_hash, response))
return -1;
- challenge_response(challenge, password_hash, response);
return 0;
}
@@ -202,9 +205,9 @@ int generate_nt_response_pwhash(const u8 *auth_challenge,
if (challenge_hash(peer_challenge, auth_challenge,
username, username_len,
- challenge))
+ challenge) ||
+ challenge_response(challenge, password_hash, response))
return -1;
- challenge_response(challenge, password_hash, response);
return 0;
}
@@ -304,9 +307,10 @@ int nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response)
{
u8 password_hash[16];
- if (nt_password_hash(password, password_len, password_hash))
+
+ if (nt_password_hash(password, password_len, password_hash) ||
+ challenge_response(challenge, password_hash, response))
return -1;
- challenge_response(challenge, password_hash, response);
return 0;
}
@@ -487,12 +491,15 @@ int new_password_encrypted_with_old_nt_password_hash(
* @password_hash: 16-octer PasswordHash (IN)
* @block: 16-octet Block (IN)
* @cypher: 16-octer Cypher (OUT)
+ * Returns: 0 on success, -1 on failure
*/
-void nt_password_hash_encrypted_with_block(const u8 *password_hash,
- const u8 *block, u8 *cypher)
+int nt_password_hash_encrypted_with_block(const u8 *password_hash,
+ const u8 *block, u8 *cypher)
{
- des_encrypt(password_hash, block, cypher);
- des_encrypt(password_hash + 8, block + 7, cypher + 8);
+ if (des_encrypt(password_hash, block, cypher) < 0 ||
+ des_encrypt(password_hash + 8, block + 7, cypher + 8) < 0)
+ return -1;
+ return 0;
}
@@ -515,10 +522,10 @@ int old_nt_password_hash_encrypted_with_new_nt_password_hash(
if (nt_password_hash(old_password, old_password_len,
old_password_hash) ||
nt_password_hash(new_password, new_password_len,
- new_password_hash))
+ new_password_hash) ||
+ nt_password_hash_encrypted_with_block(old_password_hash,
+ new_password_hash,
+ encrypted_password_hash))
return -1;
- nt_password_hash_encrypted_with_block(old_password_hash,
- new_password_hash,
- encrypted_password_hash);
return 0;
}
diff --git a/contrib/wpa/src/crypto/ms_funcs.h b/contrib/wpa/src/crypto/ms_funcs.h
index b5b5918..b8d55f0 100644
--- a/contrib/wpa/src/crypto/ms_funcs.h
+++ b/contrib/wpa/src/crypto/ms_funcs.h
@@ -31,8 +31,8 @@ int generate_authenticator_response_pwhash(
int nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response);
-void challenge_response(const u8 *challenge, const u8 *password_hash,
- u8 *response);
+int challenge_response(const u8 *challenge, const u8 *password_hash,
+ u8 *response);
int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len, u8 *challenge);
int nt_password_hash(const u8 *password, size_t password_len,
@@ -50,8 +50,8 @@ int __must_check new_password_encrypted_with_old_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_pw_block);
-void nt_password_hash_encrypted_with_block(const u8 *password_hash,
- const u8 *block, u8 *cypher);
+int nt_password_hash_encrypted_with_block(const u8 *password_hash,
+ const u8 *block, u8 *cypher);
int old_nt_password_hash_encrypted_with_new_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
diff --git a/contrib/wpa/src/crypto/random.c b/contrib/wpa/src/crypto/random.c
index 3a86a93..1cabf3f 100644
--- a/contrib/wpa/src/crypto/random.c
+++ b/contrib/wpa/src/crypto/random.c
@@ -25,6 +25,9 @@
#include "utils/includes.h"
#ifdef __linux__
#include <fcntl.h>
+#ifdef CONFIG_GETRANDOM
+#include <sys/random.h>
+#endif /* CONFIG_GETRANDOM */
#endif /* __linux__ */
#include "utils/common.h"
@@ -54,7 +57,6 @@ static int random_fd = -1;
static unsigned int own_pool_ready = 0;
#define RANDOM_ENTROPY_SIZE 20
static char *random_entropy_file = NULL;
-static int random_entropy_file_read = 0;
#define MIN_COLLECT_ENTROPY 1000
static unsigned int entropy = 0;
@@ -66,6 +68,9 @@ static void random_write_entropy(void);
static u32 __ROL32(u32 x, u32 y)
{
+ if (y == 0)
+ return x;
+
return (x << (y & 31)) | (x >> (32 - (y & 31)));
}
@@ -226,30 +231,52 @@ int random_pool_ready(void)
return 1; /* Already initialized - good to continue */
/*
- * Try to fetch some more data from the kernel high quality
- * /dev/random. There may not be enough data available at this point,
+ * Try to fetch some more data from the kernel high quality RNG.
+ * There may not be enough data available at this point,
* so use non-blocking read to avoid blocking the application
* completely.
*/
- fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(errno));
- return -1;
- }
- res = read(fd, dummy_key + dummy_key_avail,
- sizeof(dummy_key) - dummy_key_avail);
+#ifdef CONFIG_GETRANDOM
+ res = getrandom(dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
if (res < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
- "%s", strerror(errno));
- res = 0;
+ if (errno == ENOSYS) {
+ wpa_printf(MSG_DEBUG,
+ "random: getrandom() not supported, falling back to /dev/random");
+ } else {
+ wpa_printf(MSG_INFO,
+ "random: no data from getrandom(): %s",
+ strerror(errno));
+ res = 0;
+ }
}
- wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
- "/dev/random", (unsigned) res,
+#else /* CONFIG_GETRANDOM */
+ res = -1;
+#endif /* CONFIG_GETRANDOM */
+ if (res < 0) {
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ wpa_printf(MSG_ERROR,
+ "random: Cannot open /dev/random: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ res = read(fd, dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "random: Cannot read from /dev/random: %s",
+ strerror(errno));
+ res = 0;
+ }
+ close(fd);
+ }
+
+ wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
(unsigned) (sizeof(dummy_key) - dummy_key_avail));
dummy_key_avail += res;
- close(fd);
if (dummy_key_avail == sizeof(dummy_key)) {
if (own_pool_ready < MIN_READY_MARK)
@@ -259,7 +286,7 @@ int random_pool_ready(void)
}
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
- "random data available from /dev/random",
+ "random data available",
(unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
if (own_pool_ready >= MIN_READY_MARK ||
@@ -354,7 +381,6 @@ static void random_read_entropy(void)
own_pool_ready = (u8) buf[0];
random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
- random_entropy_file_read = 1;
os_free(buf);
wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
"(own_pool_ready=%u)",
@@ -412,6 +438,19 @@ void random_init(const char *entropy_file)
if (random_fd >= 0)
return;
+#ifdef CONFIG_GETRANDOM
+ {
+ u8 dummy;
+
+ if (getrandom(&dummy, 0, GRND_NONBLOCK) == 0 ||
+ errno != ENOSYS) {
+ wpa_printf(MSG_DEBUG,
+ "random: getrandom() support available");
+ return;
+ }
+ }
+#endif /* CONFIG_GETRANDOM */
+
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (random_fd < 0) {
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
diff --git a/contrib/wpa/src/crypto/sha1-internal.c b/contrib/wpa/src/crypto/sha1-internal.c
index 24bc3ff..a491707 100644
--- a/contrib/wpa/src/crypto/sha1-internal.c
+++ b/contrib/wpa/src/crypto/sha1-internal.c
@@ -33,6 +33,9 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
SHA1_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
SHA1Init(&ctx);
for (i = 0; i < num_elem; i++)
SHA1Update(&ctx, addr[i], len[i]);
@@ -50,7 +53,7 @@ By Steve Reid <sreid@sea-to-sky.net>
100% Public Domain
-----------------
-Modified 7/98
+Modified 7/98
By James H. Brown <jbrown@burgoyne.com>
Still 100% Public Domain
@@ -72,7 +75,7 @@ Since the file IO in main() reads 16K at a time, any file 8K or larger would
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
"a"s).
-I also changed the declaration of variables i & j in SHA1Update to
+I also changed the declaration of variables i & j in SHA1Update to
unsigned long from unsigned int for the same reason.
These changes should make no difference to any 32 bit implementations since
@@ -99,7 +102,7 @@ Still 100% public domain
Modified 4/01
By Saul Kravitz <Saul.Kravitz@celera.com>
Still 100% PD
-Modified to run on Compaq Alpha hardware.
+Modified to run on Compaq Alpha hardware.
-----------------
Modified 4/01
@@ -159,7 +162,7 @@ void SHAPrintContext(SHA1_CTX *context, char *msg)
{
printf("%s (%d,%d) %x %x %x %x %x\n",
msg,
- context->count[0], context->count[1],
+ context->count[0], context->count[1],
context->state[0],
context->state[1],
context->state[2],
@@ -294,7 +297,6 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
255);
}
/* Wipe variables */
- i = 0;
os_memset(context->buffer, 0, 64);
os_memset(context->state, 0, 20);
os_memset(context->count, 0, 8);
diff --git a/contrib/wpa/src/crypto/sha1-tlsprf.c b/contrib/wpa/src/crypto/sha1-tlsprf.c
index f9bc0eb..a11649a 100644
--- a/contrib/wpa/src/crypto/sha1-tlsprf.c
+++ b/contrib/wpa/src/crypto/sha1-tlsprf.c
@@ -40,9 +40,6 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
const unsigned char *SHA1_addr[3];
size_t SHA1_len[3];
- if (secret_len & 1)
- return -1;
-
MD5_addr[0] = A_MD5;
MD5_len[0] = MD5_MAC_LEN;
MD5_addr[1] = (unsigned char *) label;
diff --git a/contrib/wpa/src/crypto/sha256-internal.c b/contrib/wpa/src/crypto/sha256-internal.c
index 35299b0..ff1e2ba1 100644
--- a/contrib/wpa/src/crypto/sha256-internal.c
+++ b/contrib/wpa/src/crypto/sha256-internal.c
@@ -28,6 +28,9 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
struct sha256_state ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
sha256_init(&ctx);
for (i = 0; i < num_elem; i++)
if (sha256_process(&ctx, addr[i], len[i]))
@@ -66,7 +69,7 @@ static const unsigned long K[64] = {
( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
@@ -97,7 +100,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf)
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
W[i - 16];
- }
+ }
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i) \
@@ -108,7 +111,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf)
for (i = 0; i < 64; ++i) {
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
- t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
}
diff --git a/contrib/wpa/src/crypto/sha256-kdf.c b/contrib/wpa/src/crypto/sha256-kdf.c
index e7509ce..af7d954 100644
--- a/contrib/wpa/src/crypto/sha256-kdf.c
+++ b/contrib/wpa/src/crypto/sha256-kdf.c
@@ -1,6 +1,6 @@
/*
- * HMAC-SHA256 KDF (RFC 5295)
- * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ * HMAC-SHA256 KDF (RFC 5295) and HKDF-Expand(SHA256) (RFC 5869)
+ * Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -16,7 +16,8 @@
* hmac_sha256_kdf - HMAC-SHA256 based KDF (RFC 5295)
* @secret: Key for KDF
* @secret_len: Length of the key in bytes
- * @label: A unique label for each purpose of the KDF
+ * @label: A unique label for each purpose of the KDF or %NULL to select
+ * RFC 5869 HKDF-Expand() with arbitrary seed (= info)
* @seed: Seed value to bind into the key
* @seed_len: Length of the seed
* @out: Buffer for the generated pseudo-random key
@@ -24,7 +25,9 @@
* Returns: 0 on success, -1 on failure.
*
* This function is used to derive new, cryptographically separate keys from a
- * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2.
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
+ * with label = NULL and seed = info, this matches HKDF-Expand() defined in
+ * RFC 5869, Chapter 2.3.
*/
int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
@@ -38,8 +41,13 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
addr[0] = T;
len[0] = SHA256_MAC_LEN;
- addr[1] = (const unsigned char *) label;
- len[1] = os_strlen(label) + 1;
+ if (label) {
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ } else {
+ addr[1] = (const u8 *) "";
+ len[1] = 0;
+ }
addr[2] = seed;
len[2] = seed_len;
addr[3] = &iter;
diff --git a/contrib/wpa/src/crypto/sha256-prf.c b/contrib/wpa/src/crypto/sha256-prf.c
index 79791c0..722cad6 100644
--- a/contrib/wpa/src/crypto/sha256-prf.c
+++ b/contrib/wpa/src/crypto/sha256-prf.c
@@ -1,6 +1,6 @@
/*
* SHA256-based PRF (IEEE 802.11r)
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,14 +22,16 @@
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key.
*/
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
+int sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
- sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+ return sha256_prf_bits(key, key_len, label, data, data_len, buf,
+ buf_len * 8);
}
@@ -42,15 +44,16 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bits of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key. If the requested buf_len is not divisible by eight, the least
* significant 1-7 bits of the last octet in the output are not part of the
* requested output.
*/
-void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits)
+int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
{
u16 counter = 1;
size_t pos, plen;
@@ -75,11 +78,14 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
plen = buf_len - pos;
WPA_PUT_LE16(counter_le, counter);
if (plen >= SHA256_MAC_LEN) {
- hmac_sha256_vector(key, key_len, 4, addr, len,
- &buf[pos]);
+ if (hmac_sha256_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
pos += SHA256_MAC_LEN;
} else {
- hmac_sha256_vector(key, key_len, 4, addr, len, hash);
+ if (hmac_sha256_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
os_memcpy(&buf[pos], hash, plen);
pos += plen;
break;
@@ -97,4 +103,6 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
}
os_memset(hash, 0, sizeof(hash));
+
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/sha256.h b/contrib/wpa/src/crypto/sha256.h
index b15f511..5219022 100644
--- a/contrib/wpa/src/crypto/sha256.h
+++ b/contrib/wpa/src/crypto/sha256.h
@@ -1,6 +1,6 @@
/*
* SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,11 +15,11 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
-void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits);
+int sha256_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
void tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
diff --git a/contrib/wpa/src/crypto/sha384-internal.c b/contrib/wpa/src/crypto/sha384-internal.c
new file mode 100644
index 0000000..646f729
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384-internal.c
@@ -0,0 +1,92 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha384_vector - SHA384 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ struct sha384_state ctx;
+ size_t i;
+
+ sha384_init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ if (sha384_process(&ctx, addr[i], len[i]))
+ return -1;
+ if (sha384_done(&ctx, mac))
+ return -1;
+ return 0;
+}
+
+
+/* ===== start - public domain SHA384 implementation ===== */
+
+/* This is based on SHA384 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define CONST64(n) n ## ULL
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+void sha384_init(struct sha384_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = CONST64(0xcbbb9d5dc1059ed8);
+ md->state[1] = CONST64(0x629a292a367cd507);
+ md->state[2] = CONST64(0x9159015a3070dd17);
+ md->state[3] = CONST64(0x152fecd8f70e5939);
+ md->state[4] = CONST64(0x67332667ffc00b31);
+ md->state[5] = CONST64(0x8eb44a8768581511);
+ md->state[6] = CONST64(0xdb0c2e0d64f98fa7);
+ md->state[7] = CONST64(0x47b5481dbefa4fa4);
+}
+
+int sha384_process(struct sha384_state *md, const unsigned char *in,
+ unsigned long inlen)
+{
+ return sha512_process(md, in, inlen);
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (48 bytes)
+ @return CRYPT_OK if successful
+*/
+int sha384_done(struct sha384_state *md, unsigned char *out)
+{
+ unsigned char buf[64];
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ if (sha512_done(md, buf) != 0)
+ return -1;
+
+ os_memcpy(out, buf, 48);
+ return 0;
+}
+
+/* ===== end - public domain SHA384 implementation ===== */
diff --git a/contrib/wpa/src/crypto/sha384-kdf.c b/contrib/wpa/src/crypto/sha384-kdf.c
new file mode 100644
index 0000000..1d19627
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384-kdf.c
@@ -0,0 +1,87 @@
+/*
+ * HMAC-SHA384 KDF (RFC 5295) and HKDF-Expand(SHA384) (RFC 5869)
+ * Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+
+
+/**
+ * hmac_sha384_kdf - HMAC-SHA384 based KDF (RFC 5295)
+ * @secret: Key for KDF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF or %NULL to select
+ * RFC 5869 HKDF-Expand() with arbitrary seed (= info)
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
+ * with label = NULL and seed = info, this matches HKDF-Expand() defined in
+ * RFC 5869, Chapter 2.3.
+ */
+int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen)
+{
+ u8 T[SHA384_MAC_LEN];
+ u8 iter = 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+ size_t pos, clen;
+
+ addr[0] = T;
+ len[0] = SHA384_MAC_LEN;
+ if (label) {
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ } else {
+ addr[1] = (const u8 *) "";
+ len[1] = 0;
+ }
+ addr[2] = seed;
+ len[2] = seed_len;
+ addr[3] = &iter;
+ len[3] = 1;
+
+ if (hmac_sha384_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
+ return -1;
+
+ pos = 0;
+ for (;;) {
+ clen = outlen - pos;
+ if (clen > SHA384_MAC_LEN)
+ clen = SHA384_MAC_LEN;
+ os_memcpy(out + pos, T, clen);
+ pos += clen;
+
+ if (pos == outlen)
+ break;
+
+ if (iter == 255) {
+ os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA384_MAC_LEN);
+ return -1;
+ }
+ iter++;
+
+ if (hmac_sha384_vector(secret, secret_len, 4, addr, len, T) < 0)
+ {
+ os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA384_MAC_LEN);
+ return -1;
+ }
+ }
+
+ os_memset(T, 0, SHA384_MAC_LEN);
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/sha384-prf.c b/contrib/wpa/src/crypto/sha384-prf.c
index 653920b..03e3cb3 100644
--- a/contrib/wpa/src/crypto/sha384-prf.c
+++ b/contrib/wpa/src/crypto/sha384-prf.c
@@ -1,6 +1,6 @@
/*
* SHA384-based KDF (IEEE 802.11ac)
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,14 +22,16 @@
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key.
*/
-void sha384_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+int sha384_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
- sha384_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+ return sha384_prf_bits(key, key_len, label, data, data_len, buf,
+ buf_len * 8);
}
@@ -42,15 +44,16 @@ void sha384_prf(const u8 *key, size_t key_len, const char *label,
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bits of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key. If the requested buf_len is not divisible by eight, the least
* significant 1-7 bits of the last octet in the output are not part of the
* requested output.
*/
-void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits)
+int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
{
u16 counter = 1;
size_t pos, plen;
@@ -75,11 +78,14 @@ void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
plen = buf_len - pos;
WPA_PUT_LE16(counter_le, counter);
if (plen >= SHA384_MAC_LEN) {
- hmac_sha384_vector(key, key_len, 4, addr, len,
- &buf[pos]);
+ if (hmac_sha384_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
pos += SHA384_MAC_LEN;
} else {
- hmac_sha384_vector(key, key_len, 4, addr, len, hash);
+ if (hmac_sha384_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
os_memcpy(&buf[pos], hash, plen);
pos += plen;
break;
@@ -97,4 +103,6 @@ void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
}
os_memset(hash, 0, sizeof(hash));
+
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/sha384.c b/contrib/wpa/src/crypto/sha384.c
new file mode 100644
index 0000000..ee136ce
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha384_vector - HMAC-SHA384 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
+ unsigned char tk[48];
+ const u8 *_addr[6];
+ size_t _len[6], i;
+
+ if (num_elem > 5) {
+ /*
+ * Fixed limit on the number of fragments to avoid having to
+ * allocate memory (which could fail).
+ */
+ return -1;
+ }
+
+ /* if key is longer than 128 bytes reset it to key = SHA384(key) */
+ if (key_len > 128) {
+ if (sha384_vector(1, &key, &key_len, tk) < 0)
+ return -1;
+ key = tk;
+ key_len = 48;
+ }
+
+ /* the HMAC_SHA384 transform looks like:
+ *
+ * SHA384(K XOR opad, SHA384(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 128 times
+ * opad is the byte 0x5c repeated 128 times
+ * and text is the data being protected */
+
+ /* start out by storing key in ipad */
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with ipad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x36;
+
+ /* perform inner SHA384 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ for (i = 0; i < num_elem; i++) {
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
+ }
+ if (sha384_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
+
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with opad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x5c;
+
+ /* perform outer SHA384 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ _addr[1] = mac;
+ _len[1] = SHA384_MAC_LEN;
+ return sha384_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha384 - HMAC-SHA384 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/contrib/wpa/src/crypto/sha384.h b/contrib/wpa/src/crypto/sha384.h
index 3deafa5..2241425 100644
--- a/contrib/wpa/src/crypto/sha384.h
+++ b/contrib/wpa/src/crypto/sha384.h
@@ -1,6 +1,6 @@
/*
* SHA384 hash implementation and interface functions
- * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,10 +15,13 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
-void sha384_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
-void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits);
+int sha384_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
+int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
#endif /* SHA384_H */
diff --git a/contrib/wpa/src/crypto/sha384_i.h b/contrib/wpa/src/crypto/sha384_i.h
new file mode 100644
index 0000000..a00253f
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384_i.h
@@ -0,0 +1,23 @@
+/*
+ * SHA-384 internal definitions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA384_I_H
+#define SHA384_I_H
+
+#include "sha512_i.h"
+
+#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
+
+#define sha384_state sha512_state
+
+void sha384_init(struct sha384_state *md);
+int sha384_process(struct sha384_state *md, const unsigned char *in,
+ unsigned long inlen);
+int sha384_done(struct sha384_state *md, unsigned char *out);
+
+#endif /* SHA384_I_H */
diff --git a/contrib/wpa/src/crypto/sha512-internal.c b/contrib/wpa/src/crypto/sha512-internal.c
new file mode 100644
index 0000000..c026394
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512-internal.c
@@ -0,0 +1,270 @@
+/*
+ * SHA-512 hash implementation and interface functions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha512_vector - SHA512 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ struct sha512_state ctx;
+ size_t i;
+
+ sha512_init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ if (sha512_process(&ctx, addr[i], len[i]))
+ return -1;
+ if (sha512_done(&ctx, mac))
+ return -1;
+ return 0;
+}
+
+
+/* ===== start - public domain SHA512 implementation ===== */
+
+/* This is based on SHA512 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define CONST64(n) n ## ULL
+
+/* the K array */
+static const u64 K[80] = {
+ CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
+ CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
+ CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
+ CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
+ CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
+ CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
+ CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
+ CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
+ CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
+ CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
+ CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
+ CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
+ CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
+ CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
+ CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
+ CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
+ CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
+ CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
+ CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
+ CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
+ CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
+ CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
+ CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
+ CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
+ CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
+ CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
+ CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
+ CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
+ CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
+ CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
+ CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
+ CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
+ CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
+ CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
+ CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
+ CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
+ CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
+ CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
+ CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
+ CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
+};
+
+/* Various logical functions */
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) ROR64c(x, n)
+#define R(x, n) (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) n))
+#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
+#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
+#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
+#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+#define ROR64c(x, y) \
+ ( ((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) (y) & CONST64(63))) | \
+ ((x) << ((u64) (64 - ((y) & CONST64(63)))))) & \
+ CONST64(0xFFFFFFFFFFFFFFFF))
+
+/* compress 1024-bits */
+static int sha512_compress(struct sha512_state *md, unsigned char *buf)
+{
+ u64 S[8], t0, t1;
+ u64 *W;
+ int i;
+
+ W = os_malloc(80 * sizeof(u64));
+ if (!W)
+ return -1;
+
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+
+ /* copy the state into 1024-bits into W[0..15] */
+ for (i = 0; i < 16; i++)
+ W[i] = WPA_GET_BE64(buf + (8 * i));
+
+ /* fill W[16..79] */
+ for (i = 16; i < 80; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+ W[i - 16];
+ }
+
+ /* Compress */
+ for (i = 0; i < 80; i++) {
+ t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i];
+ t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]);
+ S[7] = S[6];
+ S[6] = S[5];
+ S[5] = S[4];
+ S[4] = S[3] + t0;
+ S[3] = S[2];
+ S[2] = S[1];
+ S[1] = S[0];
+ S[0] = t0 + t1;
+ }
+
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+
+ os_free(W);
+ return 0;
+}
+
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+void sha512_init(struct sha512_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = CONST64(0x6a09e667f3bcc908);
+ md->state[1] = CONST64(0xbb67ae8584caa73b);
+ md->state[2] = CONST64(0x3c6ef372fe94f82b);
+ md->state[3] = CONST64(0xa54ff53a5f1d36f1);
+ md->state[4] = CONST64(0x510e527fade682d1);
+ md->state[5] = CONST64(0x9b05688c2b3e6c1f);
+ md->state[6] = CONST64(0x1f83d9abfb41bd6b);
+ md->state[7] = CONST64(0x5be0cd19137e2179);
+}
+
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+int sha512_process(struct sha512_state *md, const unsigned char *in,
+ unsigned long inlen)
+{
+ unsigned long n;
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= SHA512_BLOCK_SIZE) {
+ if (sha512_compress(md, (unsigned char *) in) < 0)
+ return -1;
+ md->length += SHA512_BLOCK_SIZE * 8;
+ in += SHA512_BLOCK_SIZE;
+ inlen -= SHA512_BLOCK_SIZE;
+ } else {
+ n = MIN(inlen, (SHA512_BLOCK_SIZE - md->curlen));
+ os_memcpy(md->buf + md->curlen, in, n);
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == SHA512_BLOCK_SIZE) {
+ if (sha512_compress(md, md->buf) < 0)
+ return -1;
+ md->length += 8 * SHA512_BLOCK_SIZE;
+ md->curlen = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (64 bytes)
+ @return CRYPT_OK if successful
+*/
+int sha512_done(struct sha512_state *md, unsigned char *out)
+{
+ int i;
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ /* increase the length of the message */
+ md->length += md->curlen * CONST64(8);
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char) 0x80;
+
+ /* if the length is currently above 112 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 112) {
+ while (md->curlen < 128) {
+ md->buf[md->curlen++] = (unsigned char) 0;
+ }
+ sha512_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad up to 120 bytes of zeroes
+ * note: that from 112 to 120 is the 64 MSB of the length. We assume
+ * that you won't hash > 2^64 bits of data... :-)
+ */
+ while (md->curlen < 120) {
+ md->buf[md->curlen++] = (unsigned char) 0;
+ }
+
+ /* store length */
+ WPA_PUT_BE64(md->buf + 120, md->length);
+ sha512_compress(md, md->buf);
+
+ /* copy output */
+ for (i = 0; i < 8; i++)
+ WPA_PUT_BE64(out + (8 * i), md->state[i]);
+
+ return 0;
+}
+
+/* ===== end - public domain SHA512 implementation ===== */
diff --git a/contrib/wpa/src/crypto/sha512-kdf.c b/contrib/wpa/src/crypto/sha512-kdf.c
new file mode 100644
index 0000000..8b71f9b
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512-kdf.c
@@ -0,0 +1,87 @@
+/*
+ * HMAC-SHA512 KDF (RFC 5295) and HKDF-Expand(SHA512) (RFC 5869)
+ * Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512.h"
+
+
+/**
+ * hmac_sha512_kdf - HMAC-SHA512 based KDF (RFC 5295)
+ * @secret: Key for KDF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF or %NULL to select
+ * RFC 5869 HKDF-Expand() with arbitrary seed (= info)
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
+ * with label = NULL and seed = info, this matches HKDF-Expand() defined in
+ * RFC 5869, Chapter 2.3.
+ */
+int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen)
+{
+ u8 T[SHA512_MAC_LEN];
+ u8 iter = 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+ size_t pos, clen;
+
+ addr[0] = T;
+ len[0] = SHA512_MAC_LEN;
+ if (label) {
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ } else {
+ addr[1] = (const u8 *) "";
+ len[1] = 0;
+ }
+ addr[2] = seed;
+ len[2] = seed_len;
+ addr[3] = &iter;
+ len[3] = 1;
+
+ if (hmac_sha512_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
+ return -1;
+
+ pos = 0;
+ for (;;) {
+ clen = outlen - pos;
+ if (clen > SHA512_MAC_LEN)
+ clen = SHA512_MAC_LEN;
+ os_memcpy(out + pos, T, clen);
+ pos += clen;
+
+ if (pos == outlen)
+ break;
+
+ if (iter == 255) {
+ os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA512_MAC_LEN);
+ return -1;
+ }
+ iter++;
+
+ if (hmac_sha512_vector(secret, secret_len, 4, addr, len, T) < 0)
+ {
+ os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA512_MAC_LEN);
+ return -1;
+ }
+ }
+
+ os_memset(T, 0, SHA512_MAC_LEN);
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/sha512-prf.c b/contrib/wpa/src/crypto/sha512-prf.c
new file mode 100644
index 0000000..3b2ad88
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512-prf.c
@@ -0,0 +1,108 @@
+/*
+ * SHA512-based KDF (IEEE 802.11ac)
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512.h"
+#include "crypto.h"
+
+
+/**
+ * sha512_prf - SHA512-based Key derivation function (IEEE 802.11ac, 11.6.1.7.2)
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+int sha512_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+ return sha512_prf_bits(key, key_len, label, data, data_len, buf,
+ buf_len * 8);
+}
+
+
+/**
+ * sha512_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bits of key to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key. If the requested buf_len is not divisible by eight, the least
+ * significant 1-7 bits of the last octet in the output are not part of the
+ * requested output.
+ */
+int sha512_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
+{
+ u16 counter = 1;
+ size_t pos, plen;
+ u8 hash[SHA512_MAC_LEN];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 counter_le[2], length_le[2];
+ size_t buf_len = (buf_len_bits + 7) / 8;
+
+ addr[0] = counter_le;
+ len[0] = 2;
+ addr[1] = (u8 *) label;
+ len[1] = os_strlen(label);
+ addr[2] = data;
+ len[2] = data_len;
+ addr[3] = length_le;
+ len[3] = sizeof(length_le);
+
+ WPA_PUT_LE16(length_le, buf_len_bits);
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ WPA_PUT_LE16(counter_le, counter);
+ if (plen >= SHA512_MAC_LEN) {
+ if (hmac_sha512_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
+ pos += SHA512_MAC_LEN;
+ } else {
+ if (hmac_sha512_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
+ os_memcpy(&buf[pos], hash, plen);
+ pos += plen;
+ break;
+ }
+ counter++;
+ }
+
+ /*
+ * Mask out unused bits in the last octet if it does not use all the
+ * bits.
+ */
+ if (buf_len_bits % 8) {
+ u8 mask = 0xff << (8 - buf_len_bits % 8);
+ buf[pos - 1] &= mask;
+ }
+
+ os_memset(hash, 0, sizeof(hash));
+
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/sha512.c b/contrib/wpa/src/crypto/sha512.c
new file mode 100644
index 0000000..66311c3
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-512 hash implementation and interface functions
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha512_vector - HMAC-SHA512 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (64 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
+ unsigned char tk[64];
+ const u8 *_addr[6];
+ size_t _len[6], i;
+
+ if (num_elem > 5) {
+ /*
+ * Fixed limit on the number of fragments to avoid having to
+ * allocate memory (which could fail).
+ */
+ return -1;
+ }
+
+ /* if key is longer than 128 bytes reset it to key = SHA512(key) */
+ if (key_len > 128) {
+ if (sha512_vector(1, &key, &key_len, tk) < 0)
+ return -1;
+ key = tk;
+ key_len = 64;
+ }
+
+ /* the HMAC_SHA512 transform looks like:
+ *
+ * SHA512(K XOR opad, SHA512(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 128 times
+ * opad is the byte 0x5c repeated 128 times
+ * and text is the data being protected */
+
+ /* start out by storing key in ipad */
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with ipad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x36;
+
+ /* perform inner SHA512 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ for (i = 0; i < num_elem; i++) {
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
+ }
+ if (sha512_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
+
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with opad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x5c;
+
+ /* perform outer SHA512 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ _addr[1] = mac;
+ _len[1] = SHA512_MAC_LEN;
+ return sha512_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha512 - HMAC-SHA512 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (64 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/contrib/wpa/src/crypto/sha512.h b/contrib/wpa/src/crypto/sha512.h
new file mode 100644
index 0000000..8e64c8b
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512.h
@@ -0,0 +1,27 @@
+/*
+ * SHA512 hash implementation and interface functions
+ * Copyright (c) 2015-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA512_H
+#define SHA512_H
+
+#define SHA512_MAC_LEN 64
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac);
+int sha512_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha512_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
+int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
+
+#endif /* SHA512_H */
diff --git a/contrib/wpa/src/crypto/sha512_i.h b/contrib/wpa/src/crypto/sha512_i.h
new file mode 100644
index 0000000..1089589
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512_i.h
@@ -0,0 +1,25 @@
+/*
+ * SHA-512 internal definitions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA512_I_H
+#define SHA512_I_H
+
+#define SHA512_BLOCK_SIZE 128
+
+struct sha512_state {
+ u64 length, state[8];
+ u32 curlen;
+ u8 buf[SHA512_BLOCK_SIZE];
+};
+
+void sha512_init(struct sha512_state *md);
+int sha512_process(struct sha512_state *md, const unsigned char *in,
+ unsigned long inlen);
+int sha512_done(struct sha512_state *md, unsigned char *out);
+
+#endif /* SHA512_I_H */
diff --git a/contrib/wpa/src/crypto/tls.h b/contrib/wpa/src/crypto/tls.h
index 2e56233..8bdb91f 100644
--- a/contrib/wpa/src/crypto/tls.h
+++ b/contrib/wpa/src/crypto/tls.h
@@ -41,6 +41,8 @@ enum tls_fail_reason {
TLS_FAIL_SERVER_CHAIN_PROBE = 8,
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
TLS_FAIL_DOMAIN_MISMATCH = 10,
+ TLS_FAIL_INSUFFICIENT_KEY_LEN = 11,
+ TLS_FAIL_DN_MISMATCH = 12,
};
@@ -63,6 +65,7 @@ union tls_event_data {
size_t hash_len;
const char *altsubject[TLS_MAX_ALT_SUBJECT];
int num_altsubject;
+ const char *serial_num;
} peer_cert;
struct {
@@ -80,6 +83,8 @@ struct tls_config {
int cert_in_cb;
const char *openssl_ciphers;
unsigned int tls_session_lifetime;
+ unsigned int crl_reload_interval;
+ unsigned int tls_flags;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
@@ -95,6 +100,14 @@ struct tls_config {
#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
#define TLS_CONN_EAP_FAST BIT(7)
#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
+#define TLS_CONN_EXT_CERT_CHECK BIT(9)
+#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
+#define TLS_CONN_SUITEB BIT(11)
+#define TLS_CONN_SUITEB_NO_ECDH BIT(12)
+#define TLS_CONN_DISABLE_TLSv1_3 BIT(13)
+#define TLS_CONN_ENABLE_TLSv1_0 BIT(14)
+#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
+#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -107,12 +120,19 @@ struct tls_config {
* %NULL to allow all subjects
* @altsubject_match: String to match in the alternative subject of the peer
* certificate or %NULL to allow all alternative subjects
- * @suffix_match: String to suffix match in the dNSName or CN of the peer
- * certificate or %NULL to allow all domain names. This may allow subdomains an
- * wildcard certificates. Each domain name label must have a full match.
+ * @suffix_match: Semicolon deliminated string of values to suffix match against
+ * the dNSName or CN of the peer certificate or %NULL to allow all domain names.
+ * This may allow subdomains and wildcard certificates. Each domain name label
+ * must have a full case-insensitive match.
* @domain_match: String to match in the dNSName or CN of the peer
* certificate or %NULL to allow all domain names. This requires a full,
* case-insensitive match.
+ *
+ * More than one match string can be provided by using semicolons to
+ * separate the strings (e.g., example.org;example.com). When multiple
+ * strings are specified, a match with any one of the values is
+ * considered a sufficient match for the certificate, i.e., the
+ * conditions are ORed together.
* @client_cert: File or reference name for client X.509 certificate in PEM or
* DER format
* @client_cert_blob: client_cert as inlined data or %NULL if not used
@@ -136,9 +156,15 @@ struct tls_config {
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
* @openssl_ciphers: OpenSSL cipher configuration
+ * @openssl_ecdh_curves: OpenSSL ECDH curve configuration. %NULL for auto if
+ * supported, empty string to disable, or a colon-separated curve list.
* @flags: Parameter options (TLS_CONN_*)
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
* or %NULL if OCSP is not enabled
+ * @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling
+ * response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if
+ * ocsp_multi is not enabled
+ * @check_cert_subject: Client certificate subject name matching string
*
* TLS connection parameters to be configured with tls_connection_set_params()
* and tls_global_set_params().
@@ -176,9 +202,12 @@ struct tls_connection_params {
const char *cert_id;
const char *ca_cert_id;
const char *openssl_ciphers;
+ const char *openssl_ecdh_curves;
unsigned int flags;
const char *ocsp_stapling_response;
+ const char *ocsp_stapling_response_multi;
+ const char *check_cert_subject;
};
@@ -242,6 +271,18 @@ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
/**
+ * tls_connection_peer_serial_num - Fetch peer certificate serial number
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Allocated string buffer containing the peer certificate serial
+ * number or %NULL on error.
+ *
+ * The caller is responsible for freeing the returned buffer with os_free().
+ */
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn);
+
+/**
* tls_connection_shutdown - Shutdown TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
@@ -297,9 +338,11 @@ int __must_check tls_global_set_params(
* @tls_ctx: TLS context data from tls_init()
* @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
* 2 = verify CRL for all certificates
+ * @strict: 0 = allow CRL time errors, 1 = do not allow CRL time errors
* Returns: 0 on success, -1 on failure
*/
-int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
+int __must_check tls_global_set_verify(void *tls_ctx, int check_crl,
+ int strict);
/**
* tls_connection_set_verify - Set certificate verification options
@@ -330,29 +373,42 @@ int __must_check tls_connection_get_random(void *tls_ctx,
struct tls_random *data);
/**
- * tls_connection_prf - Use TLS-PRF to derive keying material
+ * tls_connection_export_key - Derive keying material from a TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
- * @skip_keyblock: Skip TLS key block from the beginning of PRF output
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * Exports keying material using the mechanism described in RFC 5705. If
+ * context is %NULL, context is not provided; otherwise, context is provided
+ * (including the case of empty context with context_len == 0).
+ */
+int __must_check tls_connection_export_key(void *tls_ctx,
+ struct tls_connection *conn,
+ const char *label,
+ const u8 *context,
+ size_t context_len,
+ u8 *out, size_t out_len);
+
+/**
+ * tls_connection_get_eap_fast_key - Derive key material for EAP-FAST
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*
- * tls_connection_prf() is required so that further keying material can be
- * derived from the master secret. Example implementation of this function is in
- * tls_prf_sha1_md5() when it is called with seed set to
- * client_random|server_random (or server_random|client_random). For TLSv1.2 and
- * newer, a different PRF is needed, though.
+ * Exports key material after the normal TLS key block for use with
+ * EAP-FAST. Most callers will want tls_connection_export_key(), but EAP-FAST
+ * uses a different legacy mechanism.
*/
-int __must_check tls_connection_prf(void *tls_ctx,
- struct tls_connection *conn,
- const char *label,
- int server_random_first,
- int skip_keyblock,
- u8 *out, size_t out_len);
+int __must_check tls_connection_get_eap_fast_key(void *tls_ctx,
+ struct tls_connection *conn,
+ u8 *out, size_t out_len);
/**
* tls_connection_handshake - Process TLS handshake (client side)
@@ -455,7 +511,9 @@ enum {
TLS_CIPHER_RC4_SHA /* 0x0005 */,
TLS_CIPHER_AES128_SHA /* 0x002f */,
TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
- TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
+ TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */,
+ TLS_CIPHER_RSA_DHE_AES256_SHA /* 0x0039 */,
+ TLS_CIPHER_AES256_SHA /* 0x0035 */,
};
/**
diff --git a/contrib/wpa/src/crypto/tls_gnutls.c b/contrib/wpa/src/crypto/tls_gnutls.c
index f994379..daa01d9 100644
--- a/contrib/wpa/src/crypto/tls_gnutls.c
+++ b/contrib/wpa/src/crypto/tls_gnutls.c
@@ -1,6 +1,6 @@
/*
* SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -37,6 +37,8 @@ struct tls_global {
union tls_event_data *data);
void *cb_ctx;
int cert_in_cb;
+
+ char *ocsp_stapling_response;
};
struct tls_connection {
@@ -133,6 +135,7 @@ void tls_deinit(void *ssl_ctx)
if (global->params_set)
gnutls_certificate_free_credentials(global->xcred);
os_free(global->session_data);
+ os_free(global->ocsp_stapling_response);
os_free(global);
}
@@ -292,6 +295,14 @@ int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* TODO */
+ return NULL;
+}
+
+
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
struct tls_global *global = ssl_ctx;
@@ -343,10 +354,25 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
int ret;
+ const char *err;
+ char prio_buf[100];
+ const char *prio = NULL;
if (conn == NULL || params == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: ocsp=3 not supported");
+ return -1;
+ }
+
+ if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: tls_ext_cert_check=1 not supported");
+ return -1;
+ }
+
if (params->subject_match) {
wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
return -1;
@@ -382,12 +408,66 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
conn->flags = params->flags;
+ if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
+ TLS_CONN_DISABLE_TLSv1_1 |
+ TLS_CONN_DISABLE_TLSv1_2)) {
+ os_snprintf(prio_buf, sizeof(prio_buf),
+ "NORMAL:-VERS-SSL3.0%s%s%s",
+ params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
+ ":-VERS-TLS1.0" : "",
+ params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
+ ":-VERS-TLS1.1" : "",
+ params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
+ ":-VERS-TLS1.2" : "");
+ prio = prio_buf;
+ }
+
if (params->openssl_ciphers) {
- wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
+ prio = "SUITEB128";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "SUITEB192") == 0) {
+ prio = "SUITEB192";
+ } else if ((params->flags & TLS_CONN_SUITEB) &&
+ os_strcmp(params->openssl_ciphers,
+ "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "DHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
+ } else if (params->flags & TLS_CONN_SUITEB) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
+ }
+
+ if (prio) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
+ ret = gnutls_priority_set_direct(conn->session, prio, &err);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "GnuTLS: Priority string failure at '%s'",
+ err);
+ return -1;
+ }
+ }
+
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: openssl_ecdh_curves not supported");
return -1;
}
- /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
+ /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
* to force peer validation(?) */
if (params->ca_cert) {
@@ -410,6 +490,13 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
gnutls_strerror(ret));
return -1;
}
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read CA cert '%s' in PEM format",
+ params->ca_cert);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read CA cert '%s' in DER format",
+ params->ca_cert);
}
} else if (params->ca_cert_blob) {
gnutls_datum_t ca;
@@ -457,6 +544,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
if (params->client_cert && params->private_key) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
+ params->client_cert, params->private_key);
#if GNUTLS_VERSION_NUMBER >= 0x03010b
ret = gnutls_certificate_set_x509_key_file2(
conn->xcred, params->client_cert, params->private_key,
@@ -468,8 +558,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
GNUTLS_X509_FMT_DER);
#endif
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
- "in DER format: %s", gnutls_strerror(ret));
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
+ gnutls_strerror(ret));
#if GNUTLS_VERSION_NUMBER >= 0x03010b
ret = gnutls_certificate_set_x509_key_file2(
conn->xcred, params->client_cert,
@@ -486,11 +577,19 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
gnutls_strerror(ret));
return ret;
}
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read client cert/key in PEM format");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read client cert/key in DER format");
}
} else if (params->private_key) {
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
+ params->private_key);
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
params->private_key_passwd);
@@ -596,12 +695,53 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
+ gnutls_datum_t *resp)
+{
+ struct tls_global *global = ptr;
+ char *cached;
+ size_t len;
+
+ if (!global->ocsp_stapling_response) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
+ return GNUTLS_E_NO_CERTIFICATE_STATUS;
+ }
+
+ cached = os_readfile(global->ocsp_stapling_response, &len);
+ if (!cached) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP status callback - could not read response file (%s)",
+ global->ocsp_stapling_response);
+ return GNUTLS_E_NO_CERTIFICATE_STATUS;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP status callback - send cached response");
+ resp->data = gnutls_malloc(len);
+ if (!resp->data) {
+ os_free(resp);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ os_memcpy(resp->data, cached, len);
+ resp->size = len;
+ os_free(cached);
+
+ return GNUTLS_E_SUCCESS;
+}
+#endif /* 3.1.3 */
+
+
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
struct tls_global *global = tls_ctx;
int ret;
+ if (params->check_cert_subject)
+ return -1; /* not yet supported */
+
/* Currently, global parameters are only set when running in server
* mode. */
global->server = 1;
@@ -690,6 +830,17 @@ int tls_global_set_params(void *tls_ctx,
}
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+ os_free(global->ocsp_stapling_response);
+ if (params->ocsp_stapling_response)
+ global->ocsp_stapling_response =
+ os_strdup(params->ocsp_stapling_response);
+ else
+ global->ocsp_stapling_response = NULL;
+ gnutls_certificate_set_ocsp_status_request_function(
+ global->xcred, server_ocsp_status_req, global);
+#endif /* 3.1.3 */
+
global->params_set = 1;
return 0;
@@ -700,7 +851,7 @@ fail:
}
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
{
/* TODO */
return 0;
@@ -746,15 +897,31 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
{
- if (conn == NULL || conn->session == NULL || skip_keyblock)
+ if (conn == NULL || conn->session == NULL)
return -1;
+#if GNUTLS_VERSION_NUMBER >= 0x030404
+ return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
+ context_len, (const char *) context,
+ out_len, (char *) out);
+#else /* 3.4.4 */
+ if (context)
+ return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
- server_random_first, 0, NULL, out_len, (char *) out);
+ 0 /* client_random first */, 0, NULL, out_len,
+ (char *) out);
+#endif /* 3.4.4 */
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ return -1;
}
@@ -919,6 +1086,52 @@ ocsp_error:
}
+static int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
+ int full)
+{
+ int res = -1;
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ if (full)
+ res = gnutls_x509_crt_check_hostname2(
+ cert, match,
+ GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
+#endif /* >= 3.3.0 */
+ if (res == -1)
+ res = gnutls_x509_crt_check_hostname(cert, match);
+
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
+ full ? "": "suffix ", match, res);
+ return res;
+}
+
+
+static int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
+ int full)
+{
+ char *values, *token, *context = NULL;
+ int ret = 0;
+
+ if (!os_strchr(match, ';'))
+ return tls_match_suffix_helper(cert, match, full);
+
+ values = os_strdup(match);
+ if (!values)
+ return 0;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = str_token(values, ";", &context))) {
+ if (tls_match_suffix_helper(cert, token, full)) {
+ ret = 1;
+ break;
+ }
+ }
+
+ os_free(values);
+ return ret;
+}
+
+
static int tls_connection_verify_peer(gnutls_session_t session)
{
struct tls_connection *conn;
@@ -1114,8 +1327,7 @@ static int tls_connection_verify_peer(gnutls_session_t session)
if (i == 0) {
if (conn->suffix_match &&
- !gnutls_x509_crt_check_hostname(
- cert, conn->suffix_match)) {
+ !tls_match_suffix(cert, conn->suffix_match, 0)) {
wpa_printf(MSG_WARNING,
"TLS: Domain suffix match '%s' not found",
conn->suffix_match);
@@ -1131,9 +1343,7 @@ static int tls_connection_verify_peer(gnutls_session_t session)
#if GNUTLS_VERSION_NUMBER >= 0x030300
if (conn->domain_match &&
- !gnutls_x509_crt_check_hostname2(
- cert, conn->domain_match,
- GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
+ !tls_match_suffix(cert, conn->domain_match, 1)) {
wpa_printf(MSG_WARNING,
"TLS: Domain match '%s' not found",
conn->domain_match);
@@ -1262,6 +1472,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
ret = gnutls_handshake(conn->session);
if (ret < 0) {
gnutls_alert_description_t alert;
+ union tls_event_data ev;
switch (ret) {
case GNUTLS_E_AGAIN:
@@ -1272,14 +1483,29 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
conn->push_buf = wpabuf_alloc(0);
}
break;
+ case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
+ wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
+ if (conn->global->event_cb) {
+ os_memset(&ev, 0, sizeof(ev));
+ ev.alert.is_local = 1;
+ ev.alert.type = "fatal";
+ ev.alert.description = "insufficient security";
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_ALERT, &ev);
+ }
+ /*
+ * Could send a TLS Alert to the server, but for now,
+ * simply terminate handshake.
+ */
+ conn->failed++;
+ conn->write_alerts++;
+ break;
case GNUTLS_E_FATAL_ALERT_RECEIVED:
alert = gnutls_alert_get(conn->session);
wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
__func__, gnutls_alert_get_name(alert));
conn->read_alerts++;
if (conn->global->event_cb != NULL) {
- union tls_event_data ev;
-
os_memset(&ev, 0, sizeof(ev));
ev.alert.is_local = 0;
ev.alert.type = gnutls_alert_get_name(alert);
@@ -1430,16 +1656,53 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
- return -1;
+ gnutls_protocol_t ver;
+
+ ver = gnutls_protocol_get_version(conn->session);
+ if (ver == GNUTLS_TLS1_0)
+ os_strlcpy(buf, "TLSv1", buflen);
+ else if (ver == GNUTLS_TLS1_1)
+ os_strlcpy(buf, "TLSv1.1", buflen);
+ else if (ver == GNUTLS_TLS1_2)
+ os_strlcpy(buf, "TLSv1.2", buflen);
+ else
+ return -1;
+ return 0;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
- buf[0] = '\0';
+ gnutls_cipher_algorithm_t cipher;
+ gnutls_kx_algorithm_t kx;
+ gnutls_mac_algorithm_t mac;
+ const char *kx_str, *cipher_str, *mac_str;
+ int res;
+
+ cipher = gnutls_cipher_get(conn->session);
+ cipher_str = gnutls_cipher_get_name(cipher);
+ if (!cipher_str)
+ cipher_str = "";
+
+ kx = gnutls_kx_get(conn->session);
+ kx_str = gnutls_kx_get_name(kx);
+ if (!kx_str)
+ kx_str = "";
+
+ mac = gnutls_mac_get(conn->session);
+ mac_str = gnutls_mac_get_name(mac);
+ if (!mac_str)
+ mac_str = "";
+
+ if (kx == GNUTLS_KX_RSA)
+ res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
+ else
+ res = os_snprintf(buf, buflen, "%s-%s-%s",
+ kx_str, cipher_str, mac_str);
+ if (os_snprintf_error(buflen, res))
+ return -1;
+
return 0;
}
diff --git a/contrib/wpa/src/crypto/tls_internal.c b/contrib/wpa/src/crypto/tls_internal.c
index 704751d..8095b43 100644
--- a/contrib/wpa/src/crypto/tls_internal.c
+++ b/contrib/wpa/src/crypto/tls_internal.c
@@ -1,6 +1,6 @@
/*
* TLS interface functions and an internal TLS implementation
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,6 +23,11 @@ struct tls_global {
int server;
struct tlsv1_credentials *server_cred;
int check_crl;
+
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
+ int cert_in_cb;
};
struct tls_connection {
@@ -51,6 +56,11 @@ void * tls_init(const struct tls_config *conf)
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
+ if (conf) {
+ global->event_cb = conf->event_cb;
+ global->cb_ctx = conf->cb_ctx;
+ global->cert_in_cb = conf->cert_in_cb;
+ }
return global;
}
@@ -64,10 +74,12 @@ void tls_deinit(void *ssl_ctx)
tlsv1_client_global_deinit();
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
- tlsv1_cred_free(global->server_cred);
tlsv1_server_global_deinit();
#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ tlsv1_cred_free(global->server_cred);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
os_free(global);
}
@@ -95,6 +107,8 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
os_free(conn);
return NULL;
}
+ tlsv1_client_set_cb(conn->client, global->event_cb,
+ global->cb_ctx, global->cert_in_cb);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -163,6 +177,14 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* TODO */
+ return NULL;
+}
+
+
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
@@ -186,6 +208,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (conn->client == NULL)
return -1;
+ if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+ wpa_printf(MSG_INFO,
+ "TLS: tls_ext_cert_check=1 not supported");
+ return -1;
+ }
+
cred = tlsv1_cred_alloc();
if (cred == NULL)
return -1;
@@ -220,6 +248,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO, "TLS: openssl_ecdh_curves not supported");
+ tlsv1_cred_free(cred);
+ return -1;
+ }
+
if (tlsv1_set_ca_cert(cred, params->ca_cert,
params->ca_cert_blob, params->ca_cert_blob_len,
params->ca_path)) {
@@ -259,8 +293,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
- tlsv1_client_set_time_checks(
- conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+ tlsv1_client_set_flags(conn->client, params->flags);
return 0;
#else /* CONFIG_TLS_INTERNAL_CLIENT */
@@ -276,6 +309,9 @@ int tls_global_set_params(void *tls_ctx,
struct tls_global *global = tls_ctx;
struct tlsv1_credentials *cred;
+ if (params->check_cert_subject)
+ return -1; /* not yet supported */
+
/* Currently, global parameters are only set when running in server
* mode. */
global->server = 1;
@@ -312,6 +348,13 @@ int tls_global_set_params(void *tls_ctx,
return -1;
}
+ if (params->ocsp_stapling_response)
+ cred->ocsp_stapling_response =
+ os_strdup(params->ocsp_stapling_response);
+ if (params->ocsp_stapling_response_multi)
+ cred->ocsp_stapling_response_multi =
+ os_strdup(params->ocsp_stapling_response_multi);
+
return 0;
#else /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
@@ -319,7 +362,7 @@ int tls_global_set_params(void *tls_ctx,
}
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
{
struct tls_global *global = tls_ctx;
global->check_crl = check_crl;
@@ -368,9 +411,10 @@ static int tls_get_keyblock_size(struct tls_connection *conn)
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, int server_random_first,
+ int skip_keyblock, u8 *out, size_t out_len)
{
int ret = -1, skip = 0;
u8 *tmp_out = NULL;
@@ -388,16 +432,16 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
- ret = tlsv1_client_prf(conn->client, label,
- server_random_first,
- _out, out_len);
+ ret = tlsv1_client_prf(conn->client, label, context,
+ context_len, server_random_first,
+ _out, skip + out_len);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
- ret = tlsv1_server_prf(conn->server, label,
- server_random_first,
- _out, out_len);
+ ret = tlsv1_server_prf(conn->server, label, context,
+ context_len, server_random_first,
+ _out, skip + out_len);
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
if (ret == 0 && skip_keyblock)
@@ -408,6 +452,23 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
}
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
+{
+ return tls_connection_prf(tls_ctx, conn, label, context, context_len,
+ 0, 0, out, out_len);
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ return tls_connection_prf(tls_ctx, conn, "key expansion", NULL, 0,
+ 1, 1, out, out_len);
+}
+
+
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
@@ -621,7 +682,12 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
+ if (conn == NULL)
+ return -1;
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_get_version(conn->client, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
return -1;
}
@@ -666,12 +732,20 @@ int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_failed(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_read_alerts(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
@@ -679,6 +753,10 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_write_alerts(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
diff --git a/contrib/wpa/src/crypto/tls_none.c b/contrib/wpa/src/crypto/tls_none.c
index ae392ad..6d6fb0c 100644
--- a/contrib/wpa/src/crypto/tls_none.c
+++ b/contrib/wpa/src/crypto/tls_none.c
@@ -45,6 +45,13 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
return -1;
@@ -65,7 +72,7 @@ int tls_global_set_params(void *tls_ctx,
}
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
{
return -1;
}
@@ -86,9 +93,16 @@ int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
+{
+ return -1;
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
{
return -1;
}
diff --git a/contrib/wpa/src/crypto/tls_openssl.c b/contrib/wpa/src/crypto/tls_openssl.c
index 8b7b47b..b0c23ae 100644
--- a/contrib/wpa/src/crypto/tls_openssl.c
+++ b/contrib/wpa/src/crypto/tls_openssl.c
@@ -18,6 +18,7 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
+#include <openssl/opensslv.h>
#include <openssl/pkcs12.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_NO_ENGINE
@@ -35,12 +36,12 @@
#include "sha1.h"
#include "sha256.h"
#include "tls.h"
+#include "tls_openssl.h"
-#if OPENSSL_VERSION_NUMBER < 0x10000000L
-/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
- * deprecated. However, OpenSSL 0.9.8 doesn't include
- * ERR_remove_thread_state. */
-#define ERR_remove_thread_state(tid) ERR_remove_state(0)
+#if !defined(CONFIG_FIPS) && \
+ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST))
+#define OPENSSL_NEED_EAP_FAST_PRF
#endif
#if defined(OPENSSL_IS_BORINGSSL)
@@ -57,6 +58,69 @@ typedef int stack_index_t;
#endif /* OPENSSL_NO_TLSEXT */
#endif /* SSL_set_tlsext_status_type */
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
+ !defined(BORINGSSL_API_VERSION)
+/*
+ * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
+ * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
+ * older versions.
+ */
+
+static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
+ size_t outlen)
+{
+ if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+ return 0;
+ os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+ return SSL3_RANDOM_SIZE;
+}
+
+
+static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
+ size_t outlen)
+{
+ if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+ return 0;
+ os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
+ return SSL3_RANDOM_SIZE;
+}
+
+
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
+static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
+ unsigned char *out, size_t outlen)
+{
+ if (!session || session->master_key_length < 0 ||
+ (size_t) session->master_key_length > outlen)
+ return 0;
+ if ((size_t) session->master_key_length < outlen)
+ outlen = session->master_key_length;
+ os_memcpy(out, session->master_key, outlen);
+ return outlen;
+}
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
+
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#ifdef CONFIG_SUITEB
+static int RSA_bits(const RSA *r)
+{
+ return BN_num_bits(r->n);
+}
+#endif /* CONFIG_SUITEB */
+
+
+static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+ return ASN1_STRING_data((ASN1_STRING *) x);
+}
+#endif
+
#ifdef ANDROID
#include <openssl/pem.h>
#include <keystore/keystore_get.h>
@@ -71,6 +135,66 @@ static BIO * BIO_from_keystore(const char *key)
free(value);
return bio;
}
+
+
+static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
+{
+ BIO *bio = BIO_from_keystore(key_alias);
+ STACK_OF(X509_INFO) *stack = NULL;
+ stack_index_t i;
+
+ if (bio) {
+ stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ }
+
+ if (!stack) {
+ wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
+ key_alias);
+ return -1;
+ }
+
+ for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+ X509_INFO *info = sk_X509_INFO_value(stack, i);
+
+ if (info->x509)
+ X509_STORE_add_cert(ctx, info->x509);
+ if (info->crl)
+ X509_STORE_add_crl(ctx, info->crl);
+ }
+
+ sk_X509_INFO_pop_free(stack, X509_INFO_free);
+
+ return 0;
+}
+
+
+static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
+ const char *encoded_key_alias)
+{
+ int rc = -1;
+ int len = os_strlen(encoded_key_alias);
+ unsigned char *decoded_alias;
+
+ if (len & 1) {
+ wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
+ encoded_key_alias);
+ return rc;
+ }
+
+ decoded_alias = os_malloc(len / 2 + 1);
+ if (decoded_alias) {
+ if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
+ decoded_alias[len / 2] = '\0';
+ rc = tls_add_ca_from_keystore(
+ ctx, (const char *) decoded_alias);
+ }
+ os_free(decoded_alias);
+ }
+
+ return rc;
+}
+
#endif /* ANDROID */
static int tls_openssl_ref_count = 0;
@@ -90,18 +214,26 @@ static struct tls_context *tls_global = NULL;
struct tls_data {
SSL_CTX *ssl;
unsigned int tls_session_lifetime;
+ int check_crl;
+ int check_crl_strict;
+ char *ca_cert;
+ unsigned int crl_reload_interval;
+ struct os_reltime crl_last_reload;
+ char *check_cert_subject;
};
struct tls_connection {
struct tls_context *context;
+ struct tls_data *data;
SSL_CTX *ssl_ctx;
SSL *ssl;
BIO *ssl_in, *ssl_out;
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
ENGINE *engine; /* functional reference to the engine */
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
char *subject_match, *altsubject_match, *suffix_match, *domain_match;
+ char *check_cert_subject;
int read_alerts, write_alerts, failed;
tls_session_ticket_cb session_ticket_cb;
@@ -116,6 +248,8 @@ struct tls_connection {
unsigned int server_cert_only:1;
unsigned int invalid_hb_used:1;
unsigned int success_data:1;
+ unsigned int client_hello_generated:1;
+ unsigned int server:1;
u8 srv_cert_hash[32];
@@ -125,10 +259,11 @@ struct tls_connection {
X509 *peer_issuer;
X509 *peer_issuer_issuer;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
unsigned char client_random[SSL3_RANDOM_SIZE];
unsigned char server_random[SSL3_RANDOM_SIZE];
-#endif
+
+ u16 cipher_suite;
+ int server_dh_prime_len;
};
@@ -176,6 +311,36 @@ static void tls_show_errors(int level, const char *func, const char *txt)
#endif /* CONFIG_NO_STDOUT_DEBUG */
+static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
+{
+ int flags;
+ X509_STORE *store;
+
+ store = X509_STORE_new();
+ if (!store) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: %s - failed to allocate new certificate store",
+ __func__);
+ return NULL;
+ }
+
+ if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to load root certificates");
+ X509_STORE_free(store);
+ return NULL;
+ }
+
+ flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
+ if (check_crl == 2)
+ flags |= X509_V_FLAG_CRL_CHECK_ALL;
+
+ X509_STORE_set_flags(store, flags);
+
+ return store;
+}
+
+
#ifdef CONFIG_NATIVE_WINDOWS
/* Windows CryptoAPI and access to certificate stores */
@@ -526,7 +691,8 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
"system certificate store: subject='%s'", buf);
- if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
+ cert)) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to add ca_cert to OpenSSL "
"certificate store");
@@ -624,10 +790,16 @@ static int tls_engine_load_dynamic_generic(const char *pre[],
engine = ENGINE_by_id(id);
if (engine) {
- ENGINE_free(engine);
wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
"available", id);
- return 0;
+ /*
+ * If it was auto-loaded by ENGINE_by_id() we might still
+ * need to tell it which PKCS#11 module to use in legacy
+ * (non-p11-kit) environments. Do so now; even if it was
+ * properly initialised before, setting it again will be
+ * harmless.
+ */
+ goto found;
}
ERR_clear_error();
@@ -664,7 +836,7 @@ static int tls_engine_load_dynamic_generic(const char *pre[],
id, ERR_error_string(ERR_get_error(), NULL));
return -1;
}
-
+ found:
while (post && post[0]) {
wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
@@ -808,6 +980,9 @@ void * tls_init(const struct tls_config *conf)
}
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
SSL_load_error_strings();
SSL_library_init();
#ifndef OPENSSL_NO_SHA256
@@ -829,6 +1004,7 @@ void * tls_init(const struct tls_config *conf)
#endif /* OPENSSL_NO_RC2 */
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
+#endif /* < 1.1.0 */
} else {
context = tls_context_new(conf);
if (context == NULL)
@@ -849,15 +1025,26 @@ void * tls_init(const struct tls_config *conf)
os_free(tls_global);
tls_global = NULL;
}
+ os_free(data);
return NULL;
}
data->ssl = ssl;
- if (conf)
+ if (conf) {
data->tls_session_lifetime = conf->tls_session_lifetime;
+ data->crl_reload_interval = conf->crl_reload_interval;
+ }
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+#ifdef SSL_MODE_NO_AUTO_CHAIN
+ /* Number of deployed use cases assume the default OpenSSL behavior of
+ * auto chaining the local certificate is in use. BoringSSL removed this
+ * functionality by default, so we need to restore it here to avoid
+ * breaking existing use cases. */
+ SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
+#endif /* SSL_MODE_NO_AUTO_CHAIN */
+
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
SSL_CTX_set_app_data(ssl, context);
if (data->tls_session_lifetime > 0) {
@@ -885,8 +1072,10 @@ void * tls_init(const struct tls_config *conf)
#ifndef OPENSSL_NO_ENGINE
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_load_ENGINE_strings();
ENGINE_load_dynamic();
+#endif /* OPENSSL_VERSION_NUMBER */
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
@@ -903,7 +1092,7 @@ void * tls_init(const struct tls_config *conf)
if (conf && conf->openssl_ciphers)
ciphers = conf->openssl_ciphers;
else
- ciphers = "DEFAULT:!EXP:!LOW";
+ ciphers = TLS_DEFAULT_CIPHERS;
if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
wpa_printf(MSG_ERROR,
"OpenSSL: Failed to set cipher string '%s'",
@@ -925,10 +1114,14 @@ void tls_deinit(void *ssl_ctx)
os_free(context);
if (data->tls_session_lifetime > 0)
SSL_CTX_flush_sessions(ssl, 0);
+ os_free(data->ca_cert);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
@@ -936,12 +1129,14 @@ void tls_deinit(void *ssl_ctx)
ERR_remove_thread_state(NULL);
ERR_free_strings();
EVP_cleanup();
+#endif /* < 1.1.0 */
os_free(tls_global->ocsp_stapling_response);
tls_global->ocsp_stapling_response = NULL;
os_free(tls_global);
tls_global = NULL;
}
+ os_free(data->check_cert_subject);
os_free(data);
}
@@ -967,10 +1162,32 @@ static int tls_is_pin_error(unsigned int err)
#endif /* OPENSSL_NO_ENGINE */
+#ifdef ANDROID
+/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
+EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
+#endif /* ANDROID */
+
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
const char *pin, const char *key_id,
const char *cert_id, const char *ca_cert_id)
{
+#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
+#if !defined(OPENSSL_NO_ENGINE)
+#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
+#endif
+ if (!key_id)
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ conn->engine = NULL;
+ conn->private_key = EVP_PKEY_from_keystore(key_id);
+ if (!conn->private_key) {
+ wpa_printf(MSG_ERROR,
+ "ENGINE: cannot load private key with id '%s' [%s]",
+ key_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ }
+#endif /* ANDROID && OPENSSL_IS_BORINGSSL */
+
#ifndef OPENSSL_NO_ENGINE
int ret = -1;
if (engine_id == NULL) {
@@ -1068,17 +1285,19 @@ err:
static void tls_engine_deinit(struct tls_connection *conn)
{
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
if (conn->private_key) {
EVP_PKEY_free(conn->private_key);
conn->private_key = NULL;
}
if (conn->engine) {
+#if !defined(OPENSSL_IS_BORINGSSL)
ENGINE_finish(conn->engine);
+#endif /* !OPENSSL_IS_BORINGSSL */
conn->engine = NULL;
}
-#endif /* OPENSSL_NO_ENGINE */
+#endif /* ANDROID || !OPENSSL_NO_ENGINE */
}
@@ -1097,14 +1316,186 @@ int tls_get_errors(void *ssl_ctx)
}
+static const char * openssl_content_type(int content_type)
+{
+ switch (content_type) {
+ case 20:
+ return "change cipher spec";
+ case 21:
+ return "alert";
+ case 22:
+ return "handshake";
+ case 23:
+ return "application data";
+ case 24:
+ return "heartbeat";
+ case 256:
+ return "TLS header info"; /* pseudo content type */
+ default:
+ return "?";
+ }
+}
+
+
+static const char * openssl_handshake_type(int content_type, const u8 *buf,
+ size_t len)
+{
+ if (content_type != 22 || !buf || len == 0)
+ return "";
+ switch (buf[0]) {
+ case 0:
+ return "hello request";
+ case 1:
+ return "client hello";
+ case 2:
+ return "server hello";
+ case 3:
+ return "hello verify request";
+ case 4:
+ return "new session ticket";
+ case 5:
+ return "end of early data";
+ case 6:
+ return "hello retry request";
+ case 8:
+ return "encrypted extensions";
+ case 11:
+ return "certificate";
+ case 12:
+ return "server key exchange";
+ case 13:
+ return "certificate request";
+ case 14:
+ return "server hello done";
+ case 15:
+ return "certificate verify";
+ case 16:
+ return "client key exchange";
+ case 20:
+ return "finished";
+ case 21:
+ return "certificate url";
+ case 22:
+ return "certificate status";
+ case 23:
+ return "supplemental data";
+ case 24:
+ return "key update";
+ case 254:
+ return "message hash";
+ default:
+ return "?";
+ }
+}
+
+
+#ifdef CONFIG_SUITEB
+
+static void check_server_hello(struct tls_connection *conn,
+ const u8 *pos, const u8 *end)
+{
+ size_t payload_len, id_len;
+
+ /*
+ * Parse ServerHello to get the selected cipher suite since OpenSSL does
+ * not make it cleanly available during handshake and we need to know
+ * whether DHE was selected.
+ */
+
+ if (end - pos < 3)
+ return;
+ payload_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) < payload_len)
+ return;
+ end = pos + payload_len;
+
+ /* Skip Version and Random */
+ if (end - pos < 2 + SSL3_RANDOM_SIZE)
+ return;
+ pos += 2 + SSL3_RANDOM_SIZE;
+
+ /* Skip Session ID */
+ if (end - pos < 1)
+ return;
+ id_len = *pos++;
+ if ((size_t) (end - pos) < id_len)
+ return;
+ pos += id_len;
+
+ if (end - pos < 2)
+ return;
+ conn->cipher_suite = WPA_GET_BE16(pos);
+ wpa_printf(MSG_DEBUG, "OpenSSL: Server selected cipher suite 0x%x",
+ conn->cipher_suite);
+}
+
+
+static void check_server_key_exchange(SSL *ssl, struct tls_connection *conn,
+ const u8 *pos, const u8 *end)
+{
+ size_t payload_len;
+ u16 dh_len;
+ BIGNUM *p;
+ int bits;
+
+ if (!(conn->flags & TLS_CONN_SUITEB))
+ return;
+
+ /* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
+ if (conn->cipher_suite != 0x9f)
+ return;
+
+ if (end - pos < 3)
+ return;
+ payload_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) < payload_len)
+ return;
+ end = pos + payload_len;
+
+ if (end - pos < 2)
+ return;
+ dh_len = WPA_GET_BE16(pos);
+ pos += 2;
+
+ if ((size_t) (end - pos) < dh_len)
+ return;
+ p = BN_bin2bn(pos, dh_len, NULL);
+ if (!p)
+ return;
+
+ bits = BN_num_bits(p);
+ BN_free(p);
+
+ conn->server_dh_prime_len = bits;
+ wpa_printf(MSG_DEBUG, "OpenSSL: Server DH prime length: %d bits",
+ conn->server_dh_prime_len);
+}
+
+#endif /* CONFIG_SUITEB */
+
+
static void tls_msg_cb(int write_p, int version, int content_type,
const void *buf, size_t len, SSL *ssl, void *arg)
{
struct tls_connection *conn = arg;
const u8 *pos = buf;
- wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d",
- write_p ? "TX" : "RX", version, content_type);
+ if (write_p == 2) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: session ver=0x%x content_type=%d",
+ version, content_type);
+ wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
+ write_p ? "TX" : "RX", version, content_type,
+ openssl_content_type(content_type),
+ openssl_handshake_type(content_type, buf, len));
wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
if (content_type == 24 && len >= 3 && pos[0] == 1) {
size_t payload_len = WPA_GET_BE16(pos + 1);
@@ -1113,6 +1504,18 @@ static void tls_msg_cb(int write_p, int version, int content_type,
conn->invalid_hb_used = 1;
}
}
+
+#ifdef CONFIG_SUITEB
+ /*
+ * Need to parse these handshake messages to be able to check DH prime
+ * length since OpenSSL does not expose the new cipher suite and DH
+ * parameters during handshake (e.g., for cert_cb() callback).
+ */
+ if (content_type == 22 && pos && len > 0 && pos[0] == 2)
+ check_server_hello(conn, pos + 1, pos + len);
+ if (content_type == 22 && pos && len > 0 && pos[0] == 12)
+ check_server_key_exchange(ssl, conn, pos + 1, pos + len);
+#endif /* CONFIG_SUITEB */
}
@@ -1122,11 +1525,32 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
SSL_CTX *ssl = data->ssl;
struct tls_connection *conn;
long options;
+ X509_STORE *new_cert_store;
+ struct os_reltime now;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
+ /* Replace X509 store if it is time to update CRL. */
+ if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
+ os_reltime_expired(&now, &data->crl_last_reload,
+ data->crl_reload_interval)) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Flushing X509 store with ca_cert file");
+ new_cert_store = tls_crl_cert_reload(data->ca_cert,
+ data->check_crl);
+ if (!new_cert_store) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Error replacing X509 store with ca_cert file");
+ } else {
+ /* Replace old store */
+ SSL_CTX_set_cert_store(ssl, new_cert_store);
+ data->crl_last_reload = now;
+ }
+ }
+
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->data = data;
conn->ssl_ctx = ssl;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
@@ -1190,6 +1614,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
os_free(conn->altsubject_match);
os_free(conn->suffix_match);
os_free(conn->domain_match);
+ os_free(conn->check_cert_subject);
os_free(conn->session_ticket);
os_free(conn);
}
@@ -1201,6 +1626,31 @@ int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ ASN1_INTEGER *ser;
+ char *serial_num;
+ size_t len;
+
+ if (!conn->peer_cert)
+ return NULL;
+
+ ser = X509_get_serialNumber(conn->peer_cert);
+ if (!ser)
+ return NULL;
+
+ len = ASN1_STRING_length(ser) * 2 + 1;
+ serial_num = os_malloc(len);
+ if (!serial_num)
+ return NULL;
+ wpa_snprintf_hex_uppercase(serial_num, len,
+ ASN1_STRING_get0_data(ser),
+ ASN1_STRING_length(ser));
+ return serial_num;
+}
+
+
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
@@ -1234,6 +1684,8 @@ static int tls_match_altsubject_component(X509 *cert, int type,
found++;
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
+
return found;
}
@@ -1283,9 +1735,9 @@ static int tls_match_altsubject(X509 *cert, const char *match)
#ifndef CONFIG_NATIVE_WINDOWS
static int domain_suffix_match(const u8 *val, size_t len, const char *match,
- int full)
+ size_t match_len, int full)
{
- size_t i, match_len;
+ size_t i;
/* Check for embedded nuls that could mess up suffix matching */
for (i = 0; i < len; i++) {
@@ -1295,7 +1747,6 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match,
}
}
- match_len = os_strlen(match);
if (match_len > len || (full && match_len != len))
return 0;
@@ -1315,12 +1766,223 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match,
#endif /* CONFIG_NATIVE_WINDOWS */
-static int tls_match_suffix(X509 *cert, const char *match, int full)
+struct tls_dn_field_order_cnt {
+ u8 cn;
+ u8 c;
+ u8 l;
+ u8 st;
+ u8 o;
+ u8 ou;
+ u8 email;
+};
+
+
+static int get_dn_field_index(const struct tls_dn_field_order_cnt *dn_cnt,
+ int nid)
+{
+ switch (nid) {
+ case NID_commonName:
+ return dn_cnt->cn;
+ case NID_countryName:
+ return dn_cnt->c;
+ case NID_localityName:
+ return dn_cnt->l;
+ case NID_stateOrProvinceName:
+ return dn_cnt->st;
+ case NID_organizationName:
+ return dn_cnt->o;
+ case NID_organizationalUnitName:
+ return dn_cnt->ou;
+ case NID_pkcs9_emailAddress:
+ return dn_cnt->email;
+ default:
+ wpa_printf(MSG_ERROR,
+ "TLS: Unknown NID '%d' in check_cert_subject",
+ nid);
+ return -1;
+ }
+}
+
+
+/**
+ * match_dn_field - Match configuration DN field against Certificate DN field
+ * @cert: Certificate
+ * @nid: NID of DN field
+ * @field: Field name
+ * @value DN field value which is passed from configuration
+ * e.g., if configuration have C=US and this argument will point to US.
+ * @dn_cnt: DN matching context
+ * Returns: 1 on success and 0 on failure
+ */
+static int match_dn_field(const X509 *cert, int nid, const char *field,
+ const char *value,
+ const struct tls_dn_field_order_cnt *dn_cnt)
+{
+ int i, ret = 0, len, config_dn_field_index, match_index = 0;
+ X509_NAME *name;
+
+ len = os_strlen(value);
+ name = X509_get_subject_name((X509 *) cert);
+
+ /* Assign incremented cnt for every field of DN to check DN field in
+ * right order */
+ config_dn_field_index = get_dn_field_index(dn_cnt, nid);
+ if (config_dn_field_index < 0)
+ return 0;
+
+ /* Fetch value based on NID */
+ for (i = -1; (i = X509_NAME_get_index_by_NID(name, nid, i)) > -1;) {
+ X509_NAME_ENTRY *e;
+ ASN1_STRING *cn;
+
+ e = X509_NAME_get_entry(name, i);
+ if (!e)
+ continue;
+
+ cn = X509_NAME_ENTRY_get_data(e);
+ if (!cn)
+ continue;
+
+ match_index++;
+
+ /* check for more than one DN field with same name */
+ if (match_index != config_dn_field_index)
+ continue;
+
+ /* Check wildcard at the right end side */
+ /* E.g., if OU=develop* mentioned in configuration, allow 'OU'
+ * of the subject in the client certificate to start with
+ * 'develop' */
+ if (len > 0 && value[len - 1] == '*') {
+ /* Compare actual certificate DN field value with
+ * configuration DN field value up to the specified
+ * length. */
+ ret = ASN1_STRING_length(cn) >= len - 1 &&
+ os_memcmp(ASN1_STRING_get0_data(cn), value,
+ len - 1) == 0;
+ } else {
+ /* Compare actual certificate DN field value with
+ * configuration DN field value */
+ ret = ASN1_STRING_length(cn) == len &&
+ os_memcmp(ASN1_STRING_get0_data(cn), value,
+ len) == 0;
+ }
+ if (!ret) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
+ field, value, ASN1_STRING_get0_data(cn));
+ }
+ break;
+ }
+
+ return ret;
+}
+
+
+/**
+ * get_value_from_field - Get value from DN field
+ * @cert: Certificate
+ * @field_str: DN field string which is passed from configuration file (e.g.,
+ * C=US)
+ * @dn_cnt: DN matching context
+ * Returns: 1 on success and 0 on failure
+ */
+static int get_value_from_field(const X509 *cert, char *field_str,
+ struct tls_dn_field_order_cnt *dn_cnt)
+{
+ int nid;
+ char *context = NULL, *name, *value;
+
+ if (os_strcmp(field_str, "*") == 0)
+ return 1; /* wildcard matches everything */
+
+ name = str_token(field_str, "=", &context);
+ if (!name)
+ return 0;
+
+ /* Compare all configured DN fields and assign nid based on that to
+ * fetch correct value from certificate subject */
+ if (os_strcmp(name, "CN") == 0) {
+ nid = NID_commonName;
+ dn_cnt->cn++;
+ } else if(os_strcmp(name, "C") == 0) {
+ nid = NID_countryName;
+ dn_cnt->c++;
+ } else if (os_strcmp(name, "L") == 0) {
+ nid = NID_localityName;
+ dn_cnt->l++;
+ } else if (os_strcmp(name, "ST") == 0) {
+ nid = NID_stateOrProvinceName;
+ dn_cnt->st++;
+ } else if (os_strcmp(name, "O") == 0) {
+ nid = NID_organizationName;
+ dn_cnt->o++;
+ } else if (os_strcmp(name, "OU") == 0) {
+ nid = NID_organizationalUnitName;
+ dn_cnt->ou++;
+ } else if (os_strcmp(name, "emailAddress") == 0) {
+ nid = NID_pkcs9_emailAddress;
+ dn_cnt->email++;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "TLS: Unknown field '%s' in check_cert_subject", name);
+ return 0;
+ }
+
+ value = str_token(field_str, "=", &context);
+ if (!value) {
+ wpa_printf(MSG_ERROR,
+ "TLS: Distinguished Name field '%s' value is not defined in check_cert_subject",
+ name);
+ return 0;
+ }
+
+ return match_dn_field(cert, nid, name, value, dn_cnt);
+}
+
+
+/**
+ * tls_match_dn_field - Match subject DN field with check_cert_subject
+ * @cert: Certificate
+ * @match: check_cert_subject string
+ * Returns: Return 1 on success and 0 on failure
+*/
+static int tls_match_dn_field(X509 *cert, const char *match)
+{
+ const char *token, *last = NULL;
+ char field[256];
+ struct tls_dn_field_order_cnt dn_cnt;
+
+ os_memset(&dn_cnt, 0, sizeof(dn_cnt));
+
+ /* Maximum length of each DN field is 255 characters */
+
+ /* Process each '/' delimited field */
+ while ((token = cstr_token(match, "/", &last))) {
+ if (last - token >= (int) sizeof(field)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Too long DN matching field value in '%s'",
+ match);
+ return 0;
+ }
+ os_memcpy(field, token, last - token);
+ field[last - token] = '\0';
+
+ if (!get_value_from_field(cert, field, &dn_cnt)) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No match for DN '%s'",
+ field);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static int tls_match_suffix_helper(X509 *cert, const char *match,
+ size_t match_len, int full)
{
-#ifdef CONFIG_NATIVE_WINDOWS
- /* wincrypt.h has conflicting X509_NAME definition */
- return -1;
-#else /* CONFIG_NATIVE_WINDOWS */
GENERAL_NAME *gen;
void *ext;
int i;
@@ -1342,13 +2004,15 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
gen->d.dNSName->data,
gen->d.dNSName->length);
if (domain_suffix_match(gen->d.dNSName->data,
- gen->d.dNSName->length, match, full) ==
- 1) {
+ gen->d.dNSName->length,
+ match, match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
full ? "Match" : "Suffix match");
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
return 1;
}
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
if (dns_name) {
wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
@@ -1372,8 +2036,8 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
continue;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
cn->data, cn->length);
- if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
- {
+ if (domain_suffix_match(cn->data, cn->length,
+ match, match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
full ? "Match" : "Suffix match");
return 1;
@@ -1383,6 +2047,25 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
full ? "": "suffix ");
return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int tls_match_suffix(X509 *cert, const char *match, int full)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ /* wincrypt.h has conflicting X509_NAME definition */
+ return -1;
+#else /* CONFIG_NATIVE_WINDOWS */
+ const char *token, *last = NULL;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = cstr_token(match, ";", &last))) {
+ if (tls_match_suffix_helper(cert, token, last - token, full))
+ return 1;
+ }
+
+ return 0;
#endif /* CONFIG_NATIVE_WINDOWS */
}
@@ -1481,6 +2164,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
GENERAL_NAME *gen;
void *ext;
stack_index_t i;
+ ASN1_INTEGER *ser;
+ char serial_num[128];
#ifdef CONFIG_SHA256
u8 hash[32];
#endif /* CONFIG_SHA256 */
@@ -1489,7 +2174,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cert_probe || context->cert_in_cb) {
+ if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+ context->cert_in_cb) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
@@ -1508,6 +2194,14 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
ev.peer_cert.depth = depth;
ev.peer_cert.subject = subject;
+ ser = X509_get_serialNumber(err_cert);
+ if (ser) {
+ wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
+ ASN1_STRING_get0_data(ser),
+ ASN1_STRING_length(ser));
+ ev.peer_cert.serial_num = serial_num;
+ }
+
ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
char *pos;
@@ -1544,6 +2238,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
pos += gen->d.ia5->length;
*pos = '\0';
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
for (alt = 0; alt < num_altsubject; alt++)
ev.peer_cert.altsubject[alt] = altsubject[alt];
@@ -1565,6 +2260,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
struct tls_connection *conn;
struct tls_context *context;
char *match, *altmatch, *suffix_match, *domain_match;
+ const char *check_cert_subject;
const char *err_str;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -1605,6 +2301,13 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
"time mismatch");
preverify_ok = 1;
}
+ if (!preverify_ok && !conn->data->check_crl_strict &&
+ (err == X509_V_ERR_CRL_HAS_EXPIRED ||
+ err == X509_V_ERR_CRL_NOT_YET_VALID)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Ignore certificate validity CRL time mismatch");
+ preverify_ok = 1;
+ }
err_str = X509_verify_cert_error_string(err);
@@ -1658,6 +2361,18 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
"err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
preverify_ok, err, err_str,
conn->ca_cert_verify, depth, buf);
+ check_cert_subject = conn->check_cert_subject;
+ if (!check_cert_subject)
+ check_cert_subject = conn->data->check_cert_subject;
+ if (check_cert_subject) {
+ if (depth == 0 &&
+ !tls_match_dn_field(err_cert, check_cert_subject)) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Distinguished Name",
+ TLS_FAIL_DN_MISMATCH);
+ }
+ }
if (depth == 0 && match && os_strstr(buf, match) == NULL) {
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
"match with '%s'", buf, match);
@@ -1701,7 +2416,64 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
TLS_FAIL_SERVER_CHAIN_PROBE);
}
- if (preverify_ok && context->event_cb != NULL)
+#ifdef CONFIG_SUITEB
+ if (conn->flags & TLS_CONN_SUITEB) {
+ EVP_PKEY *pk;
+ RSA *rsa;
+ int len = -1;
+
+ pk = X509_get_pubkey(err_cert);
+ if (pk) {
+ rsa = EVP_PKEY_get1_RSA(pk);
+ if (rsa) {
+ len = RSA_bits(rsa);
+ RSA_free(rsa);
+ }
+ EVP_PKEY_free(pk);
+ }
+
+ if (len >= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: RSA modulus size: %d bits", len);
+ if (len < 3072) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(
+ conn, err_cert, err,
+ depth, buf,
+ "Insufficient RSA modulus size",
+ TLS_FAIL_INSUFFICIENT_KEY_LEN);
+ }
+ }
+ }
+#endif /* CONFIG_SUITEB */
+
+#ifdef OPENSSL_IS_BORINGSSL
+ if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ preverify_ok) {
+ enum ocsp_result res;
+
+ res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+ conn->peer_issuer,
+ conn->peer_issuer_issuer);
+ if (res == OCSP_REVOKED) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "certificate revoked",
+ TLS_FAIL_REVOKED);
+ if (err == X509_V_OK)
+ X509_STORE_CTX_set_error(
+ x509_ctx, X509_V_ERR_CERT_REVOKED);
+ } else if (res != OCSP_GOOD &&
+ (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "bad certificate status response",
+ TLS_FAIL_UNSPECIFIED);
+ }
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ if (depth == 0 && preverify_ok && context->event_cb != NULL)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
@@ -1837,30 +2609,40 @@ static int tls_connection_ca_cert(struct tls_data *data,
}
#ifdef ANDROID
+ /* Single alias */
if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
- BIO *bio = BIO_from_keystore(&ca_cert[11]);
- STACK_OF(X509_INFO) *stack = NULL;
- stack_index_t i;
-
- if (bio) {
- stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
- BIO_free(bio);
- }
- if (!stack)
+ if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
+ &ca_cert[11]) < 0)
return -1;
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+ }
- for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
- X509_INFO *info = sk_X509_INFO_value(stack, i);
- if (info->x509) {
- X509_STORE_add_cert(ssl_ctx->cert_store,
- info->x509);
- }
- if (info->crl) {
- X509_STORE_add_crl(ssl_ctx->cert_store,
- info->crl);
+ /* Multiple aliases separated by space */
+ if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
+ char *aliases = os_strdup(&ca_cert[12]);
+ const char *delim = " ";
+ int rc = 0;
+ char *savedptr;
+ char *alias;
+
+ if (!aliases)
+ return -1;
+ alias = strtok_r(aliases, delim, &savedptr);
+ for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
+ if (tls_add_ca_from_keystore_encoded(
+ SSL_CTX_get_cert_store(ssl_ctx), alias)) {
+ wpa_printf(MSG_WARNING,
+ "OpenSSL: %s - Failed to add ca_cert %s from keystore",
+ __func__, alias);
+ rc = -1;
+ break;
}
}
- sk_X509_INFO_pop_free(stack, X509_INFO_free);
+ os_free(aliases);
+ if (rc)
+ return rc;
+
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
return 0;
}
@@ -1928,13 +2710,16 @@ static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
SSL_CTX_set_client_CA_list(ssl_ctx,
SSL_load_client_CA_file(ca_cert));
#endif /* OPENSSL_NO_STDIO */
+
+ os_free(data->ca_cert);
+ data->ca_cert = os_strdup(ca_cert);
}
return 0;
}
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
{
int flags;
@@ -1951,6 +2736,10 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
if (check_crl == 2)
flags |= X509_V_FLAG_CRL_CHECK_ALL;
X509_STORE_set_flags(cs, flags);
+
+ data->check_crl = check_crl;
+ data->check_crl_strict = strict;
+ os_get_reltime(&data->crl_last_reload);
}
return 0;
}
@@ -1960,7 +2749,8 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
const char *subject_match,
const char *altsubject_match,
const char *suffix_match,
- const char *domain_match)
+ const char *domain_match,
+ const char *check_cert_subject)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
@@ -1994,19 +2784,60 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
return -1;
}
+ os_free(conn->check_cert_subject);
+ conn->check_cert_subject = NULL;
+ if (check_cert_subject) {
+ conn->check_cert_subject = os_strdup(check_cert_subject);
+ if (!conn->check_cert_subject)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_SUITEB
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+static int suiteb_cert_cb(SSL *ssl, void *arg)
+{
+ struct tls_connection *conn = arg;
+
+ /*
+ * This cert_cb() is not really the best location for doing a
+ * constraint check for the ServerKeyExchange message, but this seems to
+ * be the only place where the current OpenSSL sequence can be
+ * terminated cleanly with an TLS alert going out to the server.
+ */
+
+ if (!(conn->flags & TLS_CONN_SUITEB))
+ return 1;
+
+ /* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
+ if (conn->cipher_suite != 0x9f)
+ return 1;
+
+ if (conn->server_dh_prime_len >= 3072)
+ return 1;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Server DH prime length (%d bits) not sufficient for Suite B RSA - reject handshake",
+ conn->server_dh_prime_len);
return 0;
}
+#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* CONFIG_SUITEB */
-static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
+static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
+ const char *openssl_ciphers)
{
+ SSL *ssl = conn->ssl;
+
#ifdef SSL_OP_NO_TICKET
if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_set_options(ssl, SSL_OP_NO_TICKET);
-#ifdef SSL_clear_options
else
SSL_clear_options(ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
#ifdef SSL_OP_NO_TLSv1
@@ -2027,6 +2858,165 @@ static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
else
SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
#endif /* SSL_OP_NO_TLSv1_2 */
+#ifdef SSL_OP_NO_TLSv1_3
+ if (flags & TLS_CONN_DISABLE_TLSv1_3)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
+#endif /* SSL_OP_NO_TLSv1_3 */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
+ TLS_CONN_ENABLE_TLSv1_1 |
+ TLS_CONN_ENABLE_TLSv1_2)) {
+ int version = 0;
+
+ /* Explicit request to enable TLS versions even if needing to
+ * override systemwide policies. */
+ if (flags & TLS_CONN_ENABLE_TLSv1_0) {
+ version = TLS1_VERSION;
+ } else if (flags & TLS_CONN_ENABLE_TLSv1_1) {
+ if (!(flags & TLS_CONN_DISABLE_TLSv1_0))
+ version = TLS1_1_VERSION;
+ } else if (flags & TLS_CONN_ENABLE_TLSv1_2) {
+ if (!(flags & (TLS_CONN_DISABLE_TLSv1_0 |
+ TLS_CONN_DISABLE_TLSv1_1)))
+ version = TLS1_2_VERSION;
+ }
+ if (!version) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid TLS version configuration");
+ return -1;
+ }
+
+ if (SSL_set_min_proto_version(ssl, version) != 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Failed to set minimum TLS version");
+ return -1;
+ }
+ }
+#endif /* >= 1.1.0 */
+
+#ifdef CONFIG_SUITEB
+#ifdef OPENSSL_IS_BORINGSSL
+ /* Start with defaults from BoringSSL */
+ SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, NULL, 0);
+#endif /* OPENSSL_IS_BORINGSSL */
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ if (flags & TLS_CONN_SUITEB_NO_ECDH) {
+ const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
+
+ if (openssl_ciphers) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Override ciphers for Suite B (no ECDH): %s",
+ openssl_ciphers);
+ ciphers = openssl_ciphers;
+ }
+ if (SSL_set_cipher_list(ssl, ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B ciphers");
+ return -1;
+ }
+ } else if (flags & TLS_CONN_SUITEB) {
+ EC_KEY *ecdh;
+ const char *ciphers =
+ "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
+ int nid[1] = { NID_secp384r1 };
+
+ if (openssl_ciphers) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Override ciphers for Suite B: %s",
+ openssl_ciphers);
+ ciphers = openssl_ciphers;
+ }
+ if (SSL_set_cipher_list(ssl, ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B ciphers");
+ return -1;
+ }
+
+ if (SSL_set1_curves(ssl, nid, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B curves");
+ return -1;
+ }
+
+ ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
+ if (!ecdh || SSL_set_tmp_ecdh(ssl, ecdh) != 1) {
+ EC_KEY_free(ecdh);
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH parameter");
+ return -1;
+ }
+ EC_KEY_free(ecdh);
+ }
+ if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
+#ifdef OPENSSL_IS_BORINGSSL
+ uint16_t sigalgs[1] = { SSL_SIGN_RSA_PKCS1_SHA384 };
+
+ if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
+ 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B sigalgs");
+ return -1;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ /* ECDSA+SHA384 if need to add EC support here */
+ if (SSL_set1_sigalgs_list(ssl, "RSA+SHA384") != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B sigalgs");
+ return -1;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
+ }
+#else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+ if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Suite B RSA case not supported with this OpenSSL version");
+ return -1;
+ }
+#endif /* OPENSSL_VERSION_NUMBER */
+
+#ifdef OPENSSL_IS_BORINGSSL
+ if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
+ uint16_t sigalgs[1] = { SSL_SIGN_ECDSA_SECP384R1_SHA384 };
+ int nid[1] = { NID_secp384r1 };
+
+ if (SSL_set1_curves(ssl, nid, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B curves");
+ return -1;
+ }
+
+ if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
+ 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B sigalgs");
+ return -1;
+ }
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
+ openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set openssl_ciphers '%s'",
+ openssl_ciphers);
+ return -1;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+#else /* CONFIG_SUITEB */
+ if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set openssl_ciphers '%s'",
+ openssl_ciphers);
+ return -1;
+ }
+#endif /* CONFIG_SUITEB */
+
+ return 0;
}
@@ -2050,7 +3040,8 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
}
- tls_set_conn_flags(conn->ssl, flags);
+ if (tls_set_conn_flags(conn, flags, NULL) < 0)
+ return -1;
conn->flags = flags;
SSL_set_accept_state(conn->ssl);
@@ -2082,6 +3073,17 @@ static int tls_connection_client_cert(struct tls_connection *conn,
if (client_cert == NULL && client_cert_blob == NULL)
return 0;
+#ifdef PKCS12_FUNCS
+#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
+ /*
+ * Clear previously set extra chain certificates, if any, from PKCS#12
+ * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
+ * chain properly.
+ */
+ SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
+#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+#endif /* PKCS12_FUNCS */
+
if (client_cert_blob &&
SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
client_cert_blob_len) == 1) {
@@ -2103,13 +3105,24 @@ static int tls_connection_client_cert(struct tls_connection *conn,
int ret = -1;
if (bio) {
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
- BIO_free(bio);
}
if (x509) {
if (SSL_use_certificate(conn->ssl, x509) == 1)
ret = 0;
X509_free(x509);
}
+
+ /* Read additional certificates into the chain. */
+ while (bio) {
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (x509) {
+ /* Takes ownership of x509 */
+ SSL_add0_chain_cert(conn->ssl, x509);
+ } else {
+ BIO_free(bio);
+ bio = NULL;
+ }
+ }
return ret;
}
#endif /* ANDROID */
@@ -2122,6 +3135,15 @@ static int tls_connection_client_cert(struct tls_connection *conn,
return 0;
}
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
+ if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
+ ERR_clear_error();
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
+ " --> OK");
+ return 0;
+ }
+#else
if (SSL_use_certificate_file(conn->ssl, client_cert,
SSL_FILETYPE_PEM) == 1) {
ERR_clear_error();
@@ -2129,6 +3151,7 @@ static int tls_connection_client_cert(struct tls_connection *conn,
" --> OK");
return 0;
}
+#endif
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_file failed");
@@ -2168,16 +3191,6 @@ static int tls_global_client_cert(struct tls_data *data,
}
-static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
-{
- if (password == NULL) {
- return 0;
- }
- os_strlcpy(buf, (char *) password, size);
- return os_strlen(buf);
-}
-
-
#ifdef PKCS12_FUNCS
static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
const char *passwd)
@@ -2229,28 +3242,42 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
}
if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
- SSL_clear_chain_certs(ssl);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+ if (ssl)
+ SSL_clear_chain_certs(ssl);
+ else
+ SSL_CTX_clear_chain_certs(data->ssl);
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
wpa_printf(MSG_DEBUG, "TLS: additional certificate"
" from PKCS12: subject='%s'", buf);
- if (SSL_add1_chain_cert(ssl, cert) != 1) {
+ if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
+ (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
+ cert) != 1)) {
tls_show_errors(MSG_DEBUG, __func__,
"Failed to add additional certificate");
res = -1;
+ X509_free(cert);
break;
}
+ X509_free(cert);
}
if (!res) {
/* Try to continue anyway */
}
- sk_X509_free(certs);
+ sk_X509_pop_free(certs, X509_free);
#ifndef OPENSSL_IS_BORINGSSL
- res = SSL_build_cert_chain(ssl,
- SSL_BUILD_CHAIN_FLAG_CHECK |
- SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+ if (ssl)
+ res = SSL_build_cert_chain(
+ ssl,
+ SSL_BUILD_CHAIN_FLAG_CHECK |
+ SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+ else
+ res = SSL_CTX_build_cert_chain(
+ data->ssl,
+ SSL_BUILD_CHAIN_FLAG_CHECK |
+ SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
if (!res) {
tls_show_errors(MSG_DEBUG, __func__,
"Failed to build certificate chain");
@@ -2265,9 +3292,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
*/
res = 0;
#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
SSL_CTX_clear_extra_chain_certs(data->ssl);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
@@ -2279,11 +3304,12 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
*/
if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
{
+ X509_free(cert);
res = -1;
break;
}
}
- sk_X509_free(certs);
+ sk_X509_pop_free(certs, X509_free);
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
}
@@ -2463,7 +3489,7 @@ static int tls_connection_engine_ca_cert(struct tls_data *data,
static int tls_connection_engine_private_key(struct tls_connection *conn)
{
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
tls_show_errors(MSG_ERROR, __func__,
"ENGINE: cannot use private key for TLS");
@@ -2483,6 +3509,64 @@ static int tls_connection_engine_private_key(struct tls_connection *conn)
}
+#ifndef OPENSSL_NO_STDIO
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+ if (!password)
+ return 0;
+ os_strlcpy(buf, (const char *) password, size);
+ return os_strlen(buf);
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
+ const char *private_key,
+ const char *private_key_passwd)
+{
+#ifndef OPENSSL_NO_STDIO
+ BIO *bio;
+ EVP_PKEY *pkey;
+ int ret;
+
+ /* First try ASN.1 (DER). */
+ bio = BIO_new_file(private_key, "r");
+ if (!bio)
+ return -1;
+ pkey = d2i_PrivateKey_bio(bio, NULL);
+ BIO_free(bio);
+
+ if (pkey) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
+ } else {
+ /* Try PEM with the provided password. */
+ bio = BIO_new_file(private_key, "r");
+ if (!bio)
+ return -1;
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
+ (void *) private_key_passwd);
+ BIO_free(bio);
+ if (!pkey)
+ return -1;
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
+ /* Clear errors from the previous failed load. */
+ ERR_clear_error();
+ }
+
+ if (ssl)
+ ret = SSL_use_PrivateKey(ssl, pkey);
+ else
+ ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
+
+ EVP_PKEY_free(pkey);
+ return ret == 1 ? 0 : -1;
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+ return -1;
+#endif /* OPENSSL_NO_STDIO */
+}
+
+
static int tls_connection_private_key(struct tls_data *data,
struct tls_connection *conn,
const char *private_key,
@@ -2490,23 +3574,11 @@ static int tls_connection_private_key(struct tls_data *data,
const u8 *private_key_blob,
size_t private_key_blob_len)
{
- SSL_CTX *ssl_ctx = data->ssl;
- char *passwd;
int ok;
if (private_key == NULL && private_key_blob == NULL)
return 0;
- if (private_key_passwd) {
- passwd = os_strdup(private_key_passwd);
- if (passwd == NULL)
- return -1;
- } else
- passwd = NULL;
-
- SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
- SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
-
ok = 0;
while (private_key_blob) {
if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
@@ -2537,7 +3609,8 @@ static int tls_connection_private_key(struct tls_data *data,
}
if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
- private_key_blob_len, passwd) == 0) {
+ private_key_blob_len,
+ private_key_passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
"OK");
ok = 1;
@@ -2548,29 +3621,14 @@ static int tls_connection_private_key(struct tls_data *data,
}
while (!ok && private_key) {
-#ifndef OPENSSL_NO_STDIO
- if (SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: "
- "SSL_use_PrivateKey_File (DER) --> OK");
- ok = 1;
- break;
- }
-
- if (SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: "
- "SSL_use_PrivateKey_File (PEM) --> OK");
+ if (tls_use_private_key_file(data, conn->ssl, private_key,
+ private_key_passwd) == 0) {
ok = 1;
break;
}
-#else /* OPENSSL_NO_STDIO */
- wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
- __func__);
-#endif /* OPENSSL_NO_STDIO */
- if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
- == 0) {
+ if (tls_read_pkcs12(data, conn->ssl, private_key,
+ private_key_passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
"--> OK");
ok = 1;
@@ -2590,12 +3648,9 @@ static int tls_connection_private_key(struct tls_data *data,
if (!ok) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
- os_free(passwd);
return -1;
}
ERR_clear_error();
- SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
- os_free(passwd);
if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -2613,37 +3668,19 @@ static int tls_global_private_key(struct tls_data *data,
const char *private_key_passwd)
{
SSL_CTX *ssl_ctx = data->ssl;
- char *passwd;
if (private_key == NULL)
return 0;
- if (private_key_passwd) {
- passwd = os_strdup(private_key_passwd);
- if (passwd == NULL)
- return -1;
- } else
- passwd = NULL;
-
- SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
- SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
- if (
-#ifndef OPENSSL_NO_STDIO
- SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
- SSL_FILETYPE_ASN1) != 1 &&
- SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
- SSL_FILETYPE_PEM) != 1 &&
-#endif /* OPENSSL_NO_STDIO */
- tls_read_pkcs12(data, NULL, private_key, passwd)) {
+ if (tls_use_private_key_file(data, NULL, private_key,
+ private_key_passwd) &&
+ tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
- os_free(passwd);
ERR_clear_error();
return -1;
}
- os_free(passwd);
ERR_clear_error();
- SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
if (!SSL_CTX_check_private_key(ssl_ctx)) {
tls_show_errors(MSG_INFO, __func__,
@@ -2812,16 +3849,6 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL || keys == NULL)
return -1;
ssl = conn->ssl;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
- return -1;
-
- os_memset(keys, 0, sizeof(*keys));
- keys->client_random = ssl->s3->client_random;
- keys->client_random_len = SSL3_RANDOM_SIZE;
- keys->server_random = ssl->s3->server_random;
- keys->server_random_len = SSL3_RANDOM_SIZE;
-#else
if (ssl == NULL)
return -1;
@@ -2832,16 +3859,17 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
keys->server_random = conn->server_random;
keys->server_random_len = SSL_get_server_random(
ssl, conn->server_random, sizeof(conn->server_random));
-#endif
return 0;
}
-#ifndef CONFIG_FIPS
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
static int openssl_get_keyblock_size(SSL *ssl)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
const EVP_CIPHER *c;
const EVP_MD *h;
int md_size;
@@ -2851,17 +3879,11 @@ static int openssl_get_keyblock_size(SSL *ssl)
return -1;
c = ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
h = EVP_MD_CTX_md(ssl->read_hash);
-#else
- h = ssl->read_hash;
-#endif
if (h)
md_size = EVP_MD_size(h);
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
else if (ssl->s3)
md_size = ssl->s3->tmp.new_mac_secret_size;
-#endif
else
return -1;
@@ -2899,86 +3921,26 @@ static int openssl_get_keyblock_size(SSL *ssl)
EVP_CIPHER_iv_length(c));
#endif
}
-#endif /* CONFIG_FIPS */
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
-static int openssl_tls_prf(struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
{
-#ifdef CONFIG_FIPS
- wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
- "mode");
- return -1;
-#else /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL *ssl;
- u8 *rnd;
- int ret = -1;
- int skip = 0;
- u8 *tmp_out = NULL;
- u8 *_out = out;
- const char *ver;
-
- /*
- * TLS library did not support key generation, so get the needed TLS
- * session parameters and use an internal implementation of TLS PRF to
- * derive the key.
- */
-
- if (conn == NULL)
- return -1;
- ssl = conn->ssl;
- if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
- ssl->session->master_key_length <= 0)
- return -1;
- ver = SSL_get_version(ssl);
-
- if (skip_keyblock) {
- skip = openssl_get_keyblock_size(ssl);
- if (skip < 0)
- return -1;
- tmp_out = os_malloc(skip + out_len);
- if (!tmp_out)
- return -1;
- _out = tmp_out;
- }
-
- rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
- if (!rnd) {
- os_free(tmp_out);
+ if (!conn ||
+ SSL_export_keying_material(conn->ssl, out, out_len, label,
+ os_strlen(label), context, context_len,
+ context != NULL) != 1)
return -1;
- }
-
- if (server_random_first) {
- os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
- SSL3_RANDOM_SIZE);
- } else {
- os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
- SSL3_RANDOM_SIZE);
- }
+ return 0;
+}
- if (os_strcmp(ver, "TLSv1.2") == 0) {
- tls_prf_sha256(ssl->session->master_key,
- ssl->session->master_key_length,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
- _out, skip + out_len);
- ret = 0;
- } else if (tls_prf_sha1_md5(ssl->session->master_key,
- ssl->session->master_key_length,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
- _out, skip + out_len) == 0) {
- ret = 0;
- }
- os_free(rnd);
- if (ret == 0 && skip_keyblock)
- os_memcpy(out, _out + skip, out_len);
- bin_clear_free(tmp_out, skip);
- return ret;
-#else
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
SSL *ssl;
SSL_SESSION *sess;
u8 *rnd;
@@ -2993,9 +3955,9 @@ static int openssl_tls_prf(struct tls_connection *conn,
const char *ver;
/*
- * TLS library did not support key generation, so get the needed TLS
- * session parameters and use an internal implementation of TLS PRF to
- * derive the key.
+ * TLS library did not support EAP-FAST key generation, so get the
+ * needed TLS session parameters and use an internal implementation of
+ * TLS PRF to derive the key.
*/
if (conn == NULL)
@@ -3008,15 +3970,13 @@ static int openssl_tls_prf(struct tls_connection *conn,
if (!ver || !sess)
return -1;
- if (skip_keyblock) {
- skip = openssl_get_keyblock_size(ssl);
- if (skip < 0)
- return -1;
- tmp_out = os_malloc(skip + out_len);
- if (!tmp_out)
- return -1;
- _out = tmp_out;
- }
+ skip = openssl_get_keyblock_size(ssl);
+ if (skip < 0)
+ return -1;
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
if (!rnd) {
@@ -3029,65 +3989,36 @@ static int openssl_tls_prf(struct tls_connection *conn,
master_key_len = SSL_SESSION_get_master_key(sess, master_key,
sizeof(master_key));
- if (server_random_first) {
- os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
- SSL3_RANDOM_SIZE);
- } else {
- os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
- SSL3_RANDOM_SIZE);
- }
+ os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
+ os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
if (os_strcmp(ver, "TLSv1.2") == 0) {
tls_prf_sha256(master_key, master_key_len,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
+ "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
_out, skip + out_len);
ret = 0;
} else if (tls_prf_sha1_md5(master_key, master_key_len,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
+ "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
_out, skip + out_len) == 0) {
ret = 0;
}
os_memset(master_key, 0, sizeof(master_key));
os_free(rnd);
- if (ret == 0 && skip_keyblock)
+ if (ret == 0)
os_memcpy(out, _out + skip, out_len);
bin_clear_free(tmp_out, skip);
return ret;
-#endif
-#endif /* CONFIG_FIPS */
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
-{
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- SSL *ssl;
- if (conn == NULL)
- return -1;
- if (server_random_first || skip_keyblock)
- return openssl_tls_prf(conn, label,
- server_random_first, skip_keyblock,
- out, out_len);
- ssl = conn->ssl;
- if (SSL_export_keying_material(ssl, out, out_len, label,
- os_strlen(label), NULL, 0, 0) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
- return 0;
- }
-#endif
- return openssl_tls_prf(conn, label, server_random_first,
- skip_keyblock, out, out_len);
+#else /* OPENSSL_NEED_EAP_FAST_PRF */
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
+ return -1;
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
}
static struct wpabuf *
-openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
- int server)
+openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
{
int res;
struct wpabuf *out_data;
@@ -3105,7 +4036,7 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
}
/* Initiate TLS handshake or continue the existing handshake */
- if (server)
+ if (conn->server)
res = SSL_accept(conn->ssl);
else
res = SSL_connect(conn->ssl);
@@ -3120,9 +4051,58 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
else {
tls_show_errors(MSG_INFO, __func__, "SSL_connect");
conn->failed++;
+ if (!conn->server && !conn->client_hello_generated) {
+ /* The server would not understand TLS Alert
+ * before ClientHello, so simply terminate
+ * handshake on this type of error case caused
+ * by a likely internal error like no ciphers
+ * available. */
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not generate ClientHello");
+ conn->write_alerts++;
+ return NULL;
+ }
}
}
+ if (!conn->server && !conn->failed)
+ conn->client_hello_generated = 1;
+
+#ifdef CONFIG_SUITEB
+ if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
+ os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
+ conn->server_dh_prime_len < 3072) {
+ struct tls_context *context = conn->context;
+
+ /*
+ * This should not be reached since earlier cert_cb should have
+ * terminated the handshake. Keep this check here for extra
+ * protection if anything goes wrong with the more low-level
+ * checks based on having to parse the TLS handshake messages.
+ */
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Server DH prime length: %d bits",
+ conn->server_dh_prime_len);
+
+ if (context->event_cb) {
+ union tls_event_data ev;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.alert.is_local = 1;
+ ev.alert.type = "fatal";
+ ev.alert.description = "insufficient security";
+ context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
+ }
+ /*
+ * Could send a TLS Alert to the server, but for now, simply
+ * terminate handshake.
+ */
+ conn->failed++;
+ conn->write_alerts++;
+ return NULL;
+ }
+#endif /* CONFIG_SUITEB */
+
/* Get the TLS handshake data to be sent to the server */
res = BIO_ctrl_pending(conn->ssl_out);
wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
@@ -3192,14 +4172,14 @@ openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
static struct wpabuf *
openssl_connection_handshake(struct tls_connection *conn,
const struct wpabuf *in_data,
- struct wpabuf **appl_data, int server)
+ struct wpabuf **appl_data)
{
struct wpabuf *out_data;
if (appl_data)
*appl_data = NULL;
- out_data = openssl_handshake(conn, in_data, server);
+ out_data = openssl_handshake(conn, in_data);
if (out_data == NULL)
return NULL;
if (conn->invalid_hb_used) {
@@ -3236,7 +4216,7 @@ tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
- return openssl_connection_handshake(conn, in_data, appl_data, 0);
+ return openssl_connection_handshake(conn, in_data, appl_data);
}
@@ -3245,7 +4225,8 @@ struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
- return openssl_connection_handshake(conn, in_data, appl_data, 1);
+ conn->server = 1;
+ return openssl_connection_handshake(conn, in_data, appl_data);
}
@@ -3340,18 +4321,14 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- return conn ? SSL_cache_hit(conn->ssl) : 0;
-#else
- return conn ? conn->ssl->hit : 0;
-#endif
+ return conn ? SSL_session_reused(conn->ssl) : 0;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
- char buf[100], *pos, *end;
+ char buf[500], *pos, *end;
u8 *c;
int ret;
@@ -3379,6 +4356,12 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
case TLS_CIPHER_ANON_DH_AES128_SHA:
suite = "ADH-AES128-SHA";
break;
+ case TLS_CIPHER_RSA_DHE_AES256_SHA:
+ suite = "DHE-RSA-AES256-SHA";
+ break;
+ case TLS_CIPHER_AES256_SHA:
+ suite = "AES256-SHA";
+ break;
default:
wpa_printf(MSG_DEBUG, "TLS: Unsupported "
"cipher selection: %d", *c);
@@ -3394,7 +4377,7 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
if (os_strstr(buf, ":ADH-")) {
/*
@@ -3579,7 +4562,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
{
struct tls_connection *conn = arg;
const unsigned char *p;
- int len, status, reason;
+ int len, status, reason, res;
OCSP_RESPONSE *rsp;
OCSP_BASICRESP *basic;
OCSP_CERTID *id;
@@ -3674,23 +4657,42 @@ static int ocsp_resp_cb(SSL *s, void *arg)
return 0;
}
- id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+ id = OCSP_cert_to_id(EVP_sha256(), conn->peer_cert, conn->peer_issuer);
if (!id) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not create OCSP certificate identifier (SHA256)");
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(rsp);
return 0;
}
- if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
- &this_update, &next_update)) {
+ res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
+ &this_update, &next_update);
+ if (!res) {
+ id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+ if (!id) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not create OCSP certificate identifier (SHA1)");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ return 0;
+ }
+
+ res = OCSP_resp_find_status(basic, id, &status, &reason,
+ &produced_at, &this_update,
+ &next_update);
+ }
+
+ if (!res) {
wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
(conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
" (OCSP not required)");
+ OCSP_CERTID_free(id);
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(rsp);
return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
}
+ OCSP_CERTID_free(id);
if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
tls_show_errors(MSG_INFO, __func__,
@@ -3765,10 +4767,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const char *cert_id = params->cert_id;
const char *ca_cert_id = params->ca_cert_id;
const char *engine_id = params->engine ? params->engine_id : NULL;
+ const char *ciphers;
if (conn == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ocsp=3 not supported");
+ return -1;
+ }
+
/*
* If the engine isn't explicitly configured, and any of the
* cert/key fields are actually PKCS#11 URIs, then automatically
@@ -3800,7 +4809,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
engine_id = "pkcs11";
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (params->flags & TLS_CONN_EAP_FAST) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Use TLSv1_method() for EAP-FAST");
@@ -3811,6 +4820,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
}
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+#ifdef SSL_OP_NO_TLSv1_3
+ if (params->flags & TLS_CONN_EAP_FAST) {
+ /* Need to disable TLS v1.3 at least for now since OpenSSL 1.1.1
+ * refuses to start the handshake with the modified ciphersuite
+ * list (no TLS v1.3 ciphersuites included) for EAP-FAST. */
+ wpa_printf(MSG_DEBUG, "OpenSSL: Disable TLSv1.3 for EAP-FAST");
+ SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_3);
+ }
+#endif /* SSL_OP_NO_TLSv1_3 */
+#endif
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
while ((err = ERR_get_error())) {
@@ -3829,7 +4849,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
params->subject_match,
params->altsubject_match,
params->suffix_match,
- params->domain_match))
+ params->domain_match,
+ params->check_cert_subject))
return -1;
if (engine_id && ca_cert_id) {
@@ -3869,16 +4890,67 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
- if (params->openssl_ciphers &&
- SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+ ciphers = params->openssl_ciphers;
+#ifdef CONFIG_SUITEB
+#ifdef OPENSSL_IS_BORINGSSL
+ if (ciphers && os_strcmp(ciphers, "SUITEB192") == 0) {
+ /* BoringSSL removed support for SUITEB192, so need to handle
+ * this with hardcoded ciphersuite and additional checks for
+ * other parameters. */
+ ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384";
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+#endif /* CONFIG_SUITEB */
+ if (ciphers && SSL_set_cipher_list(conn->ssl, ciphers) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set cipher string '%s'",
- params->openssl_ciphers);
+ ciphers);
return -1;
}
- tls_set_conn_flags(conn->ssl, params->flags);
+ if (!params->openssl_ecdh_curves) {
+#ifndef OPENSSL_IS_BORINGSSL
+#ifndef OPENSSL_NO_EC
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
+ (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves to auto");
+ return -1;
+ }
+#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ } else if (params->openssl_ecdh_curves[0]) {
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ECDH configuration nnot supported");
+ return -1;
+#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#ifndef OPENSSL_NO_EC
+ if (SSL_set1_curves_list(conn->ssl,
+ params->openssl_ecdh_curves) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
+ return -1;
+ }
+#else /* OPENSSL_NO_EC */
+ wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
+ return -1;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
+ if (tls_set_conn_flags(conn, params->flags,
+ params->openssl_ciphers) < 0)
+ return -1;
+#ifdef OPENSSL_IS_BORINGSSL
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ SSL_enable_ocsp_stapling(conn->ssl);
+ }
+#else /* OPENSSL_IS_BORINGSSL */
#ifdef HAVE_OCSP
if (params->flags & TLS_CONN_REQUEST_OCSP) {
SSL_CTX *ssl_ctx = data->ssl;
@@ -3897,6 +4969,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
"OpenSSL: No OCSP support included - allow optional OCSP case to continue");
}
#endif /* HAVE_OCSP */
+#endif /* OPENSSL_IS_BORINGSSL */
conn->flags = params->flags;
@@ -3918,6 +4991,15 @@ int tls_global_set_params(void *tls_ctx,
__func__, ERR_error_string(err, NULL));
}
+ os_free(data->check_cert_subject);
+ data->check_cert_subject = NULL;
+ if (params->check_cert_subject) {
+ data->check_cert_subject =
+ os_strdup(params->check_cert_subject);
+ if (!data->check_cert_subject)
+ return -1;
+ }
+
if (tls_global_ca_cert(data, params->ca_cert) ||
tls_global_client_cert(data, params->client_cert) ||
tls_global_private_key(data, params->private_key,
@@ -3935,13 +5017,49 @@ int tls_global_set_params(void *tls_ctx,
return -1;
}
+ if (!params->openssl_ecdh_curves) {
+#ifndef OPENSSL_IS_BORINGSSL
+#ifndef OPENSSL_NO_EC
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
+ (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves to auto");
+ return -1;
+ }
+#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ } else if (params->openssl_ecdh_curves[0]) {
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ECDH configuration nnot supported");
+ return -1;
+#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#ifndef OPENSSL_NO_EC
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
+#endif
+ if (SSL_CTX_set1_curves_list(ssl_ctx,
+ params->openssl_ecdh_curves) !=
+ 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
+ return -1;
+ }
+#else /* OPENSSL_NO_EC */
+ wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
+ return -1;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
-#ifdef SSL_CTX_clear_options
else
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
#ifdef HAVE_OCSP
@@ -3964,7 +5082,7 @@ int tls_global_set_params(void *tls_ctx,
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
-#ifdef OPENSSL_IS_BORINGSSL
+#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
const SSL_CIPHER **cipher, void *arg)
@@ -3977,7 +5095,9 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
struct tls_connection *conn = arg;
int ret;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
@@ -4030,11 +5150,10 @@ static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
"extension", data, len);
- conn->session_ticket = os_malloc(len);
+ conn->session_ticket = os_memdup(data, len);
if (conn->session_ticket == NULL)
return 0;
- os_memcpy(conn->session_ticket, data, len);
conn->session_ticket_len = len;
return 1;
@@ -4072,9 +5191,15 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
int tls_get_library_version(char *buf, size_t buf_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+ OPENSSL_VERSION_TEXT,
+ OpenSSL_version(OPENSSL_VERSION));
+#else
return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
OPENSSL_VERSION_TEXT,
SSLeay_version(SSLEAY_VERSION));
+#endif
}
diff --git a/contrib/wpa/src/crypto/tls_openssl.h b/contrib/wpa/src/crypto/tls_openssl.h
new file mode 100644
index 0000000..2a62d5c
--- /dev/null
+++ b/contrib/wpa/src/crypto/tls_openssl.h
@@ -0,0 +1,19 @@
+/*
+ * SSL/TLS interface functions for OpenSSL
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLS_OPENSSL_H
+#define TLS_OPENSSL_H
+
+enum ocsp_result {
+ OCSP_GOOD, OCSP_REVOKED, OCSP_NO_RESPONSE, OCSP_INVALID
+};
+
+enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
+ X509 *issuer, X509 *issuer_issuer);
+
+#endif /* TLS_OPENSSL_H */
diff --git a/contrib/wpa/src/crypto/tls_openssl_ocsp.c b/contrib/wpa/src/crypto/tls_openssl_ocsp.c
new file mode 100644
index 0000000..8b37b34
--- /dev/null
+++ b/contrib/wpa/src/crypto/tls_openssl_ocsp.c
@@ -0,0 +1,846 @@
+/*
+ * SSL/TLS interface functions for OpenSSL - BoringSSL OCSP
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#endif /* OPENSSL_IS_BORINGSSL */
+
+#include "common.h"
+#include "tls_openssl.h"
+
+
+#ifdef OPENSSL_IS_BORINGSSL
+
+static void tls_show_errors(int level, const char *func, const char *txt)
+{
+ unsigned long err;
+
+ wpa_printf(level, "OpenSSL: %s - %s %s",
+ func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+ while ((err = ERR_get_error())) {
+ wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
+ ERR_error_string(err, NULL));
+ }
+}
+
+
+/*
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuer's public key
+ * serialNumber CertificateSerialNumber }
+ */
+typedef struct {
+ X509_ALGOR *hashAlgorithm;
+ ASN1_OCTET_STRING *issuerNameHash;
+ ASN1_OCTET_STRING *issuerKeyHash;
+ ASN1_INTEGER *serialNumber;
+} CertID;
+
+/*
+ * ResponseBytes ::= SEQUENCE {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ */
+typedef struct {
+ ASN1_OBJECT *responseType;
+ ASN1_OCTET_STRING *response;
+} ResponseBytes;
+
+/*
+ * OCSPResponse ::= SEQUENCE {
+ * responseStatus OCSPResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+typedef struct {
+ ASN1_ENUMERATED *responseStatus;
+ ResponseBytes *responseBytes;
+} OCSPResponse;
+
+ASN1_SEQUENCE(ResponseBytes) = {
+ ASN1_SIMPLE(ResponseBytes, responseType, ASN1_OBJECT),
+ ASN1_SIMPLE(ResponseBytes, response, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(ResponseBytes);
+
+ASN1_SEQUENCE(OCSPResponse) = {
+ ASN1_SIMPLE(OCSPResponse, responseStatus, ASN1_ENUMERATED),
+ ASN1_EXP_OPT(OCSPResponse, responseBytes, ResponseBytes, 0)
+} ASN1_SEQUENCE_END(OCSPResponse);
+
+IMPLEMENT_ASN1_FUNCTIONS(OCSPResponse);
+
+/*
+ * ResponderID ::= CHOICE {
+ * byName [1] Name,
+ * byKey [2] KeyHash }
+ */
+typedef struct {
+ int type;
+ union {
+ X509_NAME *byName;
+ ASN1_OCTET_STRING *byKey;
+ } value;
+} ResponderID;
+
+/*
+ * RevokedInfo ::= SEQUENCE {
+ * revocationTime GeneralizedTime,
+ * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+ */
+typedef struct {
+ ASN1_GENERALIZEDTIME *revocationTime;
+ ASN1_ENUMERATED *revocationReason;
+} RevokedInfo;
+
+/*
+ * CertStatus ::= CHOICE {
+ * good [0] IMPLICIT NULL,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ */
+typedef struct {
+ int type;
+ union {
+ ASN1_NULL *good;
+ RevokedInfo *revoked;
+ ASN1_NULL *unknown;
+ } value;
+} CertStatus;
+
+/*
+ * SingleResponse ::= SEQUENCE {
+ * certID CertID,
+ * certStatus CertStatus,
+ * thisUpdate GeneralizedTime,
+ * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct {
+ CertID *certID;
+ CertStatus *certStatus;
+ ASN1_GENERALIZEDTIME *thisUpdate;
+ ASN1_GENERALIZEDTIME *nextUpdate;
+ STACK_OF(X509_EXTENSION) *singleExtensions;
+} SingleResponse;
+
+/*
+ * ResponseData ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * responderID ResponderID,
+ * producedAt GeneralizedTime,
+ * responses SEQUENCE OF SingleResponse,
+ * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct {
+ ASN1_INTEGER *version;
+ ResponderID *responderID;
+ ASN1_GENERALIZEDTIME *producedAt;
+ STACK_OF(SingleResponse) *responses;
+ STACK_OF(X509_EXTENSION) *responseExtensions;
+} ResponseData;
+
+/*
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+typedef struct {
+ ResponseData *tbsResponseData;
+ X509_ALGOR *signatureAlgorithm;
+ ASN1_BIT_STRING *signature;
+ STACK_OF(X509) *certs;
+} BasicOCSPResponse;
+
+ASN1_SEQUENCE(CertID) = {
+ ASN1_SIMPLE(CertID, hashAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(CertID, issuerNameHash, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(CertID, issuerKeyHash, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(CertID, serialNumber, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(CertID);
+
+ASN1_CHOICE(ResponderID) = {
+ ASN1_EXP(ResponderID, value.byName, X509_NAME, 1),
+ ASN1_EXP(ResponderID, value.byKey, ASN1_OCTET_STRING, 2)
+} ASN1_CHOICE_END(ResponderID);
+
+ASN1_SEQUENCE(RevokedInfo) = {
+ ASN1_SIMPLE(RevokedInfo, revocationTime, ASN1_GENERALIZEDTIME),
+ ASN1_EXP_OPT(RevokedInfo, revocationReason, ASN1_ENUMERATED, 0)
+} ASN1_SEQUENCE_END(RevokedInfo);
+
+ASN1_CHOICE(CertStatus) = {
+ ASN1_IMP(CertStatus, value.good, ASN1_NULL, 0),
+ ASN1_IMP(CertStatus, value.revoked, RevokedInfo, 1),
+ ASN1_IMP(CertStatus, value.unknown, ASN1_NULL, 2)
+} ASN1_CHOICE_END(CertStatus);
+
+ASN1_SEQUENCE(SingleResponse) = {
+ ASN1_SIMPLE(SingleResponse, certID, CertID),
+ ASN1_SIMPLE(SingleResponse, certStatus, CertStatus),
+ ASN1_SIMPLE(SingleResponse, thisUpdate, ASN1_GENERALIZEDTIME),
+ ASN1_EXP_OPT(SingleResponse, nextUpdate, ASN1_GENERALIZEDTIME, 0),
+ ASN1_EXP_SEQUENCE_OF_OPT(SingleResponse, singleExtensions,
+ X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(SingleResponse);
+
+ASN1_SEQUENCE(ResponseData) = {
+ ASN1_EXP_OPT(ResponseData, version, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(ResponseData, responderID, ResponderID),
+ ASN1_SIMPLE(ResponseData, producedAt, ASN1_GENERALIZEDTIME),
+ ASN1_SEQUENCE_OF(ResponseData, responses, SingleResponse),
+ ASN1_EXP_SEQUENCE_OF_OPT(ResponseData, responseExtensions,
+ X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(ResponseData);
+
+ASN1_SEQUENCE(BasicOCSPResponse) = {
+ ASN1_SIMPLE(BasicOCSPResponse, tbsResponseData, ResponseData),
+ ASN1_SIMPLE(BasicOCSPResponse, signatureAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(BasicOCSPResponse, signature, ASN1_BIT_STRING),
+ ASN1_EXP_SEQUENCE_OF_OPT(BasicOCSPResponse, certs, X509, 0)
+} ASN1_SEQUENCE_END(BasicOCSPResponse);
+
+IMPLEMENT_ASN1_FUNCTIONS(BasicOCSPResponse);
+
+#define sk_SingleResponse_num(sk) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk))
+
+#define sk_SingleResponse_value(sk, i) \
+ ((SingleResponse *) \
+ sk_value(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk), (i)))
+
+
+static char * mem_bio_to_str(BIO *out)
+{
+ char *txt;
+ size_t rlen;
+ int res;
+
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (!txt) {
+ BIO_free(out);
+ return NULL;
+ }
+
+ res = BIO_read(out, txt, rlen);
+ BIO_free(out);
+ if (res < 0) {
+ os_free(txt);
+ return NULL;
+ }
+
+ txt[res] = '\0';
+ return txt;
+}
+
+
+static char * generalizedtime_str(ASN1_GENERALIZEDTIME *t)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ if (!ASN1_GENERALIZEDTIME_print(out, t)) {
+ BIO_free(out);
+ return NULL;
+ }
+
+ return mem_bio_to_str(out);
+}
+
+
+static char * responderid_str(ResponderID *rid)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ switch (rid->type) {
+ case 0:
+ X509_NAME_print_ex(out, rid->value.byName, 0, XN_FLAG_ONELINE);
+ break;
+ case 1:
+ i2a_ASN1_STRING(out, rid->value.byKey, V_ASN1_OCTET_STRING);
+ break;
+ default:
+ BIO_free(out);
+ return NULL;
+ }
+
+ return mem_bio_to_str(out);
+}
+
+
+static char * octet_string_str(ASN1_OCTET_STRING *o)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_STRING(out, o, V_ASN1_OCTET_STRING);
+ return mem_bio_to_str(out);
+}
+
+
+static char * integer_str(ASN1_INTEGER *i)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_INTEGER(out, i);
+ return mem_bio_to_str(out);
+}
+
+
+static char * algor_str(X509_ALGOR *alg)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_OBJECT(out, alg->algorithm);
+ return mem_bio_to_str(out);
+}
+
+
+static char * extensions_str(const char *title, STACK_OF(X509_EXTENSION) *ext)
+{
+ BIO *out;
+
+ if (!ext)
+ return NULL;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ if (!X509V3_extensions_print(out, title, ext, 0, 0)) {
+ BIO_free(out);
+ return NULL;
+ }
+ return mem_bio_to_str(out);
+}
+
+
+static int ocsp_resp_valid(ASN1_GENERALIZEDTIME *thisupd,
+ ASN1_GENERALIZEDTIME *nextupd)
+{
+ time_t now, tmp;
+
+ if (!ASN1_GENERALIZEDTIME_check(thisupd)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid OCSP response thisUpdate");
+ return 0;
+ }
+
+ time(&now);
+ tmp = now + 5 * 60; /* allow five minute clock difference */
+ if (X509_cmp_time(thisupd, &tmp) > 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response not yet valid");
+ return 0;
+ }
+
+ if (!nextupd)
+ return 1; /* OK - no limit on response age */
+
+ if (!ASN1_GENERALIZEDTIME_check(nextupd)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid OCSP response nextUpdate");
+ return 0;
+ }
+
+ tmp = now - 5 * 60; /* allow five minute clock difference */
+ if (X509_cmp_time(nextupd, &tmp) < 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response expired");
+ return 0;
+ }
+
+ if (ASN1_STRING_cmp(nextupd, thisupd) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response nextUpdate before thisUpdate");
+ return 0;
+ }
+
+ /* Both thisUpdate and nextUpdate are valid */
+ return -1;
+}
+
+
+static int issuer_match(X509 *cert, X509 *issuer, CertID *certid)
+{
+ X509_NAME *iname;
+ ASN1_BIT_STRING *ikey;
+ const EVP_MD *dgst;
+ unsigned int len;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ ASN1_OCTET_STRING *hash;
+ char *txt;
+
+ dgst = EVP_get_digestbyobj(certid->hashAlgorithm->algorithm);
+ if (!dgst) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find matching hash algorithm for OCSP");
+ return -1;
+ }
+
+ iname = X509_get_issuer_name(cert);
+ if (!X509_NAME_digest(iname, dgst, md, &len))
+ return -1;
+ hash = ASN1_OCTET_STRING_new();
+ if (!hash)
+ return -1;
+ if (!ASN1_OCTET_STRING_set(hash, md, len)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ txt = octet_string_str(hash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerNameHash: %s",
+ txt);
+ os_free(txt);
+ }
+
+ if (ASN1_OCTET_STRING_cmp(certid->issuerNameHash, hash)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ ikey = X509_get0_pubkey_bitstr(issuer);
+ if (!ikey ||
+ !EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
+ !ASN1_OCTET_STRING_set(hash, md, len)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ txt = octet_string_str(hash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerKeyHash: %s",
+ txt);
+ os_free(txt);
+ }
+
+ if (ASN1_OCTET_STRING_cmp(certid->issuerKeyHash, hash)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ ASN1_OCTET_STRING_free(hash);
+ return 0;
+}
+
+
+static X509 * ocsp_find_signer(STACK_OF(X509) *certs, ResponderID *rid)
+{
+ unsigned int i;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (rid->type == 0) {
+ /* byName */
+ return X509_find_by_subject(certs, rid->value.byName);
+ }
+
+ /* byKey */
+ if (rid->value.byKey->length != SHA_DIGEST_LENGTH)
+ return NULL;
+ for (i = 0; i < sk_X509_num(certs); i++) {
+ X509 *x = sk_X509_value(certs, i);
+
+ X509_pubkey_digest(x, EVP_sha1(), hash, NULL);
+ if (os_memcmp(rid->value.byKey->data, hash,
+ SHA_DIGEST_LENGTH) == 0)
+ return x;
+ }
+
+ return NULL;
+}
+
+
+enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
+ X509 *issuer, X509 *issuer_issuer)
+{
+ const uint8_t *resp_data;
+ size_t resp_len;
+ OCSPResponse *resp;
+ int status;
+ ResponseBytes *bytes;
+ const u8 *basic_data;
+ size_t basic_len;
+ BasicOCSPResponse *basic;
+ ResponseData *rd;
+ char *txt;
+ int i, num;
+ unsigned int j, num_resp;
+ SingleResponse *matching_resp = NULL, *cmp_sresp;
+ enum ocsp_result result = OCSP_INVALID;
+ X509_STORE *store;
+ STACK_OF(X509) *untrusted = NULL, *certs = NULL, *chain = NULL;
+ X509_STORE_CTX ctx;
+ X509 *signer, *tmp_cert;
+ int signer_trusted = 0;
+ EVP_PKEY *skey;
+ int ret;
+ char buf[256];
+
+ txt = integer_str(X509_get_serialNumber(cert));
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Searching OCSP response for peer certificate serialNumber: %s", txt);
+ os_free(txt);
+ }
+
+ SSL_get0_ocsp_response(ssl, &resp_data, &resp_len);
+ if (resp_data == NULL || resp_len == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+ return OCSP_NO_RESPONSE;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", resp_data, resp_len);
+
+ resp = d2i_OCSPResponse(NULL, &resp_data, resp_len);
+ if (!resp) {
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSPResponse");
+ return OCSP_INVALID;
+ }
+
+ status = ASN1_ENUMERATED_get(resp->responseStatus);
+ if (status != 0) {
+ wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d",
+ status);
+ return OCSP_INVALID;
+ }
+
+ bytes = resp->responseBytes;
+
+ if (!bytes ||
+ OBJ_obj2nid(bytes->responseType) != NID_id_pkix_OCSP_basic) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Could not find BasicOCSPResponse");
+ return OCSP_INVALID;
+ }
+
+ basic_data = ASN1_STRING_data(bytes->response);
+ basic_len = ASN1_STRING_length(bytes->response);
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: BasicOCSPResponse",
+ basic_data, basic_len);
+
+ basic = d2i_BasicOCSPResponse(NULL, &basic_data, basic_len);
+ if (!basic) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Could not parse BasicOCSPResponse");
+ OCSPResponse_free(resp);
+ return OCSP_INVALID;
+ }
+
+ rd = basic->tbsResponseData;
+
+ if (basic->certs) {
+ untrusted = sk_X509_dup(basic->certs);
+ if (!untrusted)
+ goto fail;
+
+ num = sk_X509_num(basic->certs);
+ for (i = 0; i < num; i++) {
+ X509 *extra_cert;
+
+ extra_cert = sk_X509_value(basic->certs, i);
+ X509_NAME_oneline(X509_get_subject_name(extra_cert),
+ buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: BasicOCSPResponse cert %s", buf);
+
+ if (!sk_X509_push(untrusted, extra_cert)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not add certificate to the untrusted stack");
+ }
+ }
+ }
+
+ store = SSL_CTX_get_cert_store(ssl_ctx);
+ if (issuer) {
+ if (X509_STORE_add_cert(store, issuer) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer to certificate store");
+ }
+ certs = sk_X509_new_null();
+ if (certs) {
+ tmp_cert = X509_dup(issuer);
+ if (tmp_cert && !sk_X509_push(certs, tmp_cert)) {
+ tls_show_errors(
+ MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer to OCSP responder trust store");
+ X509_free(tmp_cert);
+ sk_X509_free(certs);
+ certs = NULL;
+ }
+ if (certs && issuer_issuer) {
+ tmp_cert = X509_dup(issuer_issuer);
+ if (tmp_cert &&
+ !sk_X509_push(certs, tmp_cert)) {
+ tls_show_errors(
+ MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
+ X509_free(tmp_cert);
+ }
+ }
+ }
+ }
+
+ signer = ocsp_find_signer(certs, rd->responderID);
+ if (!signer)
+ signer = ocsp_find_signer(untrusted, rd->responderID);
+ else
+ signer_trusted = 1;
+ if (!signer) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find OCSP signer certificate");
+ goto fail;
+ }
+
+ skey = X509_get_pubkey(signer);
+ if (!skey) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not get OCSP signer public key");
+ goto fail;
+ }
+ if (ASN1_item_verify(ASN1_ITEM_rptr(ResponseData),
+ basic->signatureAlgorithm, basic->signature,
+ basic->tbsResponseData, skey) <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: BasicOCSPResponse signature is invalid");
+ goto fail;
+ }
+
+ X509_NAME_oneline(X509_get_subject_name(signer), buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Found OCSP signer certificate %s and verified BasicOCSPResponse signature",
+ buf);
+
+ if (!X509_STORE_CTX_init(&ctx, store, signer, untrusted))
+ goto fail;
+ X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
+ ret = X509_verify_cert(&ctx);
+ chain = X509_STORE_CTX_get1_chain(&ctx);
+ X509_STORE_CTX_cleanup(&ctx);
+ if (ret <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not validate OCSP signer certificate");
+ goto fail;
+ }
+
+ if (!chain || sk_X509_num(chain) <= 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP signer chain found");
+ goto fail;
+ }
+
+ if (!signer_trusted) {
+ X509_check_purpose(signer, -1, 0);
+ if ((signer->ex_flags & EXFLAG_XKUSAGE) &&
+ (signer->ex_xkusage & XKU_OCSP_SIGN)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP signer certificate delegation OK");
+ } else {
+ tmp_cert = sk_X509_value(chain, sk_X509_num(chain) - 1);
+ if (X509_check_trust(tmp_cert, NID_OCSP_sign, 0) !=
+ X509_TRUST_TRUSTED) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP signer certificate not trusted");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP version: %lu",
+ ASN1_INTEGER_get(rd->version));
+
+ txt = responderid_str(rd->responderID);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP responderID: %s",
+ txt);
+ os_free(txt);
+ }
+
+ txt = generalizedtime_str(rd->producedAt);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP producedAt: %s",
+ txt);
+ os_free(txt);
+ }
+
+ num_resp = sk_SingleResponse_num(rd->responses);
+ if (num_resp == 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: No OCSP SingleResponse within BasicOCSPResponse");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+ cmp_sresp = sk_SingleResponse_value(rd->responses, 0);
+ for (j = 0; j < num_resp; j++) {
+ SingleResponse *sresp;
+ CertID *cid1, *cid2;
+
+ sresp = sk_SingleResponse_value(rd->responses, j);
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP SingleResponse %u/%u",
+ j + 1, num_resp);
+
+ txt = algor_str(sresp->certID->hashAlgorithm);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID hashAlgorithm: %s", txt);
+ os_free(txt);
+ }
+
+ txt = octet_string_str(sresp->certID->issuerNameHash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID issuerNameHash: %s", txt);
+ os_free(txt);
+ }
+
+ txt = octet_string_str(sresp->certID->issuerKeyHash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID issuerKeyHash: %s", txt);
+ os_free(txt);
+ }
+
+ txt = integer_str(sresp->certID->serialNumber);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID serialNumber: %s", txt);
+ os_free(txt);
+ }
+
+ switch (sresp->certStatus->type) {
+ case 0:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: good");
+ break;
+ case 1:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: revoked");
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: unknown");
+ break;
+ }
+
+ txt = generalizedtime_str(sresp->thisUpdate);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: thisUpdate: %s", txt);
+ os_free(txt);
+ }
+
+ if (sresp->nextUpdate) {
+ txt = generalizedtime_str(sresp->nextUpdate);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: nextUpdate: %s",
+ txt);
+ os_free(txt);
+ }
+ }
+
+ txt = extensions_str("singleExtensions",
+ sresp->singleExtensions);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
+ os_free(txt);
+ }
+
+ cid1 = cmp_sresp->certID;
+ cid2 = sresp->certID;
+ if (j > 0 &&
+ (OBJ_cmp(cid1->hashAlgorithm->algorithm,
+ cid2->hashAlgorithm->algorithm) != 0 ||
+ ASN1_OCTET_STRING_cmp(cid1->issuerNameHash,
+ cid2->issuerNameHash) != 0 ||
+ ASN1_OCTET_STRING_cmp(cid1->issuerKeyHash,
+ cid2->issuerKeyHash) != 0)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Different OCSP response issuer information between SingleResponse values within BasicOCSPResponse");
+ goto fail;
+ }
+
+ if (!matching_resp && issuer &&
+ ASN1_INTEGER_cmp(sresp->certID->serialNumber,
+ X509_get_serialNumber(cert)) == 0 &&
+ issuer_match(cert, issuer, sresp->certID) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: This response matches peer certificate");
+ matching_resp = sresp;
+ }
+ }
+
+ txt = extensions_str("responseExtensions", rd->responseExtensions);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
+ os_free(txt);
+ }
+
+ if (!matching_resp) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find OCSP response that matches the peer certificate");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+
+ if (!ocsp_resp_valid(matching_resp->thisUpdate,
+ matching_resp->nextUpdate)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response not valid at this time");
+ goto fail;
+ }
+
+ if (matching_resp->certStatus->type == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response indicated that the peer certificate has been revoked");
+ result = OCSP_REVOKED;
+ goto fail;
+ }
+
+ if (matching_resp->certStatus->type != 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response did not indicate good status");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+
+ /* OCSP response indicated the certificate is good. */
+ result = OCSP_GOOD;
+fail:
+ sk_X509_pop_free(chain, X509_free);
+ sk_X509_free(untrusted);
+ sk_X509_pop_free(certs, X509_free);
+ BasicOCSPResponse_free(basic);
+ OCSPResponse_free(resp);
+
+ return result;
+}
+
+#endif /* OPENSSL_IS_BORINGSSL */
diff --git a/contrib/wpa/src/crypto/tls_wolfssl.c b/contrib/wpa/src/crypto/tls_wolfssl.c
new file mode 100644
index 0000000..e9cb425
--- /dev/null
+++ b/contrib/wpa/src/crypto/tls_wolfssl.c
@@ -0,0 +1,2201 @@
+/*
+ * SSL/TLS interface functions for wolfSSL TLS case
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "tls.h"
+
+/* wolfSSL includes */
+#include <wolfssl/options.h>
+#include <wolfssl/ssl.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/wolfcrypt/asn.h>
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#define HAVE_AESGCM
+#include <wolfssl/wolfcrypt/aes.h>
+#endif
+
+#if !defined(CONFIG_FIPS) && \
+ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST))
+#define WOLFSSL_NEED_EAP_FAST_PRF
+#endif
+
+#define SECRET_LEN 48
+#define RAN_LEN 32
+#define SESSION_TICKET_LEN 256
+
+static int tls_ref_count = 0;
+
+static int tls_ex_idx_session = 0;
+
+
+/* tls input data for wolfSSL Read Callback */
+struct tls_in_data {
+ const struct wpabuf *in_data;
+ size_t consumed; /* how many bytes have we used already */
+};
+
+/* tls output data for wolfSSL Write Callback */
+struct tls_out_data {
+ struct wpabuf *out_data;
+};
+
+struct tls_context {
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
+ int cert_in_cb;
+ char *ocsp_stapling_response;
+};
+
+static struct tls_context *tls_global = NULL;
+
+/* wolfssl tls_connection */
+struct tls_connection {
+ struct tls_context *context;
+ WOLFSSL *ssl;
+ int read_alerts;
+ int write_alerts;
+ int failed;
+ struct tls_in_data input;
+ struct tls_out_data output;
+ char *subject_match;
+ char *alt_subject_match;
+ char *suffix_match;
+ char *domain_match;
+
+ u8 srv_cert_hash[32];
+
+ unsigned char client_random[RAN_LEN];
+ unsigned char server_random[RAN_LEN];
+ unsigned int flags;
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+ tls_session_ticket_cb session_ticket_cb;
+ void *session_ticket_cb_ctx;
+ byte session_ticket[SESSION_TICKET_LEN];
+#endif
+ unsigned int ca_cert_verify:1;
+ unsigned int cert_probe:1;
+ unsigned int server_cert_only:1;
+ unsigned int success_data:1;
+
+ WOLFSSL_X509 *peer_cert;
+ WOLFSSL_X509 *peer_issuer;
+ WOLFSSL_X509 *peer_issuer_issuer;
+};
+
+
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+ struct tls_context *context = os_zalloc(sizeof(*context));
+
+ if (!context)
+ return NULL;
+
+ if (conf) {
+ context->event_cb = conf->event_cb;
+ context->cb_ctx = conf->cb_ctx;
+ context->cert_in_cb = conf->cert_in_cb;
+ }
+
+ return context;
+}
+
+
+static void wolfssl_reset_in_data(struct tls_in_data *in,
+ const struct wpabuf *buf)
+{
+ /* old one not owned by us so don't free */
+ in->in_data = buf;
+ in->consumed = 0;
+}
+
+
+static void wolfssl_reset_out_data(struct tls_out_data *out)
+{
+ /* old one not owned by us so don't free */
+ out->out_data = wpabuf_alloc_copy("", 0);
+}
+
+
+/* wolfSSL I/O Receive CallBack */
+static int wolfssl_receive_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+ size_t get = sz;
+ struct tls_in_data *data = ctx;
+
+ if (!data)
+ return -1;
+
+ if (get > (wpabuf_len(data->in_data) - data->consumed))
+ get = wpabuf_len(data->in_data) - data->consumed;
+
+ os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
+ data->consumed += get;
+
+ if (get == 0)
+ return -2; /* WANT_READ */
+
+ return (int) get;
+}
+
+
+/* wolfSSL I/O Send CallBack */
+static int wolfssl_send_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+ struct wpabuf *tmp;
+ struct tls_out_data *data = ctx;
+
+ if (!data)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: adding %d bytes", sz);
+
+ tmp = wpabuf_alloc_copy(buf, sz);
+ if (!tmp)
+ return -1;
+ data->out_data = wpabuf_concat(data->out_data, tmp);
+ if (!data->out_data)
+ return -1;
+
+ return sz;
+}
+
+
+static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
+{
+ struct wpabuf *buf;
+
+ buf = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (!buf)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Free application session data %p (sess %p)",
+ buf, sess);
+ wpabuf_free(buf);
+
+ wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+ WOLFSSL_CTX *ssl_ctx;
+ struct tls_context *context;
+ const char *ciphers;
+
+#ifdef DEBUG_WOLFSSL
+ wolfSSL_Debugging_ON();
+#endif /* DEBUG_WOLFSSL */
+
+ context = tls_context_new(conf);
+ if (!context)
+ return NULL;
+
+ if (tls_ref_count == 0) {
+ tls_global = context;
+
+ if (wolfSSL_Init() < 0)
+ return NULL;
+ /* wolfSSL_Debugging_ON(); */
+ }
+
+ tls_ref_count++;
+
+ /* start as client */
+ ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
+ if (!ssl_ctx) {
+ tls_ref_count--;
+ if (context != tls_global)
+ os_free(context);
+ if (tls_ref_count == 0) {
+ os_free(tls_global);
+ tls_global = NULL;
+ }
+ }
+ wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
+ wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
+ wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
+
+ if (conf->tls_session_lifetime > 0) {
+ wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1);
+ wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
+ SSL_SESS_CACHE_SERVER);
+ wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime);
+ wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb);
+ } else {
+ wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
+ SSL_SESS_CACHE_CLIENT);
+ }
+
+ if (conf && conf->openssl_ciphers)
+ ciphers = conf->openssl_ciphers;
+ else
+ ciphers = "ALL";
+ if (wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Failed to set cipher string '%s'",
+ ciphers);
+ tls_deinit(ssl_ctx);
+ return NULL;
+ }
+
+ return ssl_ctx;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+ struct tls_context *context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+ if (context != tls_global)
+ os_free(context);
+
+ wolfSSL_CTX_free((WOLFSSL_CTX *) ssl_ctx);
+
+ tls_ref_count--;
+ if (tls_ref_count == 0) {
+ wolfSSL_Cleanup();
+ os_free(tls_global);
+ tls_global = NULL;
+ }
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+#ifdef DEBUG_WOLFSSL
+#if 0
+ unsigned long err;
+
+ err = wolfSSL_ERR_peek_last_error_line(NULL, NULL);
+ if (err != 0) {
+ wpa_printf(MSG_INFO, "TLS - SSL error: %s",
+ wolfSSL_ERR_error_string(err, NULL));
+ return 1;
+ }
+#endif
+#endif /* DEBUG_WOLFSSL */
+ return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+ WOLFSSL_CTX *ssl_ctx = tls_ctx;
+ struct tls_connection *conn;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection init");
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn)
+ return NULL;
+ conn->ssl = wolfSSL_new(ssl_ctx);
+ if (!conn->ssl) {
+ os_free(conn);
+ return NULL;
+ }
+
+ wolfSSL_SetIOReadCtx(conn->ssl, &conn->input);
+ wolfSSL_SetIOWriteCtx(conn->ssl, &conn->output);
+ wolfSSL_set_ex_data(conn->ssl, 0, conn);
+ conn->context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+ /* Need randoms post-hanshake for EAP-FAST, export key and deriving
+ * session ID in EAP methods. */
+ wolfSSL_KeepArrays(conn->ssl);
+ wolfSSL_KeepHandshakeResources(conn->ssl);
+ wolfSSL_UseClientSuites(conn->ssl);
+
+ return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection deinit");
+
+ /* parts */
+ wolfSSL_free(conn->ssl);
+ os_free(conn->subject_match);
+ os_free(conn->alt_subject_match);
+ os_free(conn->suffix_match);
+ os_free(conn->domain_match);
+
+ /* self */
+ os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+ return conn ? wolfSSL_is_init_finished(conn->ssl) : 0;
+}
+
+
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* TODO */
+ return NULL;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+ WOLFSSL_SESSION *session;
+
+ if (!conn)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection shutdown");
+
+ /* Set quiet as OpenSSL does */
+ wolfSSL_set_quiet_shutdown(conn->ssl, 1);
+ wolfSSL_shutdown(conn->ssl);
+
+ session = wolfSSL_get_session(conn->ssl);
+ if (wolfSSL_clear(conn->ssl) != 1)
+ return -1;
+ wolfSSL_set_session(conn->ssl, session);
+
+ return 0;
+}
+
+
+static int tls_connection_set_subject_match(struct tls_connection *conn,
+ const char *subject_match,
+ const char *alt_subject_match,
+ const char *suffix_match,
+ const char *domain_match)
+{
+ os_free(conn->subject_match);
+ conn->subject_match = NULL;
+ if (subject_match) {
+ conn->subject_match = os_strdup(subject_match);
+ if (!conn->subject_match)
+ return -1;
+ }
+
+ os_free(conn->alt_subject_match);
+ conn->alt_subject_match = NULL;
+ if (alt_subject_match) {
+ conn->alt_subject_match = os_strdup(alt_subject_match);
+ if (!conn->alt_subject_match)
+ return -1;
+ }
+
+ os_free(conn->suffix_match);
+ conn->suffix_match = NULL;
+ if (suffix_match) {
+ conn->suffix_match = os_strdup(suffix_match);
+ if (!conn->suffix_match)
+ return -1;
+ }
+
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (domain_match) {
+ conn->domain_match = os_strdup(domain_match);
+ if (!conn->domain_match)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file,
+ const u8 *dh_blob, size_t blob_len)
+{
+ if (!dh_file && !dh_blob)
+ return 0;
+
+ wolfSSL_set_accept_state(conn->ssl);
+
+ if (dh_blob) {
+ if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO, "SSL: use DH DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use DH blob OK");
+ return 0;
+ }
+
+ if (dh_file) {
+ wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file);
+ if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+ SSL_FILETYPE_PEM) < 0) {
+ wpa_printf(MSG_INFO, "SSL: use DH PEM file failed");
+ if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use DH DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use DH file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int tls_connection_client_cert(struct tls_connection *conn,
+ const char *client_cert,
+ const u8 *client_cert_blob,
+ size_t blob_len)
+{
+ if (!client_cert && !client_cert_blob)
+ return 0;
+
+ if (client_cert_blob) {
+ if (wolfSSL_use_certificate_chain_buffer_format(
+ conn->ssl, client_cert_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
+ return 0;
+ }
+
+ if (client_cert) {
+ if (wolfSSL_use_certificate_chain_file(conn->ssl,
+ client_cert) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert PEM file failed");
+ if (wolfSSL_use_certificate_chain_file_format(
+ conn->ssl, client_cert,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use client cert file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+ if (!password)
+ return 0;
+ os_strlcpy(buf, (char *) password, size);
+ return os_strlen(buf);
+}
+
+
+static int tls_connection_private_key(void *tls_ctx,
+ struct tls_connection *conn,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t blob_len)
+{
+ WOLFSSL_CTX *ctx = tls_ctx;
+ char *passwd = NULL;
+ int ok = 0;
+
+ if (!private_key && !private_key_blob)
+ return 0;
+
+ if (private_key_passwd) {
+ passwd = os_strdup(private_key_passwd);
+ if (!passwd)
+ return -1;
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+ wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+ if (private_key_blob) {
+ if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
+ private_key_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use private DER blob failed");
+ } else {
+ wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
+ ok = 1;
+ }
+ }
+
+ if (!ok && private_key) {
+ if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_PEM) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use private key PEM file failed");
+ if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_ASN1) < 0)
+ {
+ wpa_printf(MSG_INFO,
+ "SSL: use private key DER file failed");
+ } else {
+ ok = 1;
+ }
+ } else {
+ ok = 1;
+ }
+
+ if (ok)
+ wpa_printf(MSG_DEBUG, "SSL: use private key file OK");
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+ os_free(passwd);
+
+ if (!ok)
+ return -1;
+
+ return 0;
+}
+
+
+static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
+ const char *value, size_t len)
+{
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int found = 0;
+ int i;
+
+ ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+ for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
+ gen = wolfSSL_sk_value(ext, i);
+ if (gen->type != type)
+ continue;
+ if (os_strlen((char *) gen->obj) == len &&
+ os_memcmp(value, gen->obj, len) == 0)
+ found++;
+ }
+
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+ return found;
+}
+
+
+static int tls_match_alt_subject(WOLFSSL_X509 *cert, const char *match)
+{
+ int type;
+ const char *pos, *end;
+ size_t len;
+
+ pos = match;
+ do {
+ if (os_strncmp(pos, "EMAIL:", 6) == 0) {
+ type = GEN_EMAIL;
+ pos += 6;
+ } else if (os_strncmp(pos, "DNS:", 4) == 0) {
+ type = GEN_DNS;
+ pos += 4;
+ } else if (os_strncmp(pos, "URI:", 4) == 0) {
+ type = GEN_URI;
+ pos += 4;
+ } else {
+ wpa_printf(MSG_INFO,
+ "TLS: Invalid altSubjectName match '%s'",
+ pos);
+ return 0;
+ }
+ end = os_strchr(pos, ';');
+ while (end) {
+ if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
+ os_strncmp(end + 1, "DNS:", 4) == 0 ||
+ os_strncmp(end + 1, "URI:", 4) == 0)
+ break;
+ end = os_strchr(end + 1, ';');
+ }
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (tls_match_alt_subject_component(cert, type, pos, len) > 0)
+ return 1;
+ pos = end + 1;
+ } while (end);
+
+ return 0;
+}
+
+
+static int domain_suffix_match(const char *val, size_t len, const char *match,
+ size_t match_len, int full)
+{
+ size_t i;
+
+ /* Check for embedded nuls that could mess up suffix matching */
+ for (i = 0; i < len; i++) {
+ if (val[i] == '\0') {
+ wpa_printf(MSG_DEBUG,
+ "TLS: Embedded null in a string - reject");
+ return 0;
+ }
+ }
+
+ if (match_len > len || (full && match_len != len))
+ return 0;
+
+ if (os_strncasecmp(val + len - match_len, match, match_len) != 0)
+ return 0; /* no match */
+
+ if (match_len == len)
+ return 1; /* exact match */
+
+ if (val[len - match_len - 1] == '.')
+ return 1; /* full label match completes suffix match */
+
+ wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
+ return 0;
+}
+
+
+static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
+ size_t match_len, int full)
+{
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int i;
+ int j;
+ int dns_name = 0;
+ WOLFSSL_X509_NAME *name;
+
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+ full ? "" : "suffix ", match);
+
+ ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+ for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
+ gen = wolfSSL_sk_value(ext, j);
+ if (gen->type != ASN_DNS_TYPE)
+ continue;
+ dns_name++;
+ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
+ gen->obj, os_strlen((char *)gen->obj));
+ if (domain_suffix_match((const char *) gen->obj,
+ os_strlen((char *) gen->obj), match,
+ match_len, full) == 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+ full ? "Match" : "Suffix match");
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+ return 1;
+ }
+ }
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+ if (dns_name) {
+ wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
+ return 0;
+ }
+
+ name = wolfSSL_X509_get_subject_name(cert);
+ i = -1;
+ for (;;) {
+ WOLFSSL_X509_NAME_ENTRY *e;
+ WOLFSSL_ASN1_STRING *cn;
+
+ i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME,
+ i);
+ if (i == -1)
+ break;
+ e = wolfSSL_X509_NAME_get_entry(name, i);
+ if (!e)
+ continue;
+ cn = wolfSSL_X509_NAME_ENTRY_get_data(e);
+ if (!cn)
+ continue;
+ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
+ cn->data, cn->length);
+ if (domain_suffix_match(cn->data, cn->length,
+ match, match_len, full) == 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+ full ? "Match" : "Suffix match");
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+ full ? "" : "suffix ");
+ return 0;
+}
+
+
+static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
+{
+ const char *token, *last = NULL;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = cstr_token(match, ";", &last))) {
+ if (tls_match_suffix_helper(cert, token, last - token, full))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static enum tls_fail_reason wolfssl_tls_fail_reason(int err)
+{
+ switch (err) {
+ case X509_V_ERR_CERT_REVOKED:
+ return TLS_FAIL_REVOKED;
+ case ASN_BEFORE_DATE_E:
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ return TLS_FAIL_NOT_YET_VALID;
+ case ASN_AFTER_DATE_E:
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ return TLS_FAIL_EXPIRED;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_INVALID_CA:
+ return TLS_FAIL_UNTRUSTED;
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ case X509_V_ERR_CERT_UNTRUSTED:
+ case X509_V_ERR_CERT_REJECTED:
+ return TLS_FAIL_BAD_CERTIFICATE;
+ default:
+ return TLS_FAIL_UNSPECIFIED;
+ }
+}
+
+
+static const char * wolfssl_tls_err_string(int err, const char *err_str)
+{
+ switch (err) {
+ case ASN_BEFORE_DATE_E:
+ return "certificate is not yet valid";
+ case ASN_AFTER_DATE_E:
+ return "certificate has expired";
+ default:
+ return err_str;
+ }
+}
+
+
+static struct wpabuf * get_x509_cert(WOLFSSL_X509 *cert)
+{
+ struct wpabuf *buf = NULL;
+ const u8 *data;
+ int cert_len;
+
+ data = wolfSSL_X509_get_der(cert, &cert_len);
+ if (!data)
+ buf = wpabuf_alloc_copy(data, cert_len);
+
+ return buf;
+}
+
+
+static void wolfssl_tls_fail_event(struct tls_connection *conn,
+ WOLFSSL_X509 *err_cert, int err, int depth,
+ const char *subject, const char *err_str,
+ enum tls_fail_reason reason)
+{
+ union tls_event_data ev;
+ struct wpabuf *cert = NULL;
+ struct tls_context *context = conn->context;
+
+ if (!context->event_cb)
+ return;
+
+ cert = get_x509_cert(err_cert);
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
+ reason : wolfssl_tls_fail_reason(err);
+ ev.cert_fail.depth = depth;
+ ev.cert_fail.subject = subject;
+ ev.cert_fail.reason_txt = wolfssl_tls_err_string(err, err_str);
+ ev.cert_fail.cert = cert;
+ context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ wpabuf_free(cert);
+}
+
+
+static void wolfssl_tls_cert_event(struct tls_connection *conn,
+ WOLFSSL_X509 *err_cert, int depth,
+ const char *subject)
+{
+ struct wpabuf *cert = NULL;
+ union tls_event_data ev;
+ struct tls_context *context = conn->context;
+ char *alt_subject[TLS_MAX_ALT_SUBJECT];
+ int alt, num_alt_subject = 0;
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int i;
+#ifdef CONFIG_SHA256
+ u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+ if (!context->event_cb)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+ context->cert_in_cb) {
+ cert = get_x509_cert(err_cert);
+ ev.peer_cert.cert = cert;
+ }
+
+#ifdef CONFIG_SHA256
+ if (cert) {
+ const u8 *addr[1];
+ size_t len[1];
+
+ addr[0] = wpabuf_head(cert);
+ len[0] = wpabuf_len(cert);
+ if (sha256_vector(1, addr, len, hash) == 0) {
+ ev.peer_cert.hash = hash;
+ ev.peer_cert.hash_len = sizeof(hash);
+ }
+ }
+#endif /* CONFIG_SHA256 */
+
+ ev.peer_cert.depth = depth;
+ ev.peer_cert.subject = subject;
+
+ ext = wolfSSL_X509_get_ext_d2i(err_cert, ALT_NAMES_OID, NULL, NULL);
+ for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
+ char *pos;
+
+ if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
+ break;
+ gen = wolfSSL_sk_value((void *) ext, i);
+ if (gen->type != GEN_EMAIL &&
+ gen->type != GEN_DNS &&
+ gen->type != GEN_URI)
+ continue;
+
+ pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
+ if (!pos)
+ break;
+ alt_subject[num_alt_subject++] = pos;
+
+ switch (gen->type) {
+ case GEN_EMAIL:
+ os_memcpy(pos, "EMAIL:", 6);
+ pos += 6;
+ break;
+ case GEN_DNS:
+ os_memcpy(pos, "DNS:", 4);
+ pos += 4;
+ break;
+ case GEN_URI:
+ os_memcpy(pos, "URI:", 4);
+ pos += 4;
+ break;
+ }
+
+ os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
+ pos += os_strlen((char *)gen->obj);
+ *pos = '\0';
+ }
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+ for (alt = 0; alt < num_alt_subject; alt++)
+ ev.peer_cert.altsubject[alt] = alt_subject[alt];
+ ev.peer_cert.num_altsubject = num_alt_subject;
+
+ context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+ wpabuf_free(cert);
+ for (alt = 0; alt < num_alt_subject; alt++)
+ os_free(alt_subject[alt]);
+}
+
+
+static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
+{
+ char buf[256];
+ WOLFSSL_X509 *err_cert;
+ int err, depth;
+ WOLFSSL *ssl;
+ struct tls_connection *conn;
+ struct tls_context *context;
+ char *match, *altmatch, *suffix_match, *domain_match;
+ const char *err_str;
+
+ err_cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx);
+ if (!err_cert) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: No Cert");
+ return 0;
+ }
+
+ err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx);
+ depth = wolfSSL_X509_STORE_CTX_get_error_depth(x509_ctx);
+ ssl = wolfSSL_X509_STORE_CTX_get_ex_data(
+ x509_ctx, wolfSSL_get_ex_data_X509_STORE_CTX_idx());
+ wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(err_cert), buf,
+ sizeof(buf));
+
+ conn = wolfSSL_get_ex_data(ssl, 0);
+ if (!conn) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: No ex_data");
+ return 0;
+ }
+
+ if (depth == 0)
+ conn->peer_cert = err_cert;
+ else if (depth == 1)
+ conn->peer_issuer = err_cert;
+ else if (depth == 2)
+ conn->peer_issuer_issuer = err_cert;
+
+ context = conn->context;
+ match = conn->subject_match;
+ altmatch = conn->alt_subject_match;
+ suffix_match = conn->suffix_match;
+ domain_match = conn->domain_match;
+
+ if (!preverify_ok && !conn->ca_cert_verify)
+ preverify_ok = 1;
+ if (!preverify_ok && depth > 0 && conn->server_cert_only)
+ preverify_ok = 1;
+ if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
+ (err == X509_V_ERR_CERT_HAS_EXPIRED ||
+ err == ASN_AFTER_DATE_E || err == ASN_BEFORE_DATE_E ||
+ err == X509_V_ERR_CERT_NOT_YET_VALID)) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Ignore certificate validity time mismatch");
+ preverify_ok = 1;
+ }
+
+ err_str = wolfSSL_X509_verify_cert_error_string(err);
+
+#ifdef CONFIG_SHA256
+ /*
+ * Do not require preverify_ok so we can explicity allow otherwise
+ * invalid pinned server certificates.
+ */
+ if (depth == 0 && conn->server_cert_only) {
+ struct wpabuf *cert;
+
+ cert = get_x509_cert(err_cert);
+ if (!cert) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Could not fetch server certificate data");
+ preverify_ok = 0;
+ } else {
+ u8 hash[32];
+ const u8 *addr[1];
+ size_t len[1];
+
+ addr[0] = wpabuf_head(cert);
+ len[0] = wpabuf_len(cert);
+ if (sha256_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
+ err_str = "Server certificate mismatch";
+ err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+ preverify_ok = 0;
+ } else if (!preverify_ok) {
+ /*
+ * Certificate matches pinned certificate, allow
+ * regardless of other problems.
+ */
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Ignore validation issues for a pinned server certificate");
+ preverify_ok = 1;
+ }
+ wpabuf_free(cert);
+ }
+ }
+#endif /* CONFIG_SHA256 */
+
+ if (!preverify_ok) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Certificate verification failed, error %d (%s) depth %d for '%s'",
+ err, err_str, depth, buf);
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ err_str, TLS_FAIL_UNSPECIFIED);
+ return preverify_ok;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLS: %s - preverify_ok=%d err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+ __func__, preverify_ok, err, err_str,
+ conn->ca_cert_verify, depth, buf);
+ if (depth == 0 && match && os_strstr(buf, match) == NULL) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Subject '%s' did not match with '%s'",
+ buf, match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Subject mismatch",
+ TLS_FAIL_SUBJECT_MISMATCH);
+ } else if (depth == 0 && altmatch &&
+ !tls_match_alt_subject(err_cert, altmatch)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: altSubjectName match '%s' not found",
+ altmatch);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "AltSubject mismatch",
+ TLS_FAIL_ALTSUBJECT_MISMATCH);
+ } else if (depth == 0 && suffix_match &&
+ !tls_match_suffix(err_cert, suffix_match, 0)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Domain suffix match '%s' not found",
+ suffix_match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain suffix mismatch",
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ } else if (depth == 0 && domain_match &&
+ !tls_match_suffix(err_cert, domain_match, 1)) {
+ wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+ domain_match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
+ } else {
+ wolfssl_tls_cert_event(conn, err_cert, depth, buf);
+ }
+
+ if (conn->cert_probe && preverify_ok && depth == 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Reject server certificate on probe-only run");
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Server certificate chain probe",
+ TLS_FAIL_SERVER_CHAIN_PROBE);
+ }
+
+#ifdef HAVE_OCSP_WOLFSSL
+ if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ preverify_ok) {
+ enum ocsp_result res;
+
+ res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+ conn->peer_issuer,
+ conn->peer_issuer_issuer);
+ if (res == OCSP_REVOKED) {
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "certificate revoked",
+ TLS_FAIL_REVOKED);
+ if (err == X509_V_OK)
+ X509_STORE_CTX_set_error(
+ x509_ctx, X509_V_ERR_CERT_REVOKED);
+ } else if (res != OCSP_GOOD &&
+ (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "bad certificate status response",
+ TLS_FAIL_UNSPECIFIED);
+ }
+ }
+#endif /* HAVE_OCSP_WOLFSSL */
+ if (depth == 0 && preverify_ok && context->event_cb != NULL)
+ context->event_cb(context->cb_ctx,
+ TLS_CERT_CHAIN_SUCCESS, NULL);
+
+ return preverify_ok;
+}
+
+
+static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
+ const char *ca_cert,
+ const u8 *ca_cert_blob, size_t blob_len,
+ const char *ca_path)
+{
+ WOLFSSL_CTX *ctx = tls_ctx;
+
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ conn->ca_cert_verify = 1;
+
+ if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Probe for server certificate chain");
+ conn->cert_probe = 1;
+ conn->ca_cert_verify = 0;
+ return 0;
+ }
+
+ if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
+#ifdef CONFIG_SHA256
+ const char *pos = ca_cert + 7;
+
+ if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Unsupported ca_cert hash value '%s'",
+ ca_cert);
+ return -1;
+ }
+ pos += 14;
+ if (os_strlen(pos) != 32 * 2) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Unexpected SHA256 hash length in ca_cert '%s'",
+ ca_cert);
+ return -1;
+ }
+ if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Invalid SHA256 hash value in ca_cert '%s'",
+ ca_cert);
+ return -1;
+ }
+ conn->server_cert_only = 1;
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Checking only server certificate match");
+ return 0;
+#else /* CONFIG_SHA256 */
+ wpa_printf(MSG_INFO,
+ "No SHA256 included in the build - cannot validate server certificate hash");
+ return -1;
+#endif /* CONFIG_SHA256 */
+ }
+
+ if (ca_cert_blob) {
+ if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len,
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO, "SSL: failed to load CA blob");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK");
+ return 0;
+ }
+
+ if (ca_cert || ca_path) {
+ WOLFSSL_X509_STORE *cm = wolfSSL_X509_STORE_new();
+
+ if (!cm) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to create certificate store");
+ return -1;
+ }
+ wolfSSL_CTX_set_cert_store(ctx, cm);
+
+ if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to load ca_cert as PEM");
+
+ if (!ca_cert)
+ return -1;
+
+ if (wolfSSL_CTX_der_load_verify_locations(
+ ctx, ca_cert, SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to load ca_cert as DER");
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ conn->ca_cert_verify = 0;
+ return 0;
+}
+
+
+static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
+{
+#ifdef HAVE_SESSION_TICKET
+#if 0
+ if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
+ wolfSSL_UseSessionTicket(ssl);
+#endif
+#endif /* HAVE_SESSION_TICKET */
+
+ if (flags & TLS_CONN_DISABLE_TLSv1_0)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ if (flags & TLS_CONN_DISABLE_TLSv1_1)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ if (flags & TLS_CONN_DISABLE_TLSv1_2)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ wpa_printf(MSG_DEBUG, "SSL: set params");
+
+ if (tls_connection_set_subject_match(conn, params->subject_match,
+ params->altsubject_match,
+ params->suffix_match,
+ params->domain_match) < 0) {
+ wpa_printf(MSG_INFO, "Error setting subject match");
+ return -1;
+ }
+
+ if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path) < 0) {
+ wpa_printf(MSG_INFO, "Error setting CA cert");
+ return -1;
+ }
+
+ if (tls_connection_client_cert(conn, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting client cert");
+ return -1;
+ }
+
+ if (tls_connection_private_key(tls_ctx, conn, params->private_key,
+ params->private_key_passwd,
+ params->private_key_blob,
+ params->private_key_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting private key");
+ return -1;
+ }
+
+ if (tls_connection_dh(conn, params->dh_file, params->dh_blob,
+ params->dh_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting DH");
+ return -1;
+ }
+
+ if (params->openssl_ciphers &&
+ wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
+ tls_set_conn_flags(conn->ssl, params->flags);
+
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ if (wolfSSL_UseOCSPStapling(conn->ssl, WOLFSSL_CSR_OCSP,
+ WOLFSSL_CSR_OCSP_USE_NONCE) !=
+ SSL_SUCCESS)
+ return -1;
+ wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ }
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ if (wolfSSL_UseOCSPStaplingV2(conn->ssl,
+ WOLFSSL_CSR2_OCSP_MULTI, 0) !=
+ SSL_SUCCESS)
+ return -1;
+ wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ }
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
+ !defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+#ifdef HAVE_OCSP
+ if (params->flags & TLS_CONN_REQUEST_OCSP)
+ wolfSSL_CTX_EnableOCSP(ctx, 0);
+#else /* HAVE_OCSP */
+ if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: No OCSP support included - reject configuration");
+ return -1;
+ }
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: No OCSP support included - allow optional OCSP case to continue");
+ }
+#endif /* HAVE_OCSP */
+#endif /* !HAVE_CERTIFICATE_STATUS_REQUEST &&
+ * !HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+
+ conn->flags = params->flags;
+
+ return 0;
+}
+
+
+static int tls_global_ca_cert(void *ssl_ctx, const char *ca_cert)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (ca_cert) {
+ if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1)
+ {
+ wpa_printf(MSG_WARNING,
+ "Failed to load root certificates");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLS: Trusted root certificate(s) loaded");
+ }
+
+ return 0;
+}
+
+
+static int tls_global_client_cert(void *ssl_ctx, const char *client_cert)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (!client_cert)
+ return 0;
+
+ if (wolfSSL_CTX_use_certificate_chain_file_format(ctx, client_cert,
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS &&
+ wolfSSL_CTX_use_certificate_chain_file(ctx, client_cert) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO, "Failed to load client certificate");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: Loaded global client certificate: %s",
+ client_cert);
+
+ return 0;
+}
+
+
+static int tls_global_private_key(void *ssl_ctx, const char *private_key,
+ const char *private_key_passwd)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+ char *passwd = NULL;
+ int ret = 0;
+
+ if (!private_key)
+ return 0;
+
+ if (private_key_passwd) {
+ passwd = os_strdup(private_key_passwd);
+ if (!passwd)
+ return -1;
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+ wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+ if (wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+ SSL_FILETYPE_ASN1) != 1 &&
+ wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+ SSL_FILETYPE_PEM) != 1) {
+ wpa_printf(MSG_INFO, "Failed to load private key");
+ ret = -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: Loaded global private key");
+
+ os_free(passwd);
+ wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+
+ return ret;
+}
+
+
+static int tls_global_dh(void *ssl_ctx, const char *dh_file,
+ const u8 *dh_blob, size_t blob_len)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (!dh_file && !dh_blob)
+ return 0;
+
+ if (dh_blob) {
+ if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK");
+ return 0;
+ }
+
+ if (dh_file) {
+ if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) <
+ 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH PEM file failed");
+ if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: global use DH file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+#ifdef HAVE_OCSP
+
+int ocsp_status_cb(void *unused, const char *url, int url_sz,
+ unsigned char *request, int request_sz,
+ unsigned char **response)
+{
+ size_t len;
+
+ (void) unused;
+
+ if (!url) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - no response configured");
+ *response = NULL;
+ return 0;
+ }
+
+ *response = (unsigned char *) os_readfile(url, &len);
+ if (!*response) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - could not read response file");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - send cached response");
+ return len;
+}
+
+
+void ocsp_resp_free_cb(void *ocsp_stapling_response, unsigned char *response)
+{
+ os_free(response);
+}
+
+#endif /* HAVE_OCSP */
+
+
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params)
+{
+ wpa_printf(MSG_DEBUG, "SSL: global set params");
+
+ if (params->check_cert_subject)
+ return -1; /* not yet supported */
+
+ if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) {
+ wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'",
+ params->ca_cert);
+ return -1;
+ }
+
+ if (tls_global_client_cert(tls_ctx, params->client_cert) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: Failed to load client cert file '%s'",
+ params->client_cert);
+ return -1;
+ }
+
+ if (tls_global_private_key(tls_ctx, params->private_key,
+ params->private_key_passwd) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: Failed to load private key file '%s'",
+ params->private_key);
+ return -1;
+ }
+
+ if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob,
+ params->dh_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
+ params->dh_file);
+ return -1;
+ }
+
+ if (params->openssl_ciphers &&
+ wolfSSL_CTX_set_cipher_list(tls_ctx,
+ params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: openssl_ecdh_curves not supported");
+ return -1;
+ }
+
+#ifdef HAVE_SESSION_TICKET
+ /* Session ticket is off by default - can't disable once on. */
+ if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
+ wolfSSL_CTX_UseSessionTicket(tls_ctx);
+#endif /* HAVE_SESSION_TICKET */
+
+#ifdef HAVE_OCSP
+ if (params->ocsp_stapling_response) {
+ wolfSSL_CTX_SetOCSP_OverrideURL(tls_ctx,
+ params->ocsp_stapling_response);
+ wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb,
+ ocsp_resp_free_cb, NULL);
+ }
+#endif /* HAVE_OCSP */
+
+ return 0;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
+{
+ wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
+
+ if (check_crl) {
+ /* Hack to Enable CRLs. */
+ wolfSSL_CTX_LoadCRLBuffer(tls_ctx, NULL, 0, SSL_FILETYPE_PEM);
+ }
+
+ return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
+{
+ if (!conn)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: set verify: %d", verify_peer);
+
+ if (verify_peer) {
+ conn->ca_cert_verify = 1;
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ tls_verify_cb);
+ } else {
+ conn->ca_cert_verify = 0;
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
+ }
+
+ wolfSSL_set_accept_state(conn->ssl);
+
+ /* TODO: do we need to fake a session like OpenSSL does here? */
+
+ return 0;
+}
+
+
+static struct wpabuf * wolfssl_handshake(struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ int server)
+{
+ int res;
+
+ wolfssl_reset_out_data(&conn->output);
+
+ /* Initiate TLS handshake or continue the existing handshake */
+ if (server) {
+ wolfSSL_set_accept_state(conn->ssl);
+ res = wolfSSL_accept(conn->ssl);
+ wpa_printf(MSG_DEBUG, "SSL: wolfSSL_accept: %d", res);
+ } else {
+ wolfSSL_set_connect_state(conn->ssl);
+ res = wolfSSL_connect(conn->ssl);
+ wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res);
+ }
+
+ if (res != 1) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - want more data");
+ } else if (err == SSL_ERROR_WANT_WRITE) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - want to write");
+ } else {
+ char msg[80];
+
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - failed %s",
+ wolfSSL_ERR_error_string(err, msg));
+ conn->failed++;
+ }
+ }
+
+ return conn->output.out_data;
+}
+
+
+static struct wpabuf * wolfssl_get_appl_data(struct tls_connection *conn,
+ size_t max_len)
+{
+ int res;
+ struct wpabuf *appl_data = wpabuf_alloc(max_len + 100);
+
+ if (!appl_data)
+ return NULL;
+
+ res = wolfSSL_read(conn->ssl, wpabuf_mhead(appl_data),
+ wpabuf_size(appl_data));
+ if (res < 0) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: No Application Data included");
+ } else {
+ char msg[80];
+
+ wpa_printf(MSG_DEBUG,
+ "Failed to read possible Application Data %s",
+ wolfSSL_ERR_error_string(err, msg));
+ }
+
+ wpabuf_free(appl_data);
+ return NULL;
+ }
+
+ wpabuf_put(appl_data, res);
+ wpa_hexdump_buf_key(MSG_MSGDUMP,
+ "SSL: Application Data in Finished message",
+ appl_data);
+ return appl_data;
+}
+
+
+static struct wpabuf *
+wolfssl_connection_handshake(struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data, int server)
+{
+ struct wpabuf *out_data;
+
+ wolfssl_reset_in_data(&conn->input, in_data);
+
+ if (appl_data)
+ *appl_data = NULL;
+
+ out_data = wolfssl_handshake(conn, in_data, server);
+ if (!out_data)
+ return NULL;
+
+ if (wolfSSL_is_init_finished(conn->ssl)) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Handshake finished - resumed=%d",
+ tls_connection_resumed(NULL, conn));
+ if (appl_data && in_data)
+ *appl_data = wolfssl_get_appl_data(conn,
+ wpabuf_len(in_data));
+ }
+
+ return out_data;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data)
+{
+ return wolfssl_connection_handshake(conn, in_data, appl_data, 0);
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data)
+{
+ return wolfssl_connection_handshake(conn, in_data, appl_data, 1);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data)
+{
+ int res;
+
+ if (!conn)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "SSL: encrypt: %ld bytes", wpabuf_len(in_data));
+
+ wolfssl_reset_out_data(&conn->output);
+
+ res = wolfSSL_write(conn->ssl, wpabuf_head(in_data),
+ wpabuf_len(in_data));
+ if (res < 0) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+ char msg[80];
+
+ wpa_printf(MSG_INFO, "Encryption failed - SSL_write: %s",
+ wolfSSL_ERR_error_string(err, msg));
+ return NULL;
+ }
+
+ return conn->output.out_data;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data)
+{
+ int res;
+ struct wpabuf *buf;
+
+ if (!conn)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "SSL: decrypt");
+
+ wolfssl_reset_in_data(&conn->input, in_data);
+
+ /* Read decrypted data for further processing */
+ /*
+ * Even though we try to disable TLS compression, it is possible that
+ * this cannot be done with all TLS libraries. Add extra buffer space
+ * to handle the possibility of the decrypted data being longer than
+ * input data.
+ */
+ buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+ if (!buf)
+ return NULL;
+ res = wolfSSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "Decryption failed - SSL_read");
+ wpabuf_free(buf);
+ return NULL;
+ }
+ wpabuf_put(buf, res);
+
+ wpa_printf(MSG_DEBUG, "SSL: decrypt: %ld bytes", wpabuf_len(buf));
+
+ return buf;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+ return conn ? wolfSSL_session_reused(conn->ssl) : 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers)
+{
+ char buf[128], *pos, *end;
+ u8 *c;
+ int ret;
+
+ if (!conn || !conn->ssl || !ciphers)
+ return -1;
+
+ buf[0] = '\0';
+ pos = buf;
+ end = pos + sizeof(buf);
+
+ c = ciphers;
+ while (*c != TLS_CIPHER_NONE) {
+ const char *suite;
+
+ switch (*c) {
+ case TLS_CIPHER_RC4_SHA:
+ suite = "RC4-SHA";
+ break;
+ case TLS_CIPHER_AES128_SHA:
+ suite = "AES128-SHA";
+ break;
+ case TLS_CIPHER_RSA_DHE_AES128_SHA:
+ suite = "DHE-RSA-AES128-SHA";
+ break;
+ case TLS_CIPHER_ANON_DH_AES128_SHA:
+ suite = "ADH-AES128-SHA";
+ break;
+ case TLS_CIPHER_RSA_DHE_AES256_SHA:
+ suite = "DHE-RSA-AES256-SHA";
+ break;
+ case TLS_CIPHER_AES256_SHA:
+ suite = "AES256-SHA";
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "TLS: Unsupported cipher selection: %d", *c);
+ return -1;
+ }
+ ret = os_snprintf(pos, end - pos, ":%s", suite);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+
+ c++;
+ }
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", buf + 1);
+
+ if (wolfSSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
+ wpa_printf(MSG_DEBUG, "Cipher suite configuration failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ WOLFSSL_CIPHER *cipher;
+ const char *name;
+
+ if (!conn || !conn->ssl)
+ return -1;
+
+ cipher = wolfSSL_get_current_cipher(conn->ssl);
+ if (!cipher)
+ return -1;
+
+ name = wolfSSL_CIPHER_get_name(cipher);
+ if (!name)
+ return -1;
+
+ if (os_strcmp(name, "SSL_RSA_WITH_RC4_128_SHA") == 0)
+ os_strlcpy(buf, "RC4-SHA", buflen);
+ else if (os_strcmp(name, "TLS_RSA_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "DHE-RSA-AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DH_anon_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "ADH-AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA") == 0)
+ os_strlcpy(buf, "DHE-RSA-AES256-SHA", buflen);
+ else if (os_strcmp(name, "TLS_RSA_WITH_AES_256_CBC_SHA") == 0)
+ os_strlcpy(buf, "AES256-SHA", buflen);
+ else
+ os_strlcpy(buf, name, buflen);
+
+ return 0;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* no empty fragments in wolfSSL for now */
+ return 0;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ /* TODO: this is not incremented anywhere */
+ return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ /* TODO: this is not incremented anywhere */
+ return conn->write_alerts;
+}
+
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "wolfSSL build=%s run=%s",
+ WOLFSSL_VERSION, wolfSSL_lib_version());
+}
+
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ const char *name;
+
+ if (!conn || !conn->ssl)
+ return -1;
+
+ name = wolfSSL_get_version(conn->ssl);
+ if (!name)
+ return -1;
+
+ os_strlcpy(buf, name, buflen);
+ return 0;
+}
+
+
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_random *keys)
+{
+ WOLFSSL *ssl;
+
+ if (!conn || !keys)
+ return -1;
+ ssl = conn->ssl;
+ if (!ssl)
+ return -1;
+
+ os_memset(keys, 0, sizeof(*keys));
+ keys->client_random = conn->client_random;
+ keys->client_random_len = wolfSSL_get_client_random(
+ ssl, conn->client_random, sizeof(conn->client_random));
+ keys->server_random = conn->server_random;
+ keys->server_random_len = wolfSSL_get_server_random(
+ ssl, conn->server_random, sizeof(conn->server_random));
+
+ return 0;
+}
+
+
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
+{
+ if (context)
+ return -1;
+ if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+ return -1;
+ return 0;
+}
+
+
+#define SEED_LEN (RAN_LEN + RAN_LEN)
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ byte seed[SEED_LEN];
+ int ret = -1;
+ WOLFSSL *ssl;
+ byte *tmp_out;
+ byte *_out;
+ int skip = 0;
+ byte *master_key;
+ unsigned int master_key_len;
+ byte *server_random;
+ unsigned int server_len;
+ byte *client_random;
+ unsigned int client_len;
+
+ if (!conn || !conn->ssl)
+ return -1;
+ ssl = conn->ssl;
+
+ skip = 2 * (wolfSSL_GetKeySize(ssl) + wolfSSL_GetHmacSize(ssl) +
+ wolfSSL_GetIVSize(ssl));
+
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
+
+ wolfSSL_get_keys(ssl, &master_key, &master_key_len, &server_random,
+ &server_len, &client_random, &client_len);
+ os_memcpy(seed, server_random, RAN_LEN);
+ os_memcpy(seed + RAN_LEN, client_random, RAN_LEN);
+
+ if (wolfSSL_GetVersion(ssl) == WOLFSSL_TLSV1_2) {
+ tls_prf_sha256(master_key, master_key_len,
+ "key expansion", seed, sizeof(seed),
+ _out, skip + out_len);
+ ret = 0;
+ } else {
+ ret = tls_prf_sha1_md5(master_key, master_key_len,
+ "key expansion", seed, sizeof(seed),
+ _out, skip + out_len);
+ }
+
+ os_memset(master_key, 0, master_key_len);
+ if (ret == 0)
+ os_memcpy(out, _out + skip, out_len);
+ bin_clear_free(tmp_out, skip + out_len);
+
+ return ret;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+ int ext_type, const u8 *data,
+ size_t data_len)
+{
+ (void) ssl_ctx;
+
+ if (!conn || !conn->ssl || ext_type != 35)
+ return -1;
+
+ if (wolfSSL_set_SessionTicket(conn->ssl, data,
+ (unsigned int) data_len) != 1)
+ return -1;
+
+ return 0;
+}
+
+
+static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg)
+{
+ struct tls_connection *conn = arg;
+ int ret;
+ unsigned char client_random[RAN_LEN];
+ unsigned char server_random[RAN_LEN];
+ word32 ticket_len = sizeof(conn->session_ticket);
+
+ if (!conn || !conn->session_ticket_cb)
+ return 1;
+
+ if (wolfSSL_get_client_random(s, client_random,
+ sizeof(client_random)) == 0 ||
+ wolfSSL_get_server_random(s, server_random,
+ sizeof(server_random)) == 0 ||
+ wolfSSL_get_SessionTicket(s, conn->session_ticket,
+ &ticket_len) != 1)
+ return 1;
+
+ if (ticket_len == 0)
+ return 0;
+
+ ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+ conn->session_ticket, ticket_len,
+ client_random, server_random, secret);
+ if (ret <= 0)
+ return 1;
+
+ *secret_len = SECRET_LEN;
+ return 0;
+}
+
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+ struct tls_connection *conn,
+ tls_session_ticket_cb cb,
+ void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+ conn->session_ticket_cb = cb;
+ conn->session_ticket_cb_ctx = ctx;
+
+ if (cb) {
+ if (wolfSSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+ conn) != 1)
+ return -1;
+ } else {
+ if (wolfSSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+ return -1;
+ }
+
+ return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+ return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Success data accepted for resumed session");
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+ WOLFSSL_SESSION *sess;
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess)
+ return;
+
+ wolfSSL_SSL_SESSION_set_timeout(sess, 0);
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Removed cached session to disable session resumption");
+}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
+{
+ WOLFSSL_SESSION *sess;
+ struct wpabuf *old;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Set success data");
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: No session found for success data");
+ goto fail;
+ }
+
+ old = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (old) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: Replacing old success data %p",
+ old);
+ wpabuf_free(old);
+ }
+ if (wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Stored success data %p", data);
+ conn->success_data = 1;
+ return;
+
+fail:
+ wpa_printf(MSG_INFO, "wolfSSL: Failed to store success data");
+ wpabuf_free(data);
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ WOLFSSL_SESSION *sess;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Get success data");
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess)
+ return NULL;
+ return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
diff --git a/contrib/wpa/src/drivers/driver.h b/contrib/wpa/src/drivers/driver.h
index 3cdab5a..e7c8f31 100644
--- a/contrib/wpa/src/drivers/driver.h
+++ b/contrib/wpa/src/drivers/driver.h
@@ -1,6 +1,6 @@
/*
* Driver interface definition
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,6 +21,10 @@
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
+#ifdef CONFIG_MACSEC
+#include "pae/ieee802_1x_kay.h"
+#endif /* CONFIG_MACSEC */
#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
@@ -45,6 +49,36 @@
#define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
#define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
+#define HOSTAPD_CHAN_VHT_10_150 0x00100000
+#define HOSTAPD_CHAN_VHT_30_130 0x00200000
+#define HOSTAPD_CHAN_VHT_50_110 0x00400000
+#define HOSTAPD_CHAN_VHT_70_90 0x00800000
+#define HOSTAPD_CHAN_VHT_90_70 0x01000000
+#define HOSTAPD_CHAN_VHT_110_50 0x02000000
+#define HOSTAPD_CHAN_VHT_130_30 0x04000000
+#define HOSTAPD_CHAN_VHT_150_10 0x08000000
+
+/* Allowed bandwidth mask */
+enum hostapd_chan_width_attr {
+ HOSTAPD_CHAN_WIDTH_10 = BIT(0),
+ HOSTAPD_CHAN_WIDTH_20 = BIT(1),
+ HOSTAPD_CHAN_WIDTH_40P = BIT(2),
+ HOSTAPD_CHAN_WIDTH_40M = BIT(3),
+ HOSTAPD_CHAN_WIDTH_80 = BIT(4),
+ HOSTAPD_CHAN_WIDTH_160 = BIT(5),
+};
+
+/* Filter gratuitous ARP */
+#define WPA_DATA_FRAME_FILTER_FLAG_ARP BIT(0)
+/* Filter unsolicited Neighbor Advertisement */
+#define WPA_DATA_FRAME_FILTER_FLAG_NA BIT(1)
+/* Filter unicast IP packets encrypted using the GTK */
+#define WPA_DATA_FRAME_FILTER_FLAG_GTK BIT(2)
+
+#define HOSTAPD_DFS_REGION_FCC 1
+#define HOSTAPD_DFS_REGION_ETSI 2
+#define HOSTAPD_DFS_REGION_JP 3
+
/**
* enum reg_change_initiator - Regulatory change initiator
*/
@@ -87,6 +121,13 @@ struct hostapd_channel_data {
int flag;
/**
+ * allowed_bw - Allowed channel width bitmask
+ *
+ * See enum hostapd_chan_width_attr.
+ */
+ u32 allowed_bw;
+
+ /**
* max_tx_power - Regulatory transmit power limit in dBm
*/
u8 max_tx_power;
@@ -117,6 +158,29 @@ struct hostapd_channel_data {
unsigned int dfs_cac_ms;
};
+#define HE_MAX_NUM_SS 8
+#define HE_MAX_PHY_CAPAB_SIZE 3
+
+/**
+ * struct he_ppe_threshold - IEEE 802.11ax HE PPE Threshold
+ */
+struct he_ppe_threshold {
+ u32 numss_m1;
+ u32 ru_count;
+ u32 ppet16_ppet8_ru3_ru0[HE_MAX_NUM_SS];
+};
+
+/**
+ * struct he_capabilities - IEEE 802.11ax HE capabilities
+ */
+struct he_capabilities {
+ u8 he_supported;
+ u32 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
+ u32 mac_cap;
+ u32 mcs;
+ struct he_ppe_threshold ppet;
+};
+
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
@@ -175,6 +239,11 @@ struct hostapd_hw_modes {
u8 vht_mcs_set[8];
unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
+
+ /**
+ * he_capab - HE (IEEE 802.11ax) capabilities
+ */
+ struct he_capabilities he_capab;
};
@@ -217,6 +286,9 @@ struct hostapd_hw_modes {
* @est_throughput: Estimated throughput in kbps (this is calculated during
* scan result processing if left zero by the driver wrapper)
* @snr: Signal-to-noise ratio in dB (calculated during scan result processing)
+ * @parent_tsf: Time when the Beacon/Probe Response frame was received in terms
+ * of TSF of the BSS specified by %tsf_bssid.
+ * @tsf_bssid: The BSS that %parent_tsf TSF time refers to.
* @ie_len: length of the following IE field in octets
* @beacon_ie_len: length of the following Beacon IE field in octets
*
@@ -247,6 +319,8 @@ struct wpa_scan_res {
unsigned int age;
unsigned int est_throughput;
int snr;
+ u64 parent_tsf;
+ u8 tsf_bssid[ETH_ALEN];
size_t ie_len;
size_t beacon_ie_len;
/* Followed by ie_len + beacon_ie_len octets of IE data */
@@ -284,6 +358,18 @@ struct wpa_interface_info {
#define WPAS_MAX_SCAN_SSIDS 16
/**
+ * struct wpa_driver_scan_ssid - SSIDs to scan for
+ * @ssid - specific SSID to scan for (ProbeReq)
+ * %NULL or zero-length SSID is used to indicate active scan
+ * with wildcard SSID.
+ * @ssid_len - Length of the SSID in octets
+ */
+struct wpa_driver_scan_ssid {
+ const u8 *ssid;
+ size_t ssid_len;
+};
+
+/**
* struct wpa_driver_scan_params - Scan parameters
* Data for struct wpa_driver_ops::scan2().
*/
@@ -291,18 +377,7 @@ struct wpa_driver_scan_params {
/**
* ssids - SSIDs to scan for
*/
- struct wpa_driver_scan_ssid {
- /**
- * ssid - specific SSID to scan for (ProbeReq)
- * %NULL or zero-length SSID is used to indicate active scan
- * with wildcard SSID.
- */
- const u8 *ssid;
- /**
- * ssid_len: Length of the SSID in octets
- */
- size_t ssid_len;
- } ssids[WPAS_MAX_SCAN_SSIDS];
+ struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
/**
* num_ssids - Number of entries in ssids array
@@ -407,6 +482,120 @@ struct wpa_driver_scan_params {
*/
const u8 *mac_addr_mask;
+ /**
+ * sched_scan_plans - Scan plans for scheduled scan
+ *
+ * Each scan plan consists of the number of iterations to scan and the
+ * interval between scans. When a scan plan finishes (i.e., it was run
+ * for the specified number of iterations), the next scan plan is
+ * executed. The scan plans are executed in the order they appear in
+ * the array (lower index first). The last scan plan will run infinitely
+ * (until requested to stop), thus must not specify the number of
+ * iterations. All other scan plans must specify the number of
+ * iterations.
+ */
+ struct sched_scan_plan {
+ u32 interval; /* In seconds */
+ u32 iterations; /* Zero to run infinitely */
+ } *sched_scan_plans;
+
+ /**
+ * sched_scan_plans_num - Number of scan plans in sched_scan_plans array
+ */
+ unsigned int sched_scan_plans_num;
+
+ /**
+ * sched_scan_start_delay - Delay to use before starting the first scan
+ *
+ * Delay (in seconds) before scheduling first scan plan cycle. The
+ * driver may ignore this parameter and start immediately (or at any
+ * other time), if this feature is not supported.
+ */
+ u32 sched_scan_start_delay;
+
+ /**
+ * bssid - Specific BSSID to scan for
+ *
+ * This optional parameter can be used to replace the default wildcard
+ * BSSID with a specific BSSID to scan for if results are needed from
+ * only a single BSS.
+ */
+ const u8 *bssid;
+
+ /**
+ * scan_cookie - Unique identification representing the scan request
+ *
+ * This scan_cookie carries a unique identification representing the
+ * scan request if the host driver/kernel supports concurrent scan
+ * requests. This cookie is returned from the corresponding driver
+ * interface.
+ *
+ * Note: Unlike other parameters in this structure, scan_cookie is used
+ * only to return information instead of setting parameters for the
+ * scan.
+ */
+ u64 scan_cookie;
+
+ /**
+ * duration - Dwell time on each channel
+ *
+ * This optional parameter can be used to set the dwell time on each
+ * channel. In TUs.
+ */
+ u16 duration;
+
+ /**
+ * duration_mandatory - Whether the specified duration is mandatory
+ *
+ * If this is set, the duration specified by the %duration field is
+ * mandatory (and the driver should reject the scan request if it is
+ * unable to comply with the specified duration), otherwise it is the
+ * maximum duration and the actual duration may be shorter.
+ */
+ unsigned int duration_mandatory:1;
+
+ /**
+ * relative_rssi_set - Whether relative RSSI parameters are set
+ */
+ unsigned int relative_rssi_set:1;
+
+ /**
+ * relative_rssi - Relative RSSI for reporting better BSSs
+ *
+ * Amount of RSSI by which a BSS should be better than the current
+ * connected BSS to report the new BSS to user space.
+ */
+ s8 relative_rssi;
+
+ /**
+ * relative_adjust_band - Band to which RSSI should be adjusted
+ *
+ * The relative_adjust_rssi should be added to the band specified
+ * by relative_adjust_band.
+ */
+ enum set_band relative_adjust_band;
+
+ /**
+ * relative_adjust_rssi - RSSI to be added to relative_adjust_band
+ *
+ * An amount of relative_band_rssi should be added to the BSSs that
+ * belong to the band specified by relative_adjust_band while comparing
+ * with other bands for BSS reporting.
+ */
+ s8 relative_adjust_rssi;
+
+ /**
+ * oce_scan
+ *
+ * Enable the following OCE scan features: (WFA OCE TechSpec v1.0)
+ * - Accept broadcast Probe Response frame.
+ * - Probe Request frame deferral and suppression.
+ * - Max Channel Time - driver fills FILS request params IE with
+ * Maximum Channel Time.
+ * - Send 1st Probe Request frame in rate of minimum 5.5 Mbps.
+ */
+ unsigned int oce_scan:1;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -437,17 +626,18 @@ struct wpa_driver_auth_params {
int p2p;
/**
- * sae_data - SAE elements for Authentication frame
+ * auth_data - Additional elements for Authentication frame
*
* This buffer starts with the Authentication transaction sequence
- * number field. If SAE is not used, this pointer is %NULL.
+ * number field. If no special handling of such elements is needed, this
+ * pointer is %NULL. This is used with SAE and FILS.
*/
- const u8 *sae_data;
+ const u8 *auth_data;
/**
- * sae_data_len - Length of sae_data buffer in octets
+ * auth_data_len - Length of auth_data buffer in octets
*/
- size_t sae_data_len;
+ size_t auth_data_len;
};
/**
@@ -529,6 +719,68 @@ struct hostapd_freq_params {
};
/**
+ * struct wpa_driver_sta_auth_params - Authentication parameters
+ * Data for struct wpa_driver_ops::sta_auth().
+ */
+struct wpa_driver_sta_auth_params {
+
+ /**
+ * own_addr - Source address and BSSID for authentication frame
+ */
+ const u8 *own_addr;
+
+ /**
+ * addr - MAC address of the station to associate
+ */
+ const u8 *addr;
+
+ /**
+ * seq - authentication sequence number
+ */
+ u16 seq;
+
+ /**
+ * status - authentication response status code
+ */
+ u16 status;
+
+ /**
+ * ie - authentication frame ie buffer
+ */
+ const u8 *ie;
+
+ /**
+ * len - ie buffer length
+ */
+ size_t len;
+
+ /**
+ * fils_auth - Indicates whether FILS authentication is being performed
+ */
+ int fils_auth;
+
+ /**
+ * fils_anonce - ANonce (required for FILS)
+ */
+ u8 fils_anonce[WPA_NONCE_LEN];
+
+ /**
+ * fils_snonce - SNonce (required for FILS)
+ */
+ u8 fils_snonce[WPA_NONCE_LEN];
+
+ /**
+ * fils_kek - key for encryption (required for FILS)
+ */
+ u8 fils_kek[WPA_KEK_MAX_LEN];
+
+ /**
+ * fils_kek_len - Length of the fils_kek in octets (required for FILS)
+ */
+ size_t fils_kek_len;
+};
+
+/**
* struct wpa_driver_associate_params - Association parameters
* Data for struct wpa_driver_ops::associate().
*/
@@ -591,7 +843,7 @@ struct wpa_driver_associate_params {
* WPA information element to be included in (Re)Association
* Request (including information element id and length). Use
* of this WPA IE is optional. If the driver generates the WPA
- * IE, it can use pairwise_suite, group_suite, and
+ * IE, it can use pairwise_suite, group_suite, group_mgmt_suite, and
* key_mgmt_suite to select proper algorithms. In this case,
* the driver has to notify wpa_supplicant about the used WPA
* IE by generating an event that the interface code will
@@ -631,6 +883,13 @@ struct wpa_driver_associate_params {
unsigned int group_suite;
/**
+ * mgmt_group_suite - Selected group management cipher suite (WPA_CIPHER_*)
+ *
+ * This is usually ignored if @wpa_ie is used.
+ */
+ unsigned int mgmt_group_suite;
+
+ /**
* key_mgmt_suite - Selected key management suite (WPA_KEY_MGMT_*)
*
* This is usually ignored if @wpa_ie is used.
@@ -669,50 +928,13 @@ struct wpa_driver_associate_params {
enum mfp_options mgmt_frame_protection;
/**
- * ft_ies - IEEE 802.11r / FT information elements
- * If the supplicant is using IEEE 802.11r (FT) and has the needed keys
- * for fast transition, this parameter is set to include the IEs that
- * are to be sent in the next FT Authentication Request message.
- * update_ft_ies() handler is called to update the IEs for further
- * FT messages in the sequence.
- *
- * The driver should use these IEs only if the target AP is advertising
- * the same mobility domain as the one included in the MDIE here.
- *
- * In ap_scan=2 mode, the driver can use these IEs when moving to a new
- * AP after the initial association. These IEs can only be used if the
- * target AP is advertising support for FT and is using the same MDIE
- * and SSID as the current AP.
- *
- * The driver is responsible for reporting the FT IEs received from the
- * AP's response using wpa_supplicant_event() with EVENT_FT_RESPONSE
- * type. update_ft_ies() handler will then be called with the FT IEs to
- * include in the next frame in the authentication sequence.
- */
- const u8 *ft_ies;
-
- /**
- * ft_ies_len - Length of ft_ies in bytes
- */
- size_t ft_ies_len;
-
- /**
- * ft_md - FT Mobility domain (6 octets) (also included inside ft_ies)
- *
- * This value is provided to allow the driver interface easier access
- * to the current mobility domain. This value is set to %NULL if no
- * mobility domain is currently active.
- */
- const u8 *ft_md;
-
- /**
* passphrase - RSN passphrase for PSK
*
* This value is made available only for WPA/WPA2-Personal (PSK) and
- * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
- * the 8..63 character ASCII passphrase, if available. Please note that
- * this can be %NULL if passphrase was not used to generate the PSK. In
- * that case, the psk field must be used to fetch the PSK.
+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK. This
+ * is the 8..63 character ASCII passphrase, if available. Please note
+ * that this can be %NULL if passphrase was not used to generate the
+ * PSK. In that case, the psk field must be used to fetch the PSK.
*/
const char *passphrase;
@@ -720,9 +942,9 @@ struct wpa_driver_associate_params {
* psk - RSN PSK (alternative for passphrase for PSK)
*
* This value is made available only for WPA/WPA2-Personal (PSK) and
- * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
- * the 32-octet (256-bit) PSK, if available. The driver wrapper should
- * be prepared to handle %NULL value as an error.
+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK. This
+ * is the 32-octet (256-bit) PSK, if available. The driver wrapper
+ * should be prepared to handle %NULL value as an error.
*/
const u8 *psk;
@@ -828,6 +1050,70 @@ struct wpa_driver_associate_params {
* RRM (Radio Resource Measurements)
*/
int rrm_used;
+
+ /**
+ * pbss - If set, connect to a PCP in a PBSS. Otherwise, connect to an
+ * AP as usual. Valid for DMG network only.
+ */
+ int pbss;
+
+ /**
+ * fils_kek - KEK for FILS association frame protection (AES-SIV)
+ */
+ const u8 *fils_kek;
+
+ /**
+ * fils_kek_len: Length of fils_kek in bytes
+ */
+ size_t fils_kek_len;
+
+ /**
+ * fils_nonces - Nonces for FILS association frame protection
+ * (AES-SIV AAD)
+ */
+ const u8 *fils_nonces;
+
+ /**
+ * fils_nonces_len: Length of fils_nonce in bytes
+ */
+ size_t fils_nonces_len;
+
+ /**
+ * fils_erp_username - Username part of keyName-NAI
+ */
+ const u8 *fils_erp_username;
+
+ /**
+ * fils_erp_username_len - Length of fils_erp_username in bytes
+ */
+ size_t fils_erp_username_len;
+
+ /**
+ * fils_erp_realm - Realm/domain name to use in FILS ERP
+ */
+ const u8 *fils_erp_realm;
+
+ /**
+ * fils_erp_realm_len - Length of fils_erp_realm in bytes
+ */
+ size_t fils_erp_realm_len;
+
+ /**
+ * fils_erp_next_seq_num - The next sequence number to use in FILS ERP
+ * messages
+ */
+ u16 fils_erp_next_seq_num;
+
+ /**
+ * fils_erp_rrk - Re-authentication root key (rRK) for the keyName-NAI
+ * specified by fils_erp_username@fils_erp_realm.
+ */
+ const u8 *fils_erp_rrk;
+
+ /**
+ * fils_erp_rrk_len - Length of fils_erp_rrk in bytes
+ */
+ size_t fils_erp_rrk_len;
};
enum hide_ssid {
@@ -886,6 +1172,22 @@ struct wpa_driver_ap_params {
int *basic_rates;
/**
+ * beacon_rate: Beacon frame data rate
+ *
+ * This parameter can be used to set a specific Beacon frame data rate
+ * for the BSS. The interpretation of this value depends on the
+ * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS). If
+ * beacon_rate == 0 and rate_type == 0 (BEACON_RATE_LEGACY), the default
+ * Beacon frame data rate is used.
+ */
+ unsigned int beacon_rate;
+
+ /**
+ * beacon_rate_type: Beacon data rate type (legacy/HT/VHT)
+ */
+ enum beacon_rate_type rate_type;
+
+ /**
* proberesp - Probe Response template
*
* This is used by drivers that reply to Probe Requests internally in
@@ -1055,16 +1357,68 @@ struct wpa_driver_ap_params {
* reenable - Whether this is to re-enable beaconing
*/
int reenable;
+
+ /**
+ * pbss - Whether to start a PCP (in PBSS) instead of an AP in
+ * infrastructure BSS. Valid only for DMG network.
+ */
+ int pbss;
+
+ /**
+ * multicast_to_unicast - Whether to use multicast_to_unicast
+ *
+ * If this is non-zero, the AP is requested to perform multicast to
+ * unicast conversion for ARP, IPv4, and IPv6 frames (possibly within
+ * 802.1Q). If enabled, such frames are to be sent to each station
+ * separately, with the DA replaced by their own MAC address rather
+ * than the group address.
+ *
+ * Note that this may break certain expectations of the receiver, such
+ * as the ability to drop unicast IP packets received within multicast
+ * L2 frames, or the ability to not send ICMP destination unreachable
+ * messages for packets received in L2 multicast (which is required,
+ * but the receiver can't tell the difference if this new option is
+ * enabled.)
+ *
+ * This also doesn't implement the 802.11 DMS (directed multicast
+ * service).
+ */
+ int multicast_to_unicast;
+
+ /**
+ * ftm_responder - Whether FTM responder is enabled
+ */
+ int ftm_responder;
+
+ /**
+ * lci - Binary data, the content of an LCI report IE with type 8 as
+ * defined in IEEE Std 802.11-2016, 9.4.2.22.10
+ */
+ const struct wpabuf *lci;
+
+ /**
+ * civic - Binary data, the content of a measurement report IE with
+ * type 11 as defined in IEEE Std 802.11-2016, 9.4.2.22.13
+ */
+ const struct wpabuf *civic;
};
struct wpa_driver_mesh_bss_params {
-#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001
+#define WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT 0x00000002
+#define WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS 0x00000004
+#define WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE 0x00000008
+#define WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD 0x00000010
/*
* TODO: Other mesh configuration parameters would go here.
* See NL80211_MESHCONF_* for all the mesh config parameters.
*/
unsigned int flags;
+ int auto_plinks;
int peer_link_timeout;
+ int max_peer_links;
+ int rssi_threshold;
+ u16 ht_opmode;
};
struct wpa_driver_mesh_join_params {
@@ -1075,7 +1429,7 @@ struct wpa_driver_mesh_join_params {
int ie_len;
struct hostapd_freq_params freq;
int beacon_int;
- int max_peer_links;
+ int dtim_period;
struct wpa_driver_mesh_bss_params conf;
#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001
#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002
@@ -1098,6 +1452,13 @@ struct wpa_driver_capa {
#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK 0x00000080
#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B 0x00000100
#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 0x00000200
+#define WPA_DRIVER_CAPA_KEY_MGMT_OWE 0x00000400
+#define WPA_DRIVER_CAPA_KEY_MGMT_DPP 0x00000800
+#define WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 0x00001000
+#define WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 0x00002000
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 0x00004000
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 0x00008000
+#define WPA_DRIVER_CAPA_KEY_MGMT_SAE 0x00010000
/** Bitfield of supported key management suites */
unsigned int key_mgmt;
@@ -1131,7 +1492,7 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004
/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
* struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
-#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X 0x00000008
/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
/** Driver provides separate commands for authentication and association (SME in
@@ -1214,8 +1575,54 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL
/** Driver supports automatic band selection */
#define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY 0x0000004000000000ULL
+/** Driver supports simultaneous off-channel operations */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS 0x0000008000000000ULL
+/** Driver supports full AP client state */
+#define WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE 0x0000010000000000ULL
+/** Driver supports P2P Listen offload */
+#define WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD 0x0000020000000000ULL
+/** Driver supports FILS */
+#define WPA_DRIVER_FLAGS_SUPPORT_FILS 0x0000040000000000ULL
+/** Driver supports Beacon frame TX rate configuration (legacy rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY 0x0000080000000000ULL
+/** Driver supports Beacon frame TX rate configuration (HT rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_HT 0x0000100000000000ULL
+/** Driver supports Beacon frame TX rate configuration (VHT rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_VHT 0x0000200000000000ULL
+/** Driver supports mgmt_tx with random TX address in non-connected state */
+#define WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA 0x0000400000000000ULL
+/** Driver supports mgmt_tx with random TX addr in connected state */
+#define WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED 0x0000800000000000ULL
+/** Driver supports better BSS reporting with sched_scan in connected mode */
+#define WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI 0x0001000000000000ULL
+/** Driver supports HE capabilities */
+#define WPA_DRIVER_FLAGS_HE_CAPABILITIES 0x0002000000000000ULL
+/** Driver supports FILS shared key offload */
+#define WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD 0x0004000000000000ULL
+/** Driver supports all OCE STA specific mandatory features */
+#define WPA_DRIVER_FLAGS_OCE_STA 0x0008000000000000ULL
+/** Driver supports all OCE AP specific mandatory features */
+#define WPA_DRIVER_FLAGS_OCE_AP 0x0010000000000000ULL
+/**
+ * Driver supports all OCE STA-CFON specific mandatory features only.
+ * If a driver sets this bit but not the %WPA_DRIVER_FLAGS_OCE_AP, the
+ * userspace shall assume that this driver may not support all OCE AP
+ * functionality but can support only OCE STA-CFON functionality.
+ */
+#define WPA_DRIVER_FLAGS_OCE_STA_CFON 0x0020000000000000ULL
+/** Driver supports MFP-optional in the connect command */
+#define WPA_DRIVER_FLAGS_MFP_OPTIONAL 0x0040000000000000ULL
+/** Driver is a self-managed regulatory device */
+#define WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY 0x0080000000000000ULL
+/** Driver supports FTM responder functionality */
+#define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL
+/** Driver support 4-way handshake offload for WPA-Personal */
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL
u64 flags;
+#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
+ (drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE)
+
#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002
unsigned int smps_modes;
@@ -1231,6 +1638,15 @@ struct wpa_driver_capa {
/** Maximum number of supported active probe SSIDs for sched_scan */
int max_sched_scan_ssids;
+ /** Maximum number of supported scan plans for scheduled scan */
+ unsigned int max_sched_scan_plans;
+
+ /** Maximum interval in a scan plan. In seconds */
+ u32 max_sched_scan_plan_interval;
+
+ /** Maximum number of iterations in a single scan plan */
+ u32 max_sched_scan_plan_iterations;
+
/** Whether sched_scan (offloaded scanning) is supported */
int sched_scan_supported;
@@ -1296,6 +1712,17 @@ struct wpa_driver_capa {
* offset, namely the 6th byte in the Action frame body.
*/
#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008
+/**
+ * Driver supports RRM. With this support, the driver will accept to use RRM in
+ * (Re)Association Request frames, without supporting quiet period.
+ */
+#define WPA_DRIVER_FLAGS_SUPPORT_RRM 0x00000010
+
+/** Driver supports setting the scan dwell time */
+#define WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL 0x00000020
+/** Driver supports Beacon Report Measurement */
+#define WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT 0x00000040
+
u32 rrm_flags;
/* Driver concurrency capabilities */
@@ -1304,21 +1731,43 @@ struct wpa_driver_capa {
unsigned int max_conc_chan_2_4;
/* Maximum number of concurrent channels on 5 GHz */
unsigned int max_conc_chan_5_0;
+
+ /* Maximum number of supported CSA counters */
+ u16 max_csa_counters;
};
struct hostapd_data;
+#define STA_DRV_DATA_TX_MCS BIT(0)
+#define STA_DRV_DATA_RX_MCS BIT(1)
+#define STA_DRV_DATA_TX_VHT_MCS BIT(2)
+#define STA_DRV_DATA_RX_VHT_MCS BIT(3)
+#define STA_DRV_DATA_TX_VHT_NSS BIT(4)
+#define STA_DRV_DATA_RX_VHT_NSS BIT(5)
+#define STA_DRV_DATA_TX_SHORT_GI BIT(6)
+#define STA_DRV_DATA_RX_SHORT_GI BIT(7)
+#define STA_DRV_DATA_LAST_ACK_RSSI BIT(8)
+
struct hostap_sta_driver_data {
- unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
+ unsigned long rx_packets, tx_packets;
+ unsigned long long rx_bytes, tx_bytes;
+ int bytes_64bit; /* whether 64-bit byte counters are supported */
unsigned long current_tx_rate;
+ unsigned long current_rx_rate;
unsigned long inactive_msec;
- unsigned long flags;
+ unsigned long flags; /* bitfield of STA_DRV_DATA_* */
unsigned long num_ps_buf_frames;
unsigned long tx_retry_failed;
unsigned long tx_retry_count;
- int last_rssi;
- int last_ack_rssi;
+ s8 last_ack_rssi;
+ s8 signal;
+ u8 rx_vhtmcs;
+ u8 tx_vhtmcs;
+ u8 rx_mcs;
+ u8 tx_mcs;
+ u8 rx_vht_nss;
+ u8 tx_vht_nss;
};
struct hostapd_sta_add_params {
@@ -1336,6 +1785,7 @@ struct hostapd_sta_add_params {
u32 flags_mask; /* unset bits in flags */
#ifdef CONFIG_MESH
enum mesh_plink_state plink_state;
+ u16 peer_aid;
#endif /* CONFIG_MESH */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
@@ -1345,6 +1795,7 @@ struct hostapd_sta_add_params {
size_t supp_channels_len;
const u8 *supp_oper_classes;
size_t supp_oper_classes_len;
+ int support_p2p_ps;
};
struct mac_address {
@@ -1450,6 +1901,7 @@ struct wpa_bss_params {
#define WPA_STA_MFP BIT(3)
#define WPA_STA_TDLS_PEER BIT(4)
#define WPA_STA_AUTHENTICATED BIT(5)
+#define WPA_STA_ASSOCIATED BIT(6)
enum tdls_oper {
TDLS_DISCOVERY_REQ,
@@ -1478,19 +1930,32 @@ enum wnm_oper {
WNM_SLEEP_TFS_IE_DEL /* AP delete the TFS IE */
};
-/* enum chan_width - Channel width definitions */
-enum chan_width {
- CHAN_WIDTH_20_NOHT,
- CHAN_WIDTH_20,
- CHAN_WIDTH_40,
- CHAN_WIDTH_80,
- CHAN_WIDTH_80P80,
- CHAN_WIDTH_160,
- CHAN_WIDTH_UNKNOWN
+/* enum smps_mode - SMPS mode definitions */
+enum smps_mode {
+ SMPS_AUTOMATIC,
+ SMPS_OFF,
+ SMPS_DYNAMIC,
+ SMPS_STATIC,
+
+ /* Keep last */
+ SMPS_INVALID,
};
+#define WPA_INVALID_NOISE 9999
+
/**
* struct wpa_signal_info - Information about channel signal quality
+ * @frequency: control frequency
+ * @above_threshold: true if the above threshold was crossed
+ * (relevant for a CQM event)
+ * @current_signal: in dBm
+ * @avg_signal: in dBm
+ * @avg_beacon_signal: in dBm
+ * @current_noise: %WPA_INVALID_NOISE if not supported
+ * @current_txrate: current TX rate
+ * @chanwidth: channel width
+ * @center_frq1: center frequency for the first segment
+ * @center_frq2: center frequency for the second segment (if relevant)
*/
struct wpa_signal_info {
u32 frequency;
@@ -1506,6 +1971,26 @@ struct wpa_signal_info {
};
/**
+ * struct wpa_channel_info - Information about the current channel
+ * @frequency: Center frequency of the primary 20 MHz channel
+ * @chanwidth: Width of the current operating channel
+ * @sec_channel: Location of the secondary 20 MHz channel (either +1 or -1).
+ * This field is only filled in when using a 40 MHz channel.
+ * @center_frq1: Center frequency of frequency segment 0
+ * @center_frq2: Center frequency of frequency segment 1 (for 80+80 channels)
+ * @seg1_idx: Frequency segment 1 index when using a 80+80 channel. This is
+ * derived from center_frq2 for convenience.
+ */
+struct wpa_channel_info {
+ u32 frequency;
+ enum chan_width chanwidth;
+ int sec_channel;
+ int center_frq1;
+ int center_frq2;
+ u8 seg1_idx;
+};
+
+/**
* struct beacon_data - Beacon data
* @head: Head portion of Beacon frame (before TIM IE)
* @tail: Tail portion of Beacon frame (after TIM IE)
@@ -1554,8 +2039,8 @@ struct csa_settings {
struct beacon_data beacon_csa;
struct beacon_data beacon_after;
- u16 counter_offset_beacon;
- u16 counter_offset_presp;
+ u16 counter_offset_beacon[2];
+ u16 counter_offset_presp[2];
};
/* TDLS peer capabilities for send_tdls_mgmt() */
@@ -1622,6 +2107,69 @@ struct drv_acs_params {
const int *freq_list;
};
+struct wpa_bss_trans_info {
+ u8 mbo_transition_reason;
+ u8 n_candidates;
+ u8 *bssid;
+};
+
+struct wpa_bss_candidate_info {
+ u8 num;
+ struct candidate_list {
+ u8 bssid[ETH_ALEN];
+ u8 is_accept;
+ u32 reject_reason;
+ } *candidates;
+};
+
+struct wpa_pmkid_params {
+ const u8 *bssid;
+ const u8 *ssid;
+ size_t ssid_len;
+ const u8 *fils_cache_id;
+ const u8 *pmkid;
+ const u8 *pmk;
+ size_t pmk_len;
+};
+
+/* Mask used to specify which connection parameters have to be updated */
+enum wpa_drv_update_connect_params_mask {
+ WPA_DRV_UPDATE_ASSOC_IES = BIT(0),
+ WPA_DRV_UPDATE_FILS_ERP_INFO = BIT(1),
+ WPA_DRV_UPDATE_AUTH_TYPE = BIT(2),
+};
+
+/**
+ * struct external_auth - External authentication trigger parameters
+ *
+ * These are used across the external authentication request and event
+ * interfaces.
+ * @action: Action type / trigger for external authentication. Only significant
+ * for the event interface.
+ * @bssid: BSSID of the peer with which the authentication has to happen. Used
+ * by both the request and event interface.
+ * @ssid: SSID of the AP. Used by both the request and event interface.
+ * @ssid_len: SSID length in octets.
+ * @key_mgmt_suite: AKM suite of the respective authentication. Optional for
+ * the request interface.
+ * @status: Status code, %WLAN_STATUS_SUCCESS for successful authentication,
+ * use %WLAN_STATUS_UNSPECIFIED_FAILURE if wpa_supplicant cannot give
+ * the real status code for failures. Used only for the request interface
+ * from user space to the driver.
+ * @pmkid: Generated PMKID as part of external auth exchange (e.g., SAE).
+ */
+struct external_auth {
+ enum {
+ EXT_AUTH_START,
+ EXT_AUTH_ABORT,
+ } action;
+ const u8 *bssid;
+ const u8 *ssid;
+ size_t ssid_len;
+ unsigned int key_mgmt_suite;
+ u16 status;
+ const u8 *pmkid;
+};
/**
* struct wpa_driver_ops - Driver interface API definition
@@ -1804,13 +2352,14 @@ struct wpa_driver_ops {
/**
* add_pmkid - Add PMKSA cache entry to the driver
* @priv: private driver interface data
- * @bssid: BSSID for the PMKSA cache entry
- * @pmkid: PMKID for the PMKSA cache entry
+ * @params: PMKSA parameters
*
* Returns: 0 on success, -1 on failure
*
* This function is called when a new PMK is received, as a result of
- * either normal authentication or RSN pre-authentication.
+ * either normal authentication or RSN pre-authentication. The PMKSA
+ * parameters are either a set of bssid, pmkid, and pmk; or a set of
+ * ssid, fils_cache_id, pmkid, and pmk.
*
* If the driver generates RSN IE, i.e., it does not use wpa_ie in
* associate(), add_pmkid() can be used to add new PMKSA cache entries
@@ -1818,18 +2367,18 @@ struct wpa_driver_ops {
* driver_ops function does not need to be implemented. Likewise, if
* the driver does not support WPA, this function is not needed.
*/
- int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+ int (*add_pmkid)(void *priv, struct wpa_pmkid_params *params);
/**
* remove_pmkid - Remove PMKSA cache entry to the driver
* @priv: private driver interface data
- * @bssid: BSSID for the PMKSA cache entry
- * @pmkid: PMKID for the PMKSA cache entry
+ * @params: PMKSA parameters
*
* Returns: 0 on success, -1 on failure
*
* This function is called when the supplicant drops a PMKSA cache
- * entry for any reason.
+ * entry for any reason. The PMKSA parameters are either a set of
+ * bssid and pmkid; or a set of ssid, fils_cache_id, and pmkid.
*
* If the driver generates RSN IE, i.e., it does not use wpa_ie in
* associate(), remove_pmkid() can be used to synchronize PMKSA caches
@@ -1838,7 +2387,7 @@ struct wpa_driver_ops {
* implemented. Likewise, if the driver does not support WPA, this
* function is not needed.
*/
- int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+ int (*remove_pmkid)(void *priv, struct wpa_pmkid_params *params);
/**
* flush_pmkid - Flush PMKSA cache
@@ -1883,6 +2432,14 @@ struct wpa_driver_ops {
void (*poll)(void *priv);
/**
+ * get_ifindex - Get interface index
+ * @priv: private driver interface data
+ *
+ * Returns: Interface index
+ */
+ unsigned int (*get_ifindex)(void *priv);
+
+ /**
* get_ifname - Get interface name
* @priv: private driver interface data
*
@@ -1945,12 +2502,13 @@ struct wpa_driver_ops {
* @priv: Private driver interface data
* @num_modes: Variable for returning the number of returned modes
* flags: Variable for returning hardware feature flags
+ * @dfs: Variable for returning DFS region (HOSTAPD_DFS_REGION_*)
* Returns: Pointer to allocated hardware data on success or %NULL on
* failure. Caller is responsible for freeing this.
*/
struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
u16 *num_modes,
- u16 *flags);
+ u16 *flags, u8 *dfs);
/**
* send_mlme - Send management frame from MLME
@@ -1960,10 +2518,13 @@ struct wpa_driver_ops {
* @noack: Do not wait for this frame to be acked (disable retries)
* @freq: Frequency (in MHz) to send the frame on, or 0 to let the
* driver decide
+ * @csa_offs: Array of CSA offsets or %NULL
+ * @csa_offs_len: Number of elements in csa_offs
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
- int noack, unsigned int freq);
+ int noack, unsigned int freq, const u16 *csa_offs,
+ size_t csa_offs_len);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -2013,6 +2574,7 @@ struct wpa_driver_ops {
/**
* global_init - Global driver initialization
+ * @ctx: wpa_global pointer
* Returns: Pointer to private data (global), %NULL on failure
*
* This optional function is called to initialize the driver wrapper
@@ -2022,7 +2584,7 @@ struct wpa_driver_ops {
* use init2() function instead of init() to get the pointer to global
* data available to per-interface initializer.
*/
- void * (*global_init)(void);
+ void * (*global_init)(void *ctx);
/**
* global_deinit - Global driver deinitialization
@@ -2308,12 +2870,17 @@ struct wpa_driver_ops {
* @params: Station parameters
* Returns: 0 on success, -1 on failure
*
- * This function is used to add a station entry to the driver once the
- * station has completed association. This is only used if the driver
+ * This function is used to add or set (params->set 1) a station
+ * entry in the driver. Adding STA entries is used only if the driver
* does not take care of association processing.
*
- * With TDLS, this function is also used to add or set (params->set 1)
- * TDLS peer entries.
+ * With drivers that don't support full AP client state, this function
+ * is used to add a station entry to the driver once the station has
+ * completed association.
+ *
+ * With TDLS, this function is used to add or set (params->set 1)
+ * TDLS peer entries (even with drivers that do not support full AP
+ * client state).
*/
int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
@@ -2399,12 +2966,13 @@ struct wpa_driver_ops {
* change interface address)
* @bridge: Bridge interface to use or %NULL if no bridge configured
* @use_existing: Whether to allow existing interface to be used
+ * @setup_ap: Whether to setup AP for %WPA_IF_AP_BSS interfaces
* Returns: 0 on success, -1 on failure
*/
int (*if_add)(void *priv, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
- const char *bridge, int use_existing);
+ const char *bridge, int use_existing, int setup_ap);
/**
* if_remove - Remove a virtual interface
@@ -2557,6 +3125,9 @@ struct wpa_driver_ops {
* transmitted on that channel; alternatively the frame may be sent on
* the current operational channel (if in associated state in station
* mode or while operating as an AP.)
+ *
+ * If @src differs from the device MAC address, use of a random
+ * transmitter address is requested for this message exchange.
*/
int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
const u8 *dst, const u8 *src, const u8 *bssid,
@@ -2857,6 +3428,14 @@ struct wpa_driver_ops {
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
/**
+ * channel_info - Get parameters of the current operating channel
+ * @priv: Private driver interface data
+ * @channel_info: Channel info structure
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*channel_info)(void *priv, struct wpa_channel_info *channel_info);
+
+ /**
* set_authmode - Set authentication algorithm(s) for static WEP
* @priv: Private driver interface data
* @authmode: 1=Open System, 2=Shared Key, 3=both
@@ -2942,19 +3521,13 @@ struct wpa_driver_ops {
/**
* sta_auth - Station authentication indication
- * @priv: Private driver interface data
- * @own_addr: Source address and BSSID for authentication frame
- * @addr: MAC address of the station to associate
- * @seq: authentication sequence number
- * @status: authentication response status code
- * @ie: authentication frame ie buffer
- * @len: ie buffer length
+ * @priv: private driver interface data
+ * @params: Station authentication parameters
*
- * This function indicates the driver to send Authentication frame
- * to the station.
+ * Returns: 0 on success, -1 on failure
*/
- int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr,
- u16 seq, u16 status, const u8 *ie, size_t len);
+ int (*sta_auth)(void *priv,
+ struct wpa_driver_sta_auth_params *params);
/**
* add_tspec - Add traffic stream
@@ -2986,7 +3559,6 @@ struct wpa_driver_ops {
* sched_scan - Request the driver to initiate scheduled scan
* @priv: Private driver interface data
* @params: Scan parameters
- * @interval: Interval between scan cycles in milliseconds
* Returns: 0 on success, -1 on failure
*
* This operation should be used for scheduled scan offload to
@@ -2997,8 +3569,7 @@ struct wpa_driver_ops {
* and if not provided or if it returns -1, we fall back to
* normal host-scheduled scans.
*/
- int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params,
- u32 interval);
+ int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params);
/**
* stop_sched_scan - Request the driver to stop a scheduled scan
@@ -3145,7 +3716,7 @@ struct wpa_driver_ops {
/**
* status - Get driver interface status information
* @priv: Private driver interface data
- * @buf: Buffer for printing tou the status information
+ * @buf: Buffer for printing the status information
* @buflen: Maximum length of the buffer
* Returns: Length of written status information or -1 on failure
*/
@@ -3168,6 +3739,17 @@ struct wpa_driver_ops {
int (*roaming)(void *priv, int allowed, const u8 *bssid);
/**
+ * disable_fils - Enable/disable FILS feature
+ * @priv: Private driver interface data
+ * @disable: 0-enable and 1-disable FILS feature
+ * Returns: 0 on success, -1 on failure
+ *
+ * This callback can be used to configure driver and below layers to
+ * enable/disable all FILS features.
+ */
+ int (*disable_fils)(void *priv, int disable);
+
+ /**
* set_mac_addr - Set MAC address
* @priv: Private driver interface data
* @addr: MAC address to use or %NULL for setting back to permanent
@@ -3181,6 +3763,14 @@ struct wpa_driver_ops {
int (*macsec_deinit)(void *priv);
/**
+ * macsec_get_capability - Inform MKA of this driver's capability
+ * @priv: Private driver interface data
+ * @cap: Driver's capability
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*macsec_get_capability)(void *priv, enum macsec_cap *cap);
+
+ /**
* enable_protect_frames - Set protect frames status
* @priv: Private driver interface data
* @enabled: TRUE = protect frames enabled
@@ -3190,6 +3780,15 @@ struct wpa_driver_ops {
int (*enable_protect_frames)(void *priv, Boolean enabled);
/**
+ * enable_encrypt - Set encryption status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = encrypt outgoing traffic
+ * FALSE = integrity-only protection on outgoing traffic
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+ int (*enable_encrypt)(void *priv, Boolean enabled);
+
+ /**
* set_replay_protect - Set replay protect status and window size
* @priv: Private driver interface data
* @enabled: TRUE = replay protect enabled
@@ -3203,11 +3802,9 @@ struct wpa_driver_ops {
* set_current_cipher_suite - Set current cipher suite
* @priv: Private driver interface data
* @cs: EUI64 identifier
- * @cs_len: Length of the cs buffer in octets
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*set_current_cipher_suite)(void *priv, const u8 *cs,
- size_t cs_len);
+ int (*set_current_cipher_suite)(void *priv, u64 cs);
/**
* enable_controlled_port - Set controlled port status
@@ -3221,155 +3818,137 @@ struct wpa_driver_ops {
/**
* get_receive_lowest_pn - Get receive lowest pn
* @priv: Private driver interface data
- * @channel: secure channel
- * @an: association number
- * @lowest_pn: lowest accept pn
+ * @sa: secure association
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*get_receive_lowest_pn)(void *priv, u32 channel, u8 an,
- u32 *lowest_pn);
+ int (*get_receive_lowest_pn)(void *priv, struct receive_sa *sa);
/**
* get_transmit_next_pn - Get transmit next pn
* @priv: Private driver interface data
- * @channel: secure channel
- * @an: association number
- * @next_pn: next pn
+ * @sa: secure association
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*get_transmit_next_pn)(void *priv, u32 channel, u8 an,
- u32 *next_pn);
+ int (*get_transmit_next_pn)(void *priv, struct transmit_sa *sa);
/**
* set_transmit_next_pn - Set transmit next pn
* @priv: Private driver interface data
- * @channel: secure channel
- * @an: association number
- * @next_pn: next pn
+ * @sa: secure association
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*set_transmit_next_pn)(void *priv, u32 channel, u8 an,
- u32 next_pn);
+ int (*set_transmit_next_pn)(void *priv, struct transmit_sa *sa);
/**
- * get_available_receive_sc - get available receive channel
+ * set_receive_lowest_pn - Set receive lowest PN
* @priv: Private driver interface data
- * @channel: secure channel
+ * @sa: secure association
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*get_available_receive_sc)(void *priv, u32 *channel);
+ int (*set_receive_lowest_pn)(void *priv, struct receive_sa *sa);
/**
* create_receive_sc - create secure channel for receiving
* @priv: Private driver interface data
- * @channel: secure channel
- * @sci_addr: secure channel identifier - address
- * @sci_port: secure channel identifier - port
+ * @sc: secure channel
* @conf_offset: confidentiality offset (0, 30, or 50)
* @validation: frame validation policy (0 = Disabled, 1 = Checked,
* 2 = Strict)
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*create_receive_sc)(void *priv, u32 channel, const u8 *sci_addr,
- u16 sci_port, unsigned int conf_offset,
+ int (*create_receive_sc)(void *priv, struct receive_sc *sc,
+ unsigned int conf_offset,
int validation);
/**
* delete_receive_sc - delete secure connection for receiving
* @priv: private driver interface data from init()
- * @channel: secure channel
+ * @sc: secure channel
* Returns: 0 on success, -1 on failure
*/
- int (*delete_receive_sc)(void *priv, u32 channel);
+ int (*delete_receive_sc)(void *priv, struct receive_sc *sc);
/**
* create_receive_sa - create secure association for receive
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @an: association number
- * @lowest_pn: the lowest packet number can be received
- * @sak: the secure association key
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*create_receive_sa)(void *priv, u32 channel, u8 an,
- u32 lowest_pn, const u8 *sak);
+ int (*create_receive_sa)(void *priv, struct receive_sa *sa);
/**
- * enable_receive_sa - enable the SA for receive
- * @priv: private driver interface data from init()
- * @channel: secure channel
- * @an: association number
+ * delete_receive_sa - Delete secure association for receive
+ * @priv: Private driver interface data from init()
+ * @sa: Secure association
* Returns: 0 on success, -1 on failure
*/
- int (*enable_receive_sa)(void *priv, u32 channel, u8 an);
+ int (*delete_receive_sa)(void *priv, struct receive_sa *sa);
/**
- * disable_receive_sa - disable SA for receive
+ * enable_receive_sa - enable the SA for receive
* @priv: private driver interface data from init()
- * @channel: secure channel index
- * @an: association number
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*disable_receive_sa)(void *priv, u32 channel, u8 an);
+ int (*enable_receive_sa)(void *priv, struct receive_sa *sa);
/**
- * get_available_transmit_sc - get available transmit channel
- * @priv: Private driver interface data
- * @channel: secure channel
- * Returns: 0 on success, -1 on failure (or if not supported)
+ * disable_receive_sa - disable SA for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
*/
- int (*get_available_transmit_sc)(void *priv, u32 *channel);
+ int (*disable_receive_sa)(void *priv, struct receive_sa *sa);
/**
* create_transmit_sc - create secure connection for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @sci_addr: secure channel identifier - address
- * @sci_port: secure channel identifier - port
+ * @sc: secure channel
+ * @conf_offset: confidentiality offset (0, 30, or 50)
* Returns: 0 on success, -1 on failure
*/
- int (*create_transmit_sc)(void *priv, u32 channel, const u8 *sci_addr,
- u16 sci_port, unsigned int conf_offset);
+ int (*create_transmit_sc)(void *priv, struct transmit_sc *sc,
+ unsigned int conf_offset);
/**
* delete_transmit_sc - delete secure connection for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel
+ * @sc: secure channel
* Returns: 0 on success, -1 on failure
*/
- int (*delete_transmit_sc)(void *priv, u32 channel);
+ int (*delete_transmit_sc)(void *priv, struct transmit_sc *sc);
/**
* create_transmit_sa - create secure association for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel index
- * @an: association number
- * @next_pn: the packet number used as next transmit packet
- * @confidentiality: True if the SA is to provide confidentiality
- * as well as integrity
- * @sak: the secure association key
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*create_transmit_sa)(void *priv, u32 channel, u8 an, u32 next_pn,
- Boolean confidentiality, const u8 *sak);
+ int (*create_transmit_sa)(void *priv, struct transmit_sa *sa);
+
+ /**
+ * delete_transmit_sa - Delete secure association for transmit
+ * @priv: Private driver interface data from init()
+ * @sa: Secure association
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*delete_transmit_sa)(void *priv, struct transmit_sa *sa);
/**
* enable_transmit_sa - enable SA for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @an: association number
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*enable_transmit_sa)(void *priv, u32 channel, u8 an);
+ int (*enable_transmit_sa)(void *priv, struct transmit_sa *sa);
/**
* disable_transmit_sa - disable SA for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @an: association number
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*disable_transmit_sa)(void *priv, u32 channel, u8 an);
+ int (*disable_transmit_sa)(void *priv, struct transmit_sa *sa);
#endif /* CONFIG_MACSEC */
/**
@@ -3439,8 +4018,156 @@ struct wpa_driver_ops {
* on. Local device is assuming P2P Client role.
*/
int (*set_prob_oper_freq)(void *priv, unsigned int freq);
-};
+ /**
+ * abort_scan - Request the driver to abort an ongoing scan
+ * @priv: Private driver interface data
+ * @scan_cookie: Cookie identifying the scan request. This is used only
+ * when the vendor interface QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN
+ * was used to trigger scan. Otherwise, 0 is used.
+ * Returns 0 on success, -1 on failure
+ */
+ int (*abort_scan)(void *priv, u64 scan_cookie);
+
+ /**
+ * configure_data_frame_filters - Request to configure frame filters
+ * @priv: Private driver interface data
+ * @filter_flags: The type of frames to filter (bitfield of
+ * WPA_DATA_FRAME_FILTER_FLAG_*)
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*configure_data_frame_filters)(void *priv, u32 filter_flags);
+
+ /**
+ * get_ext_capab - Get extended capabilities for the specified interface
+ * @priv: Private driver interface data
+ * @type: Interface type for which to get extended capabilities
+ * @ext_capab: Extended capabilities fetched
+ * @ext_capab_mask: Extended capabilities mask
+ * @ext_capab_len: Length of the extended capabilities
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type,
+ const u8 **ext_capab, const u8 **ext_capab_mask,
+ unsigned int *ext_capab_len);
+
+ /**
+ * p2p_lo_start - Start offloading P2P listen to device
+ * @priv: Private driver interface data
+ * @freq: Listening frequency (MHz) for P2P listen
+ * @period: Length of the listen operation in milliseconds
+ * @interval: Interval for running the listen operation in milliseconds
+ * @count: Number of times to run the listen operation
+ * @device_types: Device primary and secondary types
+ * @dev_types_len: Number of bytes for device_types
+ * @ies: P2P IE and WSC IE for Probe Response frames
+ * @ies_len: Length of ies in bytes
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*p2p_lo_start)(void *priv, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count,
+ const u8 *device_types, size_t dev_types_len,
+ const u8 *ies, size_t ies_len);
+
+ /**
+ * p2p_lo_stop - Stop P2P listen offload
+ * @priv: Private driver interface data
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*p2p_lo_stop)(void *priv);
+
+ /**
+ * set_default_scan_ies - Set default scan IEs
+ * @priv: Private driver interface data
+ * @ies: Scan default IEs buffer
+ * @ies_len: Length of IEs in bytes
+ * Returns: 0 on success or -1 on failure
+ *
+ * The driver can use these by default when there are no scan IEs coming
+ * in the subsequent scan requests. Also in case of one or more of IEs
+ * given in set_default_scan_ies() are missing in the subsequent scan
+ * request, the driver should merge the missing scan IEs in the scan
+ * request from the IEs set by set_default_scan_ies() in the Probe
+ * Request frames sent.
+ */
+ int (*set_default_scan_ies)(void *priv, const u8 *ies, size_t ies_len);
+
+ /**
+ * set_tdls_mode - Set TDLS trigger mode to the host driver
+ * @priv: Private driver interface data
+ * @tdls_external_control: Represents if TDLS external trigger control
+ * mode is enabled/disabled.
+ *
+ * This optional callback can be used to configure the TDLS external
+ * trigger control mode to the host driver.
+ */
+ int (*set_tdls_mode)(void *priv, int tdls_external_control);
+
+ /**
+ * get_bss_transition_status - Get candidate BSS's transition status
+ * @priv: Private driver interface data
+ * @params: Candidate BSS list
+ *
+ * Get the accept or reject reason code for a list of BSS transition
+ * candidates.
+ */
+ struct wpa_bss_candidate_info *
+ (*get_bss_transition_status)(void *priv,
+ struct wpa_bss_trans_info *params);
+ /**
+ * ignore_assoc_disallow - Configure driver to ignore assoc_disallow
+ * @priv: Private driver interface data
+ * @ignore_disallow: 0 to not ignore, 1 to ignore
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*ignore_assoc_disallow)(void *priv, int ignore_disallow);
+
+ /**
+ * set_bssid_blacklist - Set blacklist of BSSIDs to the driver
+ * @priv: Private driver interface data
+ * @num_bssid: Number of blacklist BSSIDs
+ * @bssids: List of blacklisted BSSIDs
+ */
+ int (*set_bssid_blacklist)(void *priv, unsigned int num_bssid,
+ const u8 *bssid);
+
+ /**
+ * update_connect_params - Update the connection parameters
+ * @priv: Private driver interface data
+ * @params: Association parameters
+ * @mask: Bit mask indicating which parameters in @params have to be
+ * updated
+ * Returns: 0 on success, -1 on failure
+ *
+ * Update the connection parameters when in connected state so that the
+ * driver uses the updated parameters for subsequent roaming. This is
+ * used only with drivers that implement internal BSS selection and
+ * roaming.
+ */
+ int (*update_connect_params)(
+ void *priv, struct wpa_driver_associate_params *params,
+ enum wpa_drv_update_connect_params_mask mask);
+
+ /**
+ * send_external_auth_status - Indicate the status of external
+ * authentication processing to the host driver.
+ * @priv: Private driver interface data
+ * @params: Status of authentication processing.
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*send_external_auth_status)(void *priv,
+ struct external_auth *params);
+
+ /**
+ * set_4addr_mode - Set 4-address mode
+ * @priv: Private driver interface data
+ * @bridge_ifname: Bridge interface name
+ * @val: 0 - disable 4addr mode, 1 - enable 4addr mode
+ * Returns: 0 on success, < 0 on failure
+ */
+ int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
+};
/**
* enum wpa_event_type - Event type for wpa_supplicant_event() calls
@@ -3550,17 +4277,6 @@ enum wpa_event_type {
EVENT_PMKID_CANDIDATE,
/**
- * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request)
- *
- * This event can be used to inform wpa_supplicant about desire to set
- * up secure direct link connection between two stations as defined in
- * IEEE 802.11e with a new PeerKey mechanism that replaced the original
- * STAKey negotiation. The caller will need to set peer address for the
- * event.
- */
- EVENT_STKSTART,
-
- /**
* EVENT_TDLS - Request TDLS operation
*
* This event can be used to request a TDLS operation to be performed.
@@ -3859,7 +4575,7 @@ enum wpa_event_type {
* EVENT_DFS_CAC_ABORTED - Notify that channel availability check has been aborted
*
* The CAC was not successful, and the channel remains in the previous
- * state. This may happen due to a radar beeing detected or other
+ * state. This may happen due to a radar being detected or other
* external influences.
*/
EVENT_DFS_CAC_ABORTED,
@@ -3923,6 +4639,70 @@ enum wpa_event_type {
* on a DFS frequency by a driver that supports DFS Offload.
*/
EVENT_DFS_CAC_STARTED,
+
+ /**
+ * EVENT_P2P_LO_STOP - Notify that P2P listen offload is stopped
+ */
+ EVENT_P2P_LO_STOP,
+
+ /**
+ * EVENT_BEACON_LOSS - Beacon loss detected
+ *
+ * This event indicates that no Beacon frames has been received from
+ * the current AP. This may indicate that the AP is not anymore in
+ * range.
+ */
+ EVENT_BEACON_LOSS,
+
+ /**
+ * EVENT_DFS_PRE_CAC_EXPIRED - Notify that channel availability check
+ * done previously (Pre-CAC) on the channel has expired. This would
+ * normally be on a non-ETSI DFS regulatory domain. DFS state of the
+ * channel will be moved from available to usable. A new CAC has to be
+ * performed before start operating on this channel.
+ */
+ EVENT_DFS_PRE_CAC_EXPIRED,
+
+ /**
+ * EVENT_EXTERNAL_AUTH - This event interface is used by host drivers
+ * that do not define separate commands for authentication and
+ * association (~WPA_DRIVER_FLAGS_SME) but offload the 802.11
+ * authentication to wpa_supplicant. This event carries all the
+ * necessary information from the host driver for the authentication to
+ * happen.
+ */
+ EVENT_EXTERNAL_AUTH,
+
+ /**
+ * EVENT_PORT_AUTHORIZED - Notification that a connection is authorized
+ *
+ * This event should be indicated when the driver completes the 4-way
+ * handshake. This event should be preceded by an EVENT_ASSOC that
+ * indicates the completion of IEEE 802.11 association.
+ */
+ EVENT_PORT_AUTHORIZED,
+
+ /**
+ * EVENT_STATION_OPMODE_CHANGED - Notify STA's HT/VHT operation mode
+ * change event.
+ */
+ EVENT_STATION_OPMODE_CHANGED,
+
+ /**
+ * EVENT_INTERFACE_MAC_CHANGED - Notify that interface MAC changed
+ *
+ * This event is emitted when the MAC changes while the interface is
+ * enabled. When an interface was disabled and becomes enabled, it
+ * must be always assumed that the MAC possibly changed.
+ */
+ EVENT_INTERFACE_MAC_CHANGED,
+
+ /**
+ * EVENT_WDS_STA_INTERFACE_STATUS - Notify WDS STA interface status
+ *
+ * This event is emitted when an interface is added/removed for WDS STA.
+ */
+ EVENT_WDS_STA_INTERFACE_STATUS,
};
@@ -4015,6 +4795,16 @@ union wpa_event_data {
size_t resp_ies_len;
/**
+ * resp_frame - (Re)Association Response frame
+ */
+ const u8 *resp_frame;
+
+ /**
+ * resp_frame_len - (Re)Association Response frame length
+ */
+ size_t resp_frame_len;
+
+ /**
* beacon_ies - Beacon or Probe Response IEs
*
* Optional Beacon/ProbeResp data: IEs included in Beacon or
@@ -4091,6 +4881,8 @@ union wpa_event_data {
/**
* ptk_kek - The derived PTK KEK
+ * This is used in key management offload and also in FILS SK
+ * offload.
*/
const u8 *ptk_kek;
@@ -4098,6 +4890,42 @@ union wpa_event_data {
* ptk_kek_len - The length of ptk_kek
*/
size_t ptk_kek_len;
+
+ /**
+ * subnet_status - The subnet status:
+ * 0 = unknown, 1 = unchanged, 2 = changed
+ */
+ u8 subnet_status;
+
+ /**
+ * The following information is used in FILS SK offload
+ * @fils_erp_next_seq_num
+ * @fils_pmk
+ * @fils_pmk_len
+ * @fils_pmkid
+ */
+
+ /**
+ * fils_erp_next_seq_num - The next sequence number to use in
+ * FILS ERP messages
+ */
+ u16 fils_erp_next_seq_num;
+
+ /**
+ * fils_pmk - A new PMK if generated in case of FILS
+ * authentication
+ */
+ const u8 *fils_pmk;
+
+ /**
+ * fils_pmk_len - Length of fils_pmk
+ */
+ size_t fils_pmk_len;
+
+ /**
+ * fils_pmkid - PMKID used or generated in FILS authentication
+ */
+ const u8 *fils_pmkid;
} assoc_info;
/**
@@ -4174,6 +5002,7 @@ union wpa_event_data {
* struct interface_status - Data for EVENT_INTERFACE_STATUS
*/
struct interface_status {
+ unsigned int ifindex;
char ifname[100];
enum {
EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
@@ -4193,13 +5022,6 @@ union wpa_event_data {
} pmkid_candidate;
/**
- * struct stkstart - Data for EVENT_STKSTART
- */
- struct stkstart {
- u8 peer[ETH_ALEN];
- } stkstart;
-
- /**
* struct tdls - Data for EVENT_TDLS
*/
struct tdls {
@@ -4301,6 +5123,23 @@ union wpa_event_data {
* status_code - Status Code from (Re)association Response
*/
u16 status_code;
+
+ /**
+ * timed_out - Whether failure is due to timeout (etc.) rather
+ * than explicit rejection response from the AP.
+ */
+ int timed_out;
+
+ /**
+ * timeout_reason - Reason for the timeout
+ */
+ const char *timeout_reason;
+
+ /**
+ * fils_erp_next_seq_num - The next sequence number to use in
+ * FILS ERP messages
+ */
+ u16 fils_erp_next_seq_num;
} assoc_reject;
struct timeout_event {
@@ -4381,6 +5220,14 @@ union wpa_event_data {
* @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
* SSID)
* @num_ssids: Number of entries in ssids array
+ * @external_scan: Whether the scan info is for an external scan
+ * @nl_scan_event: 1 if the source of this scan event is a normal scan,
+ * 0 if the source of the scan event is a vendor scan
+ * @scan_start_tsf: Time when the scan started in terms of TSF of the
+ * BSS that the interface that requested the scan is connected to
+ * (if available).
+ * @scan_start_tsf_bssid: The BSSID according to which %scan_start_tsf
+ * is set.
*/
struct scan_info {
int aborted;
@@ -4388,6 +5235,10 @@ union wpa_event_data {
size_t num_freqs;
struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
size_t num_ssids;
+ int external_scan;
+ int nl_scan_event;
+ u64 scan_start_tsf;
+ u8 scan_start_tsf_bssid[ETH_ALEN];
} scan_info;
/**
@@ -4477,9 +5328,12 @@ union wpa_event_data {
/**
* struct low_ack - Data for EVENT_STATION_LOW_ACK events
* @addr: station address
+ * @num_packets: Number of packets lost (consecutive packets not
+ * acknowledged)
*/
struct low_ack {
u8 addr[ETH_ALEN];
+ u32 num_packets;
} low_ack;
/**
@@ -4630,6 +5484,58 @@ union wpa_event_data {
u16 ch_width;
enum hostapd_hw_mode hw_mode;
} acs_selected_channels;
+
+ /**
+ * struct p2p_lo_stop - Reason code for P2P Listen offload stop event
+ * @reason_code: Reason for stopping offload
+ * P2P_LO_STOPPED_REASON_COMPLETE: Listen offload finished as
+ * scheduled.
+ * P2P_LO_STOPPED_REASON_RECV_STOP_CMD: Host requested offload to
+ * be stopped.
+ * P2P_LO_STOPPED_REASON_INVALID_PARAM: Invalid listen offload
+ * parameters.
+ * P2P_LO_STOPPED_REASON_NOT_SUPPORTED: Listen offload not
+ * supported by device.
+ */
+ struct p2p_lo_stop {
+ enum {
+ P2P_LO_STOPPED_REASON_COMPLETE = 0,
+ P2P_LO_STOPPED_REASON_RECV_STOP_CMD,
+ P2P_LO_STOPPED_REASON_INVALID_PARAM,
+ P2P_LO_STOPPED_REASON_NOT_SUPPORTED,
+ } reason_code;
+ } p2p_lo_stop;
+
+ /* For EVENT_EXTERNAL_AUTH */
+ struct external_auth external_auth;
+
+ /**
+ * struct sta_opmode - Station's operation mode change event
+ * @addr: The station MAC address
+ * @smps_mode: SMPS mode of the station
+ * @chan_width: Channel width of the station
+ * @rx_nss: RX_NSS of the station
+ *
+ * This is used as data with EVENT_STATION_OPMODE_CHANGED.
+ */
+ struct sta_opmode {
+ const u8 *addr;
+ enum smps_mode smps_mode;
+ enum chan_width chan_width;
+ u8 rx_nss;
+ } sta_opmode;
+
+ /**
+ * struct wds_sta_interface - Data for EVENT_WDS_STA_INTERFACE_STATUS.
+ */
+ struct wds_sta_interface {
+ const u8 *sta_addr;
+ const char *ifname;
+ enum {
+ INTERFACE_ADDED,
+ INTERFACE_REMOVED
+ } istatus;
+ } wds_sta_interface;
};
/**
@@ -4645,6 +5551,18 @@ union wpa_event_data {
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data);
+/**
+ * wpa_supplicant_event_global - Report a driver event for wpa_supplicant
+ * @ctx: Context pointer (wpa_s); this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @event: event type (defined above)
+ * @data: possible extra data for the event
+ *
+ * Same as wpa_supplicant_event(), but we search for the interface in
+ * wpa_global.
+ */
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data);
/*
* The following inline functions are provided for convenience to simplify
@@ -4691,14 +5609,64 @@ const char * event_to_string(enum wpa_event_type event);
/* Convert chan_width to a string for logging and control interfaces */
const char * channel_width_to_string(enum chan_width width);
+int channel_width_to_int(enum chan_width width);
+
int ht_supported(const struct hostapd_hw_modes *mode);
int vht_supported(const struct hostapd_hw_modes *mode);
struct wowlan_triggers *
wpa_get_wowlan_triggers(const char *wowlan_triggers,
const struct wpa_driver_capa *capa);
+/* Convert driver flag to string */
+const char * driver_flag_to_string(u64 flag);
/* NULL terminated array of linked in driver wrappers */
extern const struct wpa_driver_ops *const wpa_drivers[];
+
+/* Available drivers */
+
+#ifdef CONFIG_DRIVER_WEXT
+extern const struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
+#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+/* driver_nl80211.c */
+extern const struct wpa_driver_ops wpa_driver_nl80211_ops;
+#endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_HOSTAP
+extern const struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
+#endif /* CONFIG_DRIVER_HOSTAP */
+#ifdef CONFIG_DRIVER_BSD
+extern const struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
+#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+/* driver_openbsd.c */
+extern const struct wpa_driver_ops wpa_driver_openbsd_ops;
+#endif /* CONFIG_DRIVER_OPENBSD */
+#ifdef CONFIG_DRIVER_NDIS
+extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
+#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_WIRED
+extern const struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
+#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_MACSEC_QCA
+/* driver_macsec_qca.c */
+extern const struct wpa_driver_ops wpa_driver_macsec_qca_ops;
+#endif /* CONFIG_DRIVER_MACSEC_QCA */
+#ifdef CONFIG_DRIVER_MACSEC_LINUX
+/* driver_macsec_linux.c */
+extern const struct wpa_driver_ops wpa_driver_macsec_linux_ops;
+#endif /* CONFIG_DRIVER_MACSEC_LINUX */
+#ifdef CONFIG_DRIVER_ROBOSWITCH
+/* driver_roboswitch.c */
+extern const struct wpa_driver_ops wpa_driver_roboswitch_ops;
+#endif /* CONFIG_DRIVER_ROBOSWITCH */
+#ifdef CONFIG_DRIVER_ATHEROS
+/* driver_atheros.c */
+extern const struct wpa_driver_ops wpa_driver_atheros_ops;
+#endif /* CONFIG_DRIVER_ATHEROS */
+#ifdef CONFIG_DRIVER_NONE
+extern const struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
+#endif /* CONFIG_DRIVER_NONE */
+
#endif /* DRIVER_H */
diff --git a/contrib/wpa/src/drivers/driver_bsd.c b/contrib/wpa/src/drivers/driver_bsd.c
index 73f455f..3eb4c50 100644
--- a/contrib/wpa/src/drivers/driver_bsd.c
+++ b/contrib/wpa/src/drivers/driver_bsd.c
@@ -47,14 +47,25 @@
#include "l2_packet/l2_packet.h"
+struct bsd_driver_global {
+ void *ctx;
+ int sock; /* socket for 802.11 ioctls */
+ int route; /* routing socket for events */
+ char *event_buf;
+ size_t event_buf_len;
+ struct dl_list ifaces; /* list of interfaces */
+};
+
struct bsd_driver_data {
+ struct dl_list list;
+ struct bsd_driver_global *global;
struct hostapd_data *hapd; /* back pointer */
- int sock; /* open socket for 802.11 ioctls */
struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
- int route; /* routing socket for events */
char ifname[IFNAMSIZ+1]; /* interface name */
+ int flags;
unsigned int ifindex; /* interface index */
+ int if_removed; /* has the interface been removed? */
void *ctx;
struct wpa_driver_capa capa; /* driver capability */
int is_ap; /* Access point mode */
@@ -62,17 +73,46 @@ struct bsd_driver_data {
int prev_privacy; /* privacy state to restore on deinit */
int prev_wpa; /* wpa state to restore on deinit */
enum ieee80211_opmode opmode; /* operation mode */
- char *event_buf;
- size_t event_buf_len;
};
/* Generic functions for hostapd and wpa_supplicant */
+static struct bsd_driver_data *
+bsd_get_drvindex(void *priv, unsigned int ifindex)
+{
+ struct bsd_driver_global *global = priv;
+ struct bsd_driver_data *drv;
+
+ dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+ if (drv->ifindex == ifindex)
+ return drv;
+ }
+ return NULL;
+}
+
+#ifndef HOSTAPD
+static struct bsd_driver_data *
+bsd_get_drvname(void *priv, const char *ifname)
+{
+ struct bsd_driver_global *global = priv;
+ struct bsd_driver_data *drv;
+
+ dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+ if (os_strcmp(drv->ifname, ifname) == 0)
+ return drv;
+ }
+ return NULL;
+}
+#endif /* HOSTAPD */
+
static int
bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req ireq;
+ if (drv->ifindex == 0 || drv->if_removed)
+ return -1;
+
os_memset(&ireq, 0, sizeof(ireq));
os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name));
ireq.i_type = op;
@@ -80,7 +120,7 @@ bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
ireq.i_data = (void *) arg;
ireq.i_len = arg_len;
- if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+ if (ioctl(drv->global->sock, SIOCS80211, &ireq) < 0) {
wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
"arg_len=%u]: %s", op, val, arg_len,
strerror(errno));
@@ -101,8 +141,8 @@ bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
ireq->i_len = arg_len;
ireq->i_data = arg;
- if (ioctl(drv->sock, SIOCG80211, ireq) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
+ if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, "
"arg_len=%u]: %s", op, arg_len, strerror(errno));
return -1;
}
@@ -142,7 +182,7 @@ bsd_get_ssid(void *priv, u8 *ssid, int len)
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
ifr.ifr_data = (void *)&nwid;
- if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+ if (ioctl(drv->global->sock, SIOCG80211NWID, &ifr) < 0 ||
nwid.i_len > IEEE80211_NWID_LEN)
return -1;
os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
@@ -165,7 +205,7 @@ bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len)
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
ifr.ifr_data = (void *)&nwid;
- return ioctl(drv->sock, SIOCS80211NWID, &ifr);
+ return ioctl(drv->global->sock, SIOCS80211NWID, &ifr);
#else
return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
#endif
@@ -180,7 +220,7 @@ bsd_get_if_media(void *priv)
os_memset(&ifmr, 0, sizeof(ifmr));
os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
- if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) {
+ if (ioctl(drv->global->sock, SIOCGIFMEDIA, &ifmr) < 0) {
wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
strerror(errno));
return -1;
@@ -199,7 +239,7 @@ bsd_set_if_media(void *priv, int media)
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
ifr.ifr_media = media;
- if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) {
+ if (ioctl(drv->global->sock, SIOCSIFMEDIA, &ifr) < 0) {
wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
strerror(errno));
return -1;
@@ -262,11 +302,12 @@ bsd_ctrl_iface(void *priv, int enable)
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
+ if (ioctl(drv->global->sock, SIOCGIFFLAGS, &ifr) < 0) {
wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
strerror(errno));
return -1;
}
+ drv->flags = ifr.ifr_flags;
if (enable) {
if (ifr.ifr_flags & IFF_UP)
@@ -278,12 +319,13 @@ bsd_ctrl_iface(void *priv, int enable)
ifr.ifr_flags &= ~IFF_UP;
}
- if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
+ if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) {
wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
strerror(errno));
return -1;
}
+ drv->flags = ifr.ifr_flags;
return 0;
}
@@ -575,7 +617,7 @@ bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
os_memset(&creq, 0, sizeof(creq));
os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
creq.i_channel = (u_int16_t)channel;
- return ioctl(drv->sock, SIOCS80211CHANNEL, &creq);
+ return ioctl(drv->global->sock, SIOCS80211CHANNEL, &creq);
#else /* SIOCS80211CHANNEL */
return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
#endif /* SIOCS80211CHANNEL */
@@ -729,7 +771,8 @@ bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
static void
bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
{
- struct bsd_driver_data *drv = ctx;
+ struct bsd_driver_global *global = sock_ctx;
+ struct bsd_driver_data *drv;
struct if_announcemsghdr *ifan;
struct rt_msghdr *rtm;
struct ieee80211_michael_event *mic;
@@ -738,7 +781,7 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
int n;
union wpa_event_data data;
- n = read(sock, drv->event_buf, drv->event_buf_len);
+ n = read(sock, global->event_buf, global->event_buf_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
wpa_printf(MSG_ERROR, "%s read() failed: %s",
@@ -746,15 +789,18 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
return;
}
- rtm = (struct rt_msghdr *) drv->event_buf;
+ rtm = (struct rt_msghdr *) global->event_buf;
if (rtm->rtm_version != RTM_VERSION) {
wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
rtm->rtm_version);
return;
}
- ifan = (struct if_announcemsghdr *) rtm;
switch (rtm->rtm_type) {
case RTM_IEEE80211:
+ ifan = (struct if_announcemsghdr *) rtm;
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv == NULL)
+ return;
switch (ifan->ifan_what) {
case RTM_IEEE80211_ASSOC:
case RTM_IEEE80211_REASSOC:
@@ -810,21 +856,15 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
return NULL;
}
- drv->event_buf_len = rtbuf_len();
-
- drv->event_buf = os_malloc(drv->event_buf_len);
- if (drv->event_buf == NULL) {
- wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+ drv->ifindex = if_nametoindex(params->ifname);
+ if (drv->ifindex == 0) {
+ wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
+ __func__, params->ifname);
goto bad;
}
drv->hapd = hapd;
- drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->sock < 0) {
- wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
- strerror(errno));
- goto bad;
- }
+ drv->global = params->global_priv;
os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
@@ -838,28 +878,18 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
if (bsd_ctrl_iface(drv, 0) < 0)
goto bad;
- drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
- if (drv->route < 0) {
- wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s",
- strerror(errno));
- goto bad;
- }
- eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
- NULL);
-
if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
__func__);
goto bad;
}
+ dl_list_add(&drv->global->ifaces, &drv->list);
+
return drv;
bad:
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
- if (drv->sock >= 0)
- close(drv->sock);
- os_free(drv->event_buf);
os_free(drv);
return NULL;
}
@@ -870,16 +900,10 @@ bsd_deinit(void *priv)
{
struct bsd_driver_data *drv = priv;
- if (drv->route >= 0) {
- eloop_unregister_read_sock(drv->route);
- close(drv->route);
- }
- bsd_ctrl_iface(drv, 0);
- if (drv->sock >= 0)
- close(drv->sock);
+ if (drv->ifindex != 0)
+ bsd_ctrl_iface(drv, 0);
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
- os_free(drv->event_buf);
os_free(drv);
}
@@ -931,7 +955,7 @@ wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
struct ieee80211_bssid bs;
os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
- if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
+ if (ioctl(drv->global->sock, SIOCG80211BSSID, &bs) < 0)
return -1;
os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
return 0;
@@ -965,7 +989,7 @@ wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
int ret = 0;
wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
- __FUNCTION__, wpa, privacy);
+ __func__, wpa, privacy);
if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0)
ret = -1;
@@ -980,7 +1004,7 @@ wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
static int
wpa_driver_bsd_set_wpa(void *priv, int enabled)
{
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
}
@@ -1199,7 +1223,8 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
static void
wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
{
- struct bsd_driver_data *drv = sock_ctx;
+ struct bsd_driver_global *global = sock_ctx;
+ struct bsd_driver_data *drv;
struct if_announcemsghdr *ifan;
struct if_msghdr *ifm;
struct rt_msghdr *rtm;
@@ -1209,7 +1234,7 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
struct ieee80211_join_event *join;
int n;
- n = read(sock, drv->event_buf, drv->event_buf_len);
+ n = read(sock, global->event_buf, global->event_buf_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
wpa_printf(MSG_ERROR, "%s read() failed: %s",
@@ -1217,7 +1242,7 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
return;
}
- rtm = (struct rt_msghdr *) drv->event_buf;
+ rtm = (struct rt_msghdr *) global->event_buf;
if (rtm->rtm_version != RTM_VERSION) {
wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
rtm->rtm_version);
@@ -1227,53 +1252,79 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
switch (rtm->rtm_type) {
case RTM_IFANNOUNCE:
ifan = (struct if_announcemsghdr *) rtm;
- if (ifan->ifan_index != drv->ifindex)
- break;
- os_strlcpy(event.interface_status.ifname, drv->ifname,
- sizeof(event.interface_status.ifname));
switch (ifan->ifan_what) {
case IFAN_DEPARTURE:
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv)
+ drv->if_removed = 1;
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ break;
+ case IFAN_ARRIVAL:
+ drv = bsd_get_drvname(global, ifan->ifan_name);
+ if (drv) {
+ drv->ifindex = ifan->ifan_index;
+ drv->if_removed = 0;
+ }
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ break;
default:
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
return;
}
wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
- event.interface_status.ifname,
+ ifan->ifan_name,
ifan->ifan_what == IFAN_DEPARTURE ?
"removed" : "added");
- wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+ os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
+ sizeof(event.interface_status.ifname));
+ if (drv) {
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ /*
+ * Set ifindex to zero after sending the event as the
+ * event might query the driver to ensure a match.
+ */
+ if (ifan->ifan_what == IFAN_DEPARTURE)
+ drv->ifindex = 0;
+ } else {
+ wpa_supplicant_event_global(global->ctx,
+ EVENT_INTERFACE_STATUS,
+ &event);
+ }
break;
case RTM_IEEE80211:
ifan = (struct if_announcemsghdr *) rtm;
- if (ifan->ifan_index != drv->ifindex)
- break;
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv == NULL)
+ return;
switch (ifan->ifan_what) {
case RTM_IEEE80211_ASSOC:
case RTM_IEEE80211_REASSOC:
if (drv->is_ap)
break;
- wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
break;
case RTM_IEEE80211_DISASSOC:
if (drv->is_ap)
break;
- wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
break;
case RTM_IEEE80211_SCAN:
if (drv->is_ap)
break;
- wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+ NULL);
break;
case RTM_IEEE80211_LEAVE:
leave = (struct ieee80211_leave_event *) &ifan[1];
- drv_event_disassoc(ctx, leave->iev_addr);
+ drv_event_disassoc(drv->ctx, leave->iev_addr);
break;
case RTM_IEEE80211_JOIN:
#ifdef RTM_IEEE80211_REJOIN
case RTM_IEEE80211_REJOIN:
#endif
join = (struct ieee80211_join_event *) &ifan[1];
- bsd_new_sta(drv, ctx, join->iev_addr);
+ bsd_new_sta(drv, drv->ctx, join->iev_addr);
break;
case RTM_IEEE80211_REPLAY:
/* ignore */
@@ -1288,23 +1339,30 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
os_memset(&event, 0, sizeof(event));
event.michael_mic_failure.unicast =
!IEEE80211_IS_MULTICAST(mic->iev_dst);
- wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
- &event);
+ wpa_supplicant_event(drv->ctx,
+ EVENT_MICHAEL_MIC_FAILURE, &event);
break;
}
break;
case RTM_IFINFO:
ifm = (struct if_msghdr *) rtm;
- if (ifm->ifm_index != drv->ifindex)
- break;
- if ((rtm->rtm_flags & RTF_UP) == 0) {
- os_strlcpy(event.interface_status.ifname, drv->ifname,
- sizeof(event.interface_status.ifname));
- event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ drv = bsd_get_drvindex(global, ifm->ifm_index);
+ if (drv == NULL)
+ return;
+ if ((ifm->ifm_flags & IFF_UP) == 0 &&
+ (drv->flags & IFF_UP) != 0) {
wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
- event.interface_status.ifname);
- wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+ NULL);
+ } else if ((ifm->ifm_flags & IFF_UP) != 0 &&
+ (drv->flags & IFF_UP) == 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
}
+ drv->flags = ifm->ifm_flags;
break;
}
}
@@ -1331,11 +1389,16 @@ wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
result->caps = sr->isr_capinfo;
result->qual = sr->isr_rssi;
result->noise = sr->isr_noise;
+
+#ifdef __FreeBSD__
/*
* the rssi value reported by the kernel is in 0.5dB steps relative to
* the reported noise floor. see ieee80211_node.h for details.
*/
result->level = sr->isr_rssi / 2 + sr->isr_noise;
+#else
+ result->level = sr->isr_rssi;
+#endif
pos = (u8 *)(result + 1);
@@ -1502,7 +1565,7 @@ get80211opmode(struct bsd_driver_data *drv)
(void) memset(&ifmr, 0, sizeof(ifmr));
(void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
- if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+ if (ioctl(drv->global->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
if (ifmr.ifm_current & IFM_FLAG0)
return IEEE80211_M_AHDEMO;
@@ -1524,7 +1587,7 @@ get80211opmode(struct bsd_driver_data *drv)
}
static void *
-wpa_driver_bsd_init(void *ctx, const char *ifname)
+wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv)
{
#define GETPARAM(drv, param, v) \
(((v) = get80211param(drv, param)) != -1)
@@ -1534,14 +1597,6 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
if (drv == NULL)
return NULL;
- drv->event_buf_len = rtbuf_len();
-
- drv->event_buf = os_malloc(drv->event_buf_len);
- if (drv->event_buf == NULL) {
- wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
- goto fail1;
- }
-
/*
* NB: We require the interface name be mappable to an index.
* This implies we do not support having wpa_supplicant
@@ -1552,24 +1607,12 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
if (drv->ifindex == 0) {
wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
__func__, ifname);
- goto fail1;
- }
- drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->sock < 0)
- goto fail1;
-
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- /* Down interface during setup. */
- if (bsd_ctrl_iface(drv, 0) < 0)
- goto fail;
-
- drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
- if (drv->route < 0)
goto fail;
- eloop_register_read_sock(drv->route,
- wpa_driver_bsd_event_receive, ctx, drv);
+ }
drv->ctx = ctx;
+ drv->global = priv;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
@@ -1590,13 +1633,15 @@ wpa_driver_bsd_init(void *ctx, const char *ifname)
if (wpa_driver_bsd_capa(drv))
goto fail;
+ /* Down interface during setup. */
+ if (bsd_ctrl_iface(drv, 0) < 0)
+ goto fail;
+
drv->opmode = get80211opmode(drv);
+ dl_list_add(&drv->global->ifaces, &drv->list);
return drv;
fail:
- close(drv->sock);
-fail1:
- os_free(drv->event_buf);
os_free(drv);
return NULL;
#undef GETPARAM
@@ -1607,22 +1652,25 @@ wpa_driver_bsd_deinit(void *priv)
{
struct bsd_driver_data *drv = priv;
- wpa_driver_bsd_set_wpa(drv, 0);
- eloop_unregister_read_sock(drv->route);
+ if (drv->ifindex != 0 && !drv->if_removed) {
+ wpa_driver_bsd_set_wpa(drv, 0);
- /* NB: mark interface down */
- bsd_ctrl_iface(drv, 0);
+ /* NB: mark interface down */
+ bsd_ctrl_iface(drv, 0);
- wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
- if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
- wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
- __func__);
+ wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa,
+ drv->prev_privacy);
+
+ if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)
+ < 0)
+ wpa_printf(MSG_DEBUG,
+ "%s: failed to restore roaming state",
+ __func__);
+ }
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
- (void) close(drv->route); /* ioctl socket */
- (void) close(drv->sock); /* event socket */
- os_free(drv->event_buf);
+ dl_list_del(&drv->list);
os_free(drv);
}
@@ -1636,10 +1684,74 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
}
#endif /* HOSTAPD */
+static void *
+bsd_global_init(void *ctx)
+{
+ struct bsd_driver_global *global;
+
+ global = os_zalloc(sizeof(*global));
+ if (global == NULL)
+ return NULL;
+
+ global->ctx = ctx;
+ dl_list_init(&global->ifaces);
+
+ global->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (global->sock < 0) {
+ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
+ goto fail1;
+ }
+
+ global->route = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (global->route < 0) {
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ global->event_buf_len = rtbuf_len();
+ global->event_buf = os_malloc(global->event_buf_len);
+ if (global->event_buf == NULL) {
+ wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
+ goto fail;
+ }
+
+#ifdef HOSTAPD
+ eloop_register_read_sock(global->route, bsd_wireless_event_receive,
+ NULL, global);
+
+#else /* HOSTAPD */
+ eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive,
+ NULL, global);
+#endif /* HOSTAPD */
+
+ return global;
+
+fail:
+ close(global->sock);
+fail1:
+ os_free(global);
+ return NULL;
+}
+
+static void
+bsd_global_deinit(void *priv)
+{
+ struct bsd_driver_global *global = priv;
+
+ eloop_unregister_read_sock(global->route);
+ (void) close(global->route);
+ (void) close(global->sock);
+ os_free(global);
+}
+
const struct wpa_driver_ops wpa_driver_bsd_ops = {
.name = "bsd",
.desc = "BSD 802.11 support",
+ .global_init = bsd_global_init,
+ .global_deinit = bsd_global_deinit,
#ifdef HOSTAPD
.hapd_init = bsd_init,
.hapd_deinit = bsd_deinit,
@@ -1652,7 +1764,7 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
.sta_set_flags = bsd_set_sta_authorized,
.commit = bsd_commit,
#else /* HOSTAPD */
- .init = wpa_driver_bsd_init,
+ .init2 = wpa_driver_bsd_init,
.deinit = wpa_driver_bsd_deinit,
.get_bssid = wpa_driver_bsd_get_bssid,
.get_ssid = wpa_driver_bsd_get_ssid,
diff --git a/contrib/wpa/src/drivers/driver_common.c b/contrib/wpa/src/drivers/driver_common.c
index aebea8c..e55e6cd 100644
--- a/contrib/wpa/src/drivers/driver_common.c
+++ b/contrib/wpa/src/drivers/driver_common.c
@@ -1,6 +1,6 @@
/*
* Common driver-related functions
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -35,7 +35,6 @@ const char * event_to_string(enum wpa_event_type event)
E2S(ASSOCINFO);
E2S(INTERFACE_STATUS);
E2S(PMKID_CANDIDATE);
- E2S(STKSTART);
E2S(TDLS);
E2S(FT_RESPONSE);
E2S(IBSS_RSN_START);
@@ -80,6 +79,14 @@ const char * event_to_string(enum wpa_event_type event)
E2S(NEW_PEER_CANDIDATE);
E2S(ACS_CHANNEL_SELECTED);
E2S(DFS_CAC_STARTED);
+ E2S(P2P_LO_STOP);
+ E2S(BEACON_LOSS);
+ E2S(DFS_PRE_CAC_EXPIRED);
+ E2S(EXTERNAL_AUTH);
+ E2S(PORT_AUTHORIZED);
+ E2S(STATION_OPMODE_CHANGED);
+ E2S(INTERFACE_MAC_CHANGED);
+ E2S(WDS_STA_INTERFACE_STATUS);
}
return "UNKNOWN";
@@ -108,6 +115,25 @@ const char * channel_width_to_string(enum chan_width width)
}
+int channel_width_to_int(enum chan_width width)
+{
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ return 20;
+ case CHAN_WIDTH_40:
+ return 40;
+ case CHAN_WIDTH_80:
+ return 80;
+ case CHAN_WIDTH_80P80:
+ case CHAN_WIDTH_160:
+ return 160;
+ default:
+ return 0;
+ }
+}
+
+
int ht_supported(const struct hostapd_hw_modes *mode)
{
if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
@@ -183,12 +209,12 @@ wpa_get_wowlan_triggers(const char *wowlan_triggers,
start = buf;
while (*start != '\0') {
- while (isblank(*start))
+ while (isblank((unsigned char) *start))
start++;
if (*start == '\0')
break;
end = start;
- while (!isblank(*end) && *end != '\0')
+ while (!isblank((unsigned char) *end) && *end != '\0')
end++;
last = *end == '\0';
*end = '\0';
@@ -218,3 +244,69 @@ out:
os_free(buf);
return triggers;
}
+
+
+const char * driver_flag_to_string(u64 flag)
+{
+#define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x
+ switch (flag) {
+ DF2S(DRIVER_IE);
+ DF2S(SET_KEYS_AFTER_ASSOC);
+ DF2S(DFS_OFFLOAD);
+ DF2S(4WAY_HANDSHAKE_PSK);
+ DF2S(4WAY_HANDSHAKE_8021X);
+ DF2S(WIRED);
+ DF2S(SME);
+ DF2S(AP);
+ DF2S(SET_KEYS_AFTER_ASSOC_DONE);
+ DF2S(HT_2040_COEX);
+ DF2S(P2P_CONCURRENT);
+ DF2S(P2P_DEDICATED_INTERFACE);
+ DF2S(P2P_CAPABLE);
+ DF2S(AP_TEARDOWN_SUPPORT);
+ DF2S(P2P_MGMT_AND_NON_P2P);
+ DF2S(SANE_ERROR_CODES);
+ DF2S(OFFCHANNEL_TX);
+ DF2S(EAPOL_TX_STATUS);
+ DF2S(DEAUTH_TX_STATUS);
+ DF2S(BSS_SELECTION);
+ DF2S(TDLS_SUPPORT);
+ DF2S(TDLS_EXTERNAL_SETUP);
+ DF2S(PROBE_RESP_OFFLOAD);
+ DF2S(AP_UAPSD);
+ DF2S(INACTIVITY_TIMER);
+ DF2S(AP_MLME);
+ DF2S(SAE);
+ DF2S(OBSS_SCAN);
+ DF2S(IBSS);
+ DF2S(RADAR);
+ DF2S(DEDICATED_P2P_DEVICE);
+ DF2S(QOS_MAPPING);
+ DF2S(AP_CSA);
+ DF2S(MESH);
+ DF2S(ACS_OFFLOAD);
+ DF2S(KEY_MGMT_OFFLOAD);
+ DF2S(TDLS_CHANNEL_SWITCH);
+ DF2S(HT_IBSS);
+ DF2S(VHT_IBSS);
+ DF2S(SUPPORT_HW_MODE_ANY);
+ DF2S(OFFCHANNEL_SIMULTANEOUS);
+ DF2S(FULL_AP_CLIENT_STATE);
+ DF2S(P2P_LISTEN_OFFLOAD);
+ DF2S(SUPPORT_FILS);
+ DF2S(BEACON_RATE_LEGACY);
+ DF2S(BEACON_RATE_HT);
+ DF2S(BEACON_RATE_VHT);
+ DF2S(MGMT_TX_RANDOM_TA);
+ DF2S(MGMT_TX_RANDOM_TA_CONNECTED);
+ DF2S(SCHED_SCAN_RELATIVE_RSSI);
+ DF2S(HE_CAPABILITIES);
+ DF2S(FILS_SK_OFFLOAD);
+ DF2S(OCE_STA);
+ DF2S(OCE_AP);
+ DF2S(OCE_STA_CFON);
+ DF2S(MFP_OPTIONAL);
+ }
+ return "UNKNOWN";
+#undef DF2S
+}
diff --git a/contrib/wpa/src/drivers/driver_macsec_linux.c b/contrib/wpa/src/drivers/driver_macsec_linux.c
new file mode 100644
index 0000000..9d981bb
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_macsec_linux.c
@@ -0,0 +1,1437 @@
+/*
+ * Driver interaction with Linux MACsec kernel module
+ * Copyright (c) 2016, Sabrina Dubroca <sd@queasysnail.net> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/macsec.h>
+#include <linux/if_macsec.h>
+#include <inttypes.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "pae/ieee802_1x_kay.h"
+#include "driver.h"
+#include "driver_wired_common.h"
+
+#define DRV_PREFIX "macsec_linux: "
+
+#define UNUSED_SCI 0xffffffffffffffff
+
+struct cb_arg {
+ struct macsec_drv_data *drv;
+ u32 *pn;
+ int ifindex;
+ u8 txsa;
+ u8 rxsa;
+ u64 rxsci;
+};
+
+struct macsec_genl_ctx {
+ struct nl_sock *sk;
+ int macsec_genl_id;
+ struct cb_arg cb_arg;
+};
+
+struct macsec_drv_data {
+ struct driver_wired_common_data common;
+ struct rtnl_link *link;
+ struct nl_cache *link_cache;
+ struct nl_sock *sk;
+ struct macsec_genl_ctx ctx;
+
+ struct netlink_data *netlink;
+ struct nl_handle *nl;
+ char ifname[IFNAMSIZ + 1];
+ int ifi;
+ int parent_ifi;
+
+ Boolean created_link;
+
+ Boolean controlled_port_enabled;
+ Boolean controlled_port_enabled_set;
+
+ Boolean protect_frames;
+ Boolean protect_frames_set;
+
+ Boolean encrypt;
+ Boolean encrypt_set;
+
+ Boolean replay_protect;
+ Boolean replay_protect_set;
+
+ u32 replay_window;
+
+ u8 encoding_sa;
+ Boolean encoding_sa_set;
+};
+
+
+static int dump_callback(struct nl_msg *msg, void *argp);
+
+
+static struct nl_msg * msg_prepare(enum macsec_nl_commands cmd,
+ const struct macsec_genl_ctx *ctx,
+ unsigned int ifindex)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc message");
+ return NULL;
+ }
+
+ if (!genlmsg_put(msg, 0, 0, ctx->macsec_genl_id, 0, 0, cmd, 0)) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to put header");
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_U32(msg, MACSEC_ATTR_IFINDEX, ifindex);
+
+ return msg;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+static int nla_put_rxsc_config(struct nl_msg *msg, u64 sci)
+{
+ struct nlattr *nest = nla_nest_start(msg, MACSEC_ATTR_RXSC_CONFIG);
+
+ if (!nest)
+ return -1;
+
+ NLA_PUT_U64(msg, MACSEC_RXSC_ATTR_SCI, sci);
+
+ nla_nest_end(msg, nest);
+
+ return 0;
+
+nla_put_failure:
+ return -1;
+}
+
+
+static int init_genl_ctx(struct macsec_drv_data *drv)
+{
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ ctx->sk = nl_socket_alloc();
+ if (!ctx->sk) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
+ return -1;
+ }
+
+ if (genl_connect(ctx->sk) < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "connection to genl socket failed");
+ goto out_free;
+ }
+
+ ctx->macsec_genl_id = genl_ctrl_resolve(ctx->sk, "macsec");
+ if (ctx->macsec_genl_id < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "genl resolve failed");
+ goto out_free;
+ }
+
+ memset(&ctx->cb_arg, 0, sizeof(ctx->cb_arg));
+ ctx->cb_arg.drv = drv;
+
+ nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, dump_callback,
+ &ctx->cb_arg);
+
+ return 0;
+
+out_free:
+ nl_socket_free(ctx->sk);
+ ctx->sk = NULL;
+ return -1;
+}
+
+
+static int try_commit(struct macsec_drv_data *drv)
+{
+ int err;
+
+ if (!drv->sk)
+ return 0;
+
+ if (!drv->link)
+ return 0;
+
+ if (drv->controlled_port_enabled_set) {
+ struct rtnl_link *change = rtnl_link_alloc();
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit controlled_port_enabled=%d",
+ drv->ifname, drv->controlled_port_enabled);
+ if (!change)
+ return -1;
+
+ rtnl_link_set_name(change, drv->ifname);
+
+ if (drv->controlled_port_enabled)
+ rtnl_link_set_flags(change, IFF_UP);
+ else
+ rtnl_link_unset_flags(change, IFF_UP);
+
+ err = rtnl_link_change(drv->sk, change, change, 0);
+ if (err < 0)
+ return err;
+
+ rtnl_link_put(change);
+
+ drv->controlled_port_enabled_set = FALSE;
+ }
+
+ if (drv->protect_frames_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit protect_frames=%d",
+ drv->ifname, drv->protect_frames);
+ rtnl_link_macsec_set_protect(drv->link, drv->protect_frames);
+ }
+
+ if (drv->encrypt_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: try_commit encrypt=%d",
+ drv->ifname, drv->encrypt);
+ rtnl_link_macsec_set_encrypt(drv->link, drv->encrypt);
+ }
+
+ if (drv->replay_protect_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit replay_protect=%d replay_window=%d",
+ drv->ifname, drv->replay_protect,
+ drv->replay_window);
+ rtnl_link_macsec_set_replay_protect(drv->link,
+ drv->replay_protect);
+ if (drv->replay_protect)
+ rtnl_link_macsec_set_window(drv->link,
+ drv->replay_window);
+ }
+
+ if (drv->encoding_sa_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit encoding_sa=%d",
+ drv->ifname, drv->encoding_sa);
+ rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
+ }
+
+ err = rtnl_link_add(drv->sk, drv->link, 0);
+ if (err < 0)
+ return err;
+
+ drv->protect_frames_set = FALSE;
+ drv->encrypt_set = FALSE;
+ drv->replay_protect_set = FALSE;
+
+ return 0;
+}
+
+
+static void macsec_drv_wpa_deinit(void *priv)
+{
+ struct macsec_drv_data *drv = priv;
+
+ driver_wired_deinit_common(&drv->common);
+ os_free(drv);
+}
+
+
+static int macsec_check_macsec(void)
+{
+ struct nl_sock *sk;
+ int err = -1;
+
+ sk = nl_socket_alloc();
+ if (!sk) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
+ return -1;
+ }
+
+ if (genl_connect(sk) < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "connection to genl socket failed");
+ goto out_free;
+ }
+
+ if (genl_ctrl_resolve(sk, "macsec") < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "genl resolve failed - macsec kernel module not present?");
+ goto out_free;
+ }
+
+ err = 0;
+
+out_free:
+ nl_socket_free(sk);
+ return err;
+}
+
+
+static void * macsec_drv_wpa_init(void *ctx, const char *ifname)
+{
+ struct macsec_drv_data *drv;
+
+ if (macsec_check_macsec() < 0)
+ return NULL;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (!drv)
+ return NULL;
+
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ drv->sk = nl_socket_alloc();
+ if (!drv->sk)
+ return -1;
+
+ err = nl_connect(drv->sk, NETLINK_ROUTE);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "Unable to connect NETLINK_ROUTE socket: %s",
+ strerror(errno));
+ goto sock;
+ }
+
+ err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
+ strerror(errno));
+ goto sock;
+ }
+
+ drv->parent_ifi = rtnl_link_name2i(drv->link_cache, drv->common.ifname);
+ if (drv->parent_ifi == 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "couldn't find ifindex for interface %s",
+ drv->common.ifname);
+ goto cache;
+ }
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "ifname=%s parent_ifi=%d",
+ drv->common.ifname, drv->parent_ifi);
+
+ err = init_genl_ctx(drv);
+ if (err < 0)
+ goto cache;
+
+ return 0;
+
+cache:
+ nl_cache_free(drv->link_cache);
+ drv->link_cache = NULL;
+sock:
+ nl_socket_free(drv->sk);
+ drv->sk = NULL;
+ return -1;
+}
+
+
+static int macsec_drv_macsec_deinit(void *priv)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ if (drv->sk)
+ nl_socket_free(drv->sk);
+ drv->sk = NULL;
+
+ if (drv->link_cache)
+ nl_cache_free(drv->link_cache);
+ drv->link_cache = NULL;
+
+ if (drv->ctx.sk)
+ nl_socket_free(drv->ctx.sk);
+
+ return 0;
+}
+
+
+static int macsec_drv_get_capability(void *priv, enum macsec_cap *cap)
+{
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ *cap = MACSEC_CAP_INTEG_AND_CONF;
+
+ return 0;
+}
+
+
+/**
+ * macsec_drv_enable_protect_frames - Set protect frames status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = protect frames enabled
+ * FALSE = protect frames disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_protect_frames(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->protect_frames_set = TRUE;
+ drv->protect_frames = enabled;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_enable_encrypt - Set protect frames status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = protect frames enabled
+ * FALSE = protect frames disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_encrypt(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->encrypt_set = TRUE;
+ drv->encrypt = enabled;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_set_replay_protect - Set replay protect status and window size
+ * @priv: Private driver interface data
+ * @enabled: TRUE = replay protect enabled
+ * FALSE = replay protect disabled
+ * @window: replay window size, valid only when replay protect enabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_replay_protect(void *priv, Boolean enabled,
+ u32 window)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__,
+ enabled ? "TRUE" : "FALSE", window);
+
+ drv->replay_protect_set = TRUE;
+ drv->replay_protect = enabled;
+ if (enabled)
+ drv->replay_window = window;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_set_current_cipher_suite - Set current cipher suite
+ * @priv: Private driver interface data
+ * @cs: EUI64 identifier
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
+{
+ wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs);
+ return 0;
+}
+
+
+/**
+ * macsec_drv_enable_controlled_port - Set controlled port status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = controlled port enabled
+ * FALSE = controlled port disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_controlled_port(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->controlled_port_enabled = enabled;
+ drv->controlled_port_enabled_set = TRUE;
+
+ return try_commit(drv);
+}
+
+
+static struct nla_policy sa_policy[MACSEC_SA_ATTR_MAX + 1] = {
+ [MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
+ [MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 },
+ [MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
+ [MACSEC_SA_ATTR_KEYID] = { .type = NLA_BINARY },
+};
+
+static struct nla_policy sc_policy[MACSEC_RXSC_ATTR_MAX + 1] = {
+ [MACSEC_RXSC_ATTR_SCI] = { .type = NLA_U64 },
+ [MACSEC_RXSC_ATTR_ACTIVE] = { .type = NLA_U8 },
+ [MACSEC_RXSC_ATTR_SA_LIST] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy main_policy[MACSEC_ATTR_MAX + 1] = {
+ [MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
+ [MACSEC_ATTR_SECY] = { .type = NLA_NESTED },
+ [MACSEC_ATTR_TXSA_LIST] = { .type = NLA_NESTED },
+ [MACSEC_ATTR_RXSC_LIST] = { .type = NLA_NESTED },
+};
+
+static int dump_callback(struct nl_msg *msg, void *argp)
+{
+ struct nlmsghdr *ret_hdr = nlmsg_hdr(msg);
+ struct nlattr *tb_msg[MACSEC_ATTR_MAX + 1];
+ struct cb_arg *arg = (struct cb_arg *) argp;
+ struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(ret_hdr);
+ int err;
+
+ if (ret_hdr->nlmsg_type != arg->drv->ctx.macsec_genl_id)
+ return 0;
+
+ err = nla_parse(tb_msg, MACSEC_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), main_policy);
+ if (err < 0)
+ return 0;
+
+ if (!tb_msg[MACSEC_ATTR_IFINDEX])
+ return 0;
+
+ if (nla_get_u32(tb_msg[MACSEC_ATTR_IFINDEX]) != (u32) arg->ifindex)
+ return 0;
+
+ if (arg->txsa < 4 && !tb_msg[MACSEC_ATTR_TXSA_LIST]) {
+ return 0;
+ } else if (arg->txsa < 4) {
+ struct nlattr *nla;
+ int rem;
+
+ nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_TXSA_LIST], rem) {
+ struct nlattr *tb[MACSEC_SA_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb, MACSEC_SA_ATTR_MAX, nla,
+ sa_policy);
+ if (err < 0)
+ continue;
+ if (!tb[MACSEC_SA_ATTR_AN])
+ continue;
+ if (nla_get_u8(tb[MACSEC_SA_ATTR_AN]) != arg->txsa)
+ continue;
+ if (!tb[MACSEC_SA_ATTR_PN])
+ return 0;
+ *arg->pn = nla_get_u32(tb[MACSEC_SA_ATTR_PN]);
+ return 0;
+ }
+
+ return 0;
+ }
+
+ if (arg->rxsci == UNUSED_SCI)
+ return 0;
+
+ if (tb_msg[MACSEC_ATTR_RXSC_LIST]) {
+ struct nlattr *nla;
+ int rem;
+
+ nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_RXSC_LIST], rem) {
+ struct nlattr *tb[MACSEC_RXSC_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb, MACSEC_RXSC_ATTR_MAX, nla,
+ sc_policy);
+ if (err < 0)
+ return 0;
+ if (!tb[MACSEC_RXSC_ATTR_SCI])
+ continue;
+ if (nla_get_u64(tb[MACSEC_RXSC_ATTR_SCI]) != arg->rxsci)
+ continue;
+ if (!tb[MACSEC_RXSC_ATTR_SA_LIST])
+ return 0;
+
+ nla_for_each_nested(nla, tb[MACSEC_RXSC_ATTR_SA_LIST],
+ rem) {
+ struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb_sa,
+ MACSEC_SA_ATTR_MAX, nla,
+ sa_policy);
+ if (err < 0)
+ continue;
+ if (!tb_sa[MACSEC_SA_ATTR_AN])
+ continue;
+ if (nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]) !=
+ arg->rxsa)
+ continue;
+ if (!tb_sa[MACSEC_SA_ATTR_PN])
+ return 0;
+ *arg->pn =
+ nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int nl_send_recv(struct nl_sock *sk, struct nl_msg *msg)
+{
+ int ret;
+
+ ret = nl_send_auto_complete(sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to send: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ return ret;
+ }
+
+ ret = nl_recvmsgs_default(sk);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to recv: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+ return ret;
+}
+
+
+static int do_dump(struct macsec_drv_data *drv, u8 txsa, u64 rxsci, u8 rxsa,
+ u32 *pn)
+{
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = 1;
+
+ ctx->cb_arg.ifindex = drv->ifi;
+ ctx->cb_arg.rxsci = rxsci;
+ ctx->cb_arg.rxsa = rxsa;
+ ctx->cb_arg.txsa = txsa;
+ ctx->cb_arg.pn = pn;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to alloc message",
+ __func__);
+ return 1;
+ }
+
+ if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->macsec_genl_id, 0,
+ NLM_F_DUMP, MACSEC_CMD_GET_TXSC, 0)) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to put header",
+ __func__);
+ goto out_free_msg;
+ }
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0)
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+
+ ctx->cb_arg.pn = NULL;
+
+out_free_msg:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_get_receive_lowest_pn - Get receive lowest PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s", __func__);
+
+ err = do_dump(drv, 0xff, mka_sci_u64(&sa->sc->sci), sa->an,
+ &sa->lowest_pn);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: result %d", __func__,
+ sa->lowest_pn);
+
+ return err;
+}
+
+
+/**
+ * macsec_drv_set_receive_lowest_pn - Set receive lowest PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_receive_lowest_pn(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: set_receive_lowest_pn -> %d: %d",
+ drv->ifname, sa->an, sa->next_pn);
+
+ msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_get_transmit_next_pn - Get transmit next PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ err = do_dump(drv, sa->an, UNUSED_SCI, 0xff, &sa->next_pn);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: err %d result %d", __func__, err,
+ sa->next_pn);
+ return err;
+}
+
+
+/**
+ * macsec_drv_set_transmit_next_pn - Set transmit next pn
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d: %d", __func__, sa->an, sa->next_pn);
+
+ msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+#define SCISTR MACSTR "::%hx"
+#define SCI2STR(addr, port) MAC2STR(addr), htons(port)
+
+/**
+ * macsec_drv_create_receive_sc - Create secure channel for receiving
+ * @priv: Private driver interface data
+ * @sc: secure channel
+ * @sci_addr: secure channel identifier - address
+ * @sci_port: secure channel identifier - port
+ * @conf_offset: confidentiality offset (0, 30, or 50)
+ * @validation: frame validation policy (0 = Disabled, 1 = Checked,
+ * 2 = Strict)
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_create_receive_sc(void *priv, struct receive_sc *sc,
+ unsigned int conf_offset,
+ int validation)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_receive_sc -> " SCISTR
+ " (conf_offset=%u validation=%d)",
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port),
+ conf_offset, validation);
+
+ msg = msg_prepare(MACSEC_CMD_ADD_RXSC, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
+ goto nla_put_failure;
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_receive_sc - Delete secure connection for receiving
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_receive_sc(void *priv, struct receive_sc *sc)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sc -> " SCISTR,
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_DEL_RXSC, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
+ goto nla_put_failure;
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_create_receive_sa - Create secure association for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: create_receive_sa -> %d on " SCISTR
+ " (enable_receive=%d next_pn=%u)",
+ drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->enable_receive, sa->next_pn);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid",
+ &sa->pkey->key_identifier,
+ sizeof(sa->pkey->key_identifier));
+ wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key",
+ sa->pkey->key, sa->pkey->key_len);
+
+ msg = msg_prepare(MACSEC_CMD_ADD_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_receive);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
+ &sa->pkey->key_identifier);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_receive_sa - Delete secure association for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_DEL_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int set_active_rx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
+ u64 sci, unsigned char an, Boolean state)
+{
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, ifindex);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, sci))
+ goto nla_put_failure;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0)
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_enable_receive_sa - Enable the SA for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_enable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
+ sa->an, TRUE);
+}
+
+
+/**
+ * macsec_drv_disable_receive_sa - Disable SA for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
+ sa->an, FALSE);
+}
+
+
+static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci)
+{
+ struct rtnl_link *needle;
+ void *match;
+
+ needle = rtnl_link_macsec_alloc();
+ if (!needle)
+ return NULL;
+
+ rtnl_link_set_link(needle, parent);
+ rtnl_link_macsec_set_sci(needle, sci);
+
+ match = nl_cache_find(cache, (struct nl_object *) needle);
+ rtnl_link_put(needle);
+
+ return (struct rtnl_link *) match;
+}
+
+
+/**
+ * macsec_drv_create_transmit_sc - Create secure connection for transmit
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * @conf_offset: confidentiality offset
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_transmit_sc(
+ void *priv, struct transmit_sc *sc,
+ unsigned int conf_offset)
+{
+ struct macsec_drv_data *drv = priv;
+ struct rtnl_link *link;
+ char *ifname;
+ u64 sci;
+ int err;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)",
+ drv->common.ifname, SCI2STR(sc->sci.addr, sc->sci.port),
+ conf_offset);
+
+ if (!drv->sk) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "NULL rtnl socket");
+ return -1;
+ }
+
+ link = rtnl_link_macsec_alloc();
+ if (!link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
+ return -1;
+ }
+
+ rtnl_link_set_link(link, drv->parent_ifi);
+
+ sci = mka_sci_u64(&sc->sci);
+ rtnl_link_macsec_set_sci(link, sci);
+
+ drv->created_link = TRUE;
+
+ err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
+ if (err == -NLE_BUSY) {
+ wpa_printf(MSG_INFO,
+ DRV_PREFIX "link already exists, using it");
+ drv->created_link = FALSE;
+ } else if (err < 0) {
+ rtnl_link_put(link);
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't create link: err %d",
+ err);
+ return err;
+ }
+
+ rtnl_link_put(link);
+
+ nl_cache_refill(drv->sk, drv->link_cache);
+ link = lookup_sc(drv->link_cache, drv->parent_ifi, sci);
+ if (!link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link");
+ return -1;
+ }
+
+ drv->ifi = rtnl_link_get_ifindex(link);
+ ifname = rtnl_link_get_name(link);
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: create_transmit_sc: ifi=%d ifname=%s",
+ drv->common.ifname, drv->ifi, ifname);
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ rtnl_link_put(link);
+
+ drv->link = rtnl_link_macsec_alloc();
+ if (!drv->link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
+ return -1;
+ }
+
+ rtnl_link_set_name(drv->link, drv->ifname);
+
+ /* In case some settings have already been done but we couldn't apply
+ * them. */
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_delete_transmit_sc - Delete secure connection for transmit
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_transmit_sc(void *priv, struct transmit_sc *sc)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sc -> " SCISTR,
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port));
+
+ if (!drv->sk)
+ return 0;
+
+ if (!drv->created_link) {
+ rtnl_link_put(drv->link);
+ drv->link = NULL;
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "we didn't create the link, leave it alone");
+ return 0;
+ }
+
+ err = rtnl_link_delete(drv->sk, drv->link);
+ if (err < 0)
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't delete link");
+ rtnl_link_put(drv->link);
+ drv->link = NULL;
+
+ return err;
+}
+
+
+/**
+ * macsec_drv_create_transmit_sa - Create secure association for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_transmit_sa -> %d on "
+ SCISTR " (enable_transmit=%d next_pn=%u)",
+ drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->enable_transmit, sa->next_pn);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid",
+ &sa->pkey->key_identifier,
+ sizeof(sa->pkey->key_identifier));
+ wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key",
+ sa->pkey->key, sa->pkey->key_len);
+
+ msg = msg_prepare(MACSEC_CMD_ADD_TXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
+ &sa->pkey->key_identifier);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_transmit);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_transmit_sa - Delete secure association for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_DEL_TXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int set_active_tx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
+ unsigned char an, Boolean state)
+{
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, ifindex);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_enable_transmit_sa - Enable SA for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_enable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ ret = set_active_tx_sa(ctx, drv->ifi, sa->an, TRUE);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to enable txsa");
+ return ret;
+ }
+
+ drv->encoding_sa_set = TRUE;
+ drv->encoding_sa = sa->an;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_disable_transmit_sa - Disable SA for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_disable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ return set_active_tx_sa(ctx, drv->ifi, sa->an, FALSE);
+}
+
+
+static int macsec_drv_status(void *priv, char *buf, size_t buflen)
+{
+ struct macsec_drv_data *drv = priv;
+ int res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos,
+ "ifname=%s\n"
+ "ifi=%d\n"
+ "parent_ifname=%s\n"
+ "parent_ifi=%d\n",
+ drv->common.ifname, drv->ifi,
+ drv->ifname, drv->parent_ifi);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
+
+
+const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
+ .name = "macsec_linux",
+ .desc = "MACsec Ethernet driver for Linux",
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
+ .init = macsec_drv_wpa_init,
+ .deinit = macsec_drv_wpa_deinit,
+
+ .macsec_init = macsec_drv_macsec_init,
+ .macsec_deinit = macsec_drv_macsec_deinit,
+ .macsec_get_capability = macsec_drv_get_capability,
+ .enable_protect_frames = macsec_drv_enable_protect_frames,
+ .enable_encrypt = macsec_drv_enable_encrypt,
+ .set_replay_protect = macsec_drv_set_replay_protect,
+ .set_current_cipher_suite = macsec_drv_set_current_cipher_suite,
+ .enable_controlled_port = macsec_drv_enable_controlled_port,
+ .get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn,
+ .set_receive_lowest_pn = macsec_drv_set_receive_lowest_pn,
+ .get_transmit_next_pn = macsec_drv_get_transmit_next_pn,
+ .set_transmit_next_pn = macsec_drv_set_transmit_next_pn,
+ .create_receive_sc = macsec_drv_create_receive_sc,
+ .delete_receive_sc = macsec_drv_delete_receive_sc,
+ .create_receive_sa = macsec_drv_create_receive_sa,
+ .delete_receive_sa = macsec_drv_delete_receive_sa,
+ .enable_receive_sa = macsec_drv_enable_receive_sa,
+ .disable_receive_sa = macsec_drv_disable_receive_sa,
+ .create_transmit_sc = macsec_drv_create_transmit_sc,
+ .delete_transmit_sc = macsec_drv_delete_transmit_sc,
+ .create_transmit_sa = macsec_drv_create_transmit_sa,
+ .delete_transmit_sa = macsec_drv_delete_transmit_sa,
+ .enable_transmit_sa = macsec_drv_enable_transmit_sa,
+ .disable_transmit_sa = macsec_drv_disable_transmit_sa,
+
+ .status = macsec_drv_status,
+};
diff --git a/contrib/wpa/src/drivers/driver_macsec_qca.c b/contrib/wpa/src/drivers/driver_macsec_qca.c
index 3eae2f8..8372393 100644
--- a/contrib/wpa/src/drivers/driver_macsec_qca.c
+++ b/contrib/wpa/src/drivers/driver_macsec_qca.c
@@ -11,6 +11,7 @@
#include "includes.h"
#include <sys/ioctl.h>
#include <net/if.h>
+#include <inttypes.h>
#ifdef __linux__
#include <netpacket/packet.h>
#include <net/if_arp.h>
@@ -28,7 +29,9 @@
#include "utils/eloop.h"
#include "common/defs.h"
#include "common/ieee802_1x_defs.h"
+#include "pae/ieee802_1x_kay.h"
#include "driver.h"
+#include "driver_wired_common.h"
#include "nss_macsec_secy.h"
#include "nss_macsec_secy_rx.h"
@@ -36,6 +39,9 @@
#define MAXSC 16
+#define SAK_128_LEN 16
+#define SAK_256_LEN 32
+
/* TCI field definition */
#define TCI_ES 0x40
#define TCI_SC 0x20
@@ -51,17 +57,14 @@
#pragma pack(pop)
#endif /* _MSC_VER */
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+struct channel_map {
+ struct ieee802_1x_mka_sci sci;
+};
struct macsec_qca_data {
- char ifname[IFNAMSIZ + 1];
- u32 secy_id;
- void *ctx;
+ struct driver_wired_common_data common;
- int sock; /* raw packet socket for driver access */
- int pf_sock;
- int membership, multi, iff_allmulti, iff_up;
+ u32 secy_id;
/* shadow */
Boolean always_include_sci;
@@ -70,192 +73,10 @@ struct macsec_qca_data {
Boolean protect_frames;
Boolean replay_protect;
u32 replay_window;
-};
-
-
-static int macsec_qca_multicast_membership(int sock, int ifindex,
- const u8 *addr, int add)
-{
-#ifdef __linux__
- struct packet_mreq mreq;
-
- if (sock < 0)
- return -1;
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.mr_ifindex = ifindex;
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = ETH_ALEN;
- os_memcpy(mreq.mr_address, addr, ETH_ALEN);
-
- if (setsockopt(sock, SOL_PACKET,
- add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
- return -1;
- }
- return 0;
-#else /* __linux__ */
- return -1;
-#endif /* __linux__ */
-}
-
-
-static int macsec_qca_get_ssid(void *priv, u8 *ssid)
-{
- ssid[0] = 0;
- return 0;
-}
-
-
-static int macsec_qca_get_bssid(void *priv, u8 *bssid)
-{
- /* Report PAE group address as the "BSSID" for macsec connection. */
- os_memcpy(bssid, pae_group_addr, ETH_ALEN);
- return 0;
-}
-
-
-static int macsec_qca_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_WIRED;
- return 0;
-}
-
-
-static int macsec_qca_get_ifflags(const char *ifname, int *flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
-}
-
-
-static int macsec_qca_set_ifflags(const char *ifname, int flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-static int macsec_qca_get_ifstatus(const char *ifname, int *status)
-{
- struct ifmediareq ifmr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_print(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifmr, 0, sizeof(ifmr));
- os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
- (IFM_ACTIVE | IFM_AVALID);
-
- return 0;
-}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-
-
-static int macsec_qca_multi(const char *ifname, const u8 *addr, int add)
-{
- struct ifreq ifr;
- int s;
-
-#ifdef __sun__
- return -1;
-#endif /* __sun__ */
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-#ifdef __linux__
- ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
- os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- struct sockaddr_dl *dlp;
- dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
- dlp->sdl_len = sizeof(struct sockaddr_dl);
- dlp->sdl_family = AF_LINK;
- dlp->sdl_index = 0;
- dlp->sdl_nlen = 0;
- dlp->sdl_alen = ETH_ALEN;
- dlp->sdl_slen = 0;
- os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
- {
- struct sockaddr *sap;
- sap = (struct sockaddr *) &ifr.ifr_addr;
- sap->sa_len = sizeof(struct sockaddr);
- sap->sa_family = AF_UNSPEC;
- os_memcpy(sap->sa_data, addr, ETH_ALEN);
- }
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
-
- if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
+ struct channel_map receive_channel_map[MAXSC];
+ struct channel_map transmit_channel_map[MAXSC];
+};
static void __macsec_drv_init(struct macsec_qca_data *drv)
@@ -308,76 +129,23 @@ static void __macsec_drv_deinit(struct macsec_qca_data *drv)
static void * macsec_qca_init(void *ctx, const char *ifname)
{
struct macsec_qca_data *drv;
- int flags;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ctx = ctx;
/* Board specific settings */
- if (os_memcmp("eth2", drv->ifname, 4) == 0)
+ if (os_memcmp("eth2", ifname, 4) == 0)
drv->secy_id = 1;
- else if (os_memcmp("eth3", drv->ifname, 4) == 0)
+ else if (os_memcmp("eth3", ifname, 4) == 0)
drv->secy_id = 2;
else
drv->secy_id = -1;
-#ifdef __linux__
- drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
- if (drv->pf_sock < 0)
- wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
-#else /* __linux__ */
- drv->pf_sock = -1;
-#endif /* __linux__ */
-
- if (macsec_qca_get_ifflags(ifname, &flags) == 0 &&
- !(flags & IFF_UP) &&
- macsec_qca_set_ifflags(ifname, flags | IFF_UP) == 0) {
- drv->iff_up = 1;
- }
-
- if (macsec_qca_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Added multicast membership with packet socket",
- __func__);
- drv->membership = 1;
- } else if (macsec_qca_multi(ifname, pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Added multicast membership with SIOCADDMULTI",
- __func__);
- drv->multi = 1;
- } else if (macsec_qca_get_ifflags(ifname, &flags) < 0) {
- wpa_printf(MSG_INFO, "%s: Could not get interface flags",
- __func__);
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
os_free(drv);
return NULL;
- } else if (flags & IFF_ALLMULTI) {
- wpa_printf(MSG_DEBUG,
- "%s: Interface is already configured for multicast",
- __func__);
- } else if (macsec_qca_set_ifflags(ifname, flags | IFF_ALLMULTI) < 0) {
- wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
- __func__);
- os_free(drv);
- return NULL;
- } else {
- wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__);
- drv->iff_allmulti = 1;
}
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- int status;
- wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
- __func__);
- while (macsec_qca_get_ifstatus(ifname, &status) == 0 &&
- status == 0)
- sleep(1);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
return drv;
}
@@ -386,42 +154,8 @@ static void * macsec_qca_init(void *ctx, const char *ifname)
static void macsec_qca_deinit(void *priv)
{
struct macsec_qca_data *drv = priv;
- int flags;
-
- if (drv->membership &&
- macsec_qca_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Failed to remove PAE multicast group (PACKET)",
- __func__);
- }
-
- if (drv->multi &&
- macsec_qca_multi(drv->ifname, pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Failed to remove PAE multicast group (SIOCDELMULTI)",
- __func__);
- }
-
- if (drv->iff_allmulti &&
- (macsec_qca_get_ifflags(drv->ifname, &flags) < 0 ||
- macsec_qca_set_ifflags(drv->ifname, flags & ~IFF_ALLMULTI) < 0)) {
- wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
- __func__);
- }
-
- if (drv->iff_up &&
- macsec_qca_get_ifflags(drv->ifname, &flags) == 0 &&
- (flags & IFF_UP) &&
- macsec_qca_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
- __func__);
- }
-
- if (drv->pf_sock != -1)
- close(drv->pf_sock);
+ driver_wired_deinit_common(&drv->common);
os_free(drv);
}
@@ -456,6 +190,16 @@ static int macsec_qca_macsec_deinit(void *priv)
}
+static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
+{
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ *cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
+
+ return 0;
+}
+
+
static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
{
struct macsec_qca_data *drv = priv;
@@ -485,22 +229,32 @@ static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
}
-static int macsec_qca_set_current_cipher_suite(void *priv, const u8 *cs,
- size_t cs_len)
+static fal_cipher_suite_e macsec_qca_cs_type_get(u64 cs)
+{
+ if (cs == CS_ID_GCM_AES_128)
+ return FAL_CIPHER_SUITE_AES_GCM_128;
+ if (cs == CS_ID_GCM_AES_256)
+ return FAL_CIPHER_SUITE_AES_GCM_256;
+ return FAL_CIPHER_SUITE_MAX;
+}
+
+
+static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
{
- u8 default_cs_id[] = CS_ID_GCM_AES_128;
+ struct macsec_qca_data *drv = priv;
+ fal_cipher_suite_e cs_type;
- if (cs_len != CS_ID_LEN ||
- os_memcmp(cs, default_cs_id, cs_len) != 0) {
- wpa_hexdump(MSG_ERROR, "macsec: NOT supported CipherSuite",
- cs, cs_len);
+ if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) {
+ wpa_printf(MSG_ERROR,
+ "%s: NOT supported CipherSuite: %016" PRIx64,
+ __func__, cs);
return -1;
}
- /* Support default Cipher Suite 0080020001000001 (GCM-AES-128) */
- wpa_printf(MSG_DEBUG, "%s: default support aes-gcm-128", __func__);
+ wpa_printf(MSG_DEBUG, "%s: CipherSuite: %016" PRIx64, __func__, cs);
- return 0;
+ cs_type = macsec_qca_cs_type_get(cs);
+ return nss_macsec_secy_cipher_suite_set(drv->secy_id, cs_type);
}
@@ -517,16 +271,82 @@ static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
}
-static int macsec_qca_get_receive_lowest_pn(void *priv, u32 channel, u8 an,
- u32 *lowest_pn)
+static int macsec_qca_lookup_channel(struct channel_map *map,
+ struct ieee802_1x_mka_sci *sci,
+ u32 *channel)
+{
+ u32 i;
+
+ for (i = 0; i < MAXSC; i++) {
+ if (os_memcmp(&map[i].sci, sci,
+ sizeof(struct ieee802_1x_mka_sci)) == 0) {
+ *channel = i;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+static void macsec_qca_register_channel(struct channel_map *map,
+ struct ieee802_1x_mka_sci *sci,
+ u32 channel)
+{
+ os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci));
+}
+
+
+static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv,
+ struct receive_sc *sc,
+ u32 *channel)
+{
+ return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci,
+ channel);
+}
+
+
+static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv,
+ struct receive_sc *sc,
+ u32 channel)
+{
+ macsec_qca_register_channel(drv->receive_channel_map, &sc->sci,
+ channel);
+}
+
+
+static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv,
+ struct transmit_sc *sc,
+ u32 *channel)
+{
+ return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci,
+ channel);
+}
+
+
+static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv,
+ struct transmit_sc *sc,
+ u32 channel)
+{
+ macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci,
+ channel);
+}
+
+
+static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
u32 next_pn = 0;
bool enabled = FALSE;
u32 win;
+ u32 channel;
+
+ ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, an,
+ ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
&next_pn);
ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
&enabled);
@@ -534,40 +354,49 @@ static int macsec_qca_get_receive_lowest_pn(void *priv, u32 channel, u8 an,
channel, &win);
if (enabled)
- *lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
+ sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
else
- *lowest_pn = next_pn;
+ sa->lowest_pn = next_pn;
- wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, *lowest_pn);
+ wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
return ret;
}
-static int macsec_qca_get_transmit_next_pn(void *priv, u32 channel, u8 an,
- u32 *next_pn)
+static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
+ u32 channel;
- ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, an,
- next_pn);
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, *next_pn);
+ ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
+ &sa->next_pn);
+
+ wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
return ret;
}
-int macsec_qca_set_transmit_next_pn(void *priv, u32 channel, u8 an, u32 next_pn)
+static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
+ u32 channel;
+
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, an,
- next_pn);
+ ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
+ sa->next_pn);
- wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, next_pn);
+ wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
return ret;
}
@@ -600,8 +429,7 @@ static int macsec_qca_get_available_receive_sc(void *priv, u32 *channel)
}
-static int macsec_qca_create_receive_sc(void *priv, u32 channel,
- const u8 *sci_addr, u16 sci_port,
+static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
unsigned int conf_offset,
int validation)
{
@@ -610,6 +438,13 @@ static int macsec_qca_create_receive_sc(void *priv, u32 channel,
fal_rx_prc_lut_t entry;
fal_rx_sc_validate_frame_e vf;
enum validate_frames validate_frames = validation;
+ u32 channel;
+ const u8 *sci_addr = sc->sci.addr;
+ u16 sci_port = be_to_host16(sc->sci.port);
+
+ ret = macsec_qca_get_available_receive_sc(priv, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
@@ -617,8 +452,8 @@ static int macsec_qca_create_receive_sc(void *priv, u32 channel,
os_memset(&entry, 0, sizeof(entry));
os_memcpy(entry.sci, sci_addr, ETH_ALEN);
- entry.sci[6] = (sci_port >> 8) & 0xf;
- entry.sci[7] = sci_port & 0xf;
+ entry.sci[6] = (sci_port >> 8) & 0xff;
+ entry.sci[7] = sci_port & 0xff;
entry.sci_mask = 0xf;
entry.valid = 1;
@@ -644,15 +479,22 @@ static int macsec_qca_create_receive_sc(void *priv, u32 channel,
channel,
drv->replay_window);
+ macsec_qca_register_receive_channel(drv, sc, channel);
+
return ret;
}
-static int macsec_qca_delete_receive_sc(void *priv, u32 channel)
+static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
fal_rx_prc_lut_t entry;
+ u32 channel;
+
+ ret = macsec_qca_lookup_receive_channel(priv, sc, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
@@ -666,49 +508,91 @@ static int macsec_qca_delete_receive_sc(void *priv, u32 channel)
}
-static int macsec_qca_create_receive_sa(void *priv, u32 channel, u8 an,
- u32 lowest_pn, const u8 *sak)
+static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
fal_rx_sak_t rx_sak;
int i = 0;
+ u32 channel;
+ fal_rx_prc_lut_t entry;
+ u32 offset;
+
+ ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
- __func__, channel, an, lowest_pn);
+ __func__, channel, sa->an, sa->lowest_pn);
os_memset(&rx_sak, 0, sizeof(rx_sak));
- for (i = 0; i < 16; i++)
- rx_sak.sak[i] = sak[15 - i];
+ rx_sak.sak_len = sa->pkey->key_len;
+ if (sa->pkey->key_len == SAK_128_LEN) {
+ for (i = 0; i < 16; i++)
+ rx_sak.sak[i] = sa->pkey->key[15 - i];
+ } else if (sa->pkey->key_len == SAK_256_LEN) {
+ for (i = 0; i < 16; i++) {
+ rx_sak.sak1[i] = sa->pkey->key[15 - i];
+ rx_sak.sak[i] = sa->pkey->key[31 - i];
+ }
+ } else {
+ return -1;
+ }
- ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, an);
- ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, an, &rx_sak);
+ if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
+ offset = 0;
+ else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
+ offset = 30;
+ else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
+ offset = 50;
+ else
+ return -1;
+ ret += nss_macsec_secy_rx_prc_lut_get(drv->secy_id, channel, &entry);
+ entry.offset = offset;
+ ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
+ ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
+ ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
+ &rx_sak);
return ret;
}
-static int macsec_qca_enable_receive_sa(void *priv, u32 channel, u8 an)
+static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
+ u32 channel;
+
+ ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
+ sa->an);
- ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, an, TRUE);
+ ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
+ TRUE);
return ret;
}
-static int macsec_qca_disable_receive_sa(void *priv, u32 channel, u8 an)
+static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
+ u32 channel;
+
+ ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
+ sa->an);
- ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, an, FALSE);
+ ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
+ FALSE);
return ret;
}
@@ -717,14 +601,12 @@ static int macsec_qca_disable_receive_sa(void *priv, u32 channel, u8 an)
static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
u32 sc_ch = 0;
bool in_use = FALSE;
for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
- ret = nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
- &in_use);
- if (ret)
+ if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
+ &in_use))
continue;
if (!in_use) {
@@ -741,14 +623,19 @@ static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
}
-static int macsec_qca_create_transmit_sc(void *priv, u32 channel,
- const u8 *sci_addr, u16 sci_port,
+static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
unsigned int conf_offset)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
fal_tx_class_lut_t entry;
u8 psci[ETH_ALEN + 2];
+ u32 channel;
+ u16 sci_port = be_to_host16(sc->sci.port);
+
+ ret = macsec_qca_get_available_transmit_sc(priv, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
@@ -759,9 +646,9 @@ static int macsec_qca_create_transmit_sc(void *priv, u32 channel,
entry.action = FAL_TX_CLASS_ACTION_FORWARD;
entry.channel = channel;
- os_memcpy(psci, sci_addr, ETH_ALEN);
- psci[6] = (sci_port >> 8) & 0xf;
- psci[7] = sci_port & 0xf;
+ os_memcpy(psci, sc->sci.addr, ETH_ALEN);
+ psci[6] = (sci_port >> 8) & 0xff;
+ psci[7] = sci_port & 0xff;
ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
@@ -771,15 +658,22 @@ static int macsec_qca_create_transmit_sc(void *priv, u32 channel,
channel,
conf_offset);
+ macsec_qca_register_transmit_channel(drv, sc, channel);
+
return ret;
}
-static int macsec_qca_delete_transmit_sc(void *priv, u32 channel)
+static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
fal_tx_class_lut_t entry;
+ u32 channel;
+
+ ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
@@ -793,19 +687,23 @@ static int macsec_qca_delete_transmit_sc(void *priv, u32 channel)
}
-static int macsec_qca_create_transmit_sa(void *priv, u32 channel, u8 an,
- u32 next_pn, Boolean confidentiality,
- const u8 *sak)
+static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
u8 tci = 0;
fal_tx_sak_t tx_sak;
int i;
+ u32 channel;
+ u32 offset;
+
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG,
"%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
- __func__, channel, an, next_pn, confidentiality);
+ __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
if (drv->always_include_sci)
tci |= TCI_SC;
@@ -814,45 +712,81 @@ static int macsec_qca_create_transmit_sa(void *priv, u32 channel, u8 an,
else if (drv->use_scb)
tci |= TCI_SCB;
- if (confidentiality)
+ if (sa->confidentiality)
tci |= TCI_E | TCI_C;
os_memset(&tx_sak, 0, sizeof(tx_sak));
- for (i = 0; i < 16; i++)
- tx_sak.sak[i] = sak[15 - i];
+ tx_sak.sak_len = sa->pkey->key_len;
+ if (sa->pkey->key_len == SAK_128_LEN) {
+ for (i = 0; i < 16; i++)
+ tx_sak.sak[i] = sa->pkey->key[15 - i];
+ } else if (sa->pkey->key_len == SAK_256_LEN) {
+ for (i = 0; i < 16; i++) {
+ tx_sak.sak1[i] = sa->pkey->key[15 - i];
+ tx_sak.sak[i] = sa->pkey->key[31 - i];
+ }
+ } else {
+ return -1;
+ }
- ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, an,
- next_pn);
- ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, an, &tx_sak);
+ if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
+ offset = 0;
+ else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
+ offset = 30;
+ else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
+ offset = 50;
+ else
+ return -1;
+ ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
+ channel,
+ offset);
+ ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
+ sa->next_pn);
+ ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
+ &tx_sak);
ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
(tci >> 2));
- ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, an);
+ ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
return ret;
}
-static int macsec_qca_enable_transmit_sa(void *priv, u32 channel, u8 an)
+static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
+ u32 channel;
- wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, an, TRUE);
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
+ sa->an);
+
+ ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
+ TRUE);
return ret;
}
-static int macsec_qca_disable_transmit_sa(void *priv, u32 channel, u8 an)
+static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
+ u32 channel;
+
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
+ sa->an);
- ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, an, FALSE);
+ ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
+ FALSE);
return ret;
}
@@ -861,14 +795,15 @@ static int macsec_qca_disable_transmit_sa(void *priv, u32 channel, u8 an)
const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
.name = "macsec_qca",
.desc = "QCA MACsec Ethernet driver",
- .get_ssid = macsec_qca_get_ssid,
- .get_bssid = macsec_qca_get_bssid,
- .get_capa = macsec_qca_get_capa,
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
.init = macsec_qca_init,
.deinit = macsec_qca_deinit,
.macsec_init = macsec_qca_macsec_init,
.macsec_deinit = macsec_qca_macsec_deinit,
+ .macsec_get_capability = macsec_qca_get_capability,
.enable_protect_frames = macsec_qca_enable_protect_frames,
.set_replay_protect = macsec_qca_set_replay_protect,
.set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
@@ -876,13 +811,11 @@ const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
.get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
.get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
.set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
- .get_available_receive_sc = macsec_qca_get_available_receive_sc,
.create_receive_sc = macsec_qca_create_receive_sc,
.delete_receive_sc = macsec_qca_delete_receive_sc,
.create_receive_sa = macsec_qca_create_receive_sa,
.enable_receive_sa = macsec_qca_enable_receive_sa,
.disable_receive_sa = macsec_qca_disable_receive_sa,
- .get_available_transmit_sc = macsec_qca_get_available_transmit_sc,
.create_transmit_sc = macsec_qca_create_transmit_sc,
.delete_transmit_sc = macsec_qca_delete_transmit_sc,
.create_transmit_sa = macsec_qca_create_transmit_sa,
diff --git a/contrib/wpa/src/drivers/driver_ndis.c b/contrib/wpa/src/drivers/driver_ndis.c
index 2f5ade6..9a08e57 100644
--- a/contrib/wpa/src/drivers/driver_ndis.c
+++ b/contrib/wpa/src/drivers/driver_ndis.c
@@ -35,6 +35,7 @@ int close(int fd);
#include "driver.h"
#include "eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "driver_ndis.h"
int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
@@ -781,20 +782,7 @@ static int wpa_driver_ndis_scan(void *priv,
static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
{
- const u8 *end, *pos;
-
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
+ return get_ie((const u8 *) (res + 1), res->ie_len, ie);
}
@@ -1233,12 +1221,16 @@ static int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv)
}
-static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
- const u8 *pmkid)
+static int wpa_driver_ndis_add_pmkid(void *priv,
+ struct wpa_pmkid_params *params)
{
struct wpa_driver_ndis_data *drv = priv;
struct ndis_pmkid_entry *entry, *prev;
+ const u8 *bssid = params->bssid;
+ const u8 *pmkid = params->pmkid;
+ if (!bssid || !pmkid)
+ return -1;
if (drv->no_of_pmkid == 0)
return 0;
@@ -1274,12 +1266,16 @@ static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
}
-static int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid,
- const u8 *pmkid)
+static int wpa_driver_ndis_remove_pmkid(void *priv,
+ struct wpa_pmkid_params *params)
{
struct wpa_driver_ndis_data *drv = priv;
struct ndis_pmkid_entry *entry, *prev;
+ const u8 *bssid = params->bssid;
+ const u8 *pmkid = params->pmkid;
+ if (!bssid || !pmkid)
+ return -1;
if (drv->no_of_pmkid == 0)
return 0;
diff --git a/contrib/wpa/src/drivers/driver_nl80211.h b/contrib/wpa/src/drivers/driver_nl80211.h
index 5c21e0f..1e7fe7a 100644
--- a/contrib/wpa/src/drivers/driver_nl80211.h
+++ b/contrib/wpa/src/drivers/driver_nl80211.h
@@ -25,6 +25,7 @@
#endif /* CONFIG_LIBNL20 */
struct nl80211_global {
+ void *ctx;
struct dl_list interfaces;
int if_add_ifindex;
u64 if_add_wdevid;
@@ -59,11 +60,13 @@ struct i802_bss {
char brname[IFNAMSIZ];
unsigned int beacon_set:1;
unsigned int added_if_into_bridge:1;
+ unsigned int already_in_bridge:1;
unsigned int added_bridge:1;
unsigned int in_deinit:1;
unsigned int wdev_id_set:1;
unsigned int added_if:1;
unsigned int static_ap:1;
+ unsigned int use_nl_connect:1;
u8 addr[ETH_ALEN];
@@ -72,11 +75,12 @@ struct i802_bss {
int if_dynamic;
void *ctx;
- struct nl_handle *nl_preq, *nl_mgmt;
+ struct nl_handle *nl_preq, *nl_mgmt, *nl_connect;
struct nl_cb *nl_cb;
struct nl80211_wiphy_data *wiphy_data;
struct dl_list wiphy_list;
+ u8 rand_addr[ETH_ALEN];
};
struct wpa_driver_nl80211_data {
@@ -84,6 +88,7 @@ struct wpa_driver_nl80211_data {
struct dl_list list;
struct dl_list wiphy_list;
char phyname[32];
+ unsigned int wiphy_idx;
u8 perm_addr[ETH_ALEN];
void *ctx;
int ifindex;
@@ -94,6 +99,13 @@ struct wpa_driver_nl80211_data {
struct wpa_driver_capa capa;
u8 *extended_capa, *extended_capa_mask;
unsigned int extended_capa_len;
+ struct drv_nl80211_ext_capa {
+ enum nl80211_iftype iftype;
+ u8 *ext_capa, *ext_capa_mask;
+ unsigned int ext_capa_len;
+ } iface_ext_capa[NL80211_IFTYPE_MAX];
+ unsigned int num_iface_ext_capa;
+
int has_capability;
int operstate;
@@ -148,9 +160,20 @@ struct wpa_driver_nl80211_data {
unsigned int setband_vendor_cmd_avail:1;
unsigned int get_pref_freq_list:1;
unsigned int set_prob_oper_freq:1;
-
+ unsigned int scan_vendor_cmd_avail:1;
+ unsigned int connect_reassoc:1;
+ unsigned int set_wifi_conf_vendor_cmd_avail:1;
+ unsigned int he_capab_vendor_cmd_avail:1;
+ unsigned int fetch_bss_trans_status:1;
+ unsigned int roam_vendor_cmd_avail:1;
+ unsigned int get_supported_akm_suites_avail:1;
+
+ u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
+#define MAX_SEND_ACTION_COOKIES 20
+ u64 send_action_cookies[MAX_SEND_ACTION_COOKIES];
+ unsigned int num_send_action_cookies;
unsigned int last_mgmt_freq;
@@ -166,7 +189,10 @@ struct wpa_driver_nl80211_data {
struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
int default_if_indices[16];
+ /* the AP/AP_VLAN iface that is in this bridge */
+ int default_if_indices_reason[16];
int *if_indices;
+ int *if_indices_reason;
int num_if_indices;
/* From failed authentication command */
@@ -182,6 +208,15 @@ struct wpa_driver_nl80211_data {
int auth_wep_tx_keyidx;
int auth_local_state_change;
int auth_p2p;
+
+ /*
+ * Tells whether the last scan issued from wpa_supplicant was a normal
+ * scan (NL80211_CMD_TRIGGER_SCAN) or a vendor scan
+ * (NL80211_CMD_VENDOR). 0 if no pending scan request.
+ */
+ int last_scan_cmd;
+
+ struct he_capabilities he_capab;
};
struct nl_msg;
@@ -202,6 +237,7 @@ int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
void *arg, int use_existing);
void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx);
unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv);
+int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid);
enum chan_width convert2width(int width);
void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv);
struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
@@ -218,7 +254,8 @@ int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
enum nl80211_iftype nlmode);
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
- int local_state_change);
+ int local_state_change,
+ struct nl_handle *nl_connect);
int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
@@ -228,11 +265,14 @@ int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv);
struct hostapd_hw_modes *
-nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags);
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
+ u8 *dfs_domain);
int process_global_event(struct nl_msg *msg, void *arg);
int process_bss_event(struct nl_msg *msg, void *arg);
+const char * nl80211_iftype_str(enum nl80211_iftype mode);
+
#ifdef ANDROID
int android_nl_socket_set_nonblocking(struct nl_handle *handle);
int android_pno_start(struct i802_bss *bss,
@@ -254,24 +294,17 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
/* driver_nl80211_scan.c */
-struct nl80211_bss_info_arg {
- struct wpa_driver_nl80211_data *drv;
- struct wpa_scan_results *res;
- unsigned int assoc_freq;
- unsigned int ibss_freq;
- u8 assoc_bssid[ETH_ALEN];
-};
-
-int bss_info_handler(struct nl_msg *msg, void *arg);
void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
int wpa_driver_nl80211_scan(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int wpa_driver_nl80211_sched_scan(void *priv,
- struct wpa_driver_scan_params *params,
- u32 interval);
+ struct wpa_driver_scan_params *params);
int wpa_driver_nl80211_stop_sched_scan(void *priv);
struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
-const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie);
+int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie);
+int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params);
+int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len);
#endif /* DRIVER_NL80211_H */
diff --git a/contrib/wpa/src/drivers/driver_nl80211_capa.c b/contrib/wpa/src/drivers/driver_nl80211_capa.c
index 4cf3123..37eeb5e 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_capa.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_capa.c
@@ -12,8 +12,8 @@
#include <netlink/genl/genl.h>
#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_common.h"
#include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h"
#include "driver_nl80211.h"
@@ -66,7 +66,6 @@ struct wiphy_info_data {
unsigned int device_ap_sme:1;
unsigned int poll_command_supported:1;
unsigned int data_tx_status:1;
- unsigned int monitor_supported:1;
unsigned int auth_supported:1;
unsigned int connect_supported:1;
unsigned int p2p_go_supported:1;
@@ -129,9 +128,6 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
case NL80211_IFTYPE_P2P_CLIENT:
info->p2p_client_supported = 1;
break;
- case NL80211_IFTYPE_MONITOR:
- info->monitor_supported = 1;
- break;
}
}
}
@@ -270,40 +266,40 @@ static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
c >> 24, (c >> 16) & 0xff,
(c >> 8) & 0xff, c & 0xff);
switch (c) {
- case WLAN_CIPHER_SUITE_CCMP_256:
+ case RSN_CIPHER_SUITE_CCMP_256:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
break;
- case WLAN_CIPHER_SUITE_GCMP_256:
+ case RSN_CIPHER_SUITE_GCMP_256:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
break;
- case WLAN_CIPHER_SUITE_CCMP:
+ case RSN_CIPHER_SUITE_CCMP:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
break;
- case WLAN_CIPHER_SUITE_GCMP:
+ case RSN_CIPHER_SUITE_GCMP:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
break;
- case WLAN_CIPHER_SUITE_TKIP:
+ case RSN_CIPHER_SUITE_TKIP:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
break;
- case WLAN_CIPHER_SUITE_WEP104:
+ case RSN_CIPHER_SUITE_WEP104:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
break;
- case WLAN_CIPHER_SUITE_WEP40:
+ case RSN_CIPHER_SUITE_WEP40:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
+ case RSN_CIPHER_SUITE_AES_128_CMAC:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case RSN_CIPHER_SUITE_BIP_GMAC_128:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ case RSN_CIPHER_SUITE_BIP_GMAC_256:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
break;
- case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ case RSN_CIPHER_SUITE_BIP_CMAC_256:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
break;
- case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
+ case RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
break;
}
@@ -352,13 +348,91 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
struct nlattr *tb)
{
struct wpa_driver_capa *capa = info->capa;
+ u8 *ext_features;
+ int len;
if (tb == NULL)
return;
- if (ext_feature_isset(nla_data(tb), nla_len(tb),
- NL80211_EXT_FEATURE_VHT_IBSS))
+ ext_features = nla_data(tb);
+ len = nla_len(tb);
+
+ if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_VHT_IBSS))
capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS;
+
+ if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_RRM))
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_RRM;
+
+ if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_FILS_STA))
+ capa->flags |= WPA_DRIVER_FLAGS_SUPPORT_FILS;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_HT))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_HT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_VHT))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SET_SCAN_DWELL))
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SCAN_START_TIME) &&
+ ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BSS_PARENT_TSF) &&
+ ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SET_SCAN_DWELL))
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
+ capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
+ capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI))
+ capa->flags |= WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD))
+ capa->flags |= WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK))
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MFP_OPTIONAL))
+ capa->flags |= WPA_DRIVER_FLAGS_MFP_OPTIONAL;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_DFS_OFFLOAD))
+ capa->flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
+
+#ifdef CONFIG_MBO
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME) &&
+ ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP) &&
+ ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE) &&
+ ext_feature_isset(
+ ext_features, len,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
+ capa->flags |= WPA_DRIVER_FLAGS_OCE_STA;
+#endif /* CONFIG_MBO */
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
+ capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER;
}
@@ -428,6 +502,9 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info,
if (flags & NL80211_FEATURE_HT_IBSS)
capa->flags |= WPA_DRIVER_FLAGS_HT_IBSS;
+
+ if (flags & NL80211_FEATURE_FULL_AP_CLIENT_STATE)
+ capa->flags |= WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
}
@@ -476,6 +553,73 @@ static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
}
+static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb)
+{
+ int rem = 0, i;
+ struct nlattr *tb1[NL80211_ATTR_MAX + 1], *attr;
+
+ if (!tb || drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
+ return;
+
+ nla_for_each_nested(attr, tb, rem) {
+ unsigned int len;
+ struct drv_nl80211_ext_capa *capa;
+
+ nla_parse(tb1, NL80211_ATTR_MAX, nla_data(attr),
+ nla_len(attr), NULL);
+
+ if (!tb1[NL80211_ATTR_IFTYPE] ||
+ !tb1[NL80211_ATTR_EXT_CAPA] ||
+ !tb1[NL80211_ATTR_EXT_CAPA_MASK])
+ continue;
+
+ capa = &drv->iface_ext_capa[drv->num_iface_ext_capa];
+ capa->iftype = nla_get_u32(tb1[NL80211_ATTR_IFTYPE]);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Driver-advertised extended capabilities for interface type %s",
+ nl80211_iftype_str(capa->iftype));
+
+ len = nla_len(tb1[NL80211_ATTR_EXT_CAPA]);
+ capa->ext_capa = os_memdup(nla_data(tb1[NL80211_ATTR_EXT_CAPA]),
+ len);
+ if (!capa->ext_capa)
+ goto err;
+
+ capa->ext_capa_len = len;
+ wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities",
+ capa->ext_capa, capa->ext_capa_len);
+
+ len = nla_len(tb1[NL80211_ATTR_EXT_CAPA_MASK]);
+ capa->ext_capa_mask =
+ os_memdup(nla_data(tb1[NL80211_ATTR_EXT_CAPA_MASK]),
+ len);
+ if (!capa->ext_capa_mask)
+ goto err;
+
+ wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities mask",
+ capa->ext_capa_mask, capa->ext_capa_len);
+
+ drv->num_iface_ext_capa++;
+ if (drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
+ break;
+ }
+
+ return;
+
+err:
+ /* Cleanup allocated memory on error */
+ for (i = 0; i < NL80211_IFTYPE_MAX; i++) {
+ os_free(drv->iface_ext_capa[i].ext_capa);
+ drv->iface_ext_capa[i].ext_capa = NULL;
+ os_free(drv->iface_ext_capa[i].ext_capa_mask);
+ drv->iface_ext_capa[i].ext_capa_mask = NULL;
+ drv->iface_ext_capa[i].ext_capa_len = 0;
+ }
+ drv->num_iface_ext_capa = 0;
+}
+
+
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -487,6 +631,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb[NL80211_ATTR_WIPHY])
+ drv->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
if (tb[NL80211_ATTR_WIPHY_NAME])
os_strlcpy(drv->phyname,
nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
@@ -499,6 +646,19 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
capa->max_sched_scan_ssids =
nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+ if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS] &&
+ tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL] &&
+ tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]) {
+ capa->max_sched_scan_plans =
+ nla_get_u32(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS]);
+
+ capa->max_sched_scan_plan_interval =
+ nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL]);
+
+ capa->max_sched_scan_plan_iterations =
+ nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]);
+ }
+
if (tb[NL80211_ATTR_MAX_MATCH_SETS])
capa->max_match_sets =
nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
@@ -550,6 +710,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
nla_len(tb[NL80211_ATTR_EXT_CAPA]));
drv->extended_capa_len =
nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+ wpa_hexdump(MSG_DEBUG,
+ "nl80211: Driver-advertised extended capabilities (default)",
+ drv->extended_capa, drv->extended_capa_len);
}
drv->extended_capa_mask =
os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
@@ -557,6 +720,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
os_memcpy(drv->extended_capa_mask,
nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
+ wpa_hexdump(MSG_DEBUG,
+ "nl80211: Driver-advertised extended capabilities mask (default)",
+ drv->extended_capa_mask,
+ drv->extended_capa_len);
} else {
os_free(drv->extended_capa);
drv->extended_capa = NULL;
@@ -564,6 +731,8 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
}
}
+ wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]);
+
if (tb[NL80211_ATTR_VENDOR_DATA]) {
struct nlattr *nl;
int rem;
@@ -580,6 +749,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_TEST:
drv->vendor_cmd_test_avail = 1;
break;
+#ifdef CONFIG_DRIVER_NL80211_QCA
case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
drv->roaming_vendor_cmd_avail = 1;
break;
@@ -602,6 +772,25 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_SETBAND:
drv->setband_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN:
+ drv->scan_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
+ drv->set_wifi_conf_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES:
+ drv->he_capab_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS:
+ drv->fetch_bss_trans_status = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_ROAM:
+ drv->roam_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS:
+ drv->get_supported_akm_suites_avail = 1;
+ break;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
@@ -633,6 +822,13 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
capa->max_stations =
nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
+ if (tb[NL80211_ATTR_MAX_CSA_COUNTERS])
+ capa->max_csa_counters =
+ nla_get_u8(tb[NL80211_ATTR_MAX_CSA_COUNTERS]);
+
+ if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG])
+ capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY;
+
return NL_SKIP;
}
@@ -689,8 +885,6 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
if (!drv->capa.max_remain_on_chan)
drv->capa.max_remain_on_chan = 5000;
- if (info->channel_switch_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
drv->capa.wmm_ac_supported = info->wmm_ac_supported;
drv->capa.mac_addr_rand_sched_scan_supported =
@@ -698,10 +892,24 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
drv->capa.mac_addr_rand_scan_supported =
info->mac_addr_rand_scan_supported;
+ if (info->channel_switch_supported) {
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
+ if (!drv->capa.max_csa_counters)
+ drv->capa.max_csa_counters = 1;
+ }
+
+ if (!drv->capa.max_sched_scan_plans) {
+ drv->capa.max_sched_scan_plans = 1;
+ drv->capa.max_sched_scan_plan_interval = UINT32_MAX;
+ drv->capa.max_sched_scan_plan_iterations = 0;
+ }
+
return 0;
}
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
static int dfs_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -754,6 +962,220 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
}
+static unsigned int get_akm_suites_info(struct nlattr *tb)
+{
+ int i, num;
+ unsigned int key_mgmt = 0;
+ u32 *akms;
+
+ if (!tb)
+ return 0;
+
+ num = nla_len(tb) / sizeof(u32);
+ akms = nla_data(tb);
+ for (i = 0; i < num; i++) {
+ u32 a = akms[i];
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Supported AKM %02x-%02x-%02x:%u",
+ a >> 24, (a >> 16) & 0xff,
+ (a >> 8) & 0xff, a & 0xff);
+ switch (a) {
+ case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
+ break;
+ case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_PSK:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+ break;
+ case RSN_AUTH_KEY_MGMT_OWE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OWE;
+ break;
+ case RSN_AUTH_KEY_MGMT_DPP:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+ break;
+ case RSN_AUTH_KEY_MGMT_FILS_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_FILS_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_SAE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SAE;
+ break;
+ }
+ }
+
+ return key_mgmt;
+}
+
+
+static int get_akm_suites_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ unsigned int *key_mgmt = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ struct nlattr *tb_data[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb_data, NL80211_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ *key_mgmt =
+ get_akm_suites_info(tb_data[NL80211_ATTR_AKM_SUITES]);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int qca_nl80211_get_akm_suites(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ unsigned int key_mgmt = 0;
+ int ret;
+
+ if (!drv->get_supported_akm_suites_avail)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, get_akm_suites_handler, &key_mgmt);
+ if (!ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Replace capa.key_mgmt based on driver advertised capabilities: 0x%x",
+ key_mgmt);
+ drv->capa.key_mgmt = key_mgmt;
+ }
+
+ return ret;
+}
+
+
+static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct he_capabilities *he_capab = arg;
+ struct nlattr *nl_vend;
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX + 1];
+ size_t len;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_VENDOR_DATA])
+ return NL_SKIP;
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]) {
+ u8 he_supported;
+
+ he_supported = nla_get_u8(
+ tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]);
+ wpa_printf(MSG_DEBUG, "nl80211: HE capabilities supported: %u",
+ he_supported);
+ he_capab->he_supported = he_supported;
+ if (!he_supported)
+ return NL_SKIP;
+ }
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]) {
+ len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]);
+
+ if (len > sizeof(he_capab->phy_cap))
+ len = sizeof(he_capab->phy_cap);
+ os_memcpy(he_capab->phy_cap,
+ nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]),
+ len);
+ }
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB])
+ he_capab->mac_cap =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS])
+ he_capab->mcs =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS])
+ he_capab->ppet.numss_m1 =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK])
+ he_capab->ppet.ru_count =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]) {
+ len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]);
+
+ if (len > sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0))
+ len = sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0);
+ os_memcpy(he_capab->ppet.ppet16_ppet8_ru3_ru0,
+ nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]),
+ len);
+ }
+
+ return NL_SKIP;
+}
+
+
+static void qca_nl80211_check_he_capab(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ if (!drv->he_capab_vendor_cmd_avail)
+ return;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, qca_nl80211_he_capab_handler,
+ &drv->he_capab);
+ if (!ret && drv->he_capab.he_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_HE_CAPABILITIES;
+}
+
+
struct features_info {
u8 *flags;
size_t flags_len;
@@ -780,8 +1202,12 @@ static int features_info_handler(struct nl_msg *msg, void *arg)
attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
if (attr) {
- info->flags = nla_data(attr);
- info->flags_len = nla_len(attr);
+ int len = nla_len(attr);
+ info->flags = os_malloc(len);
+ if (info->flags != NULL) {
+ os_memcpy(info->flags, nla_data(attr), len);
+ info->flags_len = len;
+ }
}
attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA];
if (attr)
@@ -840,8 +1266,23 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info))
drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
+
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS,
+ &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_OCE_STA, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_OCE_STA;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_OCE_AP, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_OCE_AP;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_OCE_STA_CFON;
+ os_free(info.flags);
}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
{
@@ -858,7 +1299,26 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
- WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 |
+ WPA_DRIVER_CAPA_KEY_MGMT_OWE |
+ WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
+ WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 |
+ WPA_DRIVER_CAPA_KEY_MGMT_SAE;
+ else if (drv->capa.flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
+ WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ /* Override drv->capa.key_mgmt based on driver advertised capability
+ * constraints, if available. */
+ qca_nl80211_get_akm_suites(drv);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
@@ -898,21 +1358,8 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
* If poll command and tx status are supported, mac80211 is new enough
* to have everything we need to not need monitor interfaces.
*/
- drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
-
- if (drv->device_ap_sme && drv->use_monitor) {
- /*
- * Non-mac80211 drivers may not support monitor interface.
- * Make sure we do not get stuck with incorrect capability here
- * by explicitly testing this.
- */
- if (!info.monitor_supported) {
- wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
- "with device_ap_sme since no monitor mode "
- "support detected");
- drv->use_monitor = 0;
- }
- }
+ drv->use_monitor = !info.device_ap_sme &&
+ (!info.poll_command_supported || !info.data_tx_status);
/*
* If we aren't going to use monitor interfaces, but the
@@ -922,8 +1369,22 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
if (!drv->use_monitor && !info.data_tx_status)
drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
- qca_nl80211_check_dfs_capa(drv);
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (!(info.capa->flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD))
+ qca_nl80211_check_dfs_capa(drv);
qca_nl80211_get_features(drv);
+ qca_nl80211_check_he_capab(drv);
+
+ /*
+ * To enable offchannel simultaneous support in wpa_supplicant, the
+ * underlying driver needs to support the same along with offchannel TX.
+ * Offchannel TX support is needed since remain_on_channel and
+ * action_tx use some common data structures and hence cannot be
+ * scheduled simultaneously.
+ */
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
return 0;
}
@@ -933,6 +1394,8 @@ struct phy_info_arg {
u16 *num_modes;
struct hostapd_hw_modes *modes;
int last_mode, last_chan_idx;
+ int failed;
+ u8 dfs_domain;
};
static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
@@ -979,6 +1442,7 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
u8 channel;
chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
chan->flag = 0;
+ chan->allowed_bw = ~0;
chan->dfs_cac_ms = 0;
if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
chan->chan = channel;
@@ -994,6 +1458,19 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT])
chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_10MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_10;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_20;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_40P;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_40M;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_80;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_160;
+
if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
enum nl80211_dfs_state state =
nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
@@ -1028,6 +1505,12 @@ static int phy_info_freqs(struct phy_info_arg *phy_info,
[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
[NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_NO_10MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_20MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_HT40_PLUS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_HT40_MINUS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_80MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_160MHZ] = { .type = NLA_FLAG },
};
int new_channels = 0;
struct hostapd_channel_data *channel;
@@ -1050,7 +1533,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info,
mode->num_channels + new_channels,
sizeof(struct hostapd_channel_data));
if (!channel)
- return NL_SKIP;
+ return NL_STOP;
mode->channels = channel;
mode->num_channels += new_channels;
@@ -1096,7 +1579,7 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
mode->rates = os_calloc(mode->num_rates, sizeof(int));
if (!mode->rates)
- return NL_SKIP;
+ return NL_STOP;
idx = 0;
@@ -1125,8 +1608,10 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
mode = os_realloc_array(phy_info->modes,
*phy_info->num_modes + 1,
sizeof(*mode));
- if (!mode)
- return NL_SKIP;
+ if (!mode) {
+ phy_info->failed = 1;
+ return NL_STOP;
+ }
phy_info->modes = mode;
mode = &phy_info->modes[*(phy_info->num_modes)];
@@ -1162,11 +1647,12 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
- if (ret != NL_OK)
- return ret;
- ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
- if (ret != NL_OK)
+ if (ret == NL_OK)
+ ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+ if (ret != NL_OK) {
+ phy_info->failed = 1;
return ret;
+ }
return NL_OK;
}
@@ -1249,14 +1735,13 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
mode11g = &modes[mode11g_idx];
mode->num_channels = mode11g->num_channels;
- mode->channels = os_malloc(mode11g->num_channels *
+ mode->channels = os_memdup(mode11g->channels,
+ mode11g->num_channels *
sizeof(struct hostapd_channel_data));
if (mode->channels == NULL) {
(*num_modes)--;
return modes; /* Could not add 802.11b mode */
}
- os_memcpy(mode->channels, mode11g->channels,
- mode11g->num_channels * sizeof(struct hostapd_channel_data));
mode->num_rates = 0;
mode->rates = os_malloc(4 * sizeof(int));
@@ -1381,7 +1866,7 @@ static void nl80211_reg_rule_sec(struct nlattr *tb[],
static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
- int end)
+ int end, int max_bw)
{
int c;
@@ -1398,6 +1883,32 @@ static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
if (chan->freq - 70 >= start && chan->freq + 10 <= end)
chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+
+ if (max_bw >= 160) {
+ if (chan->freq - 10 >= start && chan->freq + 150 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_10_150;
+
+ if (chan->freq - 30 >= start && chan->freq + 130 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_30_130;
+
+ if (chan->freq - 50 >= start && chan->freq + 110 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_50_110;
+
+ if (chan->freq - 70 >= start && chan->freq + 90 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_70_90;
+
+ if (chan->freq - 90 >= start && chan->freq + 70 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_90_70;
+
+ if (chan->freq - 110 >= start && chan->freq + 50 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_110_50;
+
+ if (chan->freq - 130 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_130_30;
+
+ if (chan->freq - 150 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_150_10;
+ }
}
}
@@ -1428,11 +1939,25 @@ static void nl80211_reg_rule_vht(struct nlattr *tb[],
if (!results->modes[m].vht_capab)
continue;
- nl80211_set_vht_mode(&results->modes[m], start, end);
+ nl80211_set_vht_mode(&results->modes[m], start, end, max_bw);
}
}
+static void nl80211_set_dfs_domain(enum nl80211_dfs_regions region,
+ u8 *dfs_domain)
+{
+ if (region == NL80211_DFS_FCC)
+ *dfs_domain = HOSTAPD_DFS_REGION_FCC;
+ else if (region == NL80211_DFS_ETSI)
+ *dfs_domain = HOSTAPD_DFS_REGION_ETSI;
+ else if (region == NL80211_DFS_JP)
+ *dfs_domain = HOSTAPD_DFS_REGION_JP;
+ else
+ *dfs_domain = 0;
+}
+
+
static const char * dfs_domain_name(enum nl80211_dfs_regions region)
{
switch (region) {
@@ -1479,6 +2004,7 @@ static int nl80211_get_reg(struct nl_msg *msg, void *arg)
if (tb_msg[NL80211_ATTR_DFS_REGION]) {
enum nl80211_dfs_regions dfs_domain;
dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
+ nl80211_set_dfs_domain(dfs_domain, &results->dfs_domain);
wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
(char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
dfs_domain_name(dfs_domain));
@@ -1550,12 +2076,75 @@ static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
return -ENOMEM;
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY) {
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
}
+static const char * modestr(enum hostapd_hw_mode mode)
+{
+ switch (mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ return "802.11b";
+ case HOSTAPD_MODE_IEEE80211G:
+ return "802.11g";
+ case HOSTAPD_MODE_IEEE80211A:
+ return "802.11a";
+ case HOSTAPD_MODE_IEEE80211AD:
+ return "802.11ad";
+ default:
+ return "?";
+ }
+}
+
+
+static void nl80211_dump_chan_list(struct hostapd_hw_modes *modes,
+ u16 num_modes)
+{
+ int i;
+
+ if (!modes)
+ return;
+
+ for (i = 0; i < num_modes; i++) {
+ struct hostapd_hw_modes *mode = &modes[i];
+ char str[200];
+ char *pos = str;
+ char *end = pos + sizeof(str);
+ int j, res;
+
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan = &mode->channels[j];
+
+ res = os_snprintf(pos, end - pos, " %d%s%s%s",
+ chan->freq,
+ (chan->flag & HOSTAPD_CHAN_DISABLED) ?
+ "[DISABLED]" : "",
+ (chan->flag & HOSTAPD_CHAN_NO_IR) ?
+ "[NO_IR]" : "",
+ (chan->flag & HOSTAPD_CHAN_RADAR) ?
+ "[RADAR]" : "");
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+
+ *pos = '\0';
+ wpa_printf(MSG_DEBUG, "nl80211: Mode IEEE %s:%s",
+ modestr(mode->mode), str);
+ }
+}
+
+
struct hostapd_hw_modes *
-nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
+ u8 *dfs_domain)
{
u32 feat;
struct i802_bss *bss = priv;
@@ -1566,10 +2155,13 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
.num_modes = num_modes,
.modes = NULL,
.last_mode = -1,
+ .failed = 0,
+ .dfs_domain = 0,
};
*num_modes = 0;
*flags = 0;
+ *dfs_domain = 0;
feat = get_nl80211_protocol_features(drv);
if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
@@ -1581,9 +2173,27 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
}
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ struct hostapd_hw_modes *modes;
+
nl80211_set_regulatory_flags(drv, &result);
- return wpa_driver_nl80211_postprocess_modes(result.modes,
- num_modes);
+ if (result.failed) {
+ int i;
+
+ for (i = 0; result.modes && i < *num_modes; i++) {
+ os_free(result.modes[i].channels);
+ os_free(result.modes[i].rates);
+ }
+ os_free(result.modes);
+ *num_modes = 0;
+ return NULL;
+ }
+
+ *dfs_domain = result.dfs_domain;
+
+ modes = wpa_driver_nl80211_postprocess_modes(result.modes,
+ num_modes);
+ nl80211_dump_chan_list(modes, *num_modes);
+ return modes;
}
return NULL;
diff --git a/contrib/wpa/src/drivers/driver_nl80211_event.c b/contrib/wpa/src/drivers/driver_nl80211_event.c
index 7b0f721..ee7b4da 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_event.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_event.c
@@ -1,6 +1,6 @@
/*
* Driver interaction with Linux nl80211/cfg80211 - Event processing
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
* Copyright (c) 2009-2010, Atheros Communications
*
@@ -131,6 +131,11 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
C2S(NL80211_CMD_SET_QOS_MAP)
C2S(NL80211_CMD_ADD_TX_TS)
C2S(NL80211_CMD_DEL_TX_TS)
+ C2S(NL80211_CMD_WIPHY_REG_CHANGE)
+ C2S(NL80211_CMD_PORT_AUTHORIZED)
+ C2S(NL80211_CMD_EXTERNAL_AUTH)
+ C2S(NL80211_CMD_STA_OPMODE_CHANGED)
+ C2S(NL80211_CMD_CONTROL_PORT_FRAME)
default:
return "NL80211_CMD_UNKNOWN";
}
@@ -201,11 +206,13 @@ static void nl80211_parse_wmm_params(struct nlattr *wmm_attr,
static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
- const u8 *frame, size_t len, struct nlattr *wmm)
+ const u8 *frame, size_t len, struct nlattr *wmm,
+ struct nlattr *req_ie)
{
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
u16 status;
+ int ssid_len;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
drv->force_connect_cmd) {
@@ -247,13 +254,31 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
os_memset(&event, 0, sizeof(event));
+ event.assoc_info.resp_frame = frame;
+ event.assoc_info.resp_frame_len = len;
if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
event.assoc_info.resp_ies_len =
len - 24 - sizeof(mgmt->u.assoc_resp);
}
+ if (req_ie) {
+ event.assoc_info.req_ies = nla_data(req_ie);
+ event.assoc_info.req_ies_len = nla_len(req_ie);
+ }
+
+ /* When this association was initiated outside of wpa_supplicant,
+ * drv->ssid needs to be set here to satisfy later checking. */
+ ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid);
+ if (ssid_len > 0) {
+ drv->ssid_len = ssid_len;
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on scan res info to '%s'",
+ wpa_ssid_txt(drv->ssid, drv->ssid_len));
+ }
+
event.assoc_info.freq = drv->assoc_freq;
+ drv->first_bss->freq = drv->assoc_freq;
nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
@@ -265,14 +290,21 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, struct nlattr *status,
struct nlattr *addr, struct nlattr *req_ie,
struct nlattr *resp_ie,
+ struct nlattr *timed_out,
+ struct nlattr *timeout_reason,
struct nlattr *authorized,
struct nlattr *key_replay_ctr,
struct nlattr *ptk_kck,
- struct nlattr *ptk_kek)
+ struct nlattr *ptk_kek,
+ struct nlattr *subnet_status,
+ struct nlattr *fils_erp_next_seq_num,
+ struct nlattr *fils_pmk,
+ struct nlattr *fils_pmkid)
{
union wpa_event_data event;
- const u8 *ssid;
+ const u8 *ssid = NULL;
u16 status_code;
+ int ssid_len;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
/*
@@ -284,6 +316,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
return;
}
+ drv->connect_reassoc = 0;
+
status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
if (cmd == NL80211_CMD_CONNECT) {
@@ -319,6 +353,28 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
event.assoc_reject.resp_ies_len = nla_len(resp_ie);
}
event.assoc_reject.status_code = status_code;
+ event.assoc_reject.timed_out = timed_out != NULL;
+ if (timed_out && timeout_reason) {
+ enum nl80211_timeout_reason reason;
+
+ reason = nla_get_u32(timeout_reason);
+ switch (reason) {
+ case NL80211_TIMEOUT_SCAN:
+ event.assoc_reject.timeout_reason = "scan";
+ break;
+ case NL80211_TIMEOUT_AUTH:
+ event.assoc_reject.timeout_reason = "auth";
+ break;
+ case NL80211_TIMEOUT_ASSOC:
+ event.assoc_reject.timeout_reason = "assoc";
+ break;
+ default:
+ break;
+ }
+ }
+ if (fils_erp_next_seq_num)
+ event.assoc_reject.fils_erp_next_seq_num =
+ nla_get_u16(fils_erp_next_seq_num);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
return;
}
@@ -334,12 +390,16 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
event.assoc_info.req_ies_len = nla_len(req_ie);
if (cmd == NL80211_CMD_ROAM) {
- ssid = nl80211_get_ie(event.assoc_info.req_ies,
- event.assoc_info.req_ies_len,
- WLAN_EID_SSID);
+ ssid = get_ie(event.assoc_info.req_ies,
+ event.assoc_info.req_ies_len,
+ WLAN_EID_SSID);
if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
drv->ssid_len = ssid[1];
os_memcpy(drv->ssid, ssid + 2, ssid[1]);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on req_ie to '%s'",
+ wpa_ssid_txt(drv->ssid,
+ drv->ssid_len));
}
}
}
@@ -349,6 +409,17 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
}
event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+ drv->first_bss->freq = drv->assoc_freq;
+
+ if ((!ssid || ssid[1] == 0 || ssid[1] > 32) &&
+ (ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) {
+ /* When this connection was initiated outside of wpa_supplicant,
+ * drv->ssid needs to be set here to satisfy later checking. */
+ drv->ssid_len = ssid_len;
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on scan res info to '%s'",
+ wpa_ssid_txt(drv->ssid, drv->ssid_len));
+ }
if (authorized && nla_get_u8(authorized)) {
event.assoc_info.authorized = 1;
@@ -367,6 +438,29 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
}
+ if (subnet_status) {
+ /*
+ * At least for now, this is only available from
+ * QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS and that
+ * attribute has the same values 0, 1, 2 as are used in the
+ * variable here, so no mapping between different values are
+ * needed.
+ */
+ event.assoc_info.subnet_status = nla_get_u8(subnet_status);
+ }
+
+ if (fils_erp_next_seq_num)
+ event.assoc_info.fils_erp_next_seq_num =
+ nla_get_u16(fils_erp_next_seq_num);
+
+ if (fils_pmk) {
+ event.assoc_info.fils_pmk = nla_data(fils_pmk);
+ event.assoc_info.fils_pmk_len = nla_len(fils_pmk);
+ }
+
+ if (fils_pmkid)
+ event.assoc_info.fils_pmkid = nla_data(fils_pmkid);
+
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
@@ -500,6 +594,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
data.ch_switch.cf2 = nla_get_u32(cf2);
bss->freq = data.ch_switch.freq;
+ drv->assoc_freq = data.ch_switch.freq;
wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
}
@@ -560,9 +655,10 @@ static void mlme_event_mgmt(struct i802_bss *bss,
rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
}
wpa_printf(MSG_DEBUG,
- "nl80211: RX frame sa=" MACSTR
+ "nl80211: RX frame da=" MACSTR " sa=" MACSTR " bssid=" MACSTR
" freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u",
- MAC2STR(mgmt->sa), rx_freq, ssi_signal, fc,
+ MAC2STR(mgmt->da), MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
+ rx_freq, ssi_signal, fc,
le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc),
(unsigned int) len);
event.rx_mgmt.frame = frame;
@@ -590,7 +686,7 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
cookie_val = nla_get_u64(cookie);
wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
- " cookie=0%llx%s (ack=%d)",
+ " cookie=0x%llx%s (ack=%d)",
(long long unsigned int) cookie_val,
cookie_val == drv->send_action_cookie ?
" (match)" : " (unknown)", ack != NULL);
@@ -639,8 +735,37 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
* Avoid issues with some roaming cases where
* disconnection event for the old AP may show up after
* we have started connection with the new AP.
+ * In case of locally generated event clear
+ * ignore_next_local_deauth as well, to avoid next local
+ * deauth event be wrongly ignored.
*/
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+ if (!os_memcmp(mgmt->sa, drv->first_bss->addr,
+ ETH_ALEN)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag");
+ drv->ignore_next_local_deauth = 0;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
+ }
+ return;
+ }
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->connect_reassoc && drv->associated &&
+ os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0 &&
+ os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0) {
+ /*
+ * Avoid issues with some roaming cases where
+ * disconnection event for the old AP may show up after
+ * we have started connection with the new AP.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore deauth/disassoc event from old AP "
+ MACSTR
+ " when already connecting with " MACSTR,
MAC2STR(bssid),
MAC2STR(drv->auth_attempt_bssid));
return;
@@ -679,13 +804,15 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
mgmt->u.disassoc.variable;
}
} else {
+ event.deauth_info.locally_generated =
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
if (drv->ignore_deauth_event) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
drv->ignore_deauth_event = 0;
+ if (event.deauth_info.locally_generated)
+ drv->ignore_next_local_deauth = 0;
return;
}
- event.deauth_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
if (drv->ignore_next_local_deauth) {
drv->ignore_next_local_deauth = 0;
if (event.deauth_info.locally_generated) {
@@ -749,7 +876,7 @@ static void mlme_event(struct i802_bss *bss,
struct nlattr *addr, struct nlattr *timed_out,
struct nlattr *freq, struct nlattr *ack,
struct nlattr *cookie, struct nlattr *sig,
- struct nlattr *wmm)
+ struct nlattr *wmm, struct nlattr *req_ie)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
const u8 *data;
@@ -783,6 +910,8 @@ static void mlme_event(struct i802_bss *bss,
MAC2STR(data + 4 + ETH_ALEN));
if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ (is_zero_ether_addr(bss->rand_addr) ||
+ os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
"for foreign address", bss->ifname);
@@ -796,7 +925,8 @@ static void mlme_event(struct i802_bss *bss,
mlme_event_auth(drv, nla_data(frame), nla_len(frame));
break;
case NL80211_CMD_ASSOCIATE:
- mlme_event_assoc(drv, nla_data(frame), nla_len(frame), wmm);
+ mlme_event_assoc(drv, nla_data(frame), nla_len(frame), wmm,
+ req_ie);
break;
case NL80211_CMD_DEAUTHENTICATE:
mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
@@ -868,6 +998,7 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
struct nlattr *tb[])
{
unsigned int freq;
+ union wpa_event_data event;
if (tb[NL80211_ATTR_MAC] == NULL) {
wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
@@ -887,7 +1018,10 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
drv->first_bss->freq = freq;
}
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_info.freq = freq;
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
@@ -968,7 +1102,7 @@ static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
- struct nlattr *tb[])
+ struct nlattr *tb[], int external_scan)
{
union wpa_event_data event;
struct nlattr *nl;
@@ -978,7 +1112,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
int freqs[MAX_REPORT_FREQS];
int num_freqs = 0;
- if (drv->scan_for_auth) {
+ if (!external_scan && drv->scan_for_auth) {
drv->scan_for_auth = 0;
wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
"cfg80211 BSS entry");
@@ -989,6 +1123,8 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
os_memset(&event, 0, sizeof(event));
info = &event.scan_info;
info->aborted = aborted;
+ info->external_scan = external_scan;
+ info->nl_scan_event = 1;
if (tb[NL80211_ATTR_SCAN_SSIDS]) {
nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
@@ -1004,7 +1140,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
}
}
if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
- char msg[200], *pos, *end;
+ char msg[300], *pos, *end;
int res;
pos = msg;
@@ -1027,6 +1163,16 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
msg);
}
+
+ if (tb[NL80211_ATTR_SCAN_START_TIME_TSF] &&
+ tb[NL80211_ATTR_SCAN_START_TIME_TSF_BSSID]) {
+ info->scan_start_tsf =
+ nla_get_u64(tb[NL80211_ATTR_SCAN_START_TIME_TSF]);
+ os_memcpy(info->scan_start_tsf_bssid,
+ nla_data(tb[NL80211_ATTR_SCAN_START_TIME_TSF_BSSID]),
+ ETH_ALEN);
+ }
+
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
}
@@ -1039,6 +1185,10 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_BEACON_LOSS_EVENT] = { .type = NLA_FLAG },
};
struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
enum nl80211_cqm_rssi_threshold_event event;
@@ -1060,12 +1210,39 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
return;
os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
ETH_ALEN);
+ ed.low_ack.num_packets =
+ nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]);
+ wpa_printf(MSG_DEBUG, "nl80211: Packet loss event for " MACSTR
+ " (num_packets %u)",
+ MAC2STR(ed.low_ack.addr), ed.low_ack.num_packets);
wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
return;
}
- if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
+ if (cqm[NL80211_ATTR_CQM_BEACON_LOSS_EVENT]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Beacon loss event");
+ wpa_supplicant_event(drv->ctx, EVENT_BEACON_LOSS, NULL);
+ return;
+ }
+
+ if (cqm[NL80211_ATTR_CQM_TXE_RATE] &&
+ cqm[NL80211_ATTR_CQM_TXE_PKTS] &&
+ cqm[NL80211_ATTR_CQM_TXE_INTVL] &&
+ cqm[NL80211_ATTR_MAC]) {
+ wpa_printf(MSG_DEBUG, "nl80211: CQM TXE event for " MACSTR
+ " (rate: %u pkts: %u interval: %u)",
+ MAC2STR((u8 *) nla_data(cqm[NL80211_ATTR_MAC])),
+ nla_get_u32(cqm[NL80211_ATTR_CQM_TXE_RATE]),
+ nla_get_u32(cqm[NL80211_ATTR_CQM_TXE_PKTS]),
+ nla_get_u32(cqm[NL80211_ATTR_CQM_TXE_INTVL]));
return;
+ }
+
+ if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not a CQM RSSI threshold event");
+ return;
+ }
event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
@@ -1076,8 +1253,12 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
"event: RSSI low");
ed.signal_change.above_threshold = 0;
- } else
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Unknown CQM RSSI threshold event: %d",
+ event);
return;
+ }
res = nl80211_get_link_signal(drv, &sig);
if (res == 0) {
@@ -1109,7 +1290,7 @@ static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv,
return;
addr = nla_data(tb[NL80211_ATTR_MAC]);
- wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR,
+ wpa_printf(MSG_DEBUG, "nl80211: New peer candidate " MACSTR,
MAC2STR(addr));
os_memset(&data, 0, sizeof(data));
@@ -1154,6 +1335,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+ struct i802_bss *bss,
struct nlattr **tb)
{
u8 *addr;
@@ -1166,7 +1348,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
MAC2STR(addr));
if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
- drv_event_disassoc(drv->ctx, addr);
+ drv_event_disassoc(bss->ctx, addr);
return;
}
@@ -1175,7 +1357,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
os_memset(&data, 0, sizeof(data));
os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
- wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+ wpa_supplicant_event(bss->ctx, EVENT_IBSS_PEER_LOST, &data);
}
@@ -1256,16 +1438,23 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
union wpa_event_data data;
+ const u8 *addr;
+ u64 cookie = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
-
- if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ if (!addr)
+ return;
+ if (tb[NL80211_ATTR_COOKIE])
+ cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+ wpa_printf(MSG_DEBUG, "nl80211: Probe client event (addr=" MACSTR
+ " ack=%d cookie=%llu)", MAC2STR(addr),
+ tb[NL80211_ATTR_ACK] != NULL,
+ (long long unsigned int) cookie);
+ if (!tb[NL80211_ATTR_ACK])
return;
os_memset(&data, 0, sizeof(data));
- os_memcpy(data.client_poll.addr,
- nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
+ os_memcpy(data.client_poll.addr, addr, ETH_ALEN);
wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
}
@@ -1418,6 +1607,13 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
case NL80211_RADAR_NOP_FINISHED:
wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
break;
+ case NL80211_RADAR_PRE_CAC_EXPIRED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_PRE_CAC_EXPIRED,
+ &data);
+ break;
+ case NL80211_RADAR_CAC_STARTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
"received", event_type);
@@ -1444,6 +1640,8 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
}
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
const u8 *data, size_t len)
{
@@ -1593,10 +1791,15 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
+ NULL, NULL,
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
- tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]);
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID]);
}
@@ -1686,6 +1889,165 @@ static void qca_nl80211_dfs_offload_radar_event(
}
+static void qca_nl80211_scan_trigger_event(struct wpa_driver_nl80211_data *drv,
+ u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
+ u64 cookie = 0;
+ union wpa_event_data event;
+ struct scan_info *info;
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE])
+ return;
+
+ cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
+ if (cookie != drv->vendor_scan_cookie) {
+ /* External scan trigger event, ignore */
+ return;
+ }
+
+ /* Cookie match, own scan */
+ os_memset(&event, 0, sizeof(event));
+ info = &event.scan_info;
+ info->external_scan = 0;
+ info->nl_scan_event = 0;
+
+ drv->scan_state = SCAN_STARTED;
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, &event);
+}
+
+
+static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv,
+ int aborted, struct nlattr *tb[],
+ int external_scan)
+{
+ union wpa_event_data event;
+ struct nlattr *nl;
+ int rem;
+ struct scan_info *info;
+ int freqs[MAX_REPORT_FREQS];
+ int num_freqs = 0;
+
+ os_memset(&event, 0, sizeof(event));
+ info = &event.scan_info;
+ info->aborted = aborted;
+ info->external_scan = external_scan;
+
+ if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) {
+ nla_for_each_nested(nl,
+ tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], rem) {
+ struct wpa_driver_scan_ssid *s =
+ &info->ssids[info->num_ssids];
+ s->ssid = nla_data(nl);
+ s->ssid_len = nla_len(nl);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Scan probed for SSID '%s'",
+ wpa_ssid_txt(s->ssid, s->ssid_len));
+ info->num_ssids++;
+ if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+ break;
+ }
+ }
+
+ if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
+ char msg[300], *pos, *end;
+ int res;
+
+ pos = msg;
+ end = pos + sizeof(msg);
+ *pos = '\0';
+
+ nla_for_each_nested(nl,
+ tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES],
+ rem) {
+ freqs[num_freqs] = nla_get_u32(nl);
+ res = os_snprintf(pos, end - pos, " %d",
+ freqs[num_freqs]);
+ if (!os_snprintf_error(end - pos, res))
+ pos += res;
+ num_freqs++;
+ if (num_freqs == MAX_REPORT_FREQS - 1)
+ break;
+ }
+
+ info->freqs = freqs;
+ info->num_freqs = num_freqs;
+ wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+ msg);
+ }
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+}
+
+
+static void qca_nl80211_scan_done_event(struct wpa_driver_nl80211_data *drv,
+ u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
+ u64 cookie = 0;
+ enum scan_status status;
+ int external_scan;
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE])
+ return;
+
+ status = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS]);
+ if (status >= VENDOR_SCAN_STATUS_MAX)
+ return; /* invalid status */
+
+ cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
+ if (cookie != drv->vendor_scan_cookie) {
+ /* Event from an external scan, get scan results */
+ external_scan = 1;
+ } else {
+ external_scan = 0;
+ if (status == VENDOR_SCAN_STATUS_NEW_RESULTS)
+ drv->scan_state = SCAN_COMPLETED;
+ else
+ drv->scan_state = SCAN_ABORTED;
+
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ drv->vendor_scan_cookie = 0;
+ drv->last_scan_cmd = 0;
+ }
+
+ send_vendor_scan_event(drv, (status == VENDOR_SCAN_STATUS_ABORTED), tb,
+ external_scan);
+}
+
+
+static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv,
+ u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1];
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: P2P listen offload stop vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.p2p_lo_stop.reason_code =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: P2P Listen offload stop reason: %d",
+ event.p2p_lo_stop.reason_code);
+ wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event);
+}
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
u32 subcmd, u8 *data, size_t len)
{
@@ -1693,6 +2055,7 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
case QCA_NL80211_VENDOR_SUBCMD_TEST:
wpa_hexdump(MSG_DEBUG, "nl80211: QCA test event", data, len);
break;
+#ifdef CONFIG_DRIVER_NL80211_QCA
case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
qca_nl80211_avoid_freq(drv, data, len);
break;
@@ -1709,6 +2072,16 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED:
qca_nl80211_dfs_offload_radar_event(drv, subcmd, data, len);
break;
+ case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN:
+ qca_nl80211_scan_trigger_event(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE:
+ qca_nl80211_scan_done_event(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP:
+ qca_nl80211_p2p_lo_stop_event(drv, data, len);
+ break;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
default:
wpa_printf(MSG_DEBUG,
"nl80211: Ignore unsupported QCA vendor event %u",
@@ -1826,11 +2199,197 @@ static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
}
+static void nl80211_dump_freq(const char *title, struct nlattr *nl_freq)
+{
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ };
+ struct nlattr *tb[NL80211_FREQUENCY_ATTR_MAX + 1];
+ u32 freq = 0, max_tx_power = 0;
+
+ nla_parse(tb, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+
+ if (tb[NL80211_FREQUENCY_ATTR_FREQ])
+ freq = nla_get_u32(tb[NL80211_FREQUENCY_ATTR_FREQ]);
+ if (tb[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
+ max_tx_power =
+ nla_get_u32(tb[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Channel (%s): freq=%u max_tx_power=%u%s%s%s",
+ title, freq, max_tx_power,
+ tb[NL80211_FREQUENCY_ATTR_DISABLED] ? " disabled" : "",
+ tb[NL80211_FREQUENCY_ATTR_NO_IR] ? " no-IR" : "",
+ tb[NL80211_FREQUENCY_ATTR_RADAR] ? " radar" : "");
+}
+
+
+static void nl80211_reg_beacon_hint_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+ os_memset(&data, 0, sizeof(data));
+ data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
+
+ if (tb[NL80211_ATTR_FREQ_BEFORE])
+ nl80211_dump_freq("before", tb[NL80211_ATTR_FREQ_BEFORE]);
+ if (tb[NL80211_ATTR_FREQ_AFTER])
+ nl80211_dump_freq("after", tb[NL80211_ATTR_FREQ_AFTER]);
+
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
+}
+
+
+static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data event;
+ enum nl80211_external_auth_action act;
+
+ if (!tb[NL80211_ATTR_AKM_SUITES] ||
+ !tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION] ||
+ !tb[NL80211_ATTR_BSSID] ||
+ !tb[NL80211_ATTR_SSID])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ act = nla_get_u32(tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION]);
+ switch (act) {
+ case NL80211_EXTERNAL_AUTH_START:
+ event.external_auth.action = EXT_AUTH_START;
+ break;
+ case NL80211_EXTERNAL_AUTH_ABORT:
+ event.external_auth.action = EXT_AUTH_ABORT;
+ break;
+ default:
+ return;
+ }
+
+ event.external_auth.key_mgmt_suite =
+ nla_get_u32(tb[NL80211_ATTR_AKM_SUITES]);
+
+ event.external_auth.ssid_len = nla_len(tb[NL80211_ATTR_SSID]);
+ if (event.external_auth.ssid_len > SSID_MAX_LEN)
+ return;
+ event.external_auth.ssid = nla_data(tb[NL80211_ATTR_SSID]);
+
+ event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: External auth action: %u, AKM: 0x%x",
+ event.external_auth.action,
+ event.external_auth.key_mgmt_suite);
+ wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event);
+}
+
+
+static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ const u8 *addr;
+
+ if (!tb[NL80211_ATTR_MAC] ||
+ nla_len(tb[NL80211_ATTR_MAC]) != ETH_ALEN) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore port authorized event without BSSID");
+ return;
+ }
+
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ if (os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore port authorized event for " MACSTR
+ " (not the currently connected BSSID " MACSTR ")",
+ MAC2STR(addr), MAC2STR(drv->bssid));
+ return;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_PORT_AUTHORIZED, NULL);
+}
+
+
+static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data ed;
+ u8 smps_mode, max_bw;
+
+ if (!tb[NL80211_ATTR_MAC] ||
+ (!tb[NL80211_ATTR_CHANNEL_WIDTH] &&
+ !tb[NL80211_ATTR_SMPS_MODE] &&
+ !tb[NL80211_ATTR_NSS]))
+ return;
+
+ ed.sta_opmode.smps_mode = SMPS_INVALID;
+ ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
+ ed.sta_opmode.rx_nss = 0xff;
+ ed.sta_opmode.addr = nla_data(tb[NL80211_ATTR_MAC]);
+
+ if (tb[NL80211_ATTR_SMPS_MODE]) {
+ smps_mode = nla_get_u8(tb[NL80211_ATTR_SMPS_MODE]);
+ switch (smps_mode) {
+ case NL80211_SMPS_OFF:
+ ed.sta_opmode.smps_mode = SMPS_OFF;
+ break;
+ case NL80211_SMPS_STATIC:
+ ed.sta_opmode.smps_mode = SMPS_STATIC;
+ break;
+ case NL80211_SMPS_DYNAMIC:
+ ed.sta_opmode.smps_mode = SMPS_DYNAMIC;
+ break;
+ default:
+ ed.sta_opmode.smps_mode = SMPS_INVALID;
+ break;
+ }
+ }
+
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+ max_bw = nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]);
+ switch (max_bw) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_20_NOHT;
+ break;
+ case NL80211_CHAN_WIDTH_20:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_20;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_40;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_80;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_80P80;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_160;
+ break;
+ default:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
+ break;
+
+ }
+ }
+
+ if (tb[NL80211_ATTR_NSS])
+ ed.sta_opmode.rx_nss = nla_get_u8(tb[NL80211_ATTR_NSS]);
+
+ wpa_supplicant_event(drv->ctx, EVENT_STATION_OPMODE_CHANGED, &ed);
+}
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
- union wpa_event_data data;
+ int external_scan_event = 0;
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
cmd, nl80211_command_to_string(cmd), bss->ifname);
@@ -1883,28 +2442,40 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
case NL80211_CMD_NEW_SCAN_RESULTS:
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: New scan results available");
- drv->scan_state = SCAN_COMPLETED;
+ if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
+ drv->scan_state = SCAN_COMPLETED;
drv->scan_complete_events = 1;
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
- drv->ctx);
- send_scan_event(drv, 0, tb);
+ if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+ drv->last_scan_cmd = 0;
+ } else {
+ external_scan_event = 1;
+ }
+ send_scan_event(drv, 0, tb, external_scan_event);
break;
case NL80211_CMD_SCHED_SCAN_RESULTS:
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: New sched scan results available");
drv->scan_state = SCHED_SCAN_RESULTS;
- send_scan_event(drv, 0, tb);
+ send_scan_event(drv, 0, tb, 0);
break;
case NL80211_CMD_SCAN_ABORTED:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
- drv->scan_state = SCAN_ABORTED;
- /*
- * Need to indicate that scan results are available in order
- * not to make wpa_supplicant stop its scanning.
- */
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
- drv->ctx);
- send_scan_event(drv, 1, tb);
+ if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
+ drv->scan_state = SCAN_ABORTED;
+ if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
+ /*
+ * Need to indicate that scan results are available in
+ * order not to make wpa_supplicant stop its scanning.
+ */
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+ drv->last_scan_cmd = 0;
+ } else {
+ external_scan_event = 1;
+ }
+ send_scan_event(drv, 1, tb, external_scan_event);
break;
case NL80211_CMD_AUTHENTICATE:
case NL80211_CMD_ASSOCIATE:
@@ -1918,7 +2489,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE],
tb[NL80211_ATTR_RX_SIGNAL_DBM],
- tb[NL80211_ATTR_STA_WME]);
+ tb[NL80211_ATTR_STA_WME],
+ tb[NL80211_ATTR_REQ_IE]);
break;
case NL80211_CMD_CONNECT:
case NL80211_CMD_ROAM:
@@ -1927,7 +2499,14 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
tb[NL80211_ATTR_MAC],
tb[NL80211_ATTR_REQ_IE],
tb[NL80211_ATTR_RESP_IE],
- NULL, NULL, NULL, NULL);
+ tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_TIMEOUT_REASON],
+ NULL, NULL, NULL,
+ tb[NL80211_ATTR_FILS_KEK],
+ NULL,
+ tb[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM],
+ tb[NL80211_ATTR_PMK],
+ tb[NL80211_ATTR_PMKID]);
break;
case NL80211_CMD_CH_SWITCH_NOTIFY:
mlme_event_ch_switch(drv,
@@ -1959,20 +2538,17 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
nl80211_cqm_event(drv, tb);
break;
case NL80211_CMD_REG_CHANGE:
+ case NL80211_CMD_WIPHY_REG_CHANGE:
nl80211_reg_change_event(drv, tb);
break;
case NL80211_CMD_REG_BEACON_HINT:
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
- os_memset(&data, 0, sizeof(data));
- data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
- wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
- &data);
+ nl80211_reg_beacon_hint_event(drv, tb);
break;
case NL80211_CMD_NEW_STATION:
nl80211_new_station_event(drv, bss, tb);
break;
case NL80211_CMD_DEL_STATION:
- nl80211_del_station_event(drv, tb);
+ nl80211_del_station_event(drv, bss, tb);
break;
case NL80211_CMD_SET_REKEY_OFFLOAD:
nl80211_rekey_offload_event(drv, tb);
@@ -2004,6 +2580,12 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
case NL80211_CMD_NEW_PEER_CANDIDATE:
nl80211_new_peer_candidate(drv, tb);
break;
+ case NL80211_CMD_PORT_AUTHORIZED:
+ nl80211_port_authorized(drv, tb);
+ break;
+ case NL80211_CMD_STA_OPMODE_CHANGED:
+ nl80211_sta_opmode_change_event(drv, tb);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -2018,10 +2600,11 @@ int process_global_event(struct nl_msg *msg, void *arg)
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct wpa_driver_nl80211_data *drv, *tmp;
- int ifidx = -1;
+ int ifidx = -1, wiphy_idx = -1, wiphy_idx_rx = -1;
struct i802_bss *bss;
u64 wdev_id = 0;
int wdev_id_set = 0;
+ int wiphy_idx_set = 0;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -2031,13 +2614,19 @@ int process_global_event(struct nl_msg *msg, void *arg)
else if (tb[NL80211_ATTR_WDEV]) {
wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
wdev_id_set = 1;
+ } else if (tb[NL80211_ATTR_WIPHY]) {
+ wiphy_idx_rx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+ wiphy_idx_set = 1;
}
dl_list_for_each_safe(drv, tmp, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
for (bss = drv->first_bss; bss; bss = bss->next) {
- if ((ifidx == -1 && !wdev_id_set) ||
+ if (wiphy_idx_set)
+ wiphy_idx = nl80211_get_wiphy_index(bss);
+ if ((ifidx == -1 && !wiphy_idx_set && !wdev_id_set) ||
ifidx == bss->ifindex ||
+ (wiphy_idx_set && wiphy_idx == wiphy_idx_rx) ||
(wdev_id_set && bss->wdev_id_set &&
wdev_id == bss->wdev_id)) {
do_process_drv_event(bss, gnlh->cmd, tb);
@@ -2074,7 +2663,7 @@ int process_bss_event(struct nl_msg *msg, void *arg)
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE],
tb[NL80211_ATTR_RX_SIGNAL_DBM],
- tb[NL80211_ATTR_STA_WME]);
+ tb[NL80211_ATTR_STA_WME], NULL);
break;
case NL80211_CMD_UNEXPECTED_FRAME:
nl80211_spurious_frame(bss, tb, 0);
@@ -2082,6 +2671,9 @@ int process_bss_event(struct nl_msg *msg, void *arg)
case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
nl80211_spurious_frame(bss, tb, 1);
break;
+ case NL80211_CMD_EXTERNAL_AUTH:
+ nl80211_external_auth(bss->drv, tb);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", gnlh->cmd);
diff --git a/contrib/wpa/src/drivers/driver_nl80211_monitor.c b/contrib/wpa/src/drivers/driver_nl80211_monitor.c
index 45385da..f25cd79 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_monitor.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_monitor.c
@@ -136,7 +136,7 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
break;
case IEEE80211_RADIOTAP_TX_FLAGS:
injected = 1;
- failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+ failed = le_to_host16((*(le16 *) iter.this_arg)) &
IEEE80211_RADIOTAP_F_TX_FAIL;
break;
case IEEE80211_RADIOTAP_DATA_RETRIES:
@@ -361,8 +361,17 @@ int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
*/
snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
} else {
+ int ret;
+
/* Non-P2P interface with AP functionality. */
- snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
+ ret = os_snprintf(buf, IFNAMSIZ, "mon.%s",
+ drv->first_bss->ifname);
+ if (ret >= (int) sizeof(buf))
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Monitor interface name has been truncated to %s",
+ buf);
+ else if (ret < 0)
+ return ret;
}
buf[IFNAMSIZ - 1] = '\0';
diff --git a/contrib/wpa/src/drivers/driver_nl80211_scan.c b/contrib/wpa/src/drivers/driver_nl80211_scan.c
index 4b762ea..9afa5b3 100644
--- a/contrib/wpa/src/drivers/driver_nl80211_scan.c
+++ b/contrib/wpa/src/drivers/driver_nl80211_scan.c
@@ -1,5 +1,6 @@
/*
* Driver interaction with Linux nl80211/cfg80211 - Scanning
+ * Copyright(c) 2015 Intel Deutschland GmbH
* Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
* Copyright (c) 2009-2010, Atheros Communications
@@ -9,14 +10,25 @@
*/
#include "includes.h"
+#include <time.h>
#include <netlink/genl/genl.h>
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/qca-vendor.h"
#include "driver_nl80211.h"
+#define MAX_NL80211_NOISE_FREQS 50
+
+struct nl80211_noise_info {
+ u32 freq[MAX_NL80211_NOISE_FREQS];
+ s8 noise[MAX_NL80211_NOISE_FREQS];
+ unsigned int count;
+};
+
static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -26,9 +38,10 @@ static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
};
- struct wpa_scan_results *scan_results = arg;
- struct wpa_scan_res *scan_res;
- size_t i;
+ struct nl80211_noise_info *info = arg;
+
+ if (info->count >= MAX_NL80211_NOISE_FREQS)
+ return NL_STOP;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -52,34 +65,81 @@ static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
return NL_SKIP;
- for (i = 0; i < scan_results->num; ++i) {
- scan_res = scan_results->res[i];
- if (!scan_res)
- continue;
- if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
- scan_res->freq)
- continue;
- if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
- continue;
- scan_res->noise = (s8)
- nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
- scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
- }
+ info->freq[info->count] =
+ nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+ info->noise[info->count] =
+ (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ info->count++;
return NL_SKIP;
}
static int nl80211_get_noise_for_scan_results(
- struct wpa_driver_nl80211_data *drv,
- struct wpa_scan_results *scan_res)
+ struct wpa_driver_nl80211_data *drv, struct nl80211_noise_info *info)
{
struct nl_msg *msg;
+ os_memset(info, 0, sizeof(*info));
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
- return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
- scan_res);
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info);
+}
+
+
+static int nl80211_abort_scan(struct i802_bss *bss)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+}
+
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static int nl80211_abort_vendor_scan(struct wpa_driver_nl80211_data *drv,
+ u64 scan_cookie)
+{
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Abort vendor scan with cookie 0x%llx",
+ (long long unsigned int) scan_cookie);
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u64(msg, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, scan_cookie))
+ goto fail;
+
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Aborting vendor scan with cookie 0x%llx failed: ret=%d (%s)",
+ (long long unsigned int) scan_cookie, ret,
+ strerror(-ret));
+ goto fail;
+ }
+ return 0;
+fail:
+ nlmsg_free(msg);
+ return -1;
}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
/**
@@ -93,12 +153,26 @@ static int nl80211_get_noise_for_scan_results(
void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_driver_nl80211_data *drv = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan timeout - try to abort it");
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (drv->vendor_scan_cookie &&
+ nl80211_abort_vendor_scan(drv, drv->vendor_scan_cookie) == 0)
+ return;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ if (!drv->vendor_scan_cookie &&
+ nl80211_abort_scan(drv->first_bss) == 0)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan");
+
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
wpa_driver_nl80211_set_mode(drv->first_bss,
drv->ap_scan_as_station);
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
}
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+
+ wpa_printf(MSG_DEBUG, "nl80211: Try to get scan results");
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
}
@@ -123,14 +197,16 @@ nl80211_scan_common(struct i802_bss *bss, u8 cmd,
if (ssids == NULL)
goto fail;
for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan SSID %s",
+ wpa_ssid_txt(params->ssids[i].ssid,
+ params->ssids[i].ssid_len));
if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
params->ssids[i].ssid))
goto fail;
}
nla_nest_end(msg, ssids);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested");
}
if (params->extra_ies) {
@@ -193,6 +269,34 @@ nl80211_scan_common(struct i802_bss *bss, u8 cmd,
}
}
+ if (params->duration) {
+ if (!(drv->capa.rrm_flags &
+ WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) ||
+ nla_put_u16(msg, NL80211_ATTR_MEASUREMENT_DURATION,
+ params->duration))
+ goto fail;
+
+ if (params->duration_mandatory &&
+ nla_put_flag(msg,
+ NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY))
+ goto fail;
+ }
+
+ if (params->oce_scan) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME");
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP");
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_OCE_PROBE_REQ_MIN_TX_RATE");
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION");
+ scan_flags |= NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME |
+ NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP |
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE |
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION;
+ }
+
if (scan_flags &&
nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
goto fail;
@@ -252,6 +356,13 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
goto fail;
}
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: "
+ MACSTR, MAC2STR(params->bssid));
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ goto fail;
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
@@ -297,6 +408,7 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
drv, drv->ctx);
+ drv->last_scan_cmd = NL80211_CMD_TRIGGER_SCAN;
fail:
nlmsg_free(msg);
@@ -304,16 +416,82 @@ fail:
}
+static int
+nl80211_sched_scan_add_scan_plans(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ struct wpa_driver_scan_params *params)
+{
+ struct nlattr *plans;
+ struct sched_scan_plan *scan_plans = params->sched_scan_plans;
+ unsigned int i;
+
+ plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
+ if (!plans)
+ return -1;
+
+ for (i = 0; i < params->sched_scan_plans_num; i++) {
+ struct nlattr *plan = nla_nest_start(msg, i + 1);
+
+ if (!plan)
+ return -1;
+
+ if (!scan_plans[i].interval ||
+ scan_plans[i].interval >
+ drv->capa.max_sched_scan_plan_interval) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: sched scan plan no. %u: Invalid interval: %u",
+ i, scan_plans[i].interval);
+ return -1;
+ }
+
+ if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
+ scan_plans[i].interval))
+ return -1;
+
+ if (scan_plans[i].iterations >
+ drv->capa.max_sched_scan_plan_iterations) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: sched scan plan no. %u: Invalid number of iterations: %u",
+ i, scan_plans[i].iterations);
+ return -1;
+ }
+
+ if (scan_plans[i].iterations &&
+ nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
+ scan_plans[i].iterations))
+ return -1;
+
+ nla_nest_end(msg, plan);
+
+ /*
+ * All the scan plans must specify the number of iterations
+ * except the last plan, which will run infinitely. So if the
+ * number of iterations is not specified, this ought to be the
+ * last scan plan.
+ */
+ if (!scan_plans[i].iterations)
+ break;
+ }
+
+ if (i != params->sched_scan_plans_num - 1) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: All sched scan plans but the last must specify number of iterations");
+ return -1;
+ }
+
+ nla_nest_end(msg, plans);
+ return 0;
+}
+
+
/**
* wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
* @priv: Pointer to private driver data from wpa_driver_nl80211_init()
* @params: Scan parameters
- * @interval: Interval between scan cycles in milliseconds
* Returns: 0 on success, -1 on failure or if not supported
*/
int wpa_driver_nl80211_sched_scan(void *priv,
- struct wpa_driver_scan_params *params,
- u32 interval)
+ struct wpa_driver_scan_params *params)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -328,11 +506,27 @@ int wpa_driver_nl80211_sched_scan(void *priv,
return android_pno_start(bss, params);
#endif /* ANDROID */
+ if (!params->sched_scan_plans_num ||
+ params->sched_scan_plans_num > drv->capa.max_sched_scan_plans) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Invalid number of sched scan plans: %u",
+ params->sched_scan_plans_num);
+ return -1;
+ }
+
msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
- if (!msg ||
- nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
+ if (!msg)
goto fail;
+ if (drv->capa.max_sched_scan_plan_iterations) {
+ if (nl80211_sched_scan_add_scan_plans(drv, msg, params))
+ goto fail;
+ } else {
+ if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
+ params->sched_scan_plans[0].interval * 1000))
+ goto fail;
+ }
+
if ((drv->num_filter_ssids &&
(int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
params->filter_rssi) {
@@ -343,10 +537,10 @@ int wpa_driver_nl80211_sched_scan(void *priv,
for (i = 0; i < drv->num_filter_ssids; i++) {
struct nlattr *match_set_ssid;
- wpa_hexdump_ascii(MSG_MSGDUMP,
- "nl80211: Sched scan filter SSID",
- drv->filter_ssids[i].ssid,
- drv->filter_ssids[i].ssid_len);
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan filter SSID %s",
+ wpa_ssid_txt(drv->filter_ssids[i].ssid,
+ drv->filter_ssids[i].ssid_len));
match_set_ssid = nla_nest_start(msg, i + 1);
if (match_set_ssid == NULL ||
@@ -384,6 +578,44 @@ int wpa_driver_nl80211_sched_scan(void *priv,
nla_nest_end(msg, match_sets);
}
+ if (params->relative_rssi_set) {
+ struct nl80211_bss_select_rssi_adjust rssi_adjust;
+
+ os_memset(&rssi_adjust, 0, sizeof(rssi_adjust));
+ wpa_printf(MSG_DEBUG, "nl80211: Relative RSSI: %d",
+ params->relative_rssi);
+ if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+ params->relative_rssi))
+ goto fail;
+
+ if (params->relative_adjust_rssi) {
+ int pref_band_set = 1;
+
+ switch (params->relative_adjust_band) {
+ case WPA_SETBAND_5G:
+ rssi_adjust.band = NL80211_BAND_5GHZ;
+ break;
+ case WPA_SETBAND_2G:
+ rssi_adjust.band = NL80211_BAND_2GHZ;
+ break;
+ default:
+ pref_band_set = 0;
+ break;
+ }
+ rssi_adjust.delta = params->relative_adjust_rssi;
+
+ if (pref_band_set &&
+ nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+ sizeof(rssi_adjust), &rssi_adjust))
+ goto fail;
+ }
+ }
+
+ if (params->sched_scan_start_delay &&
+ nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY,
+ params->sched_scan_start_delay))
+ goto fail;
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
/* TODO: if we get an error here, we should fall back to normal scan */
@@ -395,8 +627,7 @@ int wpa_driver_nl80211_sched_scan(void *priv,
goto fail;
}
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
- "scan interval %d msec", ret, interval);
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d)", ret);
fail:
nlmsg_free(msg);
@@ -436,28 +667,6 @@ int wpa_driver_nl80211_stop_sched_scan(void *priv)
}
-const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
-{
- const u8 *end, *pos;
-
- if (ies == NULL)
- return NULL;
-
- pos = ies;
- end = ies + ies_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
-}
-
-
static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
const u8 *ie, size_t ie_len)
{
@@ -467,7 +676,7 @@ static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
if (drv->filter_ssids == NULL)
return 0;
- ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+ ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
if (ssid == NULL)
return 1;
@@ -482,7 +691,9 @@ static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
}
-int bss_info_handler(struct nl_msg *msg, void *arg)
+static struct wpa_scan_res *
+nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
@@ -499,50 +710,22 @@ int bss_info_handler(struct nl_msg *msg, void *arg)
[NL80211_BSS_STATUS] = { .type = NLA_U32 },
[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_PARENT_TSF] = { .type = NLA_U64 },
+ [NL80211_BSS_PARENT_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_LAST_SEEN_BOOTTIME] = { .type = NLA_U64 },
};
- struct nl80211_bss_info_arg *_arg = arg;
- struct wpa_scan_results *res = _arg->res;
- struct wpa_scan_res **tmp;
struct wpa_scan_res *r;
const u8 *ie, *beacon_ie;
size_t ie_len, beacon_ie_len;
u8 *pos;
- size_t i;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (!tb[NL80211_ATTR_BSS])
- return NL_SKIP;
+ return NULL;
if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
bss_policy))
- return NL_SKIP;
- if (bss[NL80211_BSS_STATUS]) {
- enum nl80211_bss_status status;
- status = nla_get_u32(bss[NL80211_BSS_STATUS]);
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->assoc_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
- _arg->assoc_freq);
- }
- if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->ibss_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
- _arg->ibss_freq);
- }
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_BSSID]) {
- os_memcpy(_arg->assoc_bssid,
- nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
- wpa_printf(MSG_DEBUG, "nl80211: Associated with "
- MACSTR, MAC2STR(_arg->assoc_bssid));
- }
- }
- if (!res)
- return NL_SKIP;
+ return NULL;
if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
@@ -558,13 +741,13 @@ int bss_info_handler(struct nl_msg *msg, void *arg)
beacon_ie_len = 0;
}
- if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+ if (nl80211_scan_filtered(drv, ie ? ie : beacon_ie,
ie ? ie_len : beacon_ie_len))
- return NL_SKIP;
+ return NULL;
r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
if (r == NULL)
- return NL_SKIP;
+ return NULL;
if (bss[NL80211_BSS_BSSID])
os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
ETH_ALEN);
@@ -593,6 +776,23 @@ int bss_info_handler(struct nl_msg *msg, void *arg)
}
if (bss[NL80211_BSS_SEEN_MS_AGO])
r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
+ if (bss[NL80211_BSS_LAST_SEEN_BOOTTIME]) {
+ u64 boottime;
+ struct timespec ts;
+
+#ifndef CLOCK_BOOTTIME
+#define CLOCK_BOOTTIME 7
+#endif
+ if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0) {
+ /* Use more accurate boottime information to update the
+ * scan result age since the driver reports this and
+ * CLOCK_BOOTTIME is available. */
+ boottime = nla_get_u64(
+ bss[NL80211_BSS_LAST_SEEN_BOOTTIME]);
+ r->age = ((u64) ts.tv_sec * 1000000000 +
+ ts.tv_nsec - boottime) / 1000000;
+ }
+ }
r->ie_len = ie_len;
pos = (u8 *) (r + 1);
if (ie) {
@@ -615,40 +815,36 @@ int bss_info_handler(struct nl_msg *msg, void *arg)
}
}
- /*
- * cfg80211 maintains separate BSS table entries for APs if the same
- * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
- * not use frequency as a separate key in the BSS table, so filter out
- * duplicated entries. Prefer associated BSS entry in such a case in
- * order to get the correct frequency into the BSS table. Similarly,
- * prefer newer entries over older.
- */
- for (i = 0; i < res->num; i++) {
- const u8 *s1, *s2;
- if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
- continue;
+ if (bss[NL80211_BSS_PARENT_TSF] && bss[NL80211_BSS_PARENT_BSSID]) {
+ r->parent_tsf = nla_get_u64(bss[NL80211_BSS_PARENT_TSF]);
+ os_memcpy(r->tsf_bssid, nla_data(bss[NL80211_BSS_PARENT_BSSID]),
+ ETH_ALEN);
+ }
- s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
- res->res[i]->ie_len, WLAN_EID_SSID);
- s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
- if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
- os_memcmp(s1, s2, 2 + s1[1]) != 0)
- continue;
+ return r;
+}
- /* Same BSSID,SSID was already included in scan results */
- wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
- "for " MACSTR, MAC2STR(r->bssid));
- if (((r->flags & WPA_SCAN_ASSOCIATED) &&
- !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
- r->age < res->res[i]->age) {
- os_free(res->res[i]);
- res->res[i] = r;
- } else
- os_free(r);
+struct nl80211_bss_info_arg {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_scan_results *res;
+};
+
+static int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_bss_info_arg *_arg = arg;
+ struct wpa_scan_results *res = _arg->res;
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+
+ r = nl80211_parse_bss_info(_arg->drv, msg);
+ if (!r)
return NL_SKIP;
- }
+ if (!res) {
+ os_free(r);
+ return NL_SKIP;
+ }
tmp = os_realloc_array(res->res, res->num + 1,
sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
@@ -670,7 +866,32 @@ static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
"mismatch (" MACSTR ")", MAC2STR(addr));
wpa_driver_nl80211_mlme(drv, addr,
NL80211_CMD_DEAUTHENTICATE,
- WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+ WLAN_REASON_PREV_AUTH_NOT_VALID, 1,
+ NULL);
+ }
+}
+
+
+static void nl80211_check_bss_status(struct wpa_driver_nl80211_data *drv,
+ struct wpa_scan_res *r)
+{
+ if (!(r->flags & WPA_SCAN_ASSOCIATED))
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results indicate BSS status with "
+ MACSTR " as associated", MAC2STR(r->bssid));
+ if (is_sta_interface(drv->nlmode) && !drv->associated) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Local state (not associated) does not match with BSS state");
+ clear_state_mismatch(drv, r->bssid);
+ } else if (is_sta_interface(drv->nlmode) &&
+ os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Local state (associated with " MACSTR
+ ") does not match with BSS state",
+ MAC2STR(drv->bssid));
+ clear_state_mismatch(drv, r->bssid);
+ clear_state_mismatch(drv, drv->bssid);
}
}
@@ -680,31 +901,22 @@ static void wpa_driver_nl80211_check_bss_status(
{
size_t i;
- for (i = 0; i < res->num; i++) {
- struct wpa_scan_res *r = res->res[i];
-
- if (r->flags & WPA_SCAN_ASSOCIATED) {
- wpa_printf(MSG_DEBUG, "nl80211: Scan results "
- "indicate BSS status with " MACSTR
- " as associated",
- MAC2STR(r->bssid));
- if (is_sta_interface(drv->nlmode) &&
- !drv->associated) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(not associated) does not match "
- "with BSS state");
- clear_state_mismatch(drv, r->bssid);
- } else if (is_sta_interface(drv->nlmode) &&
- os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
- 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(associated with " MACSTR ") does "
- "not match with BSS state",
- MAC2STR(drv->bssid));
- clear_state_mismatch(drv, r->bssid);
- clear_state_mismatch(drv, drv->bssid);
- }
- }
+ for (i = 0; i < res->num; i++)
+ nl80211_check_bss_status(drv, res->res[i]);
+}
+
+
+static void nl80211_update_scan_res_noise(struct wpa_scan_res *res,
+ struct nl80211_noise_info *info)
+{
+ unsigned int i;
+
+ for (i = 0; res && i < info->count; i++) {
+ if ((int) info->freq[i] != res->freq ||
+ !(res->flags & WPA_SCAN_NOISE_INVALID))
+ continue;
+ res->noise = info->noise[i];
+ res->flags &= ~WPA_SCAN_NOISE_INVALID;
}
}
@@ -730,9 +942,17 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
arg.res = res;
ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
if (ret == 0) {
+ struct nl80211_noise_info info;
+
wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
"BSSes)", (unsigned long) res->num);
- nl80211_get_noise_for_scan_results(drv, res);
+ if (nl80211_get_noise_for_scan_results(drv, &info) == 0) {
+ size_t i;
+
+ for (i = 0; i < res->num; ++i)
+ nl80211_update_scan_res_noise(res->res[i],
+ &info);
+ }
return res;
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -760,24 +980,306 @@ struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
}
+struct nl80211_dump_scan_ctx {
+ struct wpa_driver_nl80211_data *drv;
+ int idx;
+};
+
+static int nl80211_dump_scan_handler(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_dump_scan_ctx *ctx = arg;
+ struct wpa_scan_res *r;
+
+ r = nl80211_parse_bss_info(ctx->drv, msg);
+ if (!r)
+ return NL_SKIP;
+ wpa_printf(MSG_DEBUG, "nl80211: %d " MACSTR " %d%s",
+ ctx->idx, MAC2STR(r->bssid), r->freq,
+ r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+ ctx->idx++;
+ os_free(r);
+ return NL_SKIP;
+}
+
+
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
{
- struct wpa_scan_results *res;
+ struct nl_msg *msg;
+ struct nl80211_dump_scan_ctx ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
+ ctx.drv = drv;
+ ctx.idx = 0;
+ msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ if (msg)
+ send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx);
+}
+
+
+int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie)
+{
+ struct i802_bss *bss = priv;
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ /*
+ * If scan_cookie is zero, a normal scan through kernel (cfg80211)
+ * was triggered, hence abort the cfg80211 scan instead of the vendor
+ * scan.
+ */
+ if (drv->scan_vendor_cmd_avail && scan_cookie)
+ return nl80211_abort_vendor_scan(drv, scan_cookie);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ return nl80211_abort_scan(bss);
+}
+
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+
+static int scan_cookie_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ u64 *cookie = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl_vendor = tb[NL80211_ATTR_VENDOR_DATA];
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1];
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_SCAN_MAX,
+ nla_data(nl_vendor), nla_len(nl_vendor), NULL);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE])
+ *cookie = nla_get_u64(
+ tb_vendor[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]);
+ }
+
+ return NL_SKIP;
+}
+
+
+/**
+ * wpa_driver_nl80211_vendor_scan - Request the driver to initiate a vendor scan
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg = NULL;
+ struct nlattr *attr;
size_t i;
+ u32 scan_flags = 0;
+ int ret = -1;
+ u64 cookie = 0;
- res = nl80211_get_scan_results(drv);
- if (res == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
- return;
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: vendor scan request");
+ drv->scan_for_auth = 0;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN) )
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (attr == NULL)
+ goto fail;
+
+ if (params->num_ssids) {
+ struct nlattr *ssids;
+
+ ssids = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS);
+ if (ssids == NULL)
+ goto fail;
+ for (i = 0; i < params->num_ssids; i++) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan SSID %s",
+ wpa_ssid_txt(params->ssids[i].ssid,
+ params->ssids[i].ssid_len));
+ if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid))
+ goto fail;
+ }
+ nla_nest_end(msg, ssids);
}
- wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
- for (i = 0; i < res->num; i++) {
- struct wpa_scan_res *r = res->res[i];
- wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
- (int) i, (int) res->num, MAC2STR(r->bssid),
- r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+ if (params->extra_ies) {
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+ params->extra_ies, params->extra_ies_len);
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_IE,
+ params->extra_ies_len, params->extra_ies))
+ goto fail;
}
- wpa_scan_results_free(res);
+ if (params->freqs) {
+ struct nlattr *freqs;
+
+ freqs = nla_nest_start(msg,
+ QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES);
+ if (freqs == NULL)
+ goto fail;
+ for (i = 0; params->freqs[i]; i++) {
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Scan frequency %u MHz",
+ params->freqs[i]);
+ if (nla_put_u32(msg, i + 1, params->freqs[i]))
+ goto fail;
+ }
+ nla_nest_end(msg, freqs);
+ }
+
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
+ if (params->low_priority && drv->have_low_prio_scan) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
+ scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
+ }
+
+ if (params->mac_addr_rand) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
+ scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
+
+ if (params->mac_addr) {
+ wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
+ MAC2STR(params->mac_addr));
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_MAC,
+ ETH_ALEN, params->mac_addr))
+ goto fail;
+ }
+
+ if (params->mac_addr_mask) {
+ wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
+ MACSTR, MAC2STR(params->mac_addr_mask));
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK,
+ ETH_ALEN, params->mac_addr_mask))
+ goto fail;
+ }
+ }
+
+ if (scan_flags &&
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, scan_flags))
+ goto fail;
+
+ if (params->p2p_probe) {
+ struct nlattr *rates;
+
+ wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
+ rates = nla_nest_start(msg,
+ QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES);
+ if (rates == NULL)
+ goto fail;
+
+ /*
+ * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
+ * by masking out everything else apart from the OFDM rates 6,
+ * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
+ * rates are left enabled.
+ */
+ if (nla_put(msg, NL80211_BAND_2GHZ, 8,
+ "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
+ goto fail;
+ nla_nest_end(msg, rates);
+
+ if (nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE))
+ goto fail;
+ }
+
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: "
+ MACSTR, MAC2STR(params->bssid));
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_BSSID, ETH_ALEN,
+ params->bssid))
+ goto fail;
+ }
+
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Vendor scan trigger failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+
+ drv->vendor_scan_cookie = cookie;
+ drv->scan_state = SCAN_REQUESTED;
+ /* Pass the cookie to the caller to help distinguish the scans. */
+ params->scan_cookie = cookie;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Vendor scan requested (ret=%d) - scan timeout 30 seconds, scan cookie:0x%llx",
+ ret, (long long unsigned int) cookie);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(30, 0, wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+ drv->last_scan_cmd = NL80211_CMD_VENDOR;
+
+fail:
+ nlmsg_free(msg);
+ return ret;
}
+
+
+/**
+ * nl80211_set_default_scan_ies - Set the scan default IEs to the driver
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @ies: Pointer to IEs buffer
+ * @ies_len: Length of IEs in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg = NULL;
+ struct nlattr *attr;
+ int ret = -1;
+
+ if (!drv->set_wifi_conf_vendor_cmd_avail)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (attr == NULL)
+ goto fail;
+
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan default IEs", ies, ies_len);
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES,
+ ies_len, ies))
+ goto fail;
+
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Set scan default IEs failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+#endif /* CONFIG_DRIVER_NL80211_QCA */
diff --git a/contrib/wpa/src/drivers/driver_openbsd.c b/contrib/wpa/src/drivers/driver_openbsd.c
index e94eda0..c06e75c 100644
--- a/contrib/wpa/src/drivers/driver_openbsd.c
+++ b/contrib/wpa/src/drivers/driver_openbsd.c
@@ -62,7 +62,8 @@ static int
wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
{
os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK |
+ WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
return 0;
}
diff --git a/contrib/wpa/src/drivers/driver_privsep.c b/contrib/wpa/src/drivers/driver_privsep.c
index 1f1676a..a3f0837 100644
--- a/contrib/wpa/src/drivers/driver_privsep.c
+++ b/contrib/wpa/src/drivers/driver_privsep.c
@@ -97,15 +97,31 @@ static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
return 0;
}
-
+
static int wpa_driver_privsep_scan(void *priv,
struct wpa_driver_scan_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
- const u8 *ssid = params->ssids[0].ssid;
- size_t ssid_len = params->ssids[0].ssid_len;
+ struct privsep_cmd_scan scan;
+ size_t i;
+
wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
- return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
+ os_memset(&scan, 0, sizeof(scan));
+ scan.num_ssids = params->num_ssids;
+ for (i = 0; i < params->num_ssids; i++) {
+ if (!params->ssids[i].ssid)
+ continue;
+ scan.ssid_lens[i] = params->ssids[i].ssid_len;
+ os_memcpy(scan.ssids[i], params->ssids[i].ssid,
+ scan.ssid_lens[i]);
+ }
+
+ for (i = 0; i < PRIVSEP_MAX_SCAN_FREQS &&
+ params->freqs && params->freqs[i]; i++)
+ scan.freqs[i] = params->freqs[i];
+ scan.num_freqs = i;
+
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, &scan, sizeof(scan),
NULL, NULL);
}
@@ -161,19 +177,22 @@ wpa_driver_privsep_get_scan_results2(void *priv)
return NULL;
}
- while (results->num < (size_t) num && pos + sizeof(int) < end) {
+ while (results->num < (size_t) num && end - pos > (int) sizeof(int)) {
int len;
os_memcpy(&len, pos, sizeof(int));
pos += sizeof(int);
- if (len < 0 || len > 10000 || pos + len > end)
+ if (len < 0 || len > 10000 || len > end - pos)
break;
- r = os_malloc(len);
+ r = os_memdup(pos, len);
if (r == NULL)
break;
- os_memcpy(r, pos, len);
pos += len;
- if (sizeof(*r) + r->ie_len > (size_t) len) {
+ if (sizeof(*r) + r->ie_len + r->beacon_ie_len > (size_t) len) {
+ wpa_printf(MSG_ERROR,
+ "privsep: Invalid scan result len (%d + %d + %d > %d)",
+ (int) sizeof(*r), (int) r->ie_len,
+ (int) r->beacon_ie_len, len);
os_free(r);
break;
}
@@ -234,7 +253,7 @@ static int wpa_driver_privsep_authenticate(
__func__, priv, params->freq, MAC2STR(params->bssid),
params->auth_alg, params->local_state_change, params->p2p);
- buflen = sizeof(*data) + params->ie_len + params->sae_data_len;
+ buflen = sizeof(*data) + params->ie_len + params->auth_data_len;
data = os_zalloc(buflen);
if (data == NULL)
return -1;
@@ -259,8 +278,8 @@ static int wpa_driver_privsep_authenticate(
os_memcpy(pos, params->ie, params->ie_len);
pos += params->ie_len;
}
- if (params->sae_data_len)
- os_memcpy(pos, params->sae_data, params->sae_data_len);
+ if (params->auth_data_len)
+ os_memcpy(pos, params->auth_data, params->auth_data_len);
res = wpa_priv_cmd(drv, PRIVSEP_CMD_AUTHENTICATE, data, buflen,
NULL, NULL);
@@ -464,19 +483,6 @@ static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
}
-static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
-{
- union wpa_event_data data;
-
- if (len != ETH_ALEN)
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
- wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
-}
-
-
static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
size_t len)
{
@@ -570,10 +576,6 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
event_len);
break;
- case PRIVSEP_EVENT_STKSTART:
- wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
- event_len);
- break;
case PRIVSEP_EVENT_FT_RESPONSE:
wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
event_len);
diff --git a/contrib/wpa/src/drivers/driver_wired.c b/contrib/wpa/src/drivers/driver_wired.c
index 960bd89..c7537b7 100644
--- a/contrib/wpa/src/drivers/driver_wired.c
+++ b/contrib/wpa/src/drivers/driver_wired.c
@@ -8,12 +8,18 @@
*/
#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "driver.h"
+#include "driver_wired_common.h"
+
#include <sys/ioctl.h>
+#undef IFNAMSIZ
#include <net/if.h>
#ifdef __linux__
#include <netpacket/packet.h>
#include <net/if_arp.h>
-#include <net/if.h>
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
#include <net/if_dl.h>
@@ -23,10 +29,6 @@
#include <sys/sockio.h>
#endif /* __sun__ */
-#include "common.h"
-#include "eloop.h"
-#include "driver.h"
-
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
@@ -41,20 +43,12 @@ struct ieee8023_hdr {
#pragma pack(pop)
#endif /* _MSC_VER */
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
struct wpa_driver_wired_data {
- char ifname[IFNAMSIZ + 1];
- void *ctx;
+ struct driver_wired_common_data common;
- int sock; /* raw packet socket for driver access */
int dhcp_sock; /* socket for dhcp packets */
int use_pae_group_addr;
-
- int pf_sock;
- int membership, multi, iff_allmulti, iff_up;
};
@@ -82,34 +76,6 @@ struct dhcp_message {
};
-static int wired_multicast_membership(int sock, int ifindex,
- const u8 *addr, int add)
-{
-#ifdef __linux__
- struct packet_mreq mreq;
-
- if (sock < 0)
- return -1;
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.mr_ifindex = ifindex;
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = ETH_ALEN;
- os_memcpy(mreq.mr_address, addr, ETH_ALEN);
-
- if (setsockopt(sock, SOL_PACKET,
- add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
- return -1;
- }
- return 0;
-#else /* __linux__ */
- return -1;
-#endif /* __linux__ */
-}
-
-
#ifdef __linux__
static void handle_data(void *ctx, unsigned char *buf, size_t len)
{
@@ -130,16 +96,16 @@ static void handle_data(void *ctx, unsigned char *buf, size_t len)
hdr = (struct ieee8023_hdr *) buf;
switch (ntohs(hdr->ethertype)) {
- case ETH_P_PAE:
- wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
- sa = hdr->src;
- os_memset(&event, 0, sizeof(event));
- event.new_sta.addr = sa;
- wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
-
- pos = (u8 *) (hdr + 1);
- left = len - sizeof(*hdr);
- drv_event_eapol_rx(ctx, sa, pos, left);
+ case ETH_P_PAE:
+ wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
+ sa = hdr->src;
+ os_memset(&event, 0, sizeof(event));
+ event.new_sta.addr = sa;
+ wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+ drv_event_eapol_rx(ctx, sa, pos, left);
break;
default:
@@ -207,21 +173,22 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
struct sockaddr_in addr2;
int n = 1;
- drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
- if (drv->sock < 0) {
+ drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->common.sock < 0) {
wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
strerror(errno));
return -1;
}
- if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
+ if (eloop_register_read_sock(drv->common.sock, handle_read,
+ drv->common.ctx, NULL)) {
wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
strerror(errno));
return -1;
@@ -233,13 +200,14 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
addr.sll_ifindex);
- if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (bind(drv->common.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
/* filter multicast address */
- if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex,
+ if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
pae_group_addr, 1) < 0) {
wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
"membership");
@@ -247,8 +215,8 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
strerror(errno));
return -1;
@@ -268,8 +236,8 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
return -1;
}
- if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
- NULL)) {
+ if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp,
+ drv->common.ctx, NULL)) {
wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
@@ -293,7 +261,7 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->common.ifname, IFNAMSIZ);
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
(char *) &ifr, sizeof(ifr)) < 0) {
wpa_printf(MSG_ERROR,
@@ -342,7 +310,7 @@ static int wired_send_eapol(void *priv, const u8 *addr,
pos = (u8 *) (hdr + 1);
os_memcpy(pos, data, data_len);
- res = send(drv->sock, (u8 *) hdr, len, 0);
+ res = send(drv->common.sock, (u8 *) hdr, len, 0);
os_free(hdr);
if (res < 0) {
@@ -367,8 +335,9 @@ static void * wired_driver_hapd_init(struct hostapd_data *hapd,
return NULL;
}
- drv->ctx = hapd;
- os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
+ drv->common.ctx = hapd;
+ os_strlcpy(drv->common.ifname, params->ifname,
+ sizeof(drv->common.ifname));
drv->use_pae_group_addr = params->use_pae_group_addr;
if (wired_init_sockets(drv, params->own_addr)) {
@@ -384,9 +353,9 @@ static void wired_driver_hapd_deinit(void *priv)
{
struct wpa_driver_wired_data *drv = priv;
- if (drv->sock >= 0) {
- eloop_unregister_read_sock(drv->sock);
- close(drv->sock);
+ if (drv->common.sock >= 0) {
+ eloop_unregister_read_sock(drv->common.sock);
+ close(drv->common.sock);
}
if (drv->dhcp_sock >= 0) {
@@ -398,226 +367,18 @@ static void wired_driver_hapd_deinit(void *priv)
}
-static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
-{
- ssid[0] = 0;
- return 0;
-}
-
-
-static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
-{
- /* Report PAE group address as the "BSSID" for wired connection. */
- os_memcpy(bssid, pae_group_addr, ETH_ALEN);
- return 0;
-}
-
-
-static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_WIRED;
- return 0;
-}
-
-
-static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
-}
-
-
-static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-static int wpa_driver_wired_get_ifstatus(const char *ifname, int *status)
-{
- struct ifmediareq ifmr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifmr, 0, sizeof(ifmr));
- os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
- (IFM_ACTIVE | IFM_AVALID);
-
- return 0;
-}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-
-
-static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
-{
- struct ifreq ifr;
- int s;
-
-#ifdef __sun__
- return -1;
-#endif /* __sun__ */
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-#ifdef __linux__
- ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
- os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- struct sockaddr_dl *dlp;
- dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
- dlp->sdl_len = sizeof(struct sockaddr_dl);
- dlp->sdl_family = AF_LINK;
- dlp->sdl_index = 0;
- dlp->sdl_nlen = 0;
- dlp->sdl_alen = ETH_ALEN;
- dlp->sdl_slen = 0;
- os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
- {
- struct sockaddr *sap;
- sap = (struct sockaddr *) &ifr.ifr_addr;
- sap->sa_len = sizeof(struct sockaddr);
- sap->sa_family = AF_UNSPEC;
- os_memcpy(sap->sa_data, addr, ETH_ALEN);
- }
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
-
- if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
static void * wpa_driver_wired_init(void *ctx, const char *ifname)
{
struct wpa_driver_wired_data *drv;
- int flags, status;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ctx = ctx;
-
-#ifdef __linux__
- drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
- if (drv->pf_sock < 0)
- wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
-#else /* __linux__ */
- drv->pf_sock = -1;
-#endif /* __linux__ */
-
- if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
- !(flags & IFF_UP) &&
- wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
- drv->iff_up = 1;
- }
- if (wired_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
- "packet socket", __func__);
- drv->membership = 1;
- } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
- "SIOCADDMULTI", __func__);
- drv->multi = 1;
- } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
- wpa_printf(MSG_INFO, "%s: Could not get interface "
- "flags", __func__);
- os_free(drv);
- return NULL;
- } else if (flags & IFF_ALLMULTI) {
- wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
- "for multicast", __func__);
- } else if (wpa_driver_wired_set_ifflags(ifname,
- flags | IFF_ALLMULTI) < 0) {
- wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
- __func__);
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
os_free(drv);
return NULL;
- } else {
- wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
- __func__);
- drv->iff_allmulti = 1;
- }
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- int status;
- wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
- __func__);
- while (wpa_driver_wired_get_ifstatus(ifname, &status) == 0 &&
- status == 0)
- sleep(1);
}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
return drv;
}
@@ -626,41 +387,8 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname)
static void wpa_driver_wired_deinit(void *priv)
{
struct wpa_driver_wired_data *drv = priv;
- int flags;
-
- if (drv->membership &&
- wired_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
- "group (PACKET)", __func__);
- }
-
- if (drv->multi &&
- wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
- "group (SIOCDELMULTI)", __func__);
- }
-
- if (drv->iff_allmulti &&
- (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
- wpa_driver_wired_set_ifflags(drv->ifname,
- flags & ~IFF_ALLMULTI) < 0)) {
- wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
- __func__);
- }
-
- if (drv->iff_up &&
- wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
- (flags & IFF_UP) &&
- wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
- __func__);
- }
-
- if (drv->pf_sock != -1)
- close(drv->pf_sock);
+ driver_wired_deinit_common(&drv->common);
os_free(drv);
}
@@ -671,9 +399,9 @@ const struct wpa_driver_ops wpa_driver_wired_ops = {
.hapd_init = wired_driver_hapd_init,
.hapd_deinit = wired_driver_hapd_deinit,
.hapd_send_eapol = wired_send_eapol,
- .get_ssid = wpa_driver_wired_get_ssid,
- .get_bssid = wpa_driver_wired_get_bssid,
- .get_capa = wpa_driver_wired_get_capa,
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
.init = wpa_driver_wired_init,
.deinit = wpa_driver_wired_deinit,
};
diff --git a/contrib/wpa/src/drivers/driver_wired_common.c b/contrib/wpa/src/drivers/driver_wired_common.c
new file mode 100644
index 0000000..a860b1c7
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_wired_common.c
@@ -0,0 +1,322 @@
+/*
+ * Common functions for Wired Ethernet driver interfaces
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "driver.h"
+#include "driver_wired_common.h"
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#ifdef __linux__
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
+#ifdef __sun__
+#include <sys/sockio.h>
+#endif /* __sun__ */
+
+
+static int driver_wired_get_ifflags(const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+static int driver_wired_set_ifflags(const char *ifname, int flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int driver_wired_multi(const char *ifname, const u8 *addr, int add)
+{
+ struct ifreq ifr;
+ int s;
+
+#ifdef __sun__
+ return -1;
+#endif /* __sun__ */
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+#ifdef __linux__
+ ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ {
+ struct sockaddr_dl *dlp;
+
+ dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
+ dlp->sdl_len = sizeof(struct sockaddr_dl);
+ dlp->sdl_family = AF_LINK;
+ dlp->sdl_index = 0;
+ dlp->sdl_nlen = 0;
+ dlp->sdl_alen = ETH_ALEN;
+ dlp->sdl_slen = 0;
+ os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
+ {
+ struct sockaddr *sap;
+
+ sap = (struct sockaddr *) &ifr.ifr_addr;
+ sap->sa_len = sizeof(struct sockaddr);
+ sap->sa_family = AF_UNSPEC;
+ os_memcpy(sap->sa_data, addr, ETH_ALEN);
+ }
+#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
+
+ if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+int wired_multicast_membership(int sock, int ifindex, const u8 *addr, int add)
+{
+#ifdef __linux__
+ struct packet_mreq mreq;
+
+ if (sock < 0)
+ return -1;
+
+ os_memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = ifindex;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ os_memcpy(mreq.mr_address, addr, ETH_ALEN);
+
+ if (setsockopt(sock, SOL_PACKET,
+ add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+int driver_wired_get_ssid(void *priv, u8 *ssid)
+{
+ ssid[0] = 0;
+ return 0;
+}
+
+
+int driver_wired_get_bssid(void *priv, u8 *bssid)
+{
+ /* Report PAE group address as the "BSSID" for wired connection. */
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+ capa->flags = WPA_DRIVER_FLAGS_WIRED;
+ return 0;
+}
+
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+static int driver_wired_get_ifstatus(const char *ifname, int *status)
+{
+ struct ifmediareq ifmr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifmr, 0, sizeof(ifmr));
+ os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
+ (IFM_ACTIVE | IFM_AVALID);
+
+ return 0;
+}
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+
+
+int driver_wired_init_common(struct driver_wired_common_data *common,
+ const char *ifname, void *ctx)
+{
+ int flags;
+
+ os_strlcpy(common->ifname, ifname, sizeof(common->ifname));
+ common->ctx = ctx;
+
+#ifdef __linux__
+ common->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (common->pf_sock < 0)
+ wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
+#else /* __linux__ */
+ common->pf_sock = -1;
+#endif /* __linux__ */
+
+ if (driver_wired_get_ifflags(ifname, &flags) == 0 &&
+ !(flags & IFF_UP) &&
+ driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0)
+ common->iff_up = 1;
+
+ if (wired_multicast_membership(common->pf_sock,
+ if_nametoindex(common->ifname),
+ pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Added multicast membership with packet socket",
+ __func__);
+ common->membership = 1;
+ } else if (driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Added multicast membership with SIOCADDMULTI",
+ __func__);
+ common->multi = 1;
+ } else if (driver_wired_get_ifflags(ifname, &flags) < 0) {
+ wpa_printf(MSG_INFO, "%s: Could not get interface flags",
+ __func__);
+ return -1;
+ } else if (flags & IFF_ALLMULTI) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Interface is already configured for multicast",
+ __func__);
+ } else if (driver_wired_set_ifflags(ifname,
+ flags | IFF_ALLMULTI) < 0) {
+ wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", __func__);
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__);
+ common->iff_allmulti = 1;
+ }
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ {
+ int status;
+
+ wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
+ __func__);
+ while (driver_wired_get_ifstatus(ifname, &status) == 0 &&
+ status == 0)
+ sleep(1);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+
+ return 0;
+}
+
+
+void driver_wired_deinit_common(struct driver_wired_common_data *common)
+{
+ int flags;
+
+ if (common->membership &&
+ wired_multicast_membership(common->pf_sock,
+ if_nametoindex(common->ifname),
+ pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Failed to remove PAE multicast group (PACKET)",
+ __func__);
+ }
+
+ if (common->multi &&
+ driver_wired_multi(common->ifname, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Failed to remove PAE multicast group (SIOCDELMULTI)",
+ __func__);
+ }
+
+ if (common->iff_allmulti &&
+ (driver_wired_get_ifflags(common->ifname, &flags) < 0 ||
+ driver_wired_set_ifflags(common->ifname,
+ flags & ~IFF_ALLMULTI) < 0)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
+ __func__);
+ }
+
+ if (common->iff_up &&
+ driver_wired_get_ifflags(common->ifname, &flags) == 0 &&
+ (flags & IFF_UP) &&
+ driver_wired_set_ifflags(common->ifname, flags & ~IFF_UP) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
+ __func__);
+ }
+
+ if (common->pf_sock != -1)
+ close(common->pf_sock);
+}
diff --git a/contrib/wpa/src/drivers/driver_wired_common.h b/contrib/wpa/src/drivers/driver_wired_common.h
new file mode 100644
index 0000000..2bb0710
--- /dev/null
+++ b/contrib/wpa/src/drivers/driver_wired_common.h
@@ -0,0 +1,34 @@
+/*
+ * Common definitions for Wired Ethernet driver interfaces
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_WIRED_COMMON_H
+#define DRIVER_WIRED_COMMON_H
+
+struct driver_wired_common_data {
+ char ifname[IFNAMSIZ + 1];
+ void *ctx;
+
+ int sock; /* raw packet socket for driver access */
+ int pf_sock;
+ int membership, multi, iff_allmulti, iff_up;
+};
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+int wired_multicast_membership(int sock, int ifindex, const u8 *addr, int add);
+int driver_wired_get_ssid(void *priv, u8 *ssid);
+int driver_wired_get_bssid(void *priv, u8 *bssid);
+int driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa);
+
+int driver_wired_init_common(struct driver_wired_common_data *common,
+ const char *ifname, void *ctx);
+void driver_wired_deinit_common(struct driver_wired_common_data *common);
+
+#endif /* DRIVER_WIRED_COMMON_H */
diff --git a/contrib/wpa/src/drivers/drivers.c b/contrib/wpa/src/drivers/drivers.c
index a98af9ac..e95df6d 100644
--- a/contrib/wpa/src/drivers/drivers.c
+++ b/contrib/wpa/src/drivers/drivers.c
@@ -10,42 +10,6 @@
#include "utils/common.h"
#include "driver.h"
-#ifdef CONFIG_DRIVER_WEXT
-extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
-#endif /* CONFIG_DRIVER_WEXT */
-#ifdef CONFIG_DRIVER_NL80211
-extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
-#endif /* CONFIG_DRIVER_NL80211 */
-#ifdef CONFIG_DRIVER_HOSTAP
-extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
-#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_BSD
-extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
-#endif /* CONFIG_DRIVER_BSD */
-#ifdef CONFIG_DRIVER_OPENBSD
-extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */
-#endif /* CONFIG_DRIVER_OPENBSD */
-#ifdef CONFIG_DRIVER_NDIS
-extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
-#endif /* CONFIG_DRIVER_NDIS */
-#ifdef CONFIG_DRIVER_WIRED
-extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
-#endif /* CONFIG_DRIVER_WIRED */
-#ifdef CONFIG_DRIVER_MACSEC_QCA
- /* driver_macsec_qca.c */
-extern struct wpa_driver_ops wpa_driver_macsec_qca_ops;
-#endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_ROBOSWITCH
-/* driver_roboswitch.c */
-extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
-#endif /* CONFIG_DRIVER_ROBOSWITCH */
-#ifdef CONFIG_DRIVER_ATHEROS
-extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */
-#endif /* CONFIG_DRIVER_ATHEROS */
-#ifdef CONFIG_DRIVER_NONE
-extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
-#endif /* CONFIG_DRIVER_NONE */
-
const struct wpa_driver_ops *const wpa_drivers[] =
{
@@ -70,6 +34,9 @@ const struct wpa_driver_ops *const wpa_drivers[] =
#ifdef CONFIG_DRIVER_WIRED
&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_MACSEC_LINUX
+ &wpa_driver_macsec_linux_ops,
+#endif /* CONFIG_DRIVER_MACSEC_LINUX */
#ifdef CONFIG_DRIVER_MACSEC_QCA
&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
diff --git a/contrib/wpa/src/eap_common/eap_eke_common.c b/contrib/wpa/src/eap_common/eap_eke_common.c
index 4dfdb3f..438baf1 100644
--- a/contrib/wpa/src/eap_common/eap_eke_common.c
+++ b/contrib/wpa/src/eap_common/eap_eke_common.c
@@ -44,9 +44,7 @@ static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
int dhlen;
dhlen = eap_eke_dh_len(dhgroup);
- if (dhlen < 0)
- return -1;
- if (encr != EAP_EKE_ENCR_AES128_CBC)
+ if (dhlen < 0 || encr != EAP_EKE_ENCR_AES128_CBC)
return -1;
return AES_BLOCK_SIZE + dhlen;
}
@@ -163,44 +161,18 @@ int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
int generator;
u8 gen;
const struct dh_group *dh;
- size_t pub_len, i;
generator = eap_eke_dh_generator(group);
- if (generator < 0 || generator > 255)
- return -1;
- gen = generator;
-
dh = eap_eke_dh_group(group);
- if (dh == NULL)
+ if (generator < 0 || generator > 255 || !dh)
return -1;
+ gen = generator;
- /* x = random number 2 .. p-1 */
- if (random_get_bytes(ret_priv, dh->prime_len))
- return -1;
- if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
- /* Make sure private value is smaller than prime */
- ret_priv[0] = 0;
- }
- for (i = 0; i < dh->prime_len - 1; i++) {
- if (ret_priv[i])
- break;
- }
- if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
+ if (crypto_dh_init(gen, dh->prime, dh->prime_len, ret_priv,
+ ret_pub) < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
ret_priv, dh->prime_len);
-
- /* y = g ^ x (mod p) */
- pub_len = dh->prime_len;
- if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
- dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
- return -1;
- if (pub_len < dh->prime_len) {
- size_t pad = dh->prime_len - pub_len;
- os_memmove(ret_pub + pad, ret_pub, pub_len);
- os_memset(ret_pub, 0, pad);
- }
-
wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
ret_pub, dh->prime_len);
@@ -411,11 +383,8 @@ int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
size_t len;
const struct dh_group *dh;
- if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
- return -1;
-
dh = eap_eke_dh_group(sess->dhgroup);
- if (dh == NULL)
+ if (sess->encr != EAP_EKE_ENCR_AES128_CBC || !dh)
return -1;
/* Decrypt peer DHComponent */
@@ -429,8 +398,9 @@ int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
/* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
len = dh->prime_len;
- if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
- dh->prime, dh->prime_len, modexp, &len) < 0)
+ if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+ NULL, 0, dhpriv, dh->prime_len, peer_pub,
+ dh->prime_len, modexp, &len) < 0)
return -1;
if (len < dh->prime_len) {
size_t pad = dh->prime_len - len;
@@ -635,6 +605,7 @@ int eap_eke_prot(struct eap_eke_session *sess,
if (*prot_len < block_size + data_len + pad + icv_len) {
wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
+ return -1;
}
pos = prot;
@@ -653,10 +624,8 @@ int eap_eke_prot(struct eap_eke_session *sess,
pos += pad;
}
- if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
- return -1;
-
- if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
+ if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0 ||
+ eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
return -1;
pos += icv_len;
@@ -684,9 +653,8 @@ int eap_eke_decrypt_prot(struct eap_eke_session *sess,
else
return -1;
- if (prot_len < 2 * block_size + icv_len)
- return -1;
- if ((prot_len - icv_len) % block_size)
+ if (prot_len < 2 * block_size + icv_len ||
+ (prot_len - icv_len) % block_size)
return -1;
if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
@@ -737,22 +705,14 @@ int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
sess->mac = mac;
sess->prf_len = eap_eke_prf_len(prf);
- if (sess->prf_len < 0)
- return -1;
sess->nonce_len = eap_eke_nonce_len(prf);
- if (sess->nonce_len < 0)
- return -1;
sess->auth_len = eap_eke_auth_len(prf);
- if (sess->auth_len < 0)
- return -1;
sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
- if (sess->dhcomp_len < 0)
- return -1;
sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
- if (sess->pnonce_len < 0)
- return -1;
sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
- if (sess->pnonce_ps_len < 0)
+ if (sess->prf_len < 0 || sess->nonce_len < 0 || sess->auth_len < 0 ||
+ sess->dhcomp_len < 0 || sess->pnonce_len < 0 ||
+ sess->pnonce_ps_len < 0)
return -1;
return 0;
diff --git a/contrib/wpa/src/eap_common/eap_fast_common.c b/contrib/wpa/src/eap_common/eap_fast_common.c
index 151cc78..57990d2 100644
--- a/contrib/wpa/src/eap_common/eap_fast_common.c
+++ b/contrib/wpa/src/eap_common/eap_fast_common.c
@@ -79,7 +79,7 @@ void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
/*
* RFC 4851, Section 5.1:
- * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
+ * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
* server_random + client_random, 48)
*/
os_memcpy(seed, server_random, TLS_RANDOM_LEN);
@@ -93,8 +93,7 @@ void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
}
-u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
- const char *label, size_t len)
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, size_t len)
{
u8 *out;
@@ -102,7 +101,7 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
if (out == NULL)
return NULL;
- if (tls_connection_prf(ssl_ctx, conn, label, 1, 1, out, len)) {
+ if (tls_connection_get_eap_fast_key(ssl_ctx, conn, out, len)) {
os_free(out);
return NULL;
}
@@ -111,22 +110,24 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
}
-void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
+int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
{
/*
* RFC 4851, Section 5.4: EAP Master Session Key Generation
* MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
*/
- sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
- "Session Key Generating Function", (u8 *) "", 0,
- msk, EAP_FAST_KEY_LEN);
+ if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+ "Session Key Generating Function", (u8 *) "", 0,
+ msk, EAP_FAST_KEY_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
msk, EAP_FAST_KEY_LEN);
+ return 0;
}
-void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
+int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
{
/*
* RFC 4851, Section 5.4: EAP Master Session Key Genreration
@@ -134,11 +135,13 @@ void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
* "Extended Session Key Generating Function", 64)
*/
- sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
- "Extended Session Key Generating Function", (u8 *) "", 0,
- emsk, EAP_EMSK_LEN);
+ if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+ "Extended Session Key Generating Function", (u8 *) "", 0,
+ emsk, EAP_EMSK_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
emsk, EAP_EMSK_LEN);
+ return 0;
}
diff --git a/contrib/wpa/src/eap_common/eap_fast_common.h b/contrib/wpa/src/eap_common/eap_fast_common.h
index d59a845..724204c 100644
--- a/contrib/wpa/src/eap_common/eap_fast_common.h
+++ b/contrib/wpa/src/eap_common/eap_fast_common.h
@@ -98,9 +98,9 @@ struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf);
void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
const u8 *client_random, u8 *master_secret);
u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
- const char *label, size_t len);
-void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
-void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
+ size_t len);
+int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
+int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
int tlv_type, u8 *pos, size_t len);
diff --git a/contrib/wpa/src/eap_common/eap_gpsk_common.c b/contrib/wpa/src/eap_common/eap_gpsk_common.c
index 8c7ae27..b081879 100644
--- a/contrib/wpa/src/eap_common/eap_gpsk_common.c
+++ b/contrib/wpa/src/eap_common/eap_gpsk_common.c
@@ -92,7 +92,8 @@ static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */,
n = (len + hashlen - 1) / hashlen;
for (i = 1; i <= n; i++) {
WPA_PUT_BE16(ibuf, i);
- hmac_sha256_vector(psk, 32, 2, addr, vlen, hash);
+ if (hmac_sha256_vector(psk, 32, 2, addr, vlen, hash))
+ return -1;
clen = left > hashlen ? hashlen : left;
os_memcpy(opos, hash, clen);
opos += clen;
@@ -534,8 +535,7 @@ int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
break;
#ifdef EAP_GPSK_SHA256
case EAP_GPSK_CIPHER_SHA256:
- hmac_sha256(sk, sk_len, data, len, mic);
- ret = 0;
+ ret = hmac_sha256(sk, sk_len, data, len, mic);
break;
#endif /* EAP_GPSK_SHA256 */
default:
@@ -545,5 +545,8 @@ int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
break;
}
+ if (ret)
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Could not compute MIC");
+
return ret;
}
diff --git a/contrib/wpa/src/eap_common/eap_pax_common.c b/contrib/wpa/src/eap_common/eap_pax_common.c
index 0e80ef5..a11bce8 100644
--- a/contrib/wpa/src/eap_common/eap_pax_common.c
+++ b/contrib/wpa/src/eap_common/eap_pax_common.c
@@ -57,7 +57,8 @@ int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
left = output_len;
for (counter = 1; counter <= (u8) num_blocks; counter++) {
size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left;
- hmac_sha1_vector(key, key_len, 3, addr, len, mac);
+ if (hmac_sha1_vector(key, key_len, 3, addr, len, mac) < 0)
+ return -1;
os_memcpy(pos, mac, clen);
pos += clen;
left -= clen;
@@ -106,7 +107,8 @@ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
len[2] = data3_len;
count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
- hmac_sha1_vector(key, key_len, count, addr, len, hash);
+ if (hmac_sha1_vector(key, key_len, count, addr, len, hash) < 0)
+ return -1;
os_memcpy(mac, hash, EAP_PAX_MAC_LEN);
return 0;
diff --git a/contrib/wpa/src/eap_common/eap_pwd_common.c b/contrib/wpa/src/eap_common/eap_pwd_common.c
index 4d27623..884150e 100644
--- a/contrib/wpa/src/eap_common/eap_pwd_common.c
+++ b/contrib/wpa/src/eap_common/eap_pwd_common.c
@@ -8,11 +8,15 @@
#include "includes.h"
#include "common.h"
+#include "utils/const_time.h"
#include "crypto/sha256.h"
#include "crypto/crypto.h"
#include "eap_defs.h"
#include "eap_pwd_common.h"
+#define MAX_ECC_PRIME_LEN 66
+
+
/* The random function H(x) = HMAC-SHA256(0^32, x) */
struct crypto_hash * eap_pwd_h_init(void)
{
@@ -81,6 +85,49 @@ static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
}
+static int eap_pwd_suitable_group(u16 num)
+{
+ /* Do not allow ECC groups with prime under 256 bits based on guidance
+ * for the similar design in SAE. */
+ return num == 19 || num == 20 || num == 21 ||
+ num == 28 || num == 29 || num == 30;
+}
+
+
+EAP_PWD_group * get_eap_pwd_group(u16 num)
+{
+ EAP_PWD_group *grp;
+
+ if (!eap_pwd_suitable_group(num)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unsuitable group %u", num);
+ return NULL;
+ }
+ grp = os_zalloc(sizeof(EAP_PWD_group));
+ if (!grp)
+ return NULL;
+ grp->group = crypto_ec_init(num);
+ if (!grp->group) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC group");
+ os_free(grp);
+ return NULL;
+ }
+
+ grp->group_num = num;
+ wpa_printf(MSG_INFO, "EAP-pwd: provisioned group %d", num);
+
+ return grp;
+}
+
+
+static void buf_shift_right(u8 *buf, size_t len, size_t bits)
+{
+ size_t i;
+ for (i = len - 1; i > 0; i--)
+ buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
+ buf[0] >>= bits;
+}
+
+
/*
* compute a "random" secret point on an elliptic curve based
* on the password and identities.
@@ -91,85 +138,78 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
const u8 *id_peer, size_t id_peer_len,
const u8 *token)
{
- BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
+ struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL;
+ struct crypto_bignum *qr_or_qnr = NULL;
+ u8 qr_bin[MAX_ECC_PRIME_LEN];
+ u8 qnr_bin[MAX_ECC_PRIME_LEN];
+ u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN];
+ u8 x_bin[MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL;
struct crypto_hash *hash;
unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
- int nid, is_odd, ret = 0;
- size_t primebytelen, primebitlen;
-
- switch (num) { /* from IANA registry for IKE D-H groups */
- case 19:
- nid = NID_X9_62_prime256v1;
- break;
- case 20:
- nid = NID_secp384r1;
- break;
- case 21:
- nid = NID_secp521r1;
- break;
-#ifndef OPENSSL_IS_BORINGSSL
- case 25:
- nid = NID_X9_62_prime192v1;
- break;
-#endif /* OPENSSL_IS_BORINGSSL */
- case 26:
- nid = NID_secp224r1;
- break;
- default:
- wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num);
+ int ret = 0, check, res;
+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+ * mask */
+ size_t primebytelen = 0, primebitlen;
+ struct crypto_bignum *x_candidate = NULL;
+ const struct crypto_bignum *prime;
+ u8 mask, found_ctr = 0, is_odd = 0;
+
+ if (grp->pwe)
return -1;
- }
- grp->pwe = NULL;
- grp->order = NULL;
- grp->prime = NULL;
+ os_memset(x_bin, 0, sizeof(x_bin));
- if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP");
- goto fail;
- }
-
- if (((rnd = BN_new()) == NULL) ||
- ((cofactor = BN_new()) == NULL) ||
- ((grp->pwe = EC_POINT_new(grp->group)) == NULL) ||
- ((grp->order = BN_new()) == NULL) ||
- ((grp->prime = BN_new()) == NULL) ||
- ((x_candidate = BN_new()) == NULL)) {
+ prime = crypto_ec_get_prime(grp->group);
+ grp->pwe = crypto_ec_point_init(grp->group);
+ tmp1 = crypto_bignum_init();
+ pm1 = crypto_bignum_init();
+ one = crypto_bignum_init_set((const u8 *) "\x01", 1);
+ if (!grp->pwe || !tmp1 || !pm1 || !one) {
wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
goto fail;
}
- if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL))
- {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp "
- "curve");
- goto fail;
- }
- if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve");
- goto fail;
- }
- if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
- "curve");
- goto fail;
- }
- primebitlen = BN_num_bits(grp->prime);
- primebytelen = BN_num_bytes(grp->prime);
+ primebitlen = crypto_ec_prime_len_bits(grp->group);
+ primebytelen = crypto_ec_prime_len(grp->group);
if ((prfbuf = os_malloc(primebytelen)) == NULL) {
wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
"buffer");
goto fail;
}
- os_memset(prfbuf, 0, primebytelen);
- ctr = 0;
- while (1) {
- if (ctr > 30) {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
- "point on curve for group %d, something's "
- "fishy", num);
+ if (crypto_bignum_sub(prime, one, pm1) < 0)
+ goto fail;
+
+ /* get a random quadratic residue and nonresidue */
+ while (!qr || !qnr) {
+ if (crypto_bignum_rand(tmp1, prime) < 0)
goto fail;
+ res = crypto_bignum_legendre(tmp1, prime);
+ if (!qr && res == 1) {
+ qr = tmp1;
+ tmp1 = crypto_bignum_init();
+ } else if (!qnr && res == -1) {
+ qnr = tmp1;
+ tmp1 = crypto_bignum_init();
}
+ if (!tmp1)
+ goto fail;
+ }
+ if (crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin),
+ primebytelen) < 0 ||
+ crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin),
+ primebytelen) < 0)
+ goto fail;
+
+ os_memset(prfbuf, 0, primebytelen);
+ ctr = 0;
+
+ /*
+ * Run through the hunting-and-pecking loop 40 times to mask the time
+ * necessary to find PWE. The odds of PWE not being found in 40 loops is
+ * roughly 1 in 1 trillion.
+ */
+ while (ctr < 40) {
ctr++;
/*
@@ -187,114 +227,156 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
eap_pwd_h_update(hash, &ctr, sizeof(ctr));
eap_pwd_h_final(hash, pwe_digest);
- BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd);
-
+ is_odd = const_time_select_u8(
+ found, is_odd, pwe_digest[SHA256_MAC_LEN - 1] & 0x01);
if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
(u8 *) "EAP-pwd Hunting And Pecking",
os_strlen("EAP-pwd Hunting And Pecking"),
prfbuf, primebitlen) < 0)
goto fail;
-
- BN_bin2bn(prfbuf, primebytelen, x_candidate);
-
- /*
- * eap_pwd_kdf() returns a string of bits 0..primebitlen but
- * BN_bin2bn will treat that string of bits as a big endian
- * number. If the primebitlen is not an even multiple of 8
- * then excessive bits-- those _after_ primebitlen-- so now
- * we have to shift right the amount we masked off.
- */
if (primebitlen % 8)
- BN_rshift(x_candidate, x_candidate,
- (8 - (primebitlen % 8)));
+ buf_shift_right(prfbuf, primebytelen,
+ 8 - primebitlen % 8);
+
+ crypto_bignum_deinit(x_candidate, 1);
+ x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
+ if (!x_candidate) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: unable to create x_candidate");
+ goto fail;
+ }
- if (BN_ucmp(x_candidate, grp->prime) >= 0)
+ if (crypto_bignum_cmp(x_candidate, prime) >= 0)
continue;
- wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
- prfbuf, primebytelen);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: x_candidate",
+ prfbuf, primebytelen);
+ const_time_select_bin(found, x_bin, prfbuf, primebytelen,
+ x_bin);
/*
- * need to unambiguously identify the solution, if there is
- * one...
+ * compute y^2 using the equation of the curve
+ *
+ * y^2 = x^3 + ax + b
*/
- if (BN_is_odd(rnd))
- is_odd = 1;
- else
- is_odd = 0;
+ crypto_bignum_deinit(tmp2, 1);
+ tmp2 = crypto_ec_point_compute_y_sqr(grp->group, x_candidate);
+ if (!tmp2)
+ goto fail;
/*
- * solve the quadratic equation, if it's not solvable then we
- * don't have a point
+ * mask tmp2 so doing legendre won't leak timing info
+ *
+ * tmp1 is a random number between 1 and p-1
*/
- if (!EC_POINT_set_compressed_coordinates_GFp(grp->group,
- grp->pwe,
- x_candidate,
- is_odd, NULL))
- continue;
+ if (crypto_bignum_rand(tmp1, pm1) < 0 ||
+ crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0 ||
+ crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0)
+ goto fail;
+
/*
- * If there's a solution to the equation then the point must be
- * on the curve so why check again explicitly? OpenSSL code
- * says this is required by X9.62. We're not X9.62 but it can't
- * hurt just to be sure.
+ * Now tmp2 (y^2) is masked, all values between 1 and p-1
+ * are equally probable. Multiplying by r^2 does not change
+ * whether or not tmp2 is a quadratic residue, just masks it.
+ *
+ * Flip a coin, multiply by the random quadratic residue or the
+ * random quadratic nonresidue and record heads or tails.
*/
- if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
- continue;
- }
+ mask = const_time_eq_u8(crypto_bignum_is_odd(tmp1), 1);
+ check = const_time_select_s8(mask, 1, -1);
+ const_time_select_bin(mask, qr_bin, qnr_bin, primebytelen,
+ qr_or_qnr_bin);
+ crypto_bignum_deinit(qr_or_qnr, 1);
+ qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, primebytelen);
+ if (!qr_or_qnr ||
+ crypto_bignum_mulmod(tmp2, qr_or_qnr, prime, tmp2) < 0)
+ goto fail;
- if (BN_cmp(cofactor, BN_value_one())) {
- /* make sure the point is not in a small sub-group */
- if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe,
- cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd: cannot "
- "multiply generator by order");
- continue;
- }
- if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) {
- wpa_printf(MSG_INFO, "EAP-pwd: point is at "
- "infinity");
- continue;
- }
- }
- /* if we got here then we have a new generator. */
- break;
+ /*
+ * Now it's safe to do legendre, if check is 1 then it's
+ * a straightforward test (multiplying by qr does not
+ * change result), if check is -1 then it's the opposite test
+ * (multiplying a qr by qnr would make a qnr).
+ */
+ res = crypto_bignum_legendre(tmp2, prime);
+ if (res == -2)
+ goto fail;
+ mask = const_time_eq(res, check);
+ found_ctr = const_time_select_u8(found, found_ctr, ctr);
+ found |= mask;
}
- wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr);
- grp->group_num = num;
+ if (found == 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: unable to find random point on curve for group %d, something's fishy",
+ num);
+ goto fail;
+ }
+
+ /*
+ * We know x_candidate is a quadratic residue so set it here.
+ */
+ crypto_bignum_deinit(x_candidate, 1);
+ x_candidate = crypto_bignum_init_set(x_bin, primebytelen);
+ if (!x_candidate ||
+ crypto_ec_point_solve_y_coord(grp->group, grp->pwe, x_candidate,
+ is_odd) != 0) {
+ wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y");
+ goto fail;
+ }
+
+ /*
+ * If there's a solution to the equation then the point must be on the
+ * curve so why check again explicitly? OpenSSL code says this is
+ * required by X9.62. We're not X9.62 but it can't hurt just to be sure.
+ */
+ if (!crypto_ec_point_is_on_curve(grp->group, grp->pwe)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %02d tries", found_ctr);
+
if (0) {
fail:
- EC_GROUP_free(grp->group);
- grp->group = NULL;
- EC_POINT_clear_free(grp->pwe);
+ crypto_ec_point_deinit(grp->pwe, 1);
grp->pwe = NULL;
- BN_clear_free(grp->order);
- grp->order = NULL;
- BN_clear_free(grp->prime);
- grp->prime = NULL;
ret = 1;
}
/* cleanliness and order.... */
- BN_clear_free(cofactor);
- BN_clear_free(x_candidate);
- BN_clear_free(rnd);
- os_free(prfbuf);
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(pm1, 0);
+ crypto_bignum_deinit(tmp1, 1);
+ crypto_bignum_deinit(tmp2, 1);
+ crypto_bignum_deinit(qr, 1);
+ crypto_bignum_deinit(qnr, 1);
+ crypto_bignum_deinit(qr_or_qnr, 1);
+ crypto_bignum_deinit(one, 0);
+ bin_clear_free(prfbuf, primebytelen);
+ os_memset(qr_bin, 0, sizeof(qr_bin));
+ os_memset(qnr_bin, 0, sizeof(qnr_bin));
+ os_memset(qr_or_qnr_bin, 0, sizeof(qr_or_qnr_bin));
+ os_memset(pwe_digest, 0, sizeof(pwe_digest));
return ret;
}
-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
- const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
+int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k,
+ const struct crypto_bignum *peer_scalar,
+ const struct crypto_bignum *server_scalar,
const u8 *confirm_peer, const u8 *confirm_server,
const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id)
{
struct crypto_hash *hash;
u8 mk[SHA256_MAC_LEN], *cruft;
u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
- int offset;
+ size_t prime_len, order_len;
+
+ prime_len = crypto_ec_prime_len(grp->group);
+ order_len = crypto_ec_order_len(grp->group);
- if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
+ cruft = os_malloc(prime_len);
+ if (!cruft)
return -1;
/*
@@ -308,14 +390,10 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
return -1;
}
eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32));
- offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
- os_memset(cruft, 0, BN_num_bytes(grp->prime));
- BN_bn2bin(peer_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
- offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
- os_memset(cruft, 0, BN_num_bytes(grp->prime));
- BN_bn2bin(server_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
+ crypto_bignum_to_bin(peer_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
+ crypto_bignum_to_bin(server_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
eap_pwd_h_final(hash, &session_id[1]);
/* then compute MK = H(k | confirm-peer | confirm-server) */
@@ -324,10 +402,8 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
os_free(cruft);
return -1;
}
- offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
- os_memset(cruft, 0, BN_num_bytes(grp->prime));
- BN_bn2bin(k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime));
+ crypto_bignum_to_bin(k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
os_free(cruft);
eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN);
eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN);
@@ -345,3 +421,108 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
return 1;
}
+
+
+static int eap_pwd_element_coord_ok(const struct crypto_bignum *prime,
+ const u8 *buf, size_t len)
+{
+ struct crypto_bignum *val;
+ int ok = 1;
+
+ val = crypto_bignum_init_set(buf, len);
+ if (!val || crypto_bignum_is_zero(val) ||
+ crypto_bignum_cmp(val, prime) >= 0)
+ ok = 0;
+ crypto_bignum_deinit(val, 0);
+ return ok;
+}
+
+
+struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
+ const u8 *buf)
+{
+ struct crypto_ec_point *element;
+ const struct crypto_bignum *prime;
+ size_t prime_len;
+
+ prime = crypto_ec_get_prime(group->group);
+ prime_len = crypto_ec_prime_len(group->group);
+
+ /* RFC 5931, 2.8.5.2.2: 0 < x,y < p */
+ if (!eap_pwd_element_coord_ok(prime, buf, prime_len) ||
+ !eap_pwd_element_coord_ok(prime, buf + prime_len, prime_len)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: Invalid coordinate in element");
+ return NULL;
+ }
+
+ element = crypto_ec_point_from_bin(group->group, buf);
+ if (!element) {
+ wpa_printf(MSG_INFO, "EAP-pwd: EC point from element failed");
+ return NULL;
+ }
+
+ /* RFC 5931, 2.8.5.2.2: on curve and not the point at infinity */
+ if (!crypto_ec_point_is_on_curve(group->group, element) ||
+ crypto_ec_point_is_at_infinity(group->group, element)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: Invalid element");
+ goto fail;
+ }
+
+out:
+ return element;
+fail:
+ crypto_ec_point_deinit(element, 0);
+ element = NULL;
+ goto out;
+}
+
+
+struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf)
+{
+ struct crypto_bignum *scalar;
+ const struct crypto_bignum *order;
+ size_t order_len;
+
+ order = crypto_ec_get_order(group->group);
+ order_len = crypto_ec_order_len(group->group);
+
+ /* RFC 5931, 2.8.5.2: 1 < scalar < r */
+ scalar = crypto_bignum_init_set(buf, order_len);
+ if (!scalar || crypto_bignum_is_zero(scalar) ||
+ crypto_bignum_is_one(scalar) ||
+ crypto_bignum_cmp(scalar, order) >= 0) {
+ wpa_printf(MSG_INFO, "EAP-pwd: received scalar is invalid");
+ crypto_bignum_deinit(scalar, 0);
+ scalar = NULL;
+ }
+
+ return scalar;
+}
+
+
+int eap_pwd_get_rand_mask(EAP_PWD_group *group, struct crypto_bignum *_rand,
+ struct crypto_bignum *_mask,
+ struct crypto_bignum *scalar)
+{
+ const struct crypto_bignum *order;
+ int count;
+
+ order = crypto_ec_get_order(group->group);
+
+ /* Select two random values rand,mask such that 1 < rand,mask < r and
+ * rand + mask mod r > 1. */
+ for (count = 0; count < 100; count++) {
+ if (crypto_bignum_rand(_rand, order) == 0 &&
+ !crypto_bignum_is_zero(_rand) &&
+ crypto_bignum_rand(_mask, order) == 0 &&
+ !crypto_bignum_is_zero(_mask) &&
+ crypto_bignum_add(_rand, _mask, scalar) == 0 &&
+ crypto_bignum_mod(scalar, order, scalar) == 0 &&
+ !crypto_bignum_is_zero(scalar) &&
+ !crypto_bignum_is_one(scalar))
+ return 0;
+ }
+
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to get randomness");
+ return -1;
+}
diff --git a/contrib/wpa/src/eap_common/eap_pwd_common.h b/contrib/wpa/src/eap_common/eap_pwd_common.h
index a0d717e..c48acee 100644
--- a/contrib/wpa/src/eap_common/eap_pwd_common.h
+++ b/contrib/wpa/src/eap_common/eap_pwd_common.h
@@ -9,20 +9,14 @@
#ifndef EAP_PWD_COMMON_H
#define EAP_PWD_COMMON_H
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/evp.h>
-
/*
* definition of a finite cyclic group
* TODO: support one based on a prime field
*/
typedef struct group_definition_ {
u16 group_num;
- EC_GROUP *group;
- EC_POINT *pwe;
- BIGNUM *order;
- BIGNUM *prime;
+ struct crypto_ec *group;
+ struct crypto_ec_point *pwe;
} EAP_PWD_group;
/*
@@ -52,21 +46,32 @@ struct eap_pwd_id {
u8 prep;
#define EAP_PWD_PREP_NONE 0
#define EAP_PWD_PREP_MS 1
+#define EAP_PWD_PREP_SSHA1 3
+#define EAP_PWD_PREP_SSHA256 4
+#define EAP_PWD_PREP_SSHA512 5
u8 identity[0]; /* length inferred from payload */
} STRUCT_PACKED;
/* common routines */
+EAP_PWD_group * get_eap_pwd_group(u16 num);
int compute_password_element(EAP_PWD_group *grp, u16 num,
const u8 *password, size_t password_len,
const u8 *id_server, size_t id_server_len,
const u8 *id_peer, size_t id_peer_len,
const u8 *token);
-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
- const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
+int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k,
+ const struct crypto_bignum *peer_scalar,
+ const struct crypto_bignum *server_scalar,
const u8 *confirm_peer, const u8 *confirm_server,
const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id);
struct crypto_hash * eap_pwd_h_init(void);
void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
+struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
+ const u8 *buf);
+struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf);
+int eap_pwd_get_rand_mask(EAP_PWD_group *group, struct crypto_bignum *_rand,
+ struct crypto_bignum *_mask,
+ struct crypto_bignum *scalar);
#endif /* EAP_PWD_COMMON_H */
diff --git a/contrib/wpa/src/eap_common/eap_sake_common.c b/contrib/wpa/src/eap_common/eap_sake_common.c
index c22e43e..8ee9e32 100644
--- a/contrib/wpa/src/eap_common/eap_sake_common.c
+++ b/contrib/wpa/src/eap_common/eap_sake_common.c
@@ -1,6 +1,6 @@
/*
* EAP server/peer: EAP-SAKE shared routines
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -121,7 +121,7 @@ static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
attr->next_tmpid_len = len;
break;
case EAP_SAKE_AT_MSK_LIFE:
- wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MSK_LIFE");
if (len != 4) {
wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
"AT_MSK_LIFE payload length %d", len);
@@ -201,14 +201,15 @@ int eap_sake_parse_attributes(const u8 *buf, size_t len,
* @data2_len: Length of the data2
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success or -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i.
*/
-static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len,
- const u8 *data2, size_t data2_len,
- u8 *buf, size_t buf_len)
+static int eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len,
+ const u8 *data2, size_t data2_len,
+ u8 *buf, size_t buf_len)
{
u8 counter = 0;
size_t pos, plen;
@@ -230,17 +231,21 @@ static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
while (pos < buf_len) {
plen = buf_len - pos;
if (plen >= SHA1_MAC_LEN) {
- hmac_sha1_vector(key, key_len, 4, addr, len,
- &buf[pos]);
+ if (hmac_sha1_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
pos += SHA1_MAC_LEN;
} else {
- hmac_sha1_vector(key, key_len, 4, addr, len,
- hash);
+ if (hmac_sha1_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
os_memcpy(&buf[pos], hash, plen);
break;
}
counter++;
}
+
+ return 0;
}
@@ -253,12 +258,13 @@ static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
* @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16])
* @msk: Buffer for 64-byte MSK
* @emsk: Buffer for 64-byte EMSK
+ * Returns: 0 on success or -1 on failure
*
* This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6.
*/
-void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
- const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
- u8 *emsk)
+int eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+ const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
+ u8 *emsk)
{
u8 sms_a[EAP_SAKE_SMS_LEN];
u8 sms_b[EAP_SAKE_SMS_LEN];
@@ -268,14 +274,16 @@ void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
- eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
- "SAKE Master Secret A",
- rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
- sms_a, EAP_SAKE_SMS_LEN);
+ if (eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
+ "SAKE Master Secret A",
+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+ sms_a, EAP_SAKE_SMS_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
- eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
- rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
- tek, EAP_SAKE_TEK_LEN);
+ if (eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+ tek, EAP_SAKE_TEK_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
tek, EAP_SAKE_TEK_AUTH_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
@@ -283,18 +291,21 @@ void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
- eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
- "SAKE Master Secret B",
- rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
- sms_b, EAP_SAKE_SMS_LEN);
+ if (eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
+ "SAKE Master Secret B",
+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+ sms_b, EAP_SAKE_SMS_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
- eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
- rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
- key_buf, sizeof(key_buf));
+ if (eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+ key_buf, sizeof(key_buf)) < 0)
+ return -1;
os_memcpy(msk, key_buf, EAP_MSK_LEN);
os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
+ return 0;
}
@@ -312,6 +323,7 @@ void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
* @eap_len: EAP packet length
* @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len])
* @mic: Buffer for the computed 16-byte MIC
+ * Returns: 0 on success or -1 on failure
*/
int eap_sake_compute_mic(const u8 *tek_auth,
const u8 *rand_s, const u8 *rand_p,
@@ -323,6 +335,7 @@ int eap_sake_compute_mic(const u8 *tek_auth,
u8 _rand[2 * EAP_SAKE_RAND_LEN];
u8 *tmp, *pos;
size_t tmplen;
+ int ret;
tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
tmp = os_malloc(tmplen);
@@ -364,14 +377,14 @@ int eap_sake_compute_mic(const u8 *tek_auth,
os_memcpy(pos, eap, eap_len);
os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
- eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
- peer ? "Peer MIC" : "Server MIC",
- _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
- mic, EAP_SAKE_MIC_LEN);
+ ret = eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
+ peer ? "Peer MIC" : "Server MIC",
+ _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
+ mic, EAP_SAKE_MIC_LEN);
os_free(tmp);
- return 0;
+ return ret;
}
diff --git a/contrib/wpa/src/eap_common/eap_sake_common.h b/contrib/wpa/src/eap_common/eap_sake_common.h
index 9e1e757..a817a35 100644
--- a/contrib/wpa/src/eap_common/eap_sake_common.h
+++ b/contrib/wpa/src/eap_common/eap_sake_common.h
@@ -1,6 +1,6 @@
/*
* EAP server/peer: EAP-SAKE shared routines
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -81,9 +81,9 @@ struct eap_sake_parse_attr {
int eap_sake_parse_attributes(const u8 *buf, size_t len,
struct eap_sake_parse_attr *attr);
-void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
- const u8 *rand_s, const u8 *rand_p,
- u8 *tek, u8 *msk, u8 *emsk);
+int eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+ const u8 *rand_s, const u8 *rand_p,
+ u8 *tek, u8 *msk, u8 *emsk);
int eap_sake_compute_mic(const u8 *tek_auth,
const u8 *rand_s, const u8 *rand_p,
const u8 *serverid, size_t serverid_len,
diff --git a/contrib/wpa/src/eap_common/eap_sim_common.c b/contrib/wpa/src/eap_common/eap_sim_common.c
index 2adc3b3..6290c35 100644
--- a/contrib/wpa/src/eap_common/eap_sim_common.c
+++ b/contrib/wpa/src/eap_common/eap_sim_common.c
@@ -175,7 +175,7 @@ int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
return -1;
- tmp = os_malloc(wpabuf_len(req));
+ tmp = os_memdup(wpabuf_head(req), wpabuf_len(req));
if (tmp == NULL)
return -1;
@@ -185,7 +185,6 @@ int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
len[1] = extra_len;
/* HMAC-SHA1-128 */
- os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg",
tmp, wpabuf_len(req));
@@ -370,7 +369,7 @@ int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
return -1;
- tmp = os_malloc(wpabuf_len(req));
+ tmp = os_memdup(wpabuf_head(req), wpabuf_len(req));
if (tmp == NULL)
return -1;
@@ -380,7 +379,6 @@ int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
len[1] = extra_len;
/* HMAC-SHA-256-128 */
- os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg",
tmp, wpabuf_len(req));
@@ -943,10 +941,9 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
return NULL;
}
- decrypted = os_malloc(encr_data_len);
+ decrypted = os_memdup(encr_data, encr_data_len);
if (decrypted == NULL)
return NULL;
- os_memcpy(decrypted, encr_data, encr_data_len);
if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
os_free(decrypted);
diff --git a/contrib/wpa/src/eap_common/ikev2_common.c b/contrib/wpa/src/eap_common/ikev2_common.c
index d60358c..90fb89e 100644
--- a/contrib/wpa/src/eap_common/ikev2_common.c
+++ b/contrib/wpa/src/eap_common/ikev2_common.c
@@ -62,13 +62,15 @@ int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
case AUTH_HMAC_SHA1_96:
if (key_len != 20)
return -1;
- hmac_sha1(key, key_len, data, data_len, tmphash);
+ if (hmac_sha1(key, key_len, data, data_len, tmphash) < 0)
+ return -1;
os_memcpy(hash, tmphash, 12);
break;
case AUTH_HMAC_MD5_96:
if (key_len != 16)
return -1;
- hmac_md5(key, key_len, data, data_len, tmphash);
+ if (hmac_md5(key, key_len, data, data_len, tmphash) < 0)
+ return -1;
os_memcpy(hash, tmphash, 12);
break;
default:
@@ -98,16 +100,13 @@ int ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
{
switch (alg) {
case PRF_HMAC_SHA1:
- hmac_sha1_vector(key, key_len, num_elem, addr, len, hash);
- break;
+ return hmac_sha1_vector(key, key_len, num_elem, addr, len,
+ hash);
case PRF_HMAC_MD5:
- hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
- break;
+ return hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
default:
return -1;
}
-
- return 0;
}
diff --git a/contrib/wpa/src/eap_peer/eap.c b/contrib/wpa/src/eap_peer/eap.c
index 56c24b5..974c475 100644
--- a/contrib/wpa/src/eap_peer/eap.c
+++ b/contrib/wpa/src/eap_peer/eap.c
@@ -48,6 +48,8 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
static const char * eap_sm_method_state_txt(EapMethodState state);
static const char * eap_sm_decision_txt(EapDecision decision);
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
+ const char *msg, size_t msglen);
@@ -93,6 +95,14 @@ static void eap_notify_status(struct eap_sm *sm, const char *status,
}
+static void eap_report_error(struct eap_sm *sm, int error_code)
+{
+ wpa_printf(MSG_DEBUG, "EAP: Error notification: %d", error_code);
+ if (sm->eapol_cb->notify_eap_error)
+ sm->eapol_cb->notify_eap_error(sm->eapol_ctx, error_code);
+}
+
+
static void eap_sm_free_key(struct eap_sm *sm)
{
if (sm->eapKeyData) {
@@ -119,15 +129,17 @@ static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
/**
- * eap_allowed_method - Check whether EAP method is allowed
+ * eap_config_allowed_method - Check whether EAP method is allowed
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @config: EAP configuration
* @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
* @method: EAP type
* Returns: 1 = allowed EAP method, 0 = not allowed
*/
-int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
+static int eap_config_allowed_method(struct eap_sm *sm,
+ struct eap_peer_config *config,
+ int vendor, u32 method)
{
- struct eap_peer_config *config = eap_get_config(sm);
int i;
struct eap_method_type *m;
@@ -144,6 +156,57 @@ int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
}
+/**
+ * eap_allowed_method - Check whether EAP method is allowed
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
+ * @method: EAP type
+ * Returns: 1 = allowed EAP method, 0 = not allowed
+ */
+int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
+{
+ return eap_config_allowed_method(sm, eap_get_config(sm), vendor,
+ method);
+}
+
+
+#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
+static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi,
+ size_t max_len, size_t *imsi_len,
+ int mnc_len)
+{
+ char *pos, mnc[4];
+
+ if (*imsi_len + 36 > max_len) {
+ wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer");
+ return -1;
+ }
+
+ if (mnc_len != 2 && mnc_len != 3)
+ mnc_len = 3;
+
+ if (mnc_len == 2) {
+ mnc[0] = '0';
+ mnc[1] = imsi[3];
+ mnc[2] = imsi[4];
+ } else if (mnc_len == 3) {
+ mnc[0] = imsi[3];
+ mnc[1] = imsi[4];
+ mnc[2] = imsi[5];
+ }
+ mnc[3] = '\0';
+
+ pos = imsi + *imsi_len;
+ pos += os_snprintf(pos, imsi + max_len - pos,
+ "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org",
+ mnc, imsi[0], imsi[1], imsi[2]);
+ *imsi_len = pos - imsi;
+
+ return 0;
+}
+#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
+
+
/*
* This state initializes state machine variables when the machine is
* activated (portEnabled = TRUE). This is also used when re-starting
@@ -188,6 +251,14 @@ SM_STATE(EAP, INITIALIZE)
*/
eapol_set_bool(sm, EAPOL_eapResp, FALSE);
eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
+ /*
+ * RFC 4137 does not reset ignore here, but since it is possible for
+ * some method code paths to end up not setting ignore=FALSE, clear the
+ * value here to avoid issues if a previous authentication attempt
+ * failed with ignore=TRUE being left behind in the last
+ * m.check(eapReqData) operation.
+ */
+ sm->ignore = 0;
sm->num_rounds = 0;
sm->prev_failure = 0;
sm->expected_failure = 0;
@@ -312,11 +383,14 @@ SM_STATE(EAP, GET_METHOD)
wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
"vendor %u method %u (%s)",
sm->reqVendor, method, sm->m->name);
- if (reinit)
+ if (reinit) {
sm->eap_method_priv = sm->m->init_for_reauth(
sm, sm->eap_method_priv);
- else
+ } else {
+ sm->waiting_ext_cert_check = 0;
+ sm->ext_cert_check = 0;
sm->eap_method_priv = sm->m->init(sm);
+ }
if (sm->eap_method_priv == NULL) {
struct eap_peer_config *config = eap_get_config(sm);
@@ -358,9 +432,8 @@ nak:
#ifdef CONFIG_ERP
-static char * eap_home_realm(struct eap_sm *sm)
+static char * eap_get_realm(struct eap_sm *sm, struct eap_peer_config *config)
{
- struct eap_peer_config *config = eap_get_config(sm);
char *realm;
size_t i, realm_len;
@@ -400,7 +473,51 @@ static char * eap_home_realm(struct eap_sm *sm)
}
}
- return os_strdup("");
+#ifdef CONFIG_EAP_PROXY
+ /* When identity is not provided in the config, build the realm from
+ * IMSI for eap_proxy based methods.
+ */
+ if (!config->identity && !config->anonymous_identity &&
+ sm->eapol_cb->get_imsi &&
+ (eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
+ EAP_TYPE_SIM) ||
+ eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
+ EAP_TYPE_AKA) ||
+ eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
+ EAP_TYPE_AKA_PRIME))) {
+ char imsi[100];
+ size_t imsi_len;
+ int mnc_len, pos;
+
+ wpa_printf(MSG_DEBUG, "EAP: Build realm from IMSI (eap_proxy)");
+ mnc_len = sm->eapol_cb->get_imsi(sm->eapol_ctx, config->sim_num,
+ imsi, &imsi_len);
+ if (mnc_len < 0)
+ return NULL;
+
+ pos = imsi_len + 1; /* points to the beginning of the realm */
+ if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len,
+ mnc_len) < 0) {
+ wpa_printf(MSG_WARNING, "Could not append realm");
+ return NULL;
+ }
+
+ realm = os_strdup(&imsi[pos]);
+ if (!realm)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "EAP: Generated realm '%s'", realm);
+ return realm;
+ }
+#endif /* CONFIG_EAP_PROXY */
+
+ return NULL;
+}
+
+
+static char * eap_home_realm(struct eap_sm *sm)
+{
+ return eap_get_realm(sm, eap_get_config(sm));
}
@@ -456,6 +573,89 @@ static void eap_erp_remove_keys_realm(struct eap_sm *sm, const char *realm)
}
}
+
+int eap_peer_update_erp_next_seq_num(struct eap_sm *sm, u16 next_seq_num)
+{
+ struct eap_erp_key *erp;
+ char *home_realm;
+
+ home_realm = eap_home_realm(sm);
+ if (!home_realm || os_strlen(home_realm) == 0) {
+ os_free(home_realm);
+ return -1;
+ }
+
+ erp = eap_erp_get_key(sm, home_realm);
+ if (!erp) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Failed to find ERP key for realm: %s",
+ home_realm);
+ os_free(home_realm);
+ return -1;
+ }
+
+ if ((u32) next_seq_num < erp->next_seq) {
+ /* Sequence number has wrapped around, clear this ERP
+ * info and do a full auth next time.
+ */
+ eap_peer_erp_free_key(erp);
+ } else {
+ erp->next_seq = (u32) next_seq_num;
+ }
+
+ os_free(home_realm);
+ return 0;
+}
+
+
+int eap_peer_get_erp_info(struct eap_sm *sm, struct eap_peer_config *config,
+ const u8 **username, size_t *username_len,
+ const u8 **realm, size_t *realm_len,
+ u16 *erp_next_seq_num, const u8 **rrk,
+ size_t *rrk_len)
+{
+ struct eap_erp_key *erp;
+ char *home_realm;
+ char *pos;
+
+ if (config)
+ home_realm = eap_get_realm(sm, config);
+ else
+ home_realm = eap_home_realm(sm);
+ if (!home_realm || os_strlen(home_realm) == 0) {
+ os_free(home_realm);
+ return -1;
+ }
+
+ erp = eap_erp_get_key(sm, home_realm);
+ os_free(home_realm);
+ if (!erp)
+ return -1;
+
+ if (erp->next_seq >= 65536)
+ return -1; /* SEQ has range of 0..65535 */
+
+ pos = os_strchr(erp->keyname_nai, '@');
+ if (!pos)
+ return -1; /* this cannot really happen */
+ *username_len = pos - erp->keyname_nai;
+ *username = (u8 *) erp->keyname_nai;
+
+ pos++;
+ *realm_len = os_strlen(pos);
+ *realm = (u8 *) pos;
+
+ *erp_next_seq_num = (u16) erp->next_seq;
+
+ *rrk_len = erp->rRK_len;
+ *rrk = erp->rRK;
+
+ if (*username_len == 0 || *realm_len == 0 || *rrk_len == 0)
+ return -1;
+
+ return 0;
+}
+
#endif /* CONFIG_ERP */
@@ -470,13 +670,20 @@ void eap_peer_erp_free_keys(struct eap_sm *sm)
}
-static void eap_peer_erp_init(struct eap_sm *sm)
+/* Note: If ext_session and/or ext_emsk are passed to this function, they are
+ * expected to point to allocated memory and those allocations will be freed
+ * unconditionally. */
+void eap_peer_erp_init(struct eap_sm *sm, u8 *ext_session_id,
+ size_t ext_session_id_len, u8 *ext_emsk,
+ size_t ext_emsk_len)
{
#ifdef CONFIG_ERP
u8 *emsk = NULL;
size_t emsk_len = 0;
+ u8 *session_id = NULL;
+ size_t session_id_len = 0;
u8 EMSKname[EAP_EMSK_NAME_LEN];
- u8 len[2];
+ u8 len[2], ctx[3];
char *realm;
size_t realm_len, nai_buf_len;
struct eap_erp_key *erp = NULL;
@@ -484,7 +691,7 @@ static void eap_peer_erp_init(struct eap_sm *sm)
realm = eap_home_realm(sm);
if (!realm)
- return;
+ goto fail;
realm_len = os_strlen(realm);
wpa_printf(MSG_DEBUG, "EAP: Realm for ERP keyName-NAI: %s", realm);
eap_erp_remove_keys_realm(sm, realm);
@@ -504,7 +711,13 @@ static void eap_peer_erp_init(struct eap_sm *sm)
if (erp == NULL)
goto fail;
- emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
+ if (ext_emsk) {
+ emsk = ext_emsk;
+ emsk_len = ext_emsk_len;
+ } else {
+ emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
+ }
+
if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
wpa_printf(MSG_DEBUG,
"EAP: No suitable EMSK available for ERP");
@@ -513,10 +726,23 @@ static void eap_peer_erp_init(struct eap_sm *sm)
wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
- WPA_PUT_BE16(len, 8);
- if (hmac_sha256_kdf(sm->eapSessionId, sm->eapSessionIdLen, "EMSK",
- len, sizeof(len),
- EMSKname, EAP_EMSK_NAME_LEN) < 0) {
+ if (ext_session_id) {
+ session_id = ext_session_id;
+ session_id_len = ext_session_id_len;
+ } else {
+ session_id = sm->eapSessionId;
+ session_id_len = sm->eapSessionIdLen;
+ }
+
+ if (!session_id || session_id_len == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No suitable session id available for ERP");
+ goto fail;
+ }
+
+ WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
+ if (hmac_sha256_kdf(session_id, session_id_len, "EMSK", len,
+ sizeof(len), EMSKname, EAP_EMSK_NAME_LEN) < 0) {
wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
goto fail;
}
@@ -537,9 +763,11 @@ static void eap_peer_erp_init(struct eap_sm *sm)
erp->rRK_len = emsk_len;
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+ ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
+ WPA_PUT_BE16(&ctx[1], erp->rRK_len);
if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
- "EAP Re-authentication Integrity Key@ietf.org",
- len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ "Re-authentication Integrity Key@ietf.org",
+ ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
goto fail;
}
@@ -550,7 +778,11 @@ static void eap_peer_erp_init(struct eap_sm *sm)
dl_list_add(&sm->erp_keys, &erp->list);
erp = NULL;
fail:
- bin_clear_free(emsk, emsk_len);
+ if (ext_emsk)
+ bin_clear_free(ext_emsk, ext_emsk_len);
+ else
+ bin_clear_free(emsk, emsk_len);
+ bin_clear_free(ext_session_id, ext_session_id_len);
bin_clear_free(erp, sizeof(*erp));
os_free(realm);
#endif /* CONFIG_ERP */
@@ -558,8 +790,7 @@ fail:
#ifdef CONFIG_ERP
-static int eap_peer_erp_reauth_start(struct eap_sm *sm,
- const struct eap_hdr *hdr, size_t len)
+struct wpabuf * eap_peer_build_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
{
char *realm;
struct eap_erp_key *erp;
@@ -568,16 +799,16 @@ static int eap_peer_erp_reauth_start(struct eap_sm *sm,
realm = eap_home_realm(sm);
if (!realm)
- return -1;
+ return NULL;
erp = eap_erp_get_key(sm, realm);
os_free(realm);
realm = NULL;
if (!erp)
- return -1;
+ return NULL;
if (erp->next_seq >= 65536)
- return -1; /* SEQ has range of 0..65535 */
+ return NULL; /* SEQ has range of 0..65535 */
/* TODO: check rRK lifetime expiration */
@@ -586,9 +817,9 @@ static int eap_peer_erp_reauth_start(struct eap_sm *sm,
msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
- EAP_CODE_INITIATE, hdr->identifier);
+ EAP_CODE_INITIATE, eap_id);
if (msg == NULL)
- return -1;
+ return NULL;
wpabuf_put_u8(msg, 0x20); /* Flags: R=0 B=0 L=1 */
wpabuf_put_be16(msg, erp->next_seq);
@@ -602,13 +833,28 @@ static int eap_peer_erp_reauth_start(struct eap_sm *sm,
if (hmac_sha256(erp->rIK, erp->rIK_len,
wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
wpabuf_free(msg);
- return -1;
+ return NULL;
}
wpabuf_put_data(msg, hash, 16);
- wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
sm->erp_seq = erp->next_seq;
erp->next_seq++;
+
+ wpa_hexdump_buf(MSG_DEBUG, "ERP: EAP-Initiate/Re-auth", msg);
+
+ return msg;
+}
+
+
+static int eap_peer_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
+{
+ struct wpabuf *msg;
+
+ msg = eap_peer_build_erp_reauth_start(sm, eap_id);
+ if (!msg)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
wpabuf_free(sm->eapRespData);
sm->eapRespData = msg;
sm->reauthInit = TRUE;
@@ -678,8 +924,6 @@ SM_STATE(EAP, METHOD)
if (sm->m->isKeyAvailable && sm->m->getKey &&
sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
- struct eap_peer_config *config = eap_get_config(sm);
-
eap_sm_free_key(sm);
sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
&sm->eapKeyDataLen);
@@ -692,8 +936,6 @@ SM_STATE(EAP, METHOD)
wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
sm->eapSessionId, sm->eapSessionIdLen);
}
- if (config->erp && sm->m->get_emsk && sm->eapSessionId)
- eap_peer_erp_init(sm);
}
}
@@ -791,6 +1033,8 @@ SM_STATE(EAP, RETRANSMIT)
*/
SM_STATE(EAP, SUCCESS)
{
+ struct eap_peer_config *config = eap_get_config(sm);
+
SM_ENTRY(EAP, SUCCESS);
if (sm->eapKeyData != NULL)
sm->eapKeyAvailable = TRUE;
@@ -813,6 +1057,11 @@ SM_STATE(EAP, SUCCESS)
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
"EAP authentication completed successfully");
+
+ if (config->erp && sm->m->get_emsk && sm->eapSessionId &&
+ sm->m->isKeyAvailable &&
+ sm->m->isKeyAvailable(sm, sm->eap_method_priv))
+ eap_peer_erp_init(sm, NULL, 0, NULL, 0);
}
@@ -1263,48 +1512,6 @@ static int mnc_len_from_imsi(const char *imsi)
}
-static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi,
- size_t max_len, size_t *imsi_len)
-{
- int mnc_len;
- char *pos, mnc[4];
-
- if (*imsi_len + 36 > max_len) {
- wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer");
- return -1;
- }
-
- /* MNC (2 or 3 digits) */
- mnc_len = scard_get_mnc_len(sm->scard_ctx);
- if (mnc_len < 0)
- mnc_len = mnc_len_from_imsi(imsi);
- if (mnc_len < 0) {
- wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM "
- "assuming 3");
- mnc_len = 3;
- }
-
- if (mnc_len == 2) {
- mnc[0] = '0';
- mnc[1] = imsi[3];
- mnc[2] = imsi[4];
- } else if (mnc_len == 3) {
- mnc[0] = imsi[3];
- mnc[1] = imsi[4];
- mnc[2] = imsi[5];
- }
- mnc[3] = '\0';
-
- pos = imsi + *imsi_len;
- pos += os_snprintf(pos, imsi + max_len - pos,
- "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org",
- mnc, imsi[0], imsi[1], imsi[2]);
- *imsi_len = pos - imsi;
-
- return 0;
-}
-
-
static int eap_sm_imsi_identity(struct eap_sm *sm,
struct eap_peer_config *conf)
{
@@ -1312,7 +1519,7 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
char imsi[100];
size_t imsi_len;
struct eap_method_type *m = conf->eap_methods;
- int i;
+ int i, mnc_len;
imsi_len = sizeof(imsi);
if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
@@ -1327,7 +1534,18 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
return -1;
}
- if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len) < 0) {
+ /* MNC (2 or 3 digits) */
+ mnc_len = scard_get_mnc_len(sm->scard_ctx);
+ if (mnc_len < 0)
+ mnc_len = mnc_len_from_imsi(imsi);
+ if (mnc_len < 0) {
+ wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM "
+ "assuming 3");
+ mnc_len = 3;
+ }
+
+ if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len,
+ mnc_len) < 0) {
wpa_printf(MSG_WARNING, "Could not add realm to SIM identity");
return -1;
}
@@ -1373,13 +1591,10 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
return 0;
}
-#endif /* PCSC_FUNCS */
-
static int eap_sm_set_scard_pin(struct eap_sm *sm,
struct eap_peer_config *conf)
{
-#ifdef PCSC_FUNCS
if (scard_set_pin(sm->scard_ctx, conf->pin)) {
/*
* Make sure the same PIN is not tried again in order to avoid
@@ -1393,24 +1608,20 @@ static int eap_sm_set_scard_pin(struct eap_sm *sm,
return -1;
}
return 0;
-#else /* PCSC_FUNCS */
- return -1;
-#endif /* PCSC_FUNCS */
}
+
static int eap_sm_get_scard_identity(struct eap_sm *sm,
struct eap_peer_config *conf)
{
-#ifdef PCSC_FUNCS
if (eap_sm_set_scard_pin(sm, conf))
return -1;
return eap_sm_imsi_identity(sm, conf);
-#else /* PCSC_FUNCS */
- return -1;
-#endif /* PCSC_FUNCS */
}
+#endif /* PCSC_FUNCS */
+
/**
* eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
@@ -1453,23 +1664,27 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
identity, identity_len);
}
- if (identity == NULL) {
- wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
- "configuration was not available");
- if (config->pcsc) {
+ if (config->pcsc) {
+#ifdef PCSC_FUNCS
+ if (!identity) {
if (eap_sm_get_scard_identity(sm, config) < 0)
return NULL;
identity = config->identity;
identity_len = config->identity_len;
- wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
- "IMSI", identity, identity_len);
- } else {
- eap_sm_request_identity(sm);
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "permanent identity from IMSI",
+ identity, identity_len);
+ } else if (eap_sm_set_scard_pin(sm, config) < 0) {
return NULL;
}
- } else if (config->pcsc) {
- if (eap_sm_set_scard_pin(sm, config) < 0)
- return NULL;
+#else /* PCSC_FUNCS */
+ return NULL;
+#endif /* PCSC_FUNCS */
+ } else if (!identity) {
+ wpa_printf(MSG_WARNING,
+ "EAP: buildIdentity: identity configuration was not available");
+ eap_sm_request_identity(sm);
+ return NULL;
}
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
@@ -1510,15 +1725,9 @@ static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
static struct wpabuf * eap_sm_buildNotify(int id)
{
- struct wpabuf *resp;
-
wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
- resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
- EAP_CODE_RESPONSE, id);
- if (resp == NULL)
- return NULL;
-
- return resp;
+ return eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
+ EAP_CODE_RESPONSE, id);
}
@@ -1562,7 +1771,7 @@ static void eap_peer_initiate(struct eap_sm *sm, const struct eap_hdr *hdr,
/* TODO: Derivation of domain specific keys for local ER */
}
- if (eap_peer_erp_reauth_start(sm, hdr, len) == 0)
+ if (eap_peer_erp_reauth_start(sm, hdr->identifier) == 0)
return;
invalid:
@@ -1573,8 +1782,7 @@ invalid:
}
-static void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr,
- size_t len)
+void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr, size_t len)
{
#ifdef CONFIG_ERP
const u8 *pos = (const u8 *) (hdr + 1);
@@ -1824,6 +2032,15 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
case EAP_CODE_FAILURE:
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
eap_notify_status(sm, "completion", "failure");
+
+ /* Get the error code from method */
+ if (sm->m && sm->m->get_error_code) {
+ int error_code;
+
+ error_code = sm->m->get_error_code(sm->eap_method_priv);
+ if (error_code != NO_EAP_METHOD_ERROR)
+ eap_report_error(sm, error_code);
+ }
sm->rxFailure = TRUE;
break;
case EAP_CODE_INITIATE:
@@ -1850,6 +2067,11 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
case TLS_CERT_CHAIN_SUCCESS:
eap_notify_status(sm, "remote certificate verification",
"success");
+ if (sm->ext_cert_check) {
+ sm->waiting_ext_cert_check = 1;
+ eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK,
+ NULL, 0);
+ }
break;
case TLS_CERT_CHAIN_FAILURE:
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
@@ -2172,10 +2394,10 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
#endif /* CONFIG_CTRL_IFACE */
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
const char *msg, size_t msglen)
{
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
struct eap_peer_config *config;
const char *txt = NULL;
char *tmp;
@@ -2222,18 +2444,20 @@ static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
config->pending_req_passphrase++;
break;
case WPA_CTRL_REQ_SIM:
+ config->pending_req_sim++;
txt = msg;
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ break;
default:
return;
}
if (sm->eapol_cb->eap_param_needed)
sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
-}
-#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+}
+
const char * eap_sm_get_method_name(struct eap_sm *sm)
{
diff --git a/contrib/wpa/src/eap_peer/eap.h b/contrib/wpa/src/eap_peer/eap.h
index 1a645af..d0837e3 100644
--- a/contrib/wpa/src/eap_peer/eap.h
+++ b/contrib/wpa/src/eap_peer/eap.h
@@ -246,12 +246,37 @@ struct eapol_callbacks {
void (*notify_status)(void *ctx, const char *status,
const char *parameter);
+ /**
+ * notify_eap_error - Report EAP method error code
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @error_code: Error code from the used EAP method
+ */
+ void (*notify_eap_error)(void *ctx, int error_code);
+
#ifdef CONFIG_EAP_PROXY
/**
* eap_proxy_cb - Callback signifying any updates from eap_proxy
* @ctx: eapol_ctx from eap_peer_sm_init() call
*/
void (*eap_proxy_cb)(void *ctx);
+
+ /**
+ * eap_proxy_notify_sim_status - Notification of SIM status change
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @sim_state: One of enum value from sim_state
+ */
+ void (*eap_proxy_notify_sim_status)(void *ctx,
+ enum eap_proxy_sim_state sim_state);
+
+ /**
+ * get_imsi - Get the IMSI value from eap_proxy
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @sim_num: SIM/USIM number to get the IMSI value for
+ * @imsi: Buffer for IMSI value
+ * @len: Buffer for returning IMSI length in octets
+ * Returns: MNC length (2 or 3) or -1 on error
+ */
+ int (*get_imsi)(void *ctx, int sim_num, char *imsi, size_t *len);
#endif /* CONFIG_EAP_PROXY */
/**
@@ -348,6 +373,16 @@ void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
int eap_peer_was_failure_expected(struct eap_sm *sm);
void eap_peer_erp_free_keys(struct eap_sm *sm);
+struct wpabuf * eap_peer_build_erp_reauth_start(struct eap_sm *sm, u8 eap_id);
+void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr, size_t len);
+int eap_peer_get_erp_info(struct eap_sm *sm, struct eap_peer_config *config,
+ const u8 **username, size_t *username_len,
+ const u8 **realm, size_t *realm_len, u16 *erp_seq_num,
+ const u8 **rrk, size_t *rrk_len);
+int eap_peer_update_erp_next_seq_num(struct eap_sm *sm, u16 seq_num);
+void eap_peer_erp_init(struct eap_sm *sm, u8 *ext_session_id,
+ size_t ext_session_id_len, u8 *ext_emsk,
+ size_t ext_emsk_len);
#endif /* IEEE8021X_EAPOL */
diff --git a/contrib/wpa/src/eap_peer/eap_aka.c b/contrib/wpa/src/eap_peer/eap_aka.c
index dc9e8cc..a444141 100644
--- a/contrib/wpa/src/eap_peer/eap_aka.c
+++ b/contrib/wpa/src/eap_peer/eap_aka.c
@@ -48,11 +48,15 @@ struct eap_aka_data {
struct wpabuf *id_msgs;
int prev_id;
int result_ind, use_result_ind;
+ int use_pseudonym;
u8 eap_method;
u8 *network_name;
size_t network_name_len;
u16 kdf;
int kdf_negotiation;
+ u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
+ size_t last_kdf_count;
+ int error_code;
};
@@ -96,12 +100,16 @@ static void * eap_aka_init(struct eap_sm *sm)
data->eap_method = EAP_TYPE_AKA;
+ /* Zero is a valid error code, so we need to initialize */
+ data->error_code = NO_EAP_METHOD_ERROR;
+
eap_aka_state(data, CONTINUE);
data->prev_id = -1;
data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
- if (config && config->anonymous_identity) {
+ data->use_pseudonym = !sm->init_phase2;
+ if (config && config->anonymous_identity && data->use_pseudonym) {
data->pseudonym = os_malloc(config->anonymous_identity_len);
if (data->pseudonym) {
os_memcpy(data->pseudonym, config->anonymous_identity,
@@ -350,7 +358,8 @@ static void eap_aka_clear_identities(struct eap_sm *sm,
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
- eap_set_anon_id(sm, NULL, 0);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
@@ -405,20 +414,21 @@ static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
- eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, data->pseudonym,
+ data->pseudonym_len);
}
if (attr->next_reauth_id) {
os_free(data->reauth_id);
- data->reauth_id = os_malloc(attr->next_reauth_id_len);
+ data->reauth_id = os_memdup(attr->next_reauth_id,
+ attr->next_reauth_id_len);
if (data->reauth_id == NULL) {
wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
"next reauth_id");
data->reauth_id_len = 0;
return -1;
}
- os_memcpy(data->reauth_id, attr->next_reauth_id,
- attr->next_reauth_id_len);
data->reauth_id_len = attr->next_reauth_id_len;
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
@@ -570,7 +580,7 @@ static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
static struct wpabuf * eap_aka_synchronization_failure(
- struct eap_aka_data *data, u8 id)
+ struct eap_aka_data *data, u8 id, struct eap_sim_attrs *attr)
{
struct eap_sim_msg *msg;
@@ -584,6 +594,15 @@ static struct wpabuf * eap_aka_synchronization_failure(
wpa_printf(MSG_DEBUG, " AT_AUTS");
eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
EAP_AKA_AUTS_LEN);
+ if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+ size_t i;
+
+ for (i = 0; i < attr->kdf_count; i++) {
+ wpa_printf(MSG_DEBUG, " AT_KDF");
+ eap_sim_msg_add(msg, EAP_SIM_AT_KDF, attr->kdf[i],
+ NULL, 0);
+ }
+ }
return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -817,9 +836,13 @@ static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
size_t i;
for (i = 0; i < attr->kdf_count; i++) {
- if (attr->kdf[i] == EAP_AKA_PRIME_KDF)
+ if (attr->kdf[i] == EAP_AKA_PRIME_KDF) {
+ os_memcpy(data->last_kdf_attrs, attr->kdf,
+ sizeof(u16) * attr->kdf_count);
+ data->last_kdf_count = attr->kdf_count;
return eap_aka_prime_kdf_select(data, id,
EAP_AKA_PRIME_KDF);
+ }
}
/* No matching KDF found - fail authentication as if AUTN had been
@@ -840,26 +863,32 @@ static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
* of the selected KDF into the beginning of the list. */
if (data->kdf_negotiation) {
+ /* When the peer receives the new EAP-Request/AKA'-Challenge
+ * message, must check only requested change occurred in the
+ * list of AT_KDF attributes. If there are any other changes,
+ * the peer must behave like the case that AT_MAC had been
+ * incorrect and authentication is failed. These are defined in
+ * EAP-AKA' specification RFC 5448, Section 3.2. */
if (attr->kdf[0] != data->kdf) {
wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
"accept the selected KDF");
- return 0;
+ return -1;
}
- for (i = 1; i < attr->kdf_count; i++) {
- if (attr->kdf[i] == data->kdf)
- break;
- }
- if (i == attr->kdf_count &&
- attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) {
- wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
- "duplicate the selected KDF");
- return 0;
+ if (attr->kdf_count > EAP_AKA_PRIME_KDF_MAX ||
+ attr->kdf_count != data->last_kdf_count + 1) {
+ wpa_printf(MSG_WARNING,
+ "EAP-AKA': The length of KDF attributes is wrong");
+ return -1;
}
- /* TODO: should check that the list is identical to the one
- * used in the previous Challenge message apart from the added
- * entry in the beginning. */
+ for (i = 1; i < attr->kdf_count; i++) {
+ if (attr->kdf[i] != data->last_kdf_attrs[i - 1]) {
+ wpa_printf(MSG_WARNING,
+ "EAP-AKA': The KDF attributes except selected KDF are not same as original one");
+ return -1;
+ }
+ }
}
for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
@@ -908,22 +937,25 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
return eap_aka_authentication_reject(data, id);
}
os_free(data->network_name);
- data->network_name = os_malloc(attr->kdf_input_len);
+ data->network_name = os_memdup(attr->kdf_input,
+ attr->kdf_input_len);
if (data->network_name == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
"storing Network Name");
return eap_aka_authentication_reject(data, id);
}
- os_memcpy(data->network_name, attr->kdf_input,
- attr->kdf_input_len);
data->network_name_len = attr->kdf_input_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
"(AT_KDF_INPUT)",
data->network_name, data->network_name_len);
/* TODO: check Network Name per 3GPP.33.402 */
- if (!eap_aka_prime_kdf_valid(data, attr))
+ res = eap_aka_prime_kdf_valid(data, attr);
+ if (res == 0)
return eap_aka_authentication_reject(data, id);
+ else if (res == -1)
+ return eap_aka_client_error(
+ data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
return eap_aka_prime_kdf_neg(data, id, attr);
@@ -966,7 +998,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
} else if (res == -2) {
wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
"failed (AUTN seq# -> AUTS)");
- return eap_aka_synchronization_failure(data, id);
+ return eap_aka_synchronization_failure(data, id, attr);
} else if (res > 0) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Wait for external USIM processing");
return NULL;
@@ -997,8 +1029,17 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
} else if (data->pseudonym) {
identity = data->pseudonym;
identity_len = data->pseudonym_len;
- } else
- identity = eap_get_config_identity(sm, &identity_len);
+ } else {
+ struct eap_peer_config *config;
+
+ config = eap_get_config(sm);
+ if (config && config->imsi_identity) {
+ identity = config->imsi_identity;
+ identity_len = config->imsi_identity_len;
+ } else {
+ identity = eap_get_config_identity(sm, &identity_len);
+ }
+ }
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
"derivation", identity, identity_len);
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
@@ -1143,6 +1184,7 @@ static struct wpabuf * eap_aka_process_notification(
eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
if (attr->notification >= 0 && attr->notification < 32768) {
+ data->error_code = attr->notification;
eap_aka_state(data, FAILURE);
} else if (attr->notification == EAP_SIM_SUCCESS &&
data->state == RESULT_SUCCESS)
@@ -1437,12 +1479,11 @@ static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
+ key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
if (key == NULL)
return NULL;
*len = EAP_SIM_KEYING_DATA_LEN;
- os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
return key;
}
@@ -1478,21 +1519,36 @@ static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
*len = EAP_EMSK_LEN;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
return key;
}
+static int eap_aka_get_error_code(void *priv)
+{
+ struct eap_aka_data *data = priv;
+ int current_data_error;
+
+ if (!data)
+ return NO_EAP_METHOD_ERROR;
+
+ current_data_error = data->error_code;
+
+ /* Now reset for next transaction */
+ data->error_code = NO_EAP_METHOD_ERROR;
+
+ return current_data_error;
+}
+
+
int eap_peer_aka_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
@@ -1510,11 +1566,9 @@ int eap_peer_aka_register(void)
eap->init_for_reauth = eap_aka_init_for_reauth;
eap->get_identity = eap_aka_get_identity;
eap->get_emsk = eap_aka_get_emsk;
+ eap->get_error_code = eap_aka_get_error_code;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
@@ -1522,7 +1576,6 @@ int eap_peer_aka_register(void)
int eap_peer_aka_prime_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
@@ -1541,11 +1594,8 @@ int eap_peer_aka_prime_register(void)
eap->init_for_reauth = eap_aka_init_for_reauth;
eap->get_identity = eap_aka_get_identity;
eap->get_emsk = eap_aka_get_emsk;
+ eap->get_error_code = eap_aka_get_error_code;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
-
- return ret;
+ return eap_peer_method_register(eap);
}
#endif /* EAP_AKA_PRIME */
diff --git a/contrib/wpa/src/eap_peer/eap_config.h b/contrib/wpa/src/eap_peer/eap_config.h
index 2b1a1d5..3a88f2a 100644
--- a/contrib/wpa/src/eap_peer/eap_config.h
+++ b/contrib/wpa/src/eap_peer/eap_config.h
@@ -46,6 +46,9 @@ struct eap_peer_config {
*/
size_t anonymous_identity_len;
+ u8 *imsi_identity;
+ size_t imsi_identity_len;
+
/**
* password - Password string for EAP
*
@@ -98,7 +101,7 @@ struct eap_peer_config {
* certificate store (My user account) is used, whereas computer store
* (Computer account) is used when running wpasvc as a service.
*/
- u8 *ca_cert;
+ char *ca_cert;
/**
* ca_path - Directory path for CA certificate files (PEM)
@@ -109,7 +112,7 @@ struct eap_peer_config {
* these certificates are added to the list of trusted CAs. ca_cert
* may also be included in that case, but it is not required.
*/
- u8 *ca_path;
+ char *ca_path;
/**
* client_cert - File path to client certificate file (PEM/DER)
@@ -123,7 +126,7 @@ struct eap_peer_config {
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *client_cert;
+ char *client_cert;
/**
* private_key - File path to client private key file (PEM/DER/PFX)
@@ -150,7 +153,7 @@ struct eap_peer_config {
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *private_key;
+ char *private_key;
/**
* private_key_passwd - Password for private key file
@@ -175,30 +178,72 @@ struct eap_peer_config {
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *dh_file;
+ char *dh_file;
/**
* subject_match - Constraint for server certificate subject
*
* This substring is matched against the subject of the authentication
- * server certificate. If this string is set, the server sertificate is
+ * server certificate. If this string is set, the server certificate is
* only accepted if it contains this string in the subject. The subject
* string is in following format:
*
* /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
*
- * Note: Since this is a substring match, this cannot be used securily
+ * Note: Since this is a substring match, this cannot be used securely
* to do a suffix match against a possible domain name in the CN entry.
* For such a use case, domain_suffix_match should be used instead.
*/
- u8 *subject_match;
+ char *subject_match;
+
+ /**
+ * check_cert_subject - Constraint for server certificate subject fields
+ *
+ * If check_cert_subject is set, the value of every field will be
+ * checked against the DN of the subject in the authentication server
+ * certificate. If the values do not match, the certificate verification
+ * will fail, rejecting the server. This option allows wpa_supplicant to
+ * match every individual field in the right order against the DN of the
+ * subject in the server certificate.
+ *
+ * For example, check_cert_subject=C=US/O=XX/OU=ABC/OU=XYZ/CN=1234 will
+ * check every individual DN field of the subject in the server
+ * certificate. If OU=XYZ comes first in terms of the order in the
+ * server certificate (DN field of server certificate
+ * C=US/O=XX/OU=XYZ/OU=ABC/CN=1234), wpa_supplicant will reject the
+ * server because the order of 'OU' is not matching the specified string
+ * in check_cert_subject.
+ *
+ * This option also allows '*' as a wildcard. This option has some
+ * limitation.
+ * It can only be used as per the following example.
+ *
+ * For example, check_cert_subject=C=US/O=XX/OU=Production* and we have
+ * two servers and DN of the subject in the first server certificate is
+ * (C=US/O=XX/OU=Production Unit) and DN of the subject in the second
+ * server is (C=US/O=XX/OU=Production Factory). In this case,
+ * wpa_supplicant will allow both servers because the value of 'OU'
+ * field in both server certificates matches 'OU' value in
+ * 'check_cert_subject' up to 'wildcard'.
+ *
+ * (Allow all servers, e.g., check_cert_subject=*)
+ */
+ char *check_cert_subject;
+
+ /**
+ * check_cert_subject2 - Constraint for server certificate subject fields
+ *
+ * This field is like check_cert_subject, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ char *check_cert_subject2;
/**
* altsubject_match - Constraint for server certificate alt. subject
*
* Semicolon separated string of entries to be matched against the
* alternative subject name of the authentication server certificate.
- * If this string is set, the server sertificate is only accepted if it
+ * If this string is set, the server certificate is only accepted if it
* contains one of the entries in an alternative subject name
* extension.
*
@@ -209,23 +254,26 @@ struct eap_peer_config {
*
* Following types are supported: EMAIL, DNS, URI
*/
- u8 *altsubject_match;
+ char *altsubject_match;
/**
* domain_suffix_match - Constraint for server domain name
*
- * If set, this FQDN is used as a suffix match requirement for the
- * server certificate in SubjectAltName dNSName element(s). If a
- * matching dNSName is found, this constraint is met. If no dNSName
- * values are present, this constraint is matched against SubjectName CN
- * using same suffix match comparison. Suffix match here means that the
- * host/domain name is compared one label at a time starting from the
- * top-level domain and all the labels in domain_suffix_match shall be
- * included in the certificate. The certificate may include additional
- * sub-level labels in addition to the required labels.
+ * If set, this semicolon deliminated list of FQDNs is used as suffix
+ * match requirements for the server certificate in SubjectAltName
+ * dNSName element(s). If a matching dNSName is found against any of the
+ * specified values, this constraint is met. If no dNSName values are
+ * present, this constraint is matched against SubjectName CN using same
+ * suffix match comparison. Suffix match here means that the host/domain
+ * name is compared case-insentively one label at a time starting from
+ * the top-level domain and all the labels in domain_suffix_match shall
+ * be included in the certificate. The certificate may include
+ * additional sub-level labels in addition to the required labels.
*
* For example, domain_suffix_match=example.com would match
- * test.example.com but would not match test-example.com.
+ * test.example.com but would not match test-example.com. Multiple
+ * match options can be specified in following manner:
+ * example.org;example.com.
*/
char *domain_suffix_match;
@@ -241,6 +289,12 @@ struct eap_peer_config {
* no subdomains or wildcard matches are allowed. Case-insensitive
* comparison is used, so "Example.com" matches "example.com", but would
* not match "test.Example.com".
+ *
+ * More than one match string can be provided by using semicolons to
+ * separate the strings (e.g., example.org;example.com). When multiple
+ * strings are specified, a match with any one of the values is
+ * considered a sufficient match for the certificate, i.e., the
+ * conditions are ORed together.
*/
char *domain_match;
@@ -260,7 +314,7 @@ struct eap_peer_config {
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *ca_cert2;
+ char *ca_cert2;
/**
* ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
@@ -274,7 +328,7 @@ struct eap_peer_config {
* This field is like ca_path, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
- u8 *ca_path2;
+ char *ca_path2;
/**
* client_cert2 - File path to client certificate file
@@ -287,7 +341,7 @@ struct eap_peer_config {
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *client_cert2;
+ char *client_cert2;
/**
* private_key2 - File path to client private key file
@@ -300,7 +354,7 @@ struct eap_peer_config {
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *private_key2;
+ char *private_key2;
/**
* private_key2_passwd - Password for private key file
@@ -321,7 +375,7 @@ struct eap_peer_config {
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *dh_file2;
+ char *dh_file2;
/**
* subject_match2 - Constraint for server certificate subject
@@ -329,7 +383,7 @@ struct eap_peer_config {
* This field is like subject_match, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
- u8 *subject_match2;
+ char *subject_match2;
/**
* altsubject_match2 - Constraint for server certificate alt. subject
@@ -337,7 +391,7 @@ struct eap_peer_config {
* This field is like altsubject_match, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
- u8 *altsubject_match2;
+ char *altsubject_match2;
/**
* domain_suffix_match2 - Constraint for server domain name
@@ -628,6 +682,15 @@ struct eap_peer_config {
int pending_req_passphrase;
/**
+ * pending_req_sim - Pending SIM request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
+ int pending_req_sim;
+
+ /**
* pending_req_otp - Whether there is a pending OTP request
*
* This field should not be set in configuration step. It is only used
@@ -739,6 +802,20 @@ struct eap_peer_config {
* erp - Whether EAP Re-authentication Protocol (ERP) is enabled
*/
int erp;
+
+ /**
+ * pending_ext_cert_check - External server certificate check status
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request external
+ * validation of server certificate chain.
+ */
+ enum {
+ NO_CHECK = 0,
+ PENDING_CHECK,
+ EXT_CERT_CHECK_GOOD,
+ EXT_CERT_CHECK_BAD,
+ } pending_ext_cert_check;
};
diff --git a/contrib/wpa/src/eap_peer/eap_eke.c b/contrib/wpa/src/eap_peer/eap_eke.c
index dfbda56..0de7d6c 100644
--- a/contrib/wpa/src/eap_peer/eap_eke.c
+++ b/contrib/wpa/src/eap_peer/eap_eke.c
@@ -85,12 +85,11 @@ static void * eap_eke_init(struct eap_sm *sm)
identity = eap_get_config_identity(sm, &identity_len);
if (identity) {
- data->peerid = os_malloc(identity_len);
+ data->peerid = os_memdup(identity, identity_len);
if (data->peerid == NULL) {
eap_eke_deinit(sm, data);
return NULL;
}
- os_memcpy(data->peerid, identity, identity_len);
data->peerid_len = identity_len;
}
@@ -310,12 +309,11 @@ static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
pos, end - pos);
os_free(data->serverid);
- data->serverid = os_malloc(end - pos);
+ data->serverid = os_memdup(pos, end - pos);
if (data->serverid == NULL) {
return eap_eke_build_fail(data, ret, id,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
}
- os_memcpy(data->serverid, pos, end - pos);
data->serverid_len = end - pos;
wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
@@ -452,6 +450,7 @@ static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
/* DHComponent_P = Encr(key, y_p) */
rpos = wpabuf_put(resp, data->sess.dhcomp_len);
if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
+ wpabuf_free(resp);
wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
os_memset(key, 0, sizeof(key));
return eap_eke_build_fail(data, ret, id,
@@ -716,10 +715,9 @@ static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -734,10 +732,9 @@ static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
@@ -770,7 +767,6 @@ static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_eke_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
@@ -785,8 +781,5 @@ int eap_peer_eke_register(void)
eap->get_emsk = eap_eke_get_emsk;
eap->getSessionId = eap_eke_get_session_id;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_fast.c b/contrib/wpa/src/eap_peer/eap_fast.c
index 4cbe3ba..94ce57d 100644
--- a/contrib/wpa/src/eap_peer/eap_fast.c
+++ b/contrib/wpa/src/eap_peer/eap_fast.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-FAST (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -67,6 +67,7 @@ struct eap_fast_data {
int simck_idx;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
};
@@ -112,8 +113,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
}
-static int eap_fast_parse_phase1(struct eap_fast_data *data,
- const char *phase1)
+static void eap_fast_parse_phase1(struct eap_fast_data *data,
+ const char *phase1)
{
const char *pos;
@@ -139,8 +140,6 @@ static int eap_fast_parse_phase1(struct eap_fast_data *data,
wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC "
"list");
}
-
- return 0;
}
@@ -158,10 +157,8 @@ static void * eap_fast_init(struct eap_sm *sm)
data->fast_version = EAP_FAST_VERSION;
data->max_pac_list_len = 10;
- if (config->phase1 && eap_fast_parse_phase1(data, config->phase1) < 0) {
- eap_fast_deinit(sm, data);
- return NULL;
- }
+ if (config->phase1)
+ eap_fast_parse_phase1(data, config->phase1);
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
@@ -253,15 +250,17 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
os_memset(data->key_data, 0, EAP_FAST_KEY_LEN);
os_memset(data->emsk, 0, EAP_EMSK_LEN);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
os_free(data);
}
static int eap_fast_derive_msk(struct eap_fast_data *data)
{
- eap_fast_derive_eap_msk(data->simck, data->key_data);
- eap_fast_derive_eap_emsk(data->simck, data->emsk);
+ if (eap_fast_derive_eap_msk(data->simck, data->key_data) < 0 ||
+ eap_fast_derive_eap_emsk(data->simck, data->emsk) < 0)
+ return -1;
data->success = 1;
return 0;
}
@@ -276,7 +275,7 @@ static int eap_fast_derive_key_auth(struct eap_sm *sm,
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+ sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -304,7 +303,6 @@ static int eap_fast_derive_key_provisioning(struct eap_sm *sm,
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
- "key expansion",
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -486,8 +484,9 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
if (*resp == NULL && config &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp || config->pending_req_new_password)) {
- wpabuf_free(data->pending_phase2_req);
+ config->pending_req_otp || config->pending_req_new_password ||
+ config->pending_req_sim)) {
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
} else if (*resp == NULL)
return -1;
@@ -711,9 +710,10 @@ static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data,
if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0)
return -1;
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
- sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck));
+ if (sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck)) < 0)
+ return -1;
data->simck_idx++;
os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
@@ -801,7 +801,7 @@ static struct wpabuf * eap_fast_process_crypto_binding(
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
data->phase2_success = 0;
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
@@ -815,7 +815,7 @@ static struct wpabuf * eap_fast_process_crypto_binding(
} else {
wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
"Session-Id");
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
}
@@ -1096,7 +1096,7 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
/* Parse TLVs from the decrypted Phase 2 data */
pos = wpabuf_mhead(decrypted);
end = pos + wpabuf_len(decrypted);
- while (pos + 4 < end) {
+ while (end - pos > 4) {
mandatory = pos[0] & 0x80;
tlv_type = WPA_GET_BE16(pos) & 0x3fff;
pos += 2;
@@ -1150,7 +1150,7 @@ static int eap_fast_encrypt_response(struct eap_sm *sm,
wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
"frame");
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return 0;
}
@@ -1328,14 +1328,14 @@ continue_req:
wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
"TLV frame (len=%lu)",
(unsigned long) wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return -1;
}
res = eap_fast_process_decrypted(sm, data, ret, identifier,
in_decrypted, out_data);
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return res;
}
@@ -1443,7 +1443,7 @@ static int eap_fast_clear_pac_opaque_ext(struct eap_sm *sm,
static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
struct eap_fast_data *data)
{
- u8 ciphers[5];
+ u8 ciphers[7];
int count = 0;
if (data->provisioning_allowed & EAP_FAST_PROV_UNAUTH) {
@@ -1455,7 +1455,9 @@ static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
if (data->provisioning_allowed & EAP_FAST_PROV_AUTH) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling authenticated "
"provisioning TLS cipher suites");
+ ciphers[count++] = TLS_CIPHER_RSA_DHE_AES256_SHA;
ciphers[count++] = TLS_CIPHER_RSA_DHE_AES128_SHA;
+ ciphers[count++] = TLS_CIPHER_AES256_SHA;
ciphers[count++] = TLS_CIPHER_AES128_SHA;
ciphers[count++] = TLS_CIPHER_RC4_SHA;
}
@@ -1567,6 +1569,34 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
res = 1;
}
} else {
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
/* Continue processing TLS handshake (phase 1). */
res = eap_peer_tls_process_helper(sm, &data->ssl,
EAP_TYPE_FAST,
@@ -1580,6 +1610,14 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
return resp;
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Waiting external server certificate validation");
+ wpabuf_clear_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
char cipher[80];
wpa_printf(MSG_DEBUG,
@@ -1603,7 +1641,7 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
"EAP-FAST: Could not derive keys");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
}
@@ -1612,7 +1650,7 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = resp;
resp = NULL;
res = eap_fast_decrypt(sm, data, ret, id, &msg, &resp);
@@ -1620,7 +1658,7 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
}
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_FAST,
data->fast_version);
}
@@ -1640,10 +1678,16 @@ static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
+
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->deinit_for_reauth)
+ data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
os_free(data->key_block_p);
data->key_block_p = NULL;
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_clear_free(data->pending_resp);
+ data->pending_resp = NULL;
}
@@ -1705,12 +1749,11 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (!data->success)
return NULL;
- key = os_malloc(EAP_FAST_KEY_LEN);
+ key = os_memdup(data->key_data, EAP_FAST_KEY_LEN);
if (key == NULL)
return NULL;
*len = EAP_FAST_KEY_LEN;
- os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
return key;
}
@@ -1721,15 +1764,14 @@ static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
struct eap_fast_data *data = priv;
u8 *id;
- if (!data->success)
+ if (!data->success || !data->session_id)
return NULL;
- id = os_malloc(data->id_len);
+ id = os_memdup(data->session_id, data->id_len);
if (id == NULL)
return NULL;
*len = data->id_len;
- os_memcpy(id, data->session_id, data->id_len);
return id;
}
@@ -1743,12 +1785,11 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (!data->success)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
*len = EAP_EMSK_LEN;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
return key;
}
@@ -1757,7 +1798,6 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_fast_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
@@ -1778,8 +1818,5 @@ int eap_peer_fast_register(void)
#endif
eap->get_emsk = eap_fast_get_emsk;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_fast_pac.c b/contrib/wpa/src/eap_peer/eap_fast_pac.c
index 89e604e..7d674c8 100644
--- a/contrib/wpa/src/eap_peer/eap_fast_pac.c
+++ b/contrib/wpa/src/eap_peer/eap_fast_pac.c
@@ -114,10 +114,9 @@ static int eap_fast_copy_buf(u8 **dst, size_t *dst_len,
const u8 *src, size_t src_len)
{
if (src) {
- *dst = os_malloc(src_len);
+ *dst = os_memdup(src, src_len);
if (*dst == NULL)
return -1;
- os_memcpy(*dst, src, src_len);
*dst_len = src_len;
}
return 0;
@@ -455,7 +454,8 @@ int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
}
if (pac) {
- err = "PAC block not terminated with END";
+ if (!err)
+ err = "PAC block not terminated with END";
eap_fast_free_pac(pac);
}
@@ -709,7 +709,7 @@ static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
pos = pac->pac_info;
end = pos + pac->pac_info_len;
- while (pos + 4 < end) {
+ while (end - pos > 4) {
type = WPA_GET_BE16(pos);
pos += 2;
len = WPA_GET_BE16(pos);
@@ -719,19 +719,17 @@ static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
if (type == PAC_TYPE_A_ID) {
os_free(pac->a_id);
- pac->a_id = os_malloc(len);
+ pac->a_id = os_memdup(pos, len);
if (pac->a_id == NULL)
break;
- os_memcpy(pac->a_id, pos, len);
pac->a_id_len = len;
}
if (type == PAC_TYPE_A_ID_INFO) {
os_free(pac->a_id_info);
- pac->a_id_info = os_malloc(len);
+ pac->a_id_info = os_memdup(pos, len);
if (pac->a_id_info == NULL)
break;
- os_memcpy(pac->a_id_info, pos, len);
pac->a_id_info_len = len;
}
@@ -801,8 +799,10 @@ int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
while (pos < end) {
u16 val;
- if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2)
+ if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2) {
+ pac = NULL;
goto parse_fail;
+ }
pac = os_zalloc(sizeof(*pac));
if (pac == NULL)
@@ -817,10 +817,9 @@ int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
if (val > end - pos)
goto parse_fail;
pac->pac_opaque_len = val;
- pac->pac_opaque = os_malloc(pac->pac_opaque_len);
+ pac->pac_opaque = os_memdup(pos, pac->pac_opaque_len);
if (pac->pac_opaque == NULL)
goto parse_fail;
- os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
pos += pac->pac_opaque_len;
if (2 > end - pos)
goto parse_fail;
@@ -829,10 +828,9 @@ int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
if (val > end - pos)
goto parse_fail;
pac->pac_info_len = val;
- pac->pac_info = os_malloc(pac->pac_info_len);
+ pac->pac_info = os_memdup(pos, pac->pac_info_len);
if (pac->pac_info == NULL)
goto parse_fail;
- os_memcpy(pac->pac_info, pos, pac->pac_info_len);
pos += pac->pac_info_len;
eap_fast_pac_get_a_id(pac);
diff --git a/contrib/wpa/src/eap_peer/eap_gpsk.c b/contrib/wpa/src/eap_peer/eap_gpsk.c
index 902b4ba..f9c4d37 100644
--- a/contrib/wpa/src/eap_peer/eap_gpsk.c
+++ b/contrib/wpa/src/eap_peer/eap_gpsk.c
@@ -96,12 +96,11 @@ static void * eap_gpsk_init(struct eap_sm *sm)
identity = eap_get_config_identity(sm, &identity_len);
if (identity) {
- data->id_peer = os_malloc(identity_len);
+ data->id_peer = os_memdup(identity, identity_len);
if (data->id_peer == NULL) {
eap_gpsk_deinit(sm, data);
return NULL;
}
- os_memcpy(data->id_peer, identity, identity_len);
data->id_peer_len = identity_len;
}
@@ -117,12 +116,11 @@ static void * eap_gpsk_init(struct eap_sm *sm)
}
}
- data->psk = os_malloc(password_len);
+ data->psk = os_memdup(password, password_len);
if (data->psk == NULL) {
eap_gpsk_deinit(sm, data);
return NULL;
}
- os_memcpy(data->psk, password, password_len);
data->psk_len = password_len;
return data;
@@ -158,12 +156,11 @@ static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
return NULL;
}
os_free(data->id_server);
- data->id_server = os_malloc(alen);
+ data->id_server = os_memdup(pos, alen);
if (data->id_server == NULL) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
return NULL;
}
- os_memcpy(data->id_server, pos, alen);
data->id_server_len = alen;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
data->id_server, data->id_server_len);
@@ -722,10 +719,9 @@ static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -740,10 +736,9 @@ static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
@@ -758,10 +753,9 @@ static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- sid = os_malloc(data->id_len);
+ sid = os_memdup(data->session_id, data->id_len);
if (sid == NULL)
return NULL;
- os_memcpy(sid, data->session_id, data->id_len);
*len = data->id_len;
return sid;
@@ -771,7 +765,6 @@ static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_gpsk_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
@@ -786,8 +779,5 @@ int eap_peer_gpsk_register(void)
eap->get_emsk = eap_gpsk_get_emsk;
eap->getSessionId = eap_gpsk_get_session_id;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_gtc.c b/contrib/wpa/src/eap_peer/eap_gtc.c
index 9f3cfbd..a519a78 100644
--- a/contrib/wpa/src/eap_peer/eap_gtc.c
+++ b/contrib/wpa/src/eap_peer/eap_gtc.c
@@ -127,7 +127,6 @@ static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv,
int eap_peer_gtc_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
@@ -138,8 +137,5 @@ int eap_peer_gtc_register(void)
eap->deinit = eap_gtc_deinit;
eap->process = eap_gtc_process;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_i.h b/contrib/wpa/src/eap_peer/eap_i.h
index 99b44da..096f0f2 100644
--- a/contrib/wpa/src/eap_peer/eap_i.h
+++ b/contrib/wpa/src/eap_peer/eap_i.h
@@ -14,6 +14,8 @@
#include "eap_peer/eap.h"
#include "eap_common/eap_common.h"
+#define NO_EAP_METHOD_ERROR (-1)
+
/* RFC 4137 - EAP Peer state machine */
typedef enum {
@@ -206,6 +208,17 @@ struct eap_method {
const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
/**
+ * get_error_code - Get the latest EAP method error code
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * Returns: An int for the EAP method specific error code if exists or
+ * NO_EAP_METHOD_ERROR otherwise.
+ *
+ * This method is an optional handler that only EAP methods that need to
+ * report their error code need to implement.
+ */
+ int (*get_error_code)(void *priv);
+
+ /**
* free - Free EAP method data
* @method: Pointer to the method data registered with
* eap_peer_method_register().
@@ -366,6 +379,8 @@ struct eap_sm {
int external_sim;
unsigned int expected_failure:1;
+ unsigned int ext_cert_check:1;
+ unsigned int waiting_ext_cert_check:1;
struct dl_list erp_keys; /* struct eap_erp_key */
};
diff --git a/contrib/wpa/src/eap_peer/eap_ikev2.c b/contrib/wpa/src/eap_peer/eap_ikev2.c
index b5ef71b..6ddf508 100644
--- a/contrib/wpa/src/eap_peer/eap_ikev2.c
+++ b/contrib/wpa/src/eap_peer/eap_ikev2.c
@@ -83,18 +83,16 @@ static void * eap_ikev2_init(struct eap_sm *sm)
if (data->ikev2.key_pad == NULL)
goto failed;
data->ikev2.key_pad_len = 21;
- data->ikev2.IDr = os_malloc(identity_len);
+ data->ikev2.IDr = os_memdup(identity, identity_len);
if (data->ikev2.IDr == NULL)
goto failed;
- os_memcpy(data->ikev2.IDr, identity, identity_len);
data->ikev2.IDr_len = identity_len;
password = eap_get_config_password(sm, &password_len);
if (password) {
- data->ikev2.shared_secret = os_malloc(password_len);
+ data->ikev2.shared_secret = os_memdup(password, password_len);
if (data->ikev2.shared_secret == NULL)
goto failed;
- os_memcpy(data->ikev2.shared_secret, password, password_len);
data->ikev2.shared_secret_len = password_len;
}
@@ -513,7 +511,6 @@ static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_ikev2_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
@@ -529,8 +526,5 @@ int eap_peer_ikev2_register(void)
eap->get_emsk = eap_ikev2_get_emsk;
eap->getSessionId = eap_ikev2_get_session_id;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_leap.c b/contrib/wpa/src/eap_peer/eap_leap.c
index e0f8bcf..233b9ee 100644
--- a/contrib/wpa/src/eap_peer/eap_leap.c
+++ b/contrib/wpa/src/eap_peer/eap_leap.c
@@ -115,10 +115,14 @@ static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
wpabuf_put_u8(resp, 0); /* unused */
wpabuf_put_u8(resp, LEAP_RESPONSE_LEN);
rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN);
- if (pwhash)
- challenge_response(challenge, password, rpos);
- else
- nt_challenge_response(challenge, password, password_len, rpos);
+ if ((pwhash && challenge_response(challenge, password, rpos)) ||
+ (!pwhash &&
+ nt_challenge_response(challenge, password, password_len, rpos))) {
+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Failed to derive response");
+ ret->ignore = TRUE;
+ wpabuf_free(resp);
+ return NULL;
+ }
os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
rpos, LEAP_RESPONSE_LEN);
@@ -239,7 +243,10 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
return NULL;
}
}
- challenge_response(data->ap_challenge, pw_hash_hash, expected);
+ if (challenge_response(data->ap_challenge, pw_hash_hash, expected)) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
ret->methodState = METHOD_DONE;
ret->allowNotifications = FALSE;
@@ -393,7 +400,6 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_leap_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
@@ -406,8 +412,5 @@ int eap_peer_leap_register(void)
eap->isKeyAvailable = eap_leap_isKeyAvailable;
eap->getKey = eap_leap_getKey;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_md5.c b/contrib/wpa/src/eap_peer/eap_md5.c
index d06befa..efae8de 100644
--- a/contrib/wpa/src/eap_peer/eap_md5.c
+++ b/contrib/wpa/src/eap_peer/eap_md5.c
@@ -102,7 +102,6 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
int eap_peer_md5_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
@@ -113,8 +112,5 @@ int eap_peer_md5_register(void)
eap->deinit = eap_md5_deinit;
eap->process = eap_md5_process;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_methods.c b/contrib/wpa/src/eap_peer/eap_methods.c
index 1bdd81e..9747954 100644
--- a/contrib/wpa/src/eap_peer/eap_methods.c
+++ b/contrib/wpa/src/eap_peer/eap_methods.c
@@ -18,6 +18,8 @@
static struct eap_method *eap_methods = NULL;
+static void eap_peer_method_free(struct eap_method *method);
+
/**
* eap_peer_get_eap_method - Get EAP method based on type number
@@ -295,7 +297,7 @@ struct eap_method * eap_peer_method_alloc(int version, int vendor,
* eap_peer_method_free - Free EAP peer method structure
* @method: Method structure allocated with eap_peer_method_alloc()
*/
-void eap_peer_method_free(struct eap_method *method)
+static void eap_peer_method_free(struct eap_method *method)
{
os_free(method);
}
@@ -303,26 +305,31 @@ void eap_peer_method_free(struct eap_method *method)
/**
* eap_peer_method_register - Register an EAP peer method
- * @method: EAP method to register
+ * @method: EAP method to register from eap_peer_method_alloc()
* Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
* has already been registered
*
* Each EAP peer method needs to call this function to register itself as a
- * supported EAP method.
+ * supported EAP method. The caller must not free the allocated method data
+ * regardless of the return value.
*/
int eap_peer_method_register(struct eap_method *method)
{
struct eap_method *m, *last = NULL;
if (method == NULL || method->name == NULL ||
- method->version != EAP_PEER_METHOD_INTERFACE_VERSION)
+ method->version != EAP_PEER_METHOD_INTERFACE_VERSION) {
+ eap_peer_method_free(method);
return -1;
+ }
for (m = eap_methods; m; m = m->next) {
if ((m->vendor == method->vendor &&
m->method == method->method) ||
- os_strcmp(m->name, method->name) == 0)
+ os_strcmp(m->name, method->name) == 0) {
+ eap_peer_method_free(method);
return -2;
+ }
last = m;
}
diff --git a/contrib/wpa/src/eap_peer/eap_methods.h b/contrib/wpa/src/eap_peer/eap_methods.h
index e35c919..b96b211 100644
--- a/contrib/wpa/src/eap_peer/eap_methods.h
+++ b/contrib/wpa/src/eap_peer/eap_methods.h
@@ -16,7 +16,6 @@ const struct eap_method * eap_peer_get_methods(size_t *count);
struct eap_method * eap_peer_method_alloc(int version, int vendor,
EapType method, const char *name);
-void eap_peer_method_free(struct eap_method *method);
int eap_peer_method_register(struct eap_method *method);
diff --git a/contrib/wpa/src/eap_peer/eap_mschapv2.c b/contrib/wpa/src/eap_peer/eap_mschapv2.c
index 6acf1e8..249baec 100644
--- a/contrib/wpa/src/eap_peer/eap_mschapv2.c
+++ b/contrib/wpa/src/eap_peer/eap_mschapv2.c
@@ -109,23 +109,21 @@ static void * eap_mschapv2_init(struct eap_sm *sm)
return NULL;
if (sm->peer_challenge) {
- data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
+ data->peer_challenge = os_memdup(sm->peer_challenge,
+ MSCHAPV2_CHAL_LEN);
if (data->peer_challenge == NULL) {
eap_mschapv2_deinit(sm, data);
return NULL;
}
- os_memcpy(data->peer_challenge, sm->peer_challenge,
- MSCHAPV2_CHAL_LEN);
}
if (sm->auth_challenge) {
- data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
+ data->auth_challenge = os_memdup(sm->auth_challenge,
+ MSCHAPV2_CHAL_LEN);
if (data->auth_challenge == NULL) {
eap_mschapv2_deinit(sm, data);
return NULL;
}
- os_memcpy(data->auth_challenge, sm->auth_challenge,
- MSCHAPV2_CHAL_LEN);
}
data->phase2 = sm->init_phase2;
@@ -567,11 +565,11 @@ static struct wpabuf * eap_mschapv2_change_password(
if (pwhash) {
u8 new_password_hash[16];
if (nt_password_hash(new_password, new_password_len,
- new_password_hash))
+ new_password_hash) ||
+ nt_password_hash_encrypted_with_block(password,
+ new_password_hash,
+ cp->encr_hash))
goto fail;
- nt_password_hash_encrypted_with_block(password,
- new_password_hash,
- cp->encr_hash);
} else {
if (old_nt_password_hash_encrypted_with_new_nt_password_hash(
new_password, new_password_len,
@@ -858,9 +856,13 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
* peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
- get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
- get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
- MSCHAPV2_KEY_LEN, 0, 0);
+ if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1,
+ 0) < 0 ||
+ get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+ MSCHAPV2_KEY_LEN, 0, 0) < 0) {
+ os_free(key);
+ return NULL;
+ }
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
key, key_len);
@@ -880,7 +882,6 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_mschapv2_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
@@ -894,8 +895,5 @@ int eap_peer_mschapv2_register(void)
eap->isKeyAvailable = eap_mschapv2_isKeyAvailable;
eap->getKey = eap_mschapv2_getKey;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_otp.c b/contrib/wpa/src/eap_peer/eap_otp.c
index 9ac744a..0ab4c79 100644
--- a/contrib/wpa/src/eap_peer/eap_otp.c
+++ b/contrib/wpa/src/eap_peer/eap_otp.c
@@ -83,7 +83,6 @@ static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv,
int eap_peer_otp_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_OTP, "OTP");
@@ -94,8 +93,5 @@ int eap_peer_otp_register(void)
eap->deinit = eap_otp_deinit;
eap->process = eap_otp_process;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_pax.c b/contrib/wpa/src/eap_peer/eap_pax.c
index c920bcd..3cef1c8 100644
--- a/contrib/wpa/src/eap_peer/eap_pax.c
+++ b/contrib/wpa/src/eap_peer/eap_pax.c
@@ -69,12 +69,11 @@ static void * eap_pax_init(struct eap_sm *sm)
return NULL;
data->state = PAX_INIT;
- data->cid = os_malloc(identity_len);
+ data->cid = os_memdup(identity, identity_len);
if (data->cid == NULL) {
eap_pax_deinit(sm, data);
return NULL;
}
- os_memcpy(data->cid, identity, identity_len);
data->cid_len = identity_len;
os_memcpy(data->ak, password, EAP_PAX_AK_LEN);
@@ -276,9 +275,16 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
left -= 2;
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
pos, EAP_PAX_MAC_LEN);
- eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
- data->rand.r.y, EAP_PAX_RAND_LEN,
- (u8 *) data->cid, data->cid_len, NULL, 0, mac);
+ if (eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
+ data->rand.r.y, EAP_PAX_RAND_LEN,
+ (u8 *) data->cid, data->cid_len, NULL, 0, mac) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-PAX: Could not derive MAC_CK(B, CID)");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+
if (os_memcmp_const(pos, mac, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
"received");
@@ -306,9 +312,12 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
/* Optional ADE could be added here, if needed */
rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN);
- eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
- wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN,
- NULL, 0, NULL, 0, rpos);
+ if (eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, rpos) < 0) {
+ wpabuf_free(resp);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
data->state = PAX_DONE;
@@ -472,9 +481,13 @@ static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
return NULL;
*len = EAP_MSK_LEN;
- eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
- "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
- EAP_MSK_LEN, key);
+ if (eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
+ "Master Session Key",
+ data->rand.e, 2 * EAP_PAX_RAND_LEN,
+ EAP_MSK_LEN, key) < 0) {
+ os_free(key);
+ return NULL;
+ }
return key;
}
@@ -493,10 +506,13 @@ static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
return NULL;
*len = EAP_EMSK_LEN;
- eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
- "Extended Master Session Key",
- data->rand.e, 2 * EAP_PAX_RAND_LEN,
- EAP_EMSK_LEN, key);
+ if (eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
+ "Extended Master Session Key",
+ data->rand.e, 2 * EAP_PAX_RAND_LEN,
+ EAP_EMSK_LEN, key) < 0) {
+ os_free(key);
+ return NULL;
+ }
return key;
}
@@ -525,7 +541,6 @@ static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_pax_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
@@ -540,8 +555,5 @@ int eap_peer_pax_register(void)
eap->get_emsk = eap_pax_get_emsk;
eap->getSessionId = eap_pax_get_session_id;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_peap.c b/contrib/wpa/src/eap_peer/eap_peap.c
index 98a48a6c..8dcf7cc 100644
--- a/contrib/wpa/src/eap_peer/eap_peap.c
+++ b/contrib/wpa/src/eap_peer/eap_peap.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -59,6 +59,7 @@ struct eap_peap_data {
size_t id_len;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
int crypto_binding_used;
u8 binding_nonce[32];
@@ -69,8 +70,8 @@ struct eap_peap_data {
};
-static int eap_peap_parse_phase1(struct eap_peap_data *data,
- const char *phase1)
+static void eap_peap_parse_phase1(struct eap_peap_data *data,
+ const char *phase1)
{
const char *pos;
@@ -125,8 +126,6 @@ static int eap_peap_parse_phase1(struct eap_peap_data *data,
wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
}
#endif /* EAP_TNC */
-
- return 0;
}
@@ -144,11 +143,8 @@ static void * eap_peap_init(struct eap_sm *sm)
data->peap_outer_success = 2;
data->crypto_binding = OPTIONAL_BINDING;
- if (config && config->phase1 &&
- eap_peap_parse_phase1(data, config->phase1) < 0) {
- eap_peap_deinit(sm, data);
- return NULL;
- }
+ if (config && config->phase1)
+ eap_peap_parse_phase1(data, config->phase1);
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
@@ -173,7 +169,7 @@ static void * eap_peap_init(struct eap_sm *sm)
static void eap_peap_free_key(struct eap_peap_data *data)
{
if (data->key_data) {
- bin_clear_free(data->key_data, EAP_TLS_KEY_LEN);
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
data->key_data = NULL;
}
}
@@ -190,8 +186,9 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_peap_free_key(data);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
- os_free(data);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
+ bin_clear_free(data, sizeof(*data));
}
@@ -256,6 +253,7 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
{
u8 *tk;
u8 isk[32], imck[60];
+ int resumed, res;
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
@@ -266,8 +264,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
- if (data->reauth &&
- tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+ resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn);
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d",
+ data->reauth, resumed, data->phase2_eap_started,
+ data->phase2_success);
+ if (data->reauth && !data->phase2_eap_started && resumed) {
/* Fast-connect: IPMK|CMK = TK */
os_memcpy(data->ipmk, tk, 40);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
@@ -290,9 +292,11 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
* in the end of the label just before ISK; is that just a typo?)
*/
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
- if (peap_prfplus(data->peap_version, tk, 40,
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck)) < 0)
+ res = peap_prfplus(data->peap_version, tk, 40,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ os_memset(isk, 0, sizeof(isk));
+ if (res < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
imck, sizeof(imck));
@@ -301,6 +305,7 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
os_memcpy(data->cmk, imck + 40, 20);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+ os_memset(imck, 0, sizeof(imck));
return 0;
}
@@ -337,7 +342,8 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
addr[0], len[0]);
wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
addr[1], len[1]);
- hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
+ if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0)
+ return -1;
wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
data->crypto_binding_used = 1;
@@ -379,7 +385,7 @@ static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
wpabuf_put_be16(msg, status); /* Status */
if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
return NULL;
}
@@ -648,10 +654,11 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
if (*resp == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
+ wpabuf_clear_free(buf);
return -1;
}
wpabuf_put_buf(*resp, buf);
- wpabuf_free(buf);
+ wpabuf_clear_free(buf);
break;
}
}
@@ -722,8 +729,9 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
if (*resp == NULL &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp || config->pending_req_new_password)) {
- wpabuf_free(data->pending_phase2_req);
+ config->pending_req_otp || config->pending_req_new_password ||
+ config->pending_req_sim)) {
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
}
@@ -802,7 +810,7 @@ continue_req:
struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
wpabuf_len(in_decrypted));
if (nmsg == NULL) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
@@ -812,7 +820,7 @@ continue_req:
nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
in_decrypted = nmsg;
}
@@ -821,7 +829,7 @@ continue_req:
wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
"EAP frame (len=%lu)",
(unsigned long) wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
len = be_to_host16(hdr->length);
@@ -830,7 +838,7 @@ continue_req:
"Phase 2 EAP frame (len=%lu hdr->length=%lu)",
(unsigned long) wpabuf_len(in_decrypted),
(unsigned long) len);
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
if (len < wpabuf_len(in_decrypted)) {
@@ -847,7 +855,7 @@ continue_req:
case EAP_CODE_REQUEST:
if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
&resp)) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
"processing failed");
return 0;
@@ -867,7 +875,7 @@ continue_req:
"completed successfully");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
@@ -877,7 +885,7 @@ continue_req:
ret->methodState = METHOD_DONE;
data->phase2_success = 1;
if (data->peap_outer_success == 2) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
"to finish authentication");
return 1;
@@ -923,7 +931,7 @@ continue_req:
break;
}
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
if (resp) {
int skip_change2 = 0;
@@ -950,7 +958,7 @@ continue_req:
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
"a Phase 2 frame");
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
}
return 0;
@@ -1006,6 +1014,34 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
!data->resuming) {
res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
} else {
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
res = eap_peer_tls_process_helper(sm, &data->ssl,
EAP_TYPE_PEAP,
data->peap_version, id, &msg,
@@ -1018,6 +1054,16 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
ret->decision = DECISION_FAIL;
return resp;
}
+
+
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: Waiting external server certificate validation");
+ wpabuf_clear_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
char *label;
wpa_printf(MSG_DEBUG,
@@ -1038,12 +1084,19 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
"key derivation", label);
data->key_data =
eap_peer_tls_derive_key(sm, &data->ssl, label,
- EAP_TLS_KEY_LEN);
+ NULL, 0,
+ EAP_TLS_KEY_LEN +
+ EAP_EMSK_LEN);
if (data->key_data) {
- wpa_hexdump_key(MSG_DEBUG,
+ wpa_hexdump_key(MSG_DEBUG,
"EAP-PEAP: Derived key",
data->key_data,
EAP_TLS_KEY_LEN);
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-PEAP: Derived EMSK",
+ data->key_data +
+ EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
} else {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
"derive key");
@@ -1088,7 +1141,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = resp;
resp = NULL;
res = eap_peap_decrypt(sm, data, ret, req, &msg,
@@ -1101,7 +1154,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
}
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
data->peap_version);
}
@@ -1121,8 +1174,14 @@ static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
- wpabuf_free(data->pending_phase2_req);
+
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->deinit_for_reauth)
+ data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_clear_free(data->pending_resp);
+ data->pending_resp = NULL;
data->crypto_binding_used = 0;
}
@@ -1208,6 +1267,7 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
os_memcpy(key, csk, EAP_TLS_KEY_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
key, EAP_TLS_KEY_LEN);
+ os_memset(csk, 0, sizeof(csk));
} else
os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
@@ -1215,6 +1275,29 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *key;
+
+ if (!data->key_data || !data->phase2_success)
+ return NULL;
+
+ if (data->crypto_binding_used) {
+ /* [MS-PEAP] does not define EMSK derivation */
+ return NULL;
+ }
+
+ key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+ if (!key)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
@@ -1223,12 +1306,11 @@ static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
if (data->session_id == NULL || !data->phase2_success)
return NULL;
- id = os_malloc(data->id_len);
+ id = os_memdup(data->session_id, data->id_len);
if (id == NULL)
return NULL;
*len = data->id_len;
- os_memcpy(id, data->session_id, data->id_len);
return id;
}
@@ -1237,7 +1319,6 @@ static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_peap_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
@@ -1249,14 +1330,12 @@ int eap_peer_peap_register(void)
eap->process = eap_peap_process;
eap->isKeyAvailable = eap_peap_isKeyAvailable;
eap->getKey = eap_peap_getKey;
+ eap->get_emsk = eap_peap_get_emsk;
eap->get_status = eap_peap_get_status;
eap->has_reauth_data = eap_peap_has_reauth_data;
eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
eap->init_for_reauth = eap_peap_init_for_reauth;
eap->getSessionId = eap_peap_get_session_id;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_proxy.h b/contrib/wpa/src/eap_peer/eap_proxy.h
index 23cdbe6..9d8e570 100644
--- a/contrib/wpa/src/eap_peer/eap_proxy.h
+++ b/contrib/wpa/src/eap_peer/eap_proxy.h
@@ -20,7 +20,7 @@ enum eap_proxy_status {
};
struct eap_proxy_sm *
-eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb,
void *msg_ctx);
void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy);
@@ -40,10 +40,16 @@ eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
int verbose);
-int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
- size_t *imsi_len);
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, int sim_num,
+ char *imsi_buf, size_t *imsi_len);
int eap_proxy_notify_config(struct eap_proxy_sm *sm,
struct eap_peer_config *config);
+u8 * eap_proxy_get_eap_session_id(struct eap_proxy_sm *sm, size_t *len);
+
+u8 * eap_proxy_get_emsk(struct eap_proxy_sm *sm, size_t *len);
+
+void eap_proxy_sm_abort(struct eap_proxy_sm *sm);
+
#endif /* EAP_PROXY_H */
diff --git a/contrib/wpa/src/eap_peer/eap_proxy_dummy.c b/contrib/wpa/src/eap_peer/eap_proxy_dummy.c
index d84f012..2cc05c9 100644
--- a/contrib/wpa/src/eap_peer/eap_proxy_dummy.c
+++ b/contrib/wpa/src/eap_peer/eap_proxy_dummy.c
@@ -12,7 +12,7 @@
#include "eap_proxy.h"
struct eap_proxy_sm *
-eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb,
void *msg_ctx)
{
return NULL;
@@ -63,8 +63,8 @@ int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
}
-int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
- size_t *imsi_len)
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, int sim_num,
+ char *imsi_buf, size_t *imsi_len)
{
return -1;
}
@@ -75,3 +75,20 @@ int eap_proxy_notify_config(struct eap_proxy_sm *sm,
{
return -1;
}
+
+
+u8 * eap_proxy_get_eap_session_id(struct eap_proxy_sm *sm, size_t *len)
+{
+ return NULL;
+}
+
+
+u8 * eap_proxy_get_emsk(struct eap_proxy_sm *sm, size_t *len)
+{
+ return NULL;
+}
+
+
+void eap_proxy_sm_abort(struct eap_proxy_sm *sm)
+{
+}
diff --git a/contrib/wpa/src/eap_peer/eap_psk.c b/contrib/wpa/src/eap_peer/eap_psk.c
index f012663..eea9430 100644
--- a/contrib/wpa/src/eap_peer/eap_psk.c
+++ b/contrib/wpa/src/eap_peer/eap_psk.c
@@ -116,14 +116,13 @@ static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
os_memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
os_free(data->id_s);
data->id_s_len = len - sizeof(*hdr1);
- data->id_s = os_malloc(data->id_s_len);
+ data->id_s = os_memdup(hdr1 + 1, data->id_s_len);
if (data->id_s == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
"ID_S (len=%lu)", (unsigned long) data->id_s_len);
ret->ignore = TRUE;
return NULL;
}
- os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
data->id_s, data->id_s_len);
@@ -273,13 +272,12 @@ static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
wpabuf_head(reqData), 5);
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
- decrypted = os_malloc(left);
+ decrypted = os_memdup(msg, left);
if (decrypted == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return NULL;
}
- os_memcpy(decrypted, msg, left);
if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
wpabuf_head(reqData),
@@ -425,12 +423,11 @@ static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != PSK_DONE)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
*len = EAP_MSK_LEN;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
return key;
}
@@ -466,12 +463,11 @@ static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != PSK_DONE)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
*len = EAP_EMSK_LEN;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
return key;
}
@@ -480,7 +476,6 @@ static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_psk_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
@@ -495,8 +490,5 @@ int eap_peer_psk_register(void)
eap->getSessionId = eap_psk_get_session_id;
eap->get_emsk = eap_psk_get_emsk;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_pwd.c b/contrib/wpa/src/eap_peer/eap_pwd.c
index 1f78544..76fcad4 100644
--- a/contrib/wpa/src/eap_peer/eap_pwd.c
+++ b/contrib/wpa/src/eap_peer/eap_pwd.c
@@ -9,8 +9,11 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha512.h"
#include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
#include "eap_peer/eap_i.h"
#include "eap_common/eap_pwd_common.h"
@@ -28,6 +31,8 @@ struct eap_pwd_data {
size_t password_len;
int password_hash;
u16 group_num;
+ u8 prep;
+ u8 token[4];
EAP_PWD_group *grp;
struct wpabuf *inbuf;
@@ -36,18 +41,16 @@ struct eap_pwd_data {
size_t out_frag_pos;
size_t mtu;
- BIGNUM *k;
- BIGNUM *private_value;
- BIGNUM *server_scalar;
- BIGNUM *my_scalar;
- EC_POINT *my_element;
- EC_POINT *server_element;
+ struct crypto_bignum *k;
+ struct crypto_bignum *private_value;
+ struct crypto_bignum *server_scalar;
+ struct crypto_bignum *my_scalar;
+ struct crypto_ec_point *my_element;
+ struct crypto_ec_point *server_element;
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
u8 session_id[1 + SHA256_MAC_LEN];
-
- BN_CTX *bnctx;
};
@@ -107,15 +110,8 @@ static void * eap_pwd_init(struct eap_sm *sm)
return NULL;
}
- if ((data->bnctx = BN_CTX_new()) == NULL) {
- wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
- os_free(data);
- return NULL;
- }
-
if ((data->id_peer = os_malloc(identity_len)) == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
- BN_CTX_free(data->bnctx);
os_free(data);
return NULL;
}
@@ -125,7 +121,6 @@ static void * eap_pwd_init(struct eap_sm *sm)
if ((data->password = os_malloc(password_len)) == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
- BN_CTX_free(data->bnctx);
bin_clear_free(data->id_peer, data->id_peer_len);
os_free(data);
return NULL;
@@ -152,21 +147,18 @@ static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
- BN_clear_free(data->private_value);
- BN_clear_free(data->server_scalar);
- BN_clear_free(data->my_scalar);
- BN_clear_free(data->k);
- BN_CTX_free(data->bnctx);
- EC_POINT_clear_free(data->my_element);
- EC_POINT_clear_free(data->server_element);
+ crypto_bignum_deinit(data->private_value, 1);
+ crypto_bignum_deinit(data->server_scalar, 1);
+ crypto_bignum_deinit(data->my_scalar, 1);
+ crypto_bignum_deinit(data->k, 1);
+ crypto_ec_point_deinit(data->my_element, 1);
+ crypto_ec_point_deinit(data->server_element, 1);
bin_clear_free(data->id_peer, data->id_peer_len);
bin_clear_free(data->id_server, data->id_server_len);
bin_clear_free(data->password, data->password_len);
if (data->grp) {
- EC_GROUP_free(data->grp->group);
- EC_POINT_clear_free(data->grp->pwe);
- BN_clear_free(data->grp->order);
- BN_clear_free(data->grp->prime);
+ crypto_ec_deinit(data->grp->group);
+ crypto_ec_point_deinit(data->grp->pwe, 1);
os_free(data->grp);
}
wpabuf_free(data->inbuf);
@@ -183,11 +175,10 @@ static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -202,11 +193,10 @@ static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- id = os_malloc(1 + SHA256_MAC_LEN);
+ id = os_memdup(data->session_id, 1 + SHA256_MAC_LEN);
if (id == NULL)
return NULL;
- os_memcpy(id, data->session_id, 1 + SHA256_MAC_LEN);
*len = 1 + SHA256_MAC_LEN;
return id;
@@ -220,10 +210,6 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
const u8 *payload, size_t payload_len)
{
struct eap_pwd_id *id;
- const u8 *password;
- size_t password_len;
- u8 pwhashhash[16];
- int res;
if (data->state != PWD_ID_Req) {
ret->ignore = TRUE;
@@ -250,7 +236,10 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
}
if (id->prep != EAP_PWD_PREP_NONE &&
- id->prep != EAP_PWD_PREP_MS) {
+ id->prep != EAP_PWD_PREP_MS &&
+ id->prep != EAP_PWD_PREP_SSHA1 &&
+ id->prep != EAP_PWD_PREP_SSHA256 &&
+ id->prep != EAP_PWD_PREP_SSHA512) {
wpa_printf(MSG_DEBUG,
"EAP-PWD: Unsupported password pre-processing technique (Prep=%u)",
id->prep);
@@ -268,6 +257,15 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d",
data->group_num);
+ data->prep = id->prep;
+ os_memcpy(data->token, id->token, sizeof(id->token));
+
+ if (data->id_server || data->grp) {
+ wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated");
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+
data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id));
if (data->id_server == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
@@ -279,7 +277,7 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of",
data->id_server, data->id_server_len);
- data->grp = os_zalloc(sizeof(EAP_PWD_group));
+ data->grp = get_eap_pwd_group(data->group_num);
if (data->grp == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
"group");
@@ -287,13 +285,74 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
return;
}
- if (id->prep == EAP_PWD_PREP_MS) {
+ data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
+ data->id_peer_len);
+ if (data->outbuf == NULL) {
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+ wpabuf_put_be16(data->outbuf, data->group_num);
+ wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
+ wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
+ wpabuf_put_data(data->outbuf, id->token, sizeof(id->token));
+ wpabuf_put_u8(data->outbuf, id->prep);
+ wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len);
+
+ eap_pwd_state(data, PWD_Commit_Req);
+}
+
+
+static void
+eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData,
+ const u8 *payload, size_t payload_len)
+{
+ struct crypto_ec_point *K = NULL;
+ struct crypto_bignum *mask = NULL;
+ const u8 *ptr = payload;
+ u8 *scalar, *element;
+ size_t prime_len, order_len;
+ const u8 *password;
+ size_t password_len;
+ u8 pwhashhash[16];
+ const u8 *salt_pwd[2];
+ size_t salt_pwd_len[2], exp_len;
+ u8 salt_len, salthashpwd[64]; /* 64 = SHA512_DIGEST_LENGTH */
+ int res;
+
+ if (data->state != PWD_Commit_Req) {
+ ret->ignore = TRUE;
+ goto fin;
+ }
+
+ if (!data->grp) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PWD (client): uninitialized EAP-pwd group");
+ ret->ignore = TRUE;
+ goto fin;
+ }
+
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
+ switch (data->prep) {
+ case EAP_PWD_PREP_MS:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is MS");
#ifdef CONFIG_FIPS
wpa_printf(MSG_ERROR,
"EAP-PWD (peer): MS password hash not supported in FIPS mode");
eap_pwd_state(data, FAILURE);
return;
#else /* CONFIG_FIPS */
+ if (payload_len != 2 * prime_len + order_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) (2 * prime_len + order_len));
+ goto fin;
+ }
if (data->password_hash) {
res = hash_nt_password_hash(data->password, pwhashhash);
} else {
@@ -314,9 +373,139 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
password = pwhashhash;
password_len = sizeof(pwhashhash);
#endif /* CONFIG_FIPS */
- } else {
+ break;
+ case EAP_PWD_PREP_SSHA1:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is salted sha1");
+ if (payload_len < 1 || *ptr == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+ goto fin;
+ }
+ salt_len = *ptr++;
+ exp_len = 1 + salt_len + 2 * prime_len + order_len;
+ if (payload_len != exp_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) exp_len);
+ goto fin;
+ }
+
+ /* salted-password = Hash(password | salt) */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+ data->password, data->password_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+ salt_pwd[0] = data->password;
+ salt_pwd[1] = ptr;
+ salt_pwd_len[0] = data->password_len;
+ salt_pwd_len[1] = salt_len;
+ if (sha1_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+ goto fin;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: sha1 hashed %d byte salt with password",
+ (int) salt_len);
+ ptr += salt_len;
+ password = salthashpwd;
+ password_len = SHA1_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+ password, password_len);
+ break;
+ case EAP_PWD_PREP_SSHA256:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is salted sha256");
+ if (payload_len < 1 || *ptr == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+ goto fin;
+ }
+ salt_len = *ptr++;
+ exp_len = 1 + salt_len + 2 * prime_len + order_len;
+ if (payload_len != exp_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) exp_len);
+ goto fin;
+ }
+
+ /* salted-password = Hash(password | salt) */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+ data->password, data->password_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+ salt_pwd[0] = data->password;
+ salt_pwd[1] = ptr;
+ salt_pwd_len[0] = data->password_len;
+ salt_pwd_len[1] = salt_len;
+ if (sha256_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+ goto fin;
+
+ ptr += salt_len;
+ password = salthashpwd;
+ password_len = SHA256_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+ password, password_len);
+ break;
+#ifdef CONFIG_SHA512
+ case EAP_PWD_PREP_SSHA512:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is salted sha512");
+ if (payload_len < 1 || *ptr == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+ goto fin;
+ }
+ salt_len = *ptr++;
+ exp_len = 1 + salt_len + 2 * prime_len + order_len;
+ if (payload_len != exp_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) exp_len);
+ goto fin;
+ }
+
+ /* salted-password = Hash(password | salt) */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+ data->password, data->password_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+ salt_pwd[0] = data->password;
+ salt_pwd[1] = ptr;
+ salt_pwd_len[0] = data->password_len;
+ salt_pwd_len[1] = salt_len;
+ if (sha512_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+ goto fin;
+
+ ptr += salt_len;
+ password = salthashpwd;
+ password_len = SHA512_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+ password, password_len);
+ break;
+#endif /* CONFIG_SHA512 */
+ case EAP_PWD_PREP_NONE:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is NONE");
+ if (data->password_hash) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PWD: Unhashed password not available");
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+ if (payload_len != 2 * prime_len + order_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) (2 * prime_len + order_len));
+ goto fin;
+ }
password = data->password;
password_len = data->password_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: Unsupported password pre-processing technique (Prep=%u)",
+ data->prep);
+ eap_pwd_state(data, FAILURE);
+ return;
}
/* compute PWE */
@@ -324,8 +513,9 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
password, password_len,
data->id_server, data->id_server_len,
data->id_peer, data->id_peer_len,
- id->token);
+ data->token);
os_memset(pwhashhash, 0, sizeof(pwhashhash));
+ os_memset(salthashpwd, 0, sizeof(salthashpwd));
if (res) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
eap_pwd_state(data, FAILURE);
@@ -333,231 +523,112 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
}
wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
- BN_num_bits(data->grp->prime));
-
- data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
- data->id_peer_len);
- if (data->outbuf == NULL) {
- eap_pwd_state(data, FAILURE);
- return;
- }
- wpabuf_put_be16(data->outbuf, data->group_num);
- wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
- wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
- wpabuf_put_data(data->outbuf, id->token, sizeof(id->token));
- wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE);
- wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len);
-
- eap_pwd_state(data, PWD_Commit_Req);
-}
-
-
-static void
-eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
- struct eap_method_ret *ret,
- const struct wpabuf *reqData,
- const u8 *payload, size_t payload_len)
-{
- EC_POINT *K = NULL, *point = NULL;
- BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL;
- u16 offset;
- u8 *ptr, *scalar = NULL, *element = NULL;
- size_t prime_len, order_len;
-
- if (data->state != PWD_Commit_Req) {
- ret->ignore = TRUE;
- goto fin;
- }
-
- prime_len = BN_num_bytes(data->grp->prime);
- order_len = BN_num_bytes(data->grp->order);
-
- if (payload_len != 2 * prime_len + order_len) {
- wpa_printf(MSG_INFO,
- "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
- (unsigned int) payload_len,
- (unsigned int) (2 * prime_len + order_len));
- goto fin;
- }
-
- if (((data->private_value = BN_new()) == NULL) ||
- ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
- ((cofactor = BN_new()) == NULL) ||
- ((data->my_scalar = BN_new()) == NULL) ||
- ((mask = BN_new()) == NULL)) {
+ (int) crypto_ec_prime_len_bits(data->grp->group));
+
+ data->private_value = crypto_bignum_init();
+ data->my_element = crypto_ec_point_init(data->grp->group);
+ data->my_scalar = crypto_bignum_init();
+ mask = crypto_bignum_init();
+ if (!data->private_value || !data->my_element ||
+ !data->my_scalar || !mask) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
goto fin;
}
- if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
- "for curve");
+ if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
+ data->my_scalar) < 0)
goto fin;
- }
-
- if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
- BN_rand_range(mask, data->grp->order) != 1 ||
- BN_add(data->my_scalar, data->private_value, mask) != 1 ||
- BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
- data->bnctx) != 1) {
- wpa_printf(MSG_INFO,
- "EAP-pwd (peer): unable to get randomness");
- goto fin;
- }
- if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
- data->grp->pwe, mask, data->bnctx)) {
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
+ data->my_element) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation "
"fail");
eap_pwd_state(data, FAILURE);
goto fin;
}
- if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
- {
+ if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
goto fin;
}
- BN_clear_free(mask);
-
- if (((x = BN_new()) == NULL) ||
- ((y = BN_new()) == NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail");
- goto fin;
- }
/* process the request */
- if (((data->server_scalar = BN_new()) == NULL) ||
- ((data->k = BN_new()) == NULL) ||
- ((K = EC_POINT_new(data->grp->group)) == NULL) ||
- ((point = EC_POINT_new(data->grp->group)) == NULL) ||
- ((data->server_element = EC_POINT_new(data->grp->group)) == NULL))
- {
+ data->k = crypto_bignum_init();
+ K = crypto_ec_point_init(data->grp->group);
+ if (!data->k || !K) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
"fail");
goto fin;
}
/* element, x then y, followed by scalar */
- ptr = (u8 *) payload;
- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
- ptr += BN_num_bytes(data->grp->prime);
- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
- ptr += BN_num_bytes(data->grp->prime);
- BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar);
- if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
- data->server_element, x, y,
- data->bnctx)) {
+ data->server_element = eap_pwd_get_element(data->grp, ptr);
+ if (!data->server_element) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
"fail");
goto fin;
}
-
- /* check to ensure server's element is not in a small sub-group */
- if (BN_cmp(cofactor, BN_value_one())) {
- if (!EC_POINT_mul(data->grp->group, point, NULL,
- data->server_element, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
- "server element by order!\n");
- goto fin;
- }
- if (EC_POINT_is_at_infinity(data->grp->group, point)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): server element "
- "is at infinity!\n");
- goto fin;
- }
+ ptr += prime_len * 2;
+ data->server_scalar = eap_pwd_get_scalar(data->grp, ptr);
+ if (!data->server_scalar) {
+ wpa_printf(MSG_INFO,
+ "EAP-PWD (peer): setting peer scalar fail");
+ goto fin;
}
/* compute the shared key, k */
- if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
- data->server_scalar, data->bnctx)) ||
- (!EC_POINT_add(data->grp->group, K, K, data->server_element,
- data->bnctx)) ||
- (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
- data->bnctx))) {
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe,
+ data->server_scalar, K) < 0 ||
+ crypto_ec_point_add(data->grp->group, K, data->server_element,
+ K) < 0 ||
+ crypto_ec_point_mul(data->grp->group, K, data->private_value,
+ K) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key "
"fail");
goto fin;
}
- /* ensure that the shared key isn't in a small sub-group */
- if (BN_cmp(cofactor, BN_value_one())) {
- if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
- NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
- "shared key point by order");
- goto fin;
- }
- }
-
/*
- * This check is strictly speaking just for the case above where
+ * This check is strictly speaking just for the case where
* co-factor > 1 but it was suggested that even though this is probably
* never going to happen it is a simple and safe check "just to be
* sure" so let's be safe.
*/
- if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+ if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at "
"infinity!\n");
goto fin;
}
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
- NULL, data->bnctx)) {
+ if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
"shared secret from point");
goto fin;
}
/* now do the response */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
- goto fin;
- }
-
- if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
- ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
- NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail");
+ data->outbuf = wpabuf_alloc(2 * prime_len + order_len);
+ if (data->outbuf == NULL)
goto fin;
- }
+ /* We send the element as (x,y) followed by the scalar */
+ element = wpabuf_put(data->outbuf, 2 * prime_len);
+ scalar = wpabuf_put(data->outbuf, order_len);
/*
* bignums occupy as little memory as possible so one that is
* sufficiently smaller than the prime or order might need pre-pending
* with zeros.
*/
- os_memset(scalar, 0, BN_num_bytes(data->grp->order));
- os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, scalar + offset);
-
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, element + offset);
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
-
- data->outbuf = wpabuf_alloc(BN_num_bytes(data->grp->order) +
- 2 * BN_num_bytes(data->grp->prime));
- if (data->outbuf == NULL)
+ crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
+ element + prime_len) != 0) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
goto fin;
-
- /* we send the element as (x,y) follwed by the scalar */
- wpabuf_put_data(data->outbuf, element,
- 2 * BN_num_bytes(data->grp->prime));
- wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
+ }
fin:
- os_free(scalar);
- os_free(element);
- BN_clear_free(x);
- BN_clear_free(y);
- BN_clear_free(cofactor);
- EC_POINT_clear_free(K);
- EC_POINT_clear_free(point);
+ crypto_bignum_deinit(mask, 1);
+ crypto_ec_point_deinit(K, 1);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
else
@@ -571,12 +642,11 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
const struct wpabuf *reqData,
const u8 *payload, size_t payload_len)
{
- BIGNUM *x = NULL, *y = NULL;
- struct crypto_hash *hash;
+ struct crypto_hash *hash = NULL;
u32 cs;
u16 grp;
u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
- int offset;
+ size_t prime_len = 0, order_len = 0;
if (data->state != PWD_Confirm_Req) {
ret->ignore = TRUE;
@@ -590,6 +660,9 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
}
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
/*
* first build up the ciphersuite which is group | random_function |
* prf
@@ -602,9 +675,9 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
ptr += sizeof(u8);
*ptr = EAP_PWD_DEFAULT_PRF;
- /* each component of the cruft will be at most as big as the prime */
- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+ /* each component of the point will be at most as big as the prime */
+ cruft = os_malloc(prime_len * 2);
+ if (!cruft) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
"fail");
goto fin;
@@ -622,65 +695,41 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
* zero the memory each time because this is mod prime math and some
* value may start with a few zeros and the previous one did not.
*/
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
- BN_bn2bin(data->k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
/* server element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->server_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
+ cruft, cruft + prime_len) != 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* server scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->server_scalar);
- BN_bn2bin(data->server_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* my element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+ cruft + prime_len) != 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
-
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* my scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* the ciphersuite */
eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* random function fin */
eap_pwd_h_final(hash, conf);
+ hash = NULL;
ptr = (u8 *) payload;
if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
@@ -700,66 +749,43 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
/* k */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
- BN_bn2bin(data->k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
/* my element */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+ cruft + prime_len) != 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
"assignment fail");
goto fin;
}
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* my scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* server element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->server_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
+ cruft, cruft + prime_len) != 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
"assignment fail");
goto fin;
}
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* server scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->server_scalar);
- BN_bn2bin(data->server_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* the ciphersuite */
eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* all done */
eap_pwd_h_final(hash, conf);
+ hash = NULL;
- if (compute_keys(data->grp, data->bnctx, data->k,
+ if (compute_keys(data->grp, data->k,
data->my_scalar, data->server_scalar, conf, ptr,
&cs, data->msk, data->emsk, data->session_id) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
@@ -774,9 +800,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
- bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
- BN_clear_free(x);
- BN_clear_free(y);
+ bin_clear_free(cruft, prime_len * 2);
if (data->outbuf == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
@@ -784,6 +808,10 @@ fin:
} else {
eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
}
+
+ /* clean allocated memory */
+ if (hash)
+ eap_pwd_h_final(hash, conf);
}
@@ -903,7 +931,14 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
/*
* buffer and ACK the fragment
*/
- if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
+ if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
+ if (!data->inbuf) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: No buffer for reassembly");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
data->in_frag_pos += len;
if (data->in_frag_pos > wpabuf_size(data->inbuf)) {
wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack "
@@ -916,7 +951,8 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
return NULL;
}
wpabuf_put_data(data->inbuf, pos, len);
-
+ }
+ if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
EAP_PWD_HDR_SIZE,
EAP_CODE_RESPONSE, eap_get_id(reqData));
@@ -929,11 +965,9 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
/*
* we're buffering and this is the last fragment
*/
- if (data->in_frag_pos) {
- wpabuf_put_data(data->inbuf, pos, len);
+ if (data->in_frag_pos && data->inbuf) {
wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
(int) len);
- data->in_frag_pos += len;
pos = wpabuf_head_u8(data->inbuf);
len = data->in_frag_pos;
}
@@ -1054,7 +1088,6 @@ static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_pwd_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
@@ -1069,8 +1102,5 @@ int eap_peer_pwd_register(void)
eap->getSessionId = eap_pwd_get_session_id;
eap->get_emsk = eap_pwd_get_emsk;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_sake.c b/contrib/wpa/src/eap_peer/eap_sake.c
index c4f9843..255241f 100644
--- a/contrib/wpa/src/eap_peer/eap_sake.c
+++ b/contrib/wpa/src/eap_peer/eap_sake.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-SAKE (RFC 4763)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -85,12 +85,11 @@ static void * eap_sake_init(struct eap_sm *sm)
identity = eap_get_config_identity(sm, &identity_len);
if (identity) {
- data->peerid = os_malloc(identity_len);
+ data->peerid = os_memdup(identity, identity_len);
if (data->peerid == NULL) {
eap_sake_deinit(sm, data);
return NULL;
}
- os_memcpy(data->peerid, identity, identity_len);
data->peerid_len = identity_len;
}
@@ -230,16 +229,19 @@ static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
if (attr.serverid) {
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
attr.serverid, attr.serverid_len);
- data->serverid = os_malloc(attr.serverid_len);
+ data->serverid = os_memdup(attr.serverid, attr.serverid_len);
if (data->serverid == NULL)
return NULL;
- os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
data->serverid_len = attr.serverid_len;
}
- eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
- data->rand_s, data->rand_p,
- (u8 *) &data->tek, data->msk, data->emsk);
+ if (eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
+ data->rand_s, data->rand_p,
+ (u8 *) &data->tek, data->msk,
+ data->emsk) < 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to derive keys");
+ return NULL;
+ }
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
@@ -309,11 +311,20 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
return NULL;
}
- eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- data->serverid, data->serverid_len,
- data->peerid, data->peerid_len, 0,
- wpabuf_head(reqData), wpabuf_len(reqData),
- attr.mic_s, mic_s);
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, 0,
+ wpabuf_head(reqData), wpabuf_len(reqData),
+ attr.mic_s, mic_s)) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ eap_sake_state(data, FAILURE);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = FALSE;
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Auth-Reject");
+ return eap_sake_build_msg(data, id, 0,
+ EAP_SAKE_SUBTYPE_AUTH_REJECT);
+ }
if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
eap_sake_state(data, FAILURE);
@@ -441,10 +452,9 @@ static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -481,10 +491,9 @@ static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
@@ -494,7 +503,6 @@ static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_sake_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
@@ -509,8 +517,5 @@ int eap_peer_sake_register(void)
eap->getSessionId = eap_sake_get_session_id;
eap->get_emsk = eap_sake_get_emsk;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_sim.c b/contrib/wpa/src/eap_peer/eap_sim.c
index 99a2816..ba5eea9 100644
--- a/contrib/wpa/src/eap_peer/eap_sim.c
+++ b/contrib/wpa/src/eap_peer/eap_sim.c
@@ -46,6 +46,8 @@ struct eap_sim_data {
CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
int result_ind, use_result_ind;
+ int use_pseudonym;
+ int error_code;
};
@@ -93,6 +95,9 @@ static void * eap_sim_init(struct eap_sm *sm)
return NULL;
}
+ /* Zero is a valid error code, so we need to initialize */
+ data->error_code = NO_EAP_METHOD_ERROR;
+
data->min_num_chal = 2;
if (config && config->phase1) {
char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
@@ -115,7 +120,8 @@ static void * eap_sim_init(struct eap_sm *sm)
NULL;
}
- if (config && config->anonymous_identity) {
+ data->use_pseudonym = !sm->init_phase2;
+ if (config && config->anonymous_identity && data->use_pseudonym) {
data->pseudonym = os_malloc(config->anonymous_identity_len);
if (data->pseudonym) {
os_memcpy(data->pseudonym, config->anonymous_identity,
@@ -249,6 +255,7 @@ static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
return eap_sim_ext_sim_req(sm, data);
}
+#ifdef PCSC_FUNCS
if (conf->pcsc) {
if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
data->sres[0], data->kc[0]) ||
@@ -263,6 +270,7 @@ static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
}
return 0;
}
+#endif /* PCSC_FUNCS */
#ifdef CONFIG_SIM_SIMULATOR
if (conf->password) {
@@ -370,7 +378,8 @@ static void eap_sim_clear_identities(struct eap_sm *sm,
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
- eap_set_anon_id(sm, NULL, 0);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
@@ -425,20 +434,21 @@ static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data,
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
- eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, data->pseudonym,
+ data->pseudonym_len);
}
if (attr->next_reauth_id) {
os_free(data->reauth_id);
- data->reauth_id = os_malloc(attr->next_reauth_id_len);
+ data->reauth_id = os_memdup(attr->next_reauth_id,
+ attr->next_reauth_id_len);
if (data->reauth_id == NULL) {
wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
"next reauth_id");
data->reauth_id_len = 0;
return -1;
}
- os_memcpy(data->reauth_id, attr->next_reauth_id,
- attr->next_reauth_id_len);
data->reauth_id_len = attr->next_reauth_id_len;
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
@@ -633,14 +643,13 @@ static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
}
os_free(data->ver_list);
- data->ver_list = os_malloc(attr->version_list_len);
+ data->ver_list = os_memdup(attr->version_list, attr->version_list_len);
if (data->ver_list == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
"memory for version list");
return eap_sim_client_error(data, id,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
- os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
data->ver_list_len = attr->version_list_len;
pos = data->ver_list;
for (i = 0; i < data->ver_list_len / 2; i++) {
@@ -762,8 +771,17 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
} else if (data->pseudonym) {
identity = data->pseudonym;
identity_len = data->pseudonym_len;
- } else
- identity = eap_get_config_identity(sm, &identity_len);
+ } else {
+ struct eap_peer_config *config;
+
+ config = eap_get_config(sm);
+ if (config && config->imsi_identity) {
+ identity = config->imsi_identity;
+ identity_len = config->imsi_identity_len;
+ } else {
+ identity = eap_get_config_identity(sm, &identity_len);
+ }
+ }
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
"derivation", identity, identity_len);
eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
@@ -906,6 +924,7 @@ static struct wpabuf * eap_sim_process_notification(
eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
if (attr->notification >= 0 && attr->notification < 32768) {
+ data->error_code = attr->notification;
eap_sim_state(data, FAILURE);
} else if (attr->notification == EAP_SIM_SUCCESS &&
data->state == RESULT_SUCCESS)
@@ -1135,7 +1154,7 @@ static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
"for NONCE_MT");
- os_free(data);
+ eap_sim_deinit(sm, data);
return NULL;
}
data->num_id_req = 0;
@@ -1179,12 +1198,11 @@ static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
+ key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
if (key == NULL)
return NULL;
*len = EAP_SIM_KEYING_DATA_LEN;
- os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
return key;
}
@@ -1221,21 +1239,36 @@ static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
*len = EAP_EMSK_LEN;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
return key;
}
+static int eap_sim_get_error_code(void *priv)
+{
+ struct eap_sim_data *data = priv;
+ int current_data_error;
+
+ if (!data)
+ return NO_EAP_METHOD_ERROR;
+
+ current_data_error = data->error_code;
+
+ /* Now reset for next transaction */
+ data->error_code = NO_EAP_METHOD_ERROR;
+
+ return current_data_error;
+}
+
+
int eap_peer_sim_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
@@ -1253,9 +1286,7 @@ int eap_peer_sim_register(void)
eap->init_for_reauth = eap_sim_init_for_reauth;
eap->get_identity = eap_sim_get_identity;
eap->get_emsk = eap_sim_get_emsk;
+ eap->get_error_code = eap_sim_get_error_code;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_tls.c b/contrib/wpa/src/eap_peer/eap_tls.c
index 66a027a..ffea9d2 100644
--- a/contrib/wpa/src/eap_peer/eap_tls.c
+++ b/contrib/wpa/src/eap_peer/eap_tls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -25,6 +25,7 @@ struct eap_tls_data {
size_t id_len;
void *ssl_ctx;
u8 eap_type;
+ struct wpabuf *pending_resp;
};
@@ -142,6 +143,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_tls_free_key(data);
os_free(data->session_id);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
@@ -171,14 +173,32 @@ static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
struct eap_method_ret *ret)
{
+ const char *label;
+
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_UNCOND_SUCC;
+ if (data->ssl.tls_out) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Fragment(s) remaining");
+ return;
+ }
+
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+
+ /* A possible NewSessionTicket may be received before
+ * EAP-Success, so need to allow it to be received. */
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_COND_SUCC;
+ } else {
+ label = "client EAP encryption";
+
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
eap_tls_free_key(data);
- data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
+ data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label,
+ NULL, 0,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (data->key_data) {
@@ -216,6 +236,32 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
struct eap_tls_data *data = priv;
struct wpabuf msg;
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
reqData, &left, &flags);
if (pos == NULL)
@@ -237,6 +283,14 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
return eap_tls_failure(sm, data, ret, res, resp, id);
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
eap_tls_success(sm, data, ret);
@@ -258,6 +312,10 @@ static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
+ struct eap_tls_data *data = priv;
+
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
}
@@ -298,12 +356,11 @@ static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->key_data == NULL)
return NULL;
- key = os_malloc(EAP_TLS_KEY_LEN);
+ key = os_memdup(data->key_data, EAP_TLS_KEY_LEN);
if (key == NULL)
return NULL;
*len = EAP_TLS_KEY_LEN;
- os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
return key;
}
@@ -317,12 +374,11 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->key_data == NULL)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
*len = EAP_EMSK_LEN;
- os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
return key;
}
@@ -336,12 +392,11 @@ static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
if (data->session_id == NULL)
return NULL;
- id = os_malloc(data->id_len);
+ id = os_memdup(data->session_id, data->id_len);
if (id == NULL)
return NULL;
*len = data->id_len;
- os_memcpy(id, data->session_id, data->id_len);
return id;
}
@@ -350,7 +405,6 @@ static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_tls_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
@@ -369,10 +423,7 @@ int eap_peer_tls_register(void)
eap->init_for_reauth = eap_tls_init_for_reauth;
eap->get_emsk = eap_tls_get_emsk;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
@@ -380,7 +431,6 @@ int eap_peer_tls_register(void)
int eap_peer_unauth_tls_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_UNAUTH_TLS,
@@ -399,10 +449,7 @@ int eap_peer_unauth_tls_register(void)
eap->init_for_reauth = eap_tls_init_for_reauth;
eap->get_emsk = eap_tls_get_emsk;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
#endif /* EAP_UNAUTH_TLS */
@@ -411,7 +458,6 @@ int eap_peer_unauth_tls_register(void)
int eap_peer_wfa_unauth_tls_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_WFA_NEW,
@@ -431,9 +477,6 @@ int eap_peer_wfa_unauth_tls_register(void)
eap->init_for_reauth = eap_tls_init_for_reauth;
eap->get_emsk = eap_tls_get_emsk;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
#endif /* CONFIG_HS20 */
diff --git a/contrib/wpa/src/eap_peer/eap_tls_common.c b/contrib/wpa/src/eap_peer/eap_tls_common.c
index af2b754..cb94c45 100644
--- a/contrib/wpa/src/eap_peer/eap_tls_common.c
+++ b/contrib/wpa/src/eap_peer/eap_tls_common.c
@@ -1,6 +1,6 @@
/*
* EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -70,30 +70,53 @@ static void eap_tls_params_flags(struct tls_connection_params *params,
params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
if (os_strstr(txt, "tls_disable_tlsv1_0=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_0;
- if (os_strstr(txt, "tls_disable_tlsv1_0=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_0=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_0;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_0;
+ }
if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_1;
- if (os_strstr(txt, "tls_disable_tlsv1_1=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_1=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_1;
+ }
if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_2;
- if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_2=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_2;
+ }
+ if (os_strstr(txt, "tls_disable_tlsv1_3=1"))
+ params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+ if (os_strstr(txt, "tls_disable_tlsv1_3=0"))
+ params->flags &= ~TLS_CONN_DISABLE_TLSv1_3;
+ if (os_strstr(txt, "tls_ext_cert_check=1"))
+ params->flags |= TLS_CONN_EXT_CERT_CHECK;
+ if (os_strstr(txt, "tls_ext_cert_check=0"))
+ params->flags &= ~TLS_CONN_EXT_CERT_CHECK;
+ if (os_strstr(txt, "tls_suiteb=1"))
+ params->flags |= TLS_CONN_SUITEB;
+ if (os_strstr(txt, "tls_suiteb=0"))
+ params->flags &= ~TLS_CONN_SUITEB;
+ if (os_strstr(txt, "tls_suiteb_no_ecdh=1"))
+ params->flags |= TLS_CONN_SUITEB_NO_ECDH;
+ if (os_strstr(txt, "tls_suiteb_no_ecdh=0"))
+ params->flags &= ~TLS_CONN_SUITEB_NO_ECDH;
}
static void eap_tls_params_from_conf1(struct tls_connection_params *params,
struct eap_peer_config *config)
{
- params->ca_cert = (char *) config->ca_cert;
- params->ca_path = (char *) config->ca_path;
- params->client_cert = (char *) config->client_cert;
- params->private_key = (char *) config->private_key;
- params->private_key_passwd = (char *) config->private_key_passwd;
- params->dh_file = (char *) config->dh_file;
- params->subject_match = (char *) config->subject_match;
- params->altsubject_match = (char *) config->altsubject_match;
+ params->ca_cert = config->ca_cert;
+ params->ca_path = config->ca_path;
+ params->client_cert = config->client_cert;
+ params->private_key = config->private_key;
+ params->private_key_passwd = config->private_key_passwd;
+ params->dh_file = config->dh_file;
+ params->subject_match = config->subject_match;
+ params->altsubject_match = config->altsubject_match;
+ params->check_cert_subject = config->check_cert_subject;
params->suffix_match = config->domain_suffix_match;
params->domain_match = config->domain_match;
params->engine = config->engine;
@@ -109,14 +132,15 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params,
static void eap_tls_params_from_conf2(struct tls_connection_params *params,
struct eap_peer_config *config)
{
- params->ca_cert = (char *) config->ca_cert2;
- params->ca_path = (char *) config->ca_path2;
- params->client_cert = (char *) config->client_cert2;
- params->private_key = (char *) config->private_key2;
- params->private_key_passwd = (char *) config->private_key2_passwd;
- params->dh_file = (char *) config->dh_file2;
- params->subject_match = (char *) config->subject_match2;
- params->altsubject_match = (char *) config->altsubject_match2;
+ params->ca_cert = config->ca_cert2;
+ params->ca_path = config->ca_path2;
+ params->client_cert = config->client_cert2;
+ params->private_key = config->private_key2;
+ params->private_key_passwd = config->private_key2_passwd;
+ params->dh_file = config->dh_file2;
+ params->subject_match = config->subject_match2;
+ params->altsubject_match = config->altsubject_match2;
+ params->check_cert_subject = config->check_cert_subject2;
params->suffix_match = config->domain_suffix_match2;
params->domain_match = config->domain_match2;
params->engine = config->engine2;
@@ -147,6 +171,25 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
*/
params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
}
+ if (data->eap_type == EAP_TYPE_FAST ||
+ data->eap_type == EAP_TYPE_TTLS ||
+ data->eap_type == EAP_TYPE_PEAP) {
+ /* The current EAP peer implementation is not yet ready for the
+ * TLS v1.3 changes, so disable this by default for now. */
+ params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+ }
+ if (data->eap_type == EAP_TYPE_TLS ||
+ data->eap_type == EAP_UNAUTH_TLS_TYPE ||
+ data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) {
+ /* While the current EAP-TLS implementation is more or less
+ * complete for TLS v1.3, there has been no interoperability
+ * testing with other implementations, so disable for by default
+ * for now until there has been chance to confirm that no
+ * significant interoperability issues show up with TLS version
+ * update.
+ */
+ params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+ }
if (phase2) {
wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
eap_tls_params_from_conf2(params, config);
@@ -177,6 +220,8 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
params->openssl_ciphers = config->openssl_ciphers;
+ sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
+
return 0;
}
@@ -190,8 +235,10 @@ static int eap_tls_init_connection(struct eap_sm *sm,
if (config->ocsp)
params->flags |= TLS_CONN_REQUEST_OCSP;
- if (config->ocsp == 2)
+ if (config->ocsp >= 2)
params->flags |= TLS_CONN_REQUIRE_OCSP;
+ if (config->ocsp == 3)
+ params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
@@ -302,6 +349,8 @@ void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @data: Data for TLS processing
* @label: Label string for deriving the keys, e.g., "client EAP encryption"
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
* @len: Length of the key material to generate (usually 64 for MSK)
* Returns: Pointer to allocated key on success or %NULL on failure
*
@@ -310,9 +359,12 @@ void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
* different label to bind the key usage into the generated material.
*
* The caller is responsible for freeing the returned buffer.
+ *
+ * Note: To provide the RFC 5705 context, the context variable must be non-NULL.
*/
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- const char *label, size_t len)
+ const char *label, const u8 *context,
+ size_t context_len, size_t len)
{
u8 *out;
@@ -320,8 +372,8 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
if (out == NULL)
return NULL;
- if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0,
- out, len)) {
+ if (tls_connection_export_key(data->ssl_ctx, data->conn, label,
+ context, context_len, out, len)) {
os_free(out);
return NULL;
}
@@ -350,10 +402,31 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct tls_random keys;
u8 *out;
- if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
- return NULL;
+ if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ u8 *id, *method_id;
- if (keys.client_random == NULL || keys.server_random == NULL)
+ /* Session-Id = <EAP-Type> || Method-Id
+ * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
+ * "", 64)
+ */
+ *len = 1 + 64;
+ id = os_malloc(*len);
+ if (!id)
+ return NULL;
+ method_id = eap_peer_tls_derive_key(
+ sm, data, "EXPORTER_EAP_TLS_Method-Id", NULL, 0, 64);
+ if (!method_id) {
+ os_free(id);
+ return NULL;
+ }
+ id[0] = eap_type;
+ os_memcpy(id + 1, method_id, 64);
+ os_free(method_id);
+ return id;
+ }
+
+ if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) ||
+ keys.client_random == NULL || keys.server_random == NULL)
return NULL;
*len = 1 + keys.client_random_len + keys.server_random_len;
@@ -655,6 +728,8 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
* the AS.
*/
int res = eap_tls_process_input(sm, data, in_data, out_data);
+ char buf[20];
+
if (res) {
/*
* Input processing failed (res = -1) or more data is
@@ -667,6 +742,12 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
* The incoming message has been reassembled and processed. The
* response was allocated into data->tls_out buffer.
*/
+
+ if (tls_get_version(data->ssl_ctx, data->conn,
+ buf, sizeof(buf)) == 0) {
+ wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
+ data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
+ }
}
if (data->tls_out == NULL) {
@@ -1035,6 +1116,9 @@ int eap_peer_select_phase2_methods(struct eap_peer_config *config,
if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) {
wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP "
"method '%s'", start);
+ os_free(methods);
+ os_free(buf);
+ return -1;
} else {
num_methods++;
_methods = os_realloc_array(methods, num_methods,
diff --git a/contrib/wpa/src/eap_peer/eap_tls_common.h b/contrib/wpa/src/eap_peer/eap_tls_common.h
index acd2b78..5f82529 100644
--- a/contrib/wpa/src/eap_peer/eap_tls_common.h
+++ b/contrib/wpa/src/eap_peer/eap_tls_common.h
@@ -73,6 +73,11 @@ struct eap_ssl_data {
* eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
*/
u8 eap_type;
+
+ /**
+ * tls_v13 - Whether TLS v1.3 or newer is used
+ */
+ int tls_v13;
};
@@ -94,7 +99,8 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
struct eap_peer_config *config, u8 eap_type);
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- const char *label, size_t len);
+ const char *label, const u8 *context,
+ size_t context_len, size_t len);
u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
diff --git a/contrib/wpa/src/eap_peer/eap_tnc.c b/contrib/wpa/src/eap_peer/eap_tnc.c
index 25b9f12..726221e 100644
--- a/contrib/wpa/src/eap_peer/eap_tnc.c
+++ b/contrib/wpa/src/eap_peer/eap_tnc.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "eap_i.h"
+#include "eap_config.h"
#include "tncc.h"
@@ -35,12 +36,16 @@ struct eap_tnc_data {
static void * eap_tnc_init(struct eap_sm *sm)
{
struct eap_tnc_data *data;
+ struct eap_peer_config *config = eap_get_config(sm);
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
data->state = WAIT_START;
- data->fragment_size = 1300;
+ if (config && config->fragment_size)
+ data->fragment_size = config->fragment_size;
+ else
+ data->fragment_size = 1300;
data->tncc = tncc_init();
if (data->tncc == NULL) {
os_free(data);
@@ -345,11 +350,6 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
ret->decision = DECISION_UNCOND_SUCC;
ret->allowNotifications = TRUE;
- if (data->out_buf) {
- data->state = PROC_MSG;
- return eap_tnc_build_msg(data, ret, id);
- }
-
if (tncs_done) {
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
EAP_CODE_RESPONSE, eap_get_id(reqData));
@@ -410,7 +410,6 @@ fail:
int eap_peer_tnc_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
@@ -421,8 +420,5 @@ int eap_peer_tnc_register(void)
eap->deinit = eap_tnc_deinit;
eap->process = eap_tnc_process;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_ttls.c b/contrib/wpa/src/eap_peer/eap_ttls.c
index b186c91..1c8dbe2 100644
--- a/contrib/wpa/src/eap_peer/eap_ttls.c
+++ b/contrib/wpa/src/eap_peer/eap_ttls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -35,6 +35,7 @@ struct eap_ttls_data {
void *phase2_priv;
int phase2_success;
int phase2_start;
+ EapDecision decision_succ;
enum phase2_types {
EAP_TTLS_PHASE2_EAP,
@@ -58,6 +59,7 @@ struct eap_ttls_data {
size_t id_len;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
#ifdef EAP_TNC
int ready_for_tnc;
@@ -70,6 +72,7 @@ static void * eap_ttls_init(struct eap_sm *sm)
{
struct eap_ttls_data *data;
struct eap_peer_config *config = eap_get_config(sm);
+ int selected_non_eap;
char *selected;
data = os_zalloc(sizeof(*data));
@@ -77,26 +80,67 @@ static void * eap_ttls_init(struct eap_sm *sm)
return NULL;
data->ttls_version = EAP_TTLS_VERSION;
selected = "EAP";
+ selected_non_eap = 0;
data->phase2_type = EAP_TTLS_PHASE2_EAP;
+ /*
+ * Either one auth= type or one or more autheap= methods can be
+ * specified.
+ */
if (config && config->phase2) {
+ const char *token, *last = NULL;
+
+ while ((token = cstr_token(config->phase2, " \t", &last))) {
+ if (os_strncmp(token, "auth=", 5) != 0)
+ continue;
+ token += 5;
+
+ if (last - token == 8 &&
+ os_strncmp(token, "MSCHAPV2", 8) == 0) {
+ selected = "MSCHAPV2";
+ data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
+ } else if (last - token == 6 &&
+ os_strncmp(token, "MSCHAP", 6) == 0) {
+ selected = "MSCHAP";
+ data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
+ } else if (last - token == 3 &&
+ os_strncmp(token, "PAP", 3) == 0) {
+ selected = "PAP";
+ data->phase2_type = EAP_TTLS_PHASE2_PAP;
+ } else if (last - token == 4 &&
+ os_strncmp(token, "CHAP", 4) == 0) {
+ selected = "CHAP";
+ data->phase2_type = EAP_TTLS_PHASE2_CHAP;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "EAP-TTLS: Unsupported Phase2 type '%s'",
+ token);
+ eap_ttls_deinit(sm, data);
+ return NULL;
+ }
+
+ if (selected_non_eap) {
+ wpa_printf(MSG_ERROR,
+ "EAP-TTLS: Only one Phase2 type can be specified");
+ eap_ttls_deinit(sm, data);
+ return NULL;
+ }
+
+ selected_non_eap = 1;
+ }
+
if (os_strstr(config->phase2, "autheap=")) {
+ if (selected_non_eap) {
+ wpa_printf(MSG_ERROR,
+ "EAP-TTLS: Both auth= and autheap= params cannot be specified");
+ eap_ttls_deinit(sm, data);
+ return NULL;
+ }
selected = "EAP";
data->phase2_type = EAP_TTLS_PHASE2_EAP;
- } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
- selected = "MSCHAPV2";
- data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
- } else if (os_strstr(config->phase2, "auth=MSCHAP")) {
- selected = "MSCHAP";
- data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
- } else if (os_strstr(config->phase2, "auth=PAP")) {
- selected = "PAP";
- data->phase2_type = EAP_TTLS_PHASE2_PAP;
- } else if (os_strstr(config->phase2, "auth=CHAP")) {
- selected = "CHAP";
- data->phase2_type = EAP_TTLS_PHASE2_CHAP;
}
}
+
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
@@ -152,7 +196,8 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_ttls_free_key(data);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
os_free(data);
}
@@ -203,7 +248,7 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
if (msg == NULL) {
- wpabuf_free(*resp);
+ wpabuf_clear_free(*resp);
*resp = NULL;
return -1;
}
@@ -213,7 +258,7 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
pos += wpabuf_len(*resp);
AVP_PAD(avp, pos);
- wpabuf_free(*resp);
+ wpabuf_clear_free(*resp);
wpabuf_put(msg, pos - avp);
*resp = msg;
return 0;
@@ -226,6 +271,7 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
eap_ttls_free_key(data);
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
"ttls keying material",
+ NULL, 0,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (!data->key_data) {
@@ -258,7 +304,8 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
struct eap_ttls_data *data, size_t len)
{
- return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
+ return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge",
+ NULL, 0, len);
}
#endif /* CONFIG_FIPS */
@@ -413,7 +460,7 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
if (*resp == NULL &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp)) {
+ config->pending_req_otp || config->pending_req_sim)) {
return 0;
}
@@ -465,7 +512,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
"implicit challenge");
return -1;
@@ -484,7 +531,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
*pos++ = 0; /* Flags */
if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
os_free(challenge);
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
"random data for peer challenge");
return -1;
@@ -498,7 +545,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
peer_challenge, pos, data->auth_response,
data->master_key)) {
os_free(challenge);
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
"response");
return -1;
@@ -559,7 +606,7 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
"implicit challenge");
return -1;
@@ -579,12 +626,28 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
os_memset(pos, 0, 24); /* LM-Response */
pos += 24;
if (pwhash) {
- challenge_response(challenge, password, pos); /* NT-Response */
+ /* NT-Response */
+ if (challenge_response(challenge, password, pos)) {
+ wpa_printf(MSG_ERROR,
+ "EAP-TTLS/MSCHAP: Failed derive password hash");
+ wpabuf_clear_free(msg);
+ os_free(challenge);
+ return -1;
+ }
+
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
password, 16);
} else {
- nt_challenge_response(challenge, password, password_len,
- pos); /* NT-Response */
+ /* NT-Response */
+ if (nt_challenge_response(challenge, password, password_len,
+ pos)) {
+ wpa_printf(MSG_ERROR,
+ "EAP-TTLS/MSCHAP: Failed derive password");
+ wpabuf_clear_free(msg);
+ os_free(challenge);
+ return -1;
+ }
+
wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
password, password_len);
}
@@ -699,7 +762,7 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
"implicit challenge");
return -1;
@@ -825,13 +888,12 @@ static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen,
{
wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
if (parse->eapdata == NULL) {
- parse->eapdata = os_malloc(dlen);
+ parse->eapdata = os_memdup(dpos, dlen);
if (parse->eapdata == NULL) {
wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
"memory for Phase 2 EAP data");
return -1;
}
- os_memcpy(parse->eapdata, dpos, dlen);
parse->eap_len = dlen;
} else {
u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen);
@@ -1013,10 +1075,10 @@ static int eap_ttls_encrypt_response(struct eap_sm *sm,
resp, out_data)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
"frame");
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return -1;
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return 0;
}
@@ -1235,8 +1297,9 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm,
} else if (config->pending_req_identity ||
config->pending_req_password ||
config->pending_req_otp ||
- config->pending_req_new_password) {
- wpabuf_free(data->pending_phase2_req);
+ config->pending_req_new_password ||
+ config->pending_req_sim) {
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_dup(in_decrypted);
}
@@ -1272,13 +1335,14 @@ static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
(config->pending_req_identity ||
config->pending_req_password ||
config->pending_req_otp ||
- config->pending_req_new_password)) {
+ config->pending_req_new_password ||
+ config->pending_req_sim)) {
/*
* Use empty buffer to force implicit request
* processing when EAP request is re-processed after
* user input.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc(0);
}
@@ -1351,7 +1415,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
in_decrypted = data->pending_phase2_req;
data->pending_phase2_req = NULL;
if (wpabuf_len(in_decrypted) == 0) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return eap_ttls_implicit_identity_request(
sm, data, ret, identifier, out_data);
}
@@ -1387,7 +1451,7 @@ continue_req:
&parse, in_decrypted, out_data);
done:
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
os_free(parse.eapdata);
if (retval < 0) {
@@ -1408,6 +1472,32 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
{
int res;
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: External certificate check succeeded - continue handshake");
+ *out_data = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return 0;
+ }
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Continuing to wait external server certificate validation");
+ return 0;
+ }
+
res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
data->ttls_version, identifier,
in_data, out_data);
@@ -1418,6 +1508,15 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
return -1;
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Waiting external server certificate validation");
+ wpabuf_clear_free(data->pending_resp);
+ data->pending_resp = *out_data;
+ *out_data = NULL;
+ return 0;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
"Phase 2");
@@ -1446,7 +1545,7 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = *out_data;
*out_data = NULL;
res = eap_ttls_decrypt(sm, data, ret, identifier, in_data,
@@ -1457,7 +1556,7 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
}
-static void eap_ttls_check_auth_status(struct eap_sm *sm,
+static void eap_ttls_check_auth_status(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret)
{
@@ -1468,6 +1567,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
"completed successfully");
data->phase2_success = 1;
+ data->decision_succ = ret->decision;
#ifdef EAP_TNC
if (!data->ready_for_tnc && !data->tnc_started) {
/*
@@ -1485,6 +1585,18 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
"completed successfully (MAY_CONT)");
data->phase2_success = 1;
+ data->decision_succ = ret->decision;
+ } else if (data->decision_succ != DECISION_FAIL &&
+ data->phase2_success &&
+ !data->ssl.tls_out) {
+ /*
+ * This is needed to cover the case where the final Phase 2
+ * message gets fragmented since fragmentation clears
+ * decision back to FAIL.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Restore success decision after fragmented frame sent completely");
+ ret->decision = data->decision_succ;
}
}
@@ -1536,7 +1648,7 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
/* FIX: what about res == -1? Could just move all error processing into
* the other functions and get rid of this res==1 case here. */
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS,
data->ttls_version);
}
@@ -1555,8 +1667,15 @@ static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
- wpabuf_free(data->pending_phase2_req);
+
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->deinit_for_reauth)
+ data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_clear_free(data->pending_resp);
+ data->pending_resp = NULL;
+ data->decision_succ = DECISION_FAIL;
#ifdef EAP_TNC
data->ready_for_tnc = 0;
data->tnc_started = 0;
@@ -1643,12 +1762,11 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->key_data == NULL || !data->phase2_success)
return NULL;
- key = os_malloc(EAP_TLS_KEY_LEN);
+ key = os_memdup(data->key_data, EAP_TLS_KEY_LEN);
if (key == NULL)
return NULL;
*len = EAP_TLS_KEY_LEN;
- os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
return key;
}
@@ -1662,12 +1780,11 @@ static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
if (data->session_id == NULL || !data->phase2_success)
return NULL;
- id = os_malloc(data->id_len);
+ id = os_memdup(data->session_id, data->id_len);
if (id == NULL)
return NULL;
*len = data->id_len;
- os_memcpy(id, data->session_id, data->id_len);
return id;
}
@@ -1681,12 +1798,11 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->key_data == NULL)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
*len = EAP_EMSK_LEN;
- os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
return key;
}
@@ -1695,7 +1811,6 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_ttls_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
@@ -1714,8 +1829,5 @@ int eap_peer_ttls_register(void)
eap->init_for_reauth = eap_ttls_init_for_reauth;
eap->get_emsk = eap_ttls_get_emsk;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_vendor_test.c b/contrib/wpa/src/eap_peer/eap_vendor_test.c
index b61057e..16e3c39 100644
--- a/contrib/wpa/src/eap_peer/eap_vendor_test.c
+++ b/contrib/wpa/src/eap_peer/eap_vendor_test.c
@@ -169,7 +169,6 @@ static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
int eap_peer_vendor_test_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_ID, EAP_VENDOR_TYPE,
@@ -183,8 +182,5 @@ int eap_peer_vendor_test_register(void)
eap->isKeyAvailable = eap_vendor_test_isKeyAvailable;
eap->getKey = eap_vendor_test_getKey;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/eap_wsc.c b/contrib/wpa/src/eap_peer/eap_wsc.c
index 7ac99c7..92d5a02 100644
--- a/contrib/wpa/src/eap_peer/eap_wsc.c
+++ b/contrib/wpa/src/eap_peer/eap_wsc.c
@@ -17,7 +17,7 @@
struct eap_wsc_data {
- enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
+ enum { WAIT_START, MESG, WAIT_FRAG_ACK, FAIL } state;
int registrar;
struct wpabuf *in_buf;
struct wpabuf *out_buf;
@@ -36,12 +36,8 @@ static const char * eap_wsc_state_txt(int state)
return "WAIT_START";
case MESG:
return "MESG";
- case FRAG_ACK:
- return "FRAG_ACK";
case WAIT_FRAG_ACK:
return "WAIT_FRAG_ACK";
- case DONE:
- return "DONE";
case FAIL:
return "FAIL";
default:
@@ -259,6 +255,9 @@ static void * eap_wsc_init(struct eap_sm *sm)
cfg.new_ap_settings = &new_ap_settings;
}
+ if (os_strstr(phase1, "multi_ap=1"))
+ cfg.multi_ap_backhaul_sta = 1;
+
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
@@ -579,7 +578,6 @@ send_msg:
int eap_peer_wsc_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
@@ -591,8 +589,5 @@ int eap_peer_wsc_register(void)
eap->deinit = eap_wsc_deinit;
eap->process = eap_wsc_process;
- ret = eap_peer_method_register(eap);
- if (ret)
- eap_peer_method_free(eap);
- return ret;
+ return eap_peer_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_peer/ikev2.c b/contrib/wpa/src/eap_peer/ikev2.c
index 55ab72a..7bd97b1 100644
--- a/contrib/wpa/src/eap_peer/ikev2.c
+++ b/contrib/wpa/src/eap_peer/ikev2.c
@@ -128,7 +128,7 @@ static int ikev2_parse_transform(struct ikev2_proposal_data *prop,
t = (const struct ikev2_transform *) pos;
transform_len = WPA_GET_BE16(t->transform_length);
- if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
+ if (transform_len < (int) sizeof(*t) || transform_len > end - pos) {
wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
transform_len);
return -1;
@@ -248,7 +248,7 @@ static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
ppos = (const u8 *) (p + 1);
pend = pos + proposal_len;
- if (ppos + p->spi_size > pend) {
+ if (p->spi_size > pend - ppos) {
wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
"in proposal");
return -1;
@@ -476,10 +476,9 @@ static int ikev2_process_idi(struct ikev2_responder_data *data,
wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type);
wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len);
os_free(data->IDi);
- data->IDi = os_malloc(idi_len);
+ data->IDi = os_memdup(idi, idi_len);
if (data->IDi == NULL)
return -1;
- os_memcpy(data->IDi, idi, idi_len);
data->IDi_len = idi_len;
data->IDi_type = id_type;
diff --git a/contrib/wpa/src/eap_peer/tncc.c b/contrib/wpa/src/eap_peer/tncc.c
index 7ca956e..a9bafe2 100644
--- a/contrib/wpa/src/eap_peer/tncc.c
+++ b/contrib/wpa/src/eap_peer/tncc.c
@@ -104,7 +104,7 @@ static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
/* TNCC functions that IMCs can call */
-TNC_Result TNC_TNCC_ReportMessageTypes(
+static TNC_Result TNC_TNCC_ReportMessageTypes(
TNC_IMCID imcID,
TNC_MessageTypeList supportedTypes,
TNC_UInt32 typeCount)
@@ -126,19 +126,17 @@ TNC_Result TNC_TNCC_ReportMessageTypes(
imc = tnc_imc[imcID];
os_free(imc->supported_types);
- imc->supported_types =
- os_malloc(typeCount * sizeof(TNC_MessageType));
+ imc->supported_types = os_memdup(supportedTypes,
+ typeCount * sizeof(TNC_MessageType));
if (imc->supported_types == NULL)
return TNC_RESULT_FATAL;
- os_memcpy(imc->supported_types, supportedTypes,
- typeCount * sizeof(TNC_MessageType));
imc->num_supported_types = typeCount;
return TNC_RESULT_SUCCESS;
}
-TNC_Result TNC_TNCC_SendMessage(
+static TNC_Result TNC_TNCC_SendMessage(
TNC_IMCID imcID,
TNC_ConnectionID connectionID,
TNC_BufferReference message,
@@ -183,7 +181,7 @@ TNC_Result TNC_TNCC_SendMessage(
}
-TNC_Result TNC_TNCC_RequestHandshakeRetry(
+static TNC_Result TNC_TNCC_RequestHandshakeRetry(
TNC_IMCID imcID,
TNC_ConnectionID connectionID,
TNC_RetryReason reason)
@@ -203,8 +201,8 @@ TNC_Result TNC_TNCC_RequestHandshakeRetry(
}
-TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
- const char *message)
+static TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
+ const char *message)
{
wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
"severity==%lu message='%s')",
@@ -213,8 +211,9 @@ TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
}
-TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
- const char *message)
+static TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ const char *message)
{
wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
"connectionID==%lu message='%s')",
@@ -223,7 +222,7 @@ TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
}
-TNC_Result TNC_TNCC_BindFunction(
+static TNC_Result TNC_TNCC_BindFunction(
TNC_IMCID imcID,
char *functionName,
void **pOutfunctionPointer)
@@ -694,6 +693,8 @@ enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
int recommendation_msg = 0;
+ wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
+ msg, len);
buf = dup_binstr(msg, len);
if (buf == NULL)
return TNCCS_PROCESS_ERROR;
diff --git a/contrib/wpa/src/eap_server/eap.h b/contrib/wpa/src/eap_server/eap.h
index 69eaab8..b130368 100644
--- a/contrib/wpa/src/eap_server/eap.h
+++ b/contrib/wpa/src/eap_server/eap.h
@@ -31,6 +31,8 @@ struct eap_user {
size_t password_len;
int password_hash; /* whether password is hashed with
* nt_password_hash() */
+ u8 *salt;
+ size_t salt_len;
int phase2;
int force_version;
unsigned int remediation:1;
@@ -38,6 +40,7 @@ struct eap_user {
int ttls_auth; /* bitfield of
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
struct hostapd_radius_attr *accept_attr;
+ u32 t_c_timestamp;
};
struct eap_eapol_interface {
@@ -132,6 +135,7 @@ struct eap_config {
size_t server_id_len;
int erp;
unsigned int tls_session_lifetime;
+ unsigned int tls_flags;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
@@ -148,10 +152,15 @@ void eap_sm_notify_cached(struct eap_sm *sm);
void eap_sm_pending_cb(struct eap_sm *sm);
int eap_sm_method_pending(struct eap_sm *sm);
const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
+const char * eap_get_serial_num(struct eap_sm *sm);
+const char * eap_get_method(struct eap_sm *sm);
+const char * eap_get_imsi(struct eap_sm *sm);
struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
void eap_server_clear_identity(struct eap_sm *sm);
void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
const u8 *username, size_t username_len,
const u8 *challenge, const u8 *response);
+void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len);
+void eap_user_free(struct eap_user *user);
#endif /* EAP_H */
diff --git a/contrib/wpa/src/eap_server/eap_i.h b/contrib/wpa/src/eap_server/eap_i.h
index c90443d..1cade10 100644
--- a/contrib/wpa/src/eap_server/eap_i.h
+++ b/contrib/wpa/src/eap_server/eap_i.h
@@ -159,6 +159,8 @@ struct eap_sm {
void *eap_method_priv;
u8 *identity;
size_t identity_len;
+ char *serial_num;
+ char imsi[20];
/* Whether Phase 2 method should validate identity match */
int require_identity_match;
int lastId; /* Identifier used in the last EAP-Packet */
@@ -211,6 +213,7 @@ struct eap_sm {
Boolean try_initiate_reauth;
int erp;
unsigned int tls_session_lifetime;
+ unsigned int tls_flags;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
diff --git a/contrib/wpa/src/eap_server/eap_methods.h b/contrib/wpa/src/eap_server/eap_methods.h
index 0baa327..3bf1495 100644
--- a/contrib/wpa/src/eap_server/eap_methods.h
+++ b/contrib/wpa/src/eap_server/eap_methods.h
@@ -15,7 +15,6 @@ const struct eap_method * eap_server_get_eap_method(int vendor,
EapType method);
struct eap_method * eap_server_method_alloc(int version, int vendor,
EapType method, const char *name);
-void eap_server_method_free(struct eap_method *method);
int eap_server_method_register(struct eap_method *method);
EapType eap_server_get_type(const char *name, int *vendor);
diff --git a/contrib/wpa/src/eap_server/eap_server.c b/contrib/wpa/src/eap_server/eap_server.c
index 84ecafc..e8b36e1 100644
--- a/contrib/wpa/src/eap_server/eap_server.c
+++ b/contrib/wpa/src/eap_server/eap_server.c
@@ -25,9 +25,6 @@
#define EAP_MAX_AUTH_ROUNDS 50
-static void eap_user_free(struct eap_user *user);
-
-
/* EAP state machines are described in RFC 4137 */
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
@@ -326,6 +323,9 @@ SM_STATE(EAP, RETRANSMIT)
if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
sm->eap_if.eapReq = TRUE;
}
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -415,7 +415,7 @@ static void eap_server_erp_init(struct eap_sm *sm)
u8 *emsk = NULL;
size_t emsk_len = 0;
u8 EMSKname[EAP_EMSK_NAME_LEN];
- u8 len[2];
+ u8 len[2], ctx[3];
const char *domain;
size_t domain_len, nai_buf_len;
struct eap_server_erp_key *erp = NULL;
@@ -452,7 +452,7 @@ static void eap_server_erp_init(struct eap_sm *sm)
wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
- WPA_PUT_BE16(len, 8);
+ WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
"EMSK", len, sizeof(len),
EMSKname, EAP_EMSK_NAME_LEN) < 0) {
@@ -476,9 +476,11 @@ static void eap_server_erp_init(struct eap_sm *sm)
erp->rRK_len = emsk_len;
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+ ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
+ WPA_PUT_BE16(&ctx[1], erp->rRK_len);
if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
- "EAP Re-authentication Integrity Key@ietf.org",
- len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ "Re-authentication Integrity Key@ietf.org",
+ ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
goto fail;
}
@@ -632,6 +634,9 @@ SM_STATE(EAP, TIMEOUT_FAILURE)
SM_ENTRY(EAP, TIMEOUT_FAILURE);
sm->eap_if.eapTimeout = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1009,6 +1014,9 @@ SM_STATE(EAP, RETRANSMIT2)
if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
sm->eap_if.eapReq = TRUE;
}
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1099,6 +1107,9 @@ SM_STATE(EAP, TIMEOUT_FAILURE2)
SM_ENTRY(EAP, TIMEOUT_FAILURE2);
sm->eap_if.eapTimeout = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1108,6 +1119,9 @@ SM_STATE(EAP, FAILURE2)
eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
sm->eap_if.eapFail = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1134,6 +1148,9 @@ SM_STATE(EAP, SUCCESS2)
* started properly.
*/
sm->start_reauth = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1794,12 +1811,14 @@ int eap_server_sm_step(struct eap_sm *sm)
}
-static void eap_user_free(struct eap_user *user)
+void eap_user_free(struct eap_user *user)
{
if (user == NULL)
return;
bin_clear_free(user->password, user->password_len);
user->password = NULL;
+ bin_clear_free(user->salt, user->salt_len);
+ user->salt = NULL;
os_free(user);
}
@@ -1866,6 +1885,7 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
sm->server_id_len = conf->server_id_len;
sm->erp = conf->erp;
sm->tls_session_lifetime = conf->tls_session_lifetime;
+ sm->tls_flags = conf->tls_flags;
#ifdef CONFIG_TESTING_OPTIONS
sm->tls_test_flags = conf->tls_test_flags;
@@ -1897,6 +1917,7 @@ void eap_server_sm_deinit(struct eap_sm *sm)
wpabuf_free(sm->lastReqData);
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
+ os_free(sm->serial_num);
os_free(sm->pac_opaque_encr_key);
os_free(sm->eap_fast_a_id);
os_free(sm->eap_fast_a_id_info);
@@ -1969,6 +1990,81 @@ const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
/**
+ * eap_get_serial_num - Get the serial number of user certificate
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to the serial number or %NULL if not available
+ */
+const char * eap_get_serial_num(struct eap_sm *sm)
+{
+ return sm->serial_num;
+}
+
+
+/**
+ * eap_get_method - Get the used EAP method
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to the method name or %NULL if not available
+ */
+const char * eap_get_method(struct eap_sm *sm)
+{
+ if (!sm || !sm->m)
+ return NULL;
+ return sm->m->name;
+}
+
+
+/**
+ * eap_get_imsi - Get IMSI of the user
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to IMSI or %NULL if not available
+ */
+const char * eap_get_imsi(struct eap_sm *sm)
+{
+ if (!sm || sm->imsi[0] == '\0')
+ return NULL;
+ return sm->imsi;
+}
+
+
+void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len)
+{
+#ifdef CONFIG_ERP
+ const struct eap_hdr *hdr;
+ const u8 *pos, *end;
+ struct erp_tlvs parse;
+
+ if (len < sizeof(*hdr) + 1)
+ return;
+ hdr = (const struct eap_hdr *) eap;
+ end = eap + len;
+ pos = (const u8 *) (hdr + 1);
+ if (hdr->code != EAP_CODE_INITIATE || *pos != EAP_ERP_TYPE_REAUTH)
+ return;
+ pos++;
+ if (pos + 3 > end)
+ return;
+
+ /* Skip Flags and SEQ */
+ pos += 3;
+
+ if (erp_parse_tlvs(pos, end, &parse, 1) < 0 || !parse.keyname)
+ return;
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP: Update identity based on EAP-Initiate/Re-auth keyName-NAI",
+ parse.keyname, parse.keyname_len);
+ os_free(sm->identity);
+ sm->identity = os_malloc(parse.keyname_len);
+ if (sm->identity) {
+ os_memcpy(sm->identity, parse.keyname, parse.keyname_len);
+ sm->identity_len = parse.keyname_len;
+ } else {
+ sm->identity_len = 0;
+ }
+#endif /* CONFIG_ERP */
+}
+
+
+/**
* eap_get_interface - Get pointer to EAP-EAPOL interface data
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
* Returns: Pointer to the EAP-EAPOL interface data
diff --git a/contrib/wpa/src/eap_server/eap_server_aka.c b/contrib/wpa/src/eap_server/eap_server_aka.c
index db9b6aa..1bea706 100644
--- a/contrib/wpa/src/eap_server/eap_server_aka.c
+++ b/contrib/wpa/src/eap_server/eap_server_aka.c
@@ -796,6 +796,10 @@ static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
return;
}
+ if (data->permanent[0] == EAP_AKA_PERMANENT_PREFIX ||
+ data->permanent[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)
+ os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
+
#ifdef EAP_SERVER_AKA_PRIME
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
@@ -1261,10 +1265,9 @@ static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
+ key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
*len = EAP_SIM_KEYING_DATA_LEN;
return key;
}
@@ -1278,10 +1281,9 @@ static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
}
@@ -1319,7 +1321,6 @@ static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_aka_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
@@ -1337,10 +1338,7 @@ int eap_server_aka_register(void)
eap->get_emsk = eap_aka_get_emsk;
eap->getSessionId = eap_aka_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
@@ -1348,7 +1346,6 @@ int eap_server_aka_register(void)
int eap_server_aka_prime_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
@@ -1367,10 +1364,6 @@ int eap_server_aka_prime_register(void)
eap->get_emsk = eap_aka_get_emsk;
eap->getSessionId = eap_aka_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
-
- return ret;
+ return eap_server_method_register(eap);
}
#endif /* EAP_SERVER_AKA_PRIME */
diff --git a/contrib/wpa/src/eap_server/eap_server_eke.c b/contrib/wpa/src/eap_server/eap_server_eke.c
index ba82be9..71580bf 100644
--- a/contrib/wpa/src/eap_server/eap_server_eke.c
+++ b/contrib/wpa/src/eap_server/eap_server_eke.c
@@ -467,13 +467,12 @@ static void eap_eke_process_identity(struct eap_sm *sm,
data->peerid_type = *pos++;
os_free(data->peerid);
- data->peerid = os_malloc(end - pos);
+ data->peerid = os_memdup(pos, end - pos);
if (data->peerid == NULL) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
return;
}
- os_memcpy(data->peerid, pos, end - pos);
data->peerid_len = end - pos;
wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
@@ -731,10 +730,9 @@ static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -749,10 +747,9 @@ static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
@@ -792,7 +789,6 @@ static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_eke_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
@@ -810,8 +806,5 @@ int eap_server_eke_register(void)
eap->get_emsk = eap_eke_get_emsk;
eap->getSessionId = eap_eke_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_fast.c b/contrib/wpa/src/eap_server/eap_server_fast.c
index bd9018e..a63f820 100644
--- a/contrib/wpa/src/eap_server/eap_server_fast.c
+++ b/contrib/wpa/src/eap_server/eap_server_fast.c
@@ -180,42 +180,47 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
buf, end - buf);
pos = buf;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ if (elen > end - pos)
break;
- switch (*pos) {
+ switch (id) {
case PAC_OPAQUE_TYPE_PAD:
goto done;
case PAC_OPAQUE_TYPE_KEY:
- if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
- wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
- "PAC-Key length %d", pos[1]);
+ if (elen != EAP_FAST_PAC_KEY_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Invalid PAC-Key length %d",
+ elen);
os_free(buf);
return -1;
}
- pac_key = pos + 2;
+ pac_key = pos;
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from "
"decrypted PAC-Opaque",
pac_key, EAP_FAST_PAC_KEY_LEN);
break;
case PAC_OPAQUE_TYPE_LIFETIME:
- if (pos[1] != 4) {
+ if (elen != 4) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
"PAC-Key lifetime length %d",
- pos[1]);
+ elen);
os_free(buf);
return -1;
}
- lifetime = WPA_GET_BE32(pos + 2);
+ lifetime = WPA_GET_BE32(pos);
break;
case PAC_OPAQUE_TYPE_IDENTITY:
- identity = pos + 2;
- identity_len = pos[1];
+ identity = pos;
+ identity_len = elen;
break;
}
- pos += 2 + pos[1];
+ pos += elen;
}
done:
@@ -273,7 +278,7 @@ static void eap_fast_derive_key_auth(struct eap_sm *sm,
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+ sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -300,7 +305,6 @@ static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
- "key expansion",
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -407,11 +411,13 @@ static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data)
static void * eap_fast_init(struct eap_sm *sm)
{
struct eap_fast_data *data;
- u8 ciphers[5] = {
+ u8 ciphers[7] = {
TLS_CIPHER_ANON_DH_AES128_SHA,
TLS_CIPHER_AES128_SHA,
TLS_CIPHER_RSA_DHE_AES128_SHA,
TLS_CIPHER_RC4_SHA,
+ TLS_CIPHER_RSA_DHE_AES256_SHA,
+ TLS_CIPHER_AES256_SHA,
TLS_CIPHER_NONE
};
@@ -465,12 +471,11 @@ static void * eap_fast_init(struct eap_sm *sm)
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id = os_malloc(sm->eap_fast_a_id_len);
+ data->srv_id = os_memdup(sm->eap_fast_a_id, sm->eap_fast_a_id_len);
if (data->srv_id == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
- os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len);
data->srv_id_len = sm->eap_fast_a_id_len;
if (sm->eap_fast_a_id_info == NULL) {
@@ -555,7 +560,7 @@ static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data)
return -1;
}
data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
-
+
if (data->anon_provisioning) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning");
eap_fast_derive_key_provisioning(sm, data);
@@ -783,7 +788,7 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
/* A-ID (inside PAC-Info) */
eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
-
+
/* Note: headers may be misaligned after A-ID */
if (sm->identity) {
@@ -1134,7 +1139,7 @@ static int eap_fast_parse_tlvs(struct wpabuf *data,
pos = wpabuf_mhead(data);
end = pos + wpabuf_len(data);
- while (pos + 4 < end) {
+ while (end - pos > 4) {
mandatory = pos[0] & 0x80;
tlv_type = WPA_GET_BE16(pos) & 0x3fff;
pos += 2;
@@ -1511,7 +1516,7 @@ static void eap_fast_process_msg(struct eap_sm *sm, void *priv,
if (eap_fast_process_phase1(sm, data))
break;
- /* fall through to PHASE2_START */
+ /* fall through */
case PHASE2_START:
eap_fast_process_phase2_start(sm, data);
break;
@@ -1559,7 +1564,10 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (eapKeyData == NULL)
return NULL;
- eap_fast_derive_eap_msk(data->simck, eapKeyData);
+ if (eap_fast_derive_eap_msk(data->simck, eapKeyData) < 0) {
+ os_free(eapKeyData);
+ return NULL;
+ }
*len = EAP_FAST_KEY_LEN;
return eapKeyData;
@@ -1578,7 +1586,10 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (eapKeyData == NULL)
return NULL;
- eap_fast_derive_eap_emsk(data->simck, eapKeyData);
+ if (eap_fast_derive_eap_emsk(data->simck, eapKeyData) < 0) {
+ os_free(eapKeyData);
+ return NULL;
+ }
*len = EAP_EMSK_LEN;
return eapKeyData;
@@ -1607,7 +1618,6 @@ static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_fast_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
@@ -1625,8 +1635,5 @@ int eap_server_fast_register(void)
eap->isSuccess = eap_fast_isSuccess;
eap->getSessionId = eap_fast_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_gpsk.c b/contrib/wpa/src/eap_server/eap_server_gpsk.c
index 50f15c3..bebb17f 100644
--- a/contrib/wpa/src/eap_server/eap_server_gpsk.c
+++ b/contrib/wpa/src/eap_server/eap_server_gpsk.c
@@ -181,7 +181,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
data->specifier, start, pos - start, pos) < 0)
{
- os_free(req);
+ wpabuf_free(req);
eap_gpsk_state(data, FAILURE);
return NULL;
}
@@ -269,13 +269,12 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
return;
}
os_free(data->id_peer);
- data->id_peer = os_malloc(alen);
+ data->id_peer = os_memdup(pos, alen);
if (data->id_peer == NULL) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
"%d-octet ID_Peer", alen);
return;
}
- os_memcpy(data->id_peer, pos, alen);
data->id_peer_len = alen;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
data->id_peer, data->id_peer_len);
@@ -380,7 +379,7 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
data->specifier = WPA_GET_BE16(csuite->specifier);
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
data->vendor, data->specifier);
- pos += sizeof(*csuite);
+ pos += sizeof(*csuite);
if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
@@ -575,10 +574,9 @@ static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -593,10 +591,9 @@ static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
@@ -618,10 +615,9 @@ static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- sid = os_malloc(data->id_len);
+ sid = os_memdup(data->session_id, data->id_len);
if (sid == NULL)
return NULL;
- os_memcpy(sid, data->session_id, data->id_len);
*len = data->id_len;
return sid;
@@ -631,7 +627,6 @@ static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_gpsk_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
@@ -649,8 +644,5 @@ int eap_server_gpsk_register(void)
eap->get_emsk = eap_gpsk_get_emsk;
eap->getSessionId = eap_gpsk_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_gtc.c b/contrib/wpa/src/eap_server/eap_server_gtc.c
index 98ac3c6..fcccbcb 100644
--- a/contrib/wpa/src/eap_server/eap_server_gtc.c
+++ b/contrib/wpa/src/eap_server/eap_server_gtc.c
@@ -141,12 +141,11 @@ static void eap_gtc_process(struct eap_sm *sm, void *priv,
} else {
os_free(sm->identity);
sm->identity_len = pos2 - pos;
- sm->identity = os_malloc(sm->identity_len);
+ sm->identity = os_memdup(pos, sm->identity_len);
if (sm->identity == NULL) {
data->state = FAILURE;
return;
}
- os_memcpy(sm->identity, pos, sm->identity_len);
}
if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
@@ -202,7 +201,6 @@ static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
int eap_server_gtc_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
@@ -217,8 +215,5 @@ int eap_server_gtc_register(void)
eap->isDone = eap_gtc_isDone;
eap->isSuccess = eap_gtc_isSuccess;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_identity.c b/contrib/wpa/src/eap_server/eap_server_identity.c
index 4501533..1b1db53 100644
--- a/contrib/wpa/src/eap_server/eap_server_identity.c
+++ b/contrib/wpa/src/eap_server/eap_server_identity.c
@@ -157,7 +157,6 @@ static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
int eap_server_identity_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
@@ -174,8 +173,5 @@ int eap_server_identity_register(void)
eap->isDone = eap_identity_isDone;
eap->isSuccess = eap_identity_isSuccess;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_ikev2.c b/contrib/wpa/src/eap_server/eap_server_ikev2.c
index 16e6276..32e6872 100644
--- a/contrib/wpa/src/eap_server/eap_server_ikev2.c
+++ b/contrib/wpa/src/eap_server/eap_server_ikev2.c
@@ -103,10 +103,9 @@ static void * eap_ikev2_init(struct eap_sm *sm)
data->ikev2.proposal.encr = ENCR_AES_CBC;
data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
- data->ikev2.IDi = os_malloc(sm->server_id_len);
+ data->ikev2.IDi = os_memdup(sm->server_id, sm->server_id_len);
if (data->ikev2.IDi == NULL)
goto failed;
- os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len);
data->ikev2.IDi_len = sm->server_id_len;
data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
@@ -224,7 +223,7 @@ static struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
data->out_used = 0;
}
- /* pass through */
+ /* fall through */
case WAIT_FRAG_ACK:
return eap_ikev2_build_msg(data, id);
case FRAG_ACK:
@@ -550,7 +549,6 @@ static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_ikev2_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
@@ -569,8 +567,5 @@ int eap_server_ikev2_register(void)
eap->get_emsk = eap_ikev2_get_emsk;
eap->getSessionId = eap_ikev2_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_md5.c b/contrib/wpa/src/eap_server/eap_server_md5.c
index 71e8d59..cf5ceb1 100644
--- a/contrib/wpa/src/eap_server/eap_server_md5.c
+++ b/contrib/wpa/src/eap_server/eap_server_md5.c
@@ -153,7 +153,6 @@ static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv)
int eap_server_md5_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
@@ -168,8 +167,5 @@ int eap_server_md5_register(void)
eap->isDone = eap_md5_isDone;
eap->isSuccess = eap_md5_isSuccess;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_methods.c b/contrib/wpa/src/eap_server/eap_server_methods.c
index 9e9dc93..79ed344 100644
--- a/contrib/wpa/src/eap_server/eap_server_methods.c
+++ b/contrib/wpa/src/eap_server/eap_server_methods.c
@@ -87,7 +87,7 @@ struct eap_method * eap_server_method_alloc(int version, int vendor,
* eap_server_method_free - Free EAP server method structure
* @method: Method structure allocated with eap_server_method_alloc()
*/
-void eap_server_method_free(struct eap_method *method)
+static void eap_server_method_free(struct eap_method *method)
{
os_free(method);
}
@@ -95,26 +95,31 @@ void eap_server_method_free(struct eap_method *method)
/**
* eap_server_method_register - Register an EAP server method
- * @method: EAP method to register
+ * @method: EAP method to register from eap_server_method_alloc()
* Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
* has already been registered
*
* Each EAP server method needs to call this function to register itself as a
- * supported EAP method.
+ * supported EAP method. The caller must not free the allocated method data
+ * regardless of the return value.
*/
int eap_server_method_register(struct eap_method *method)
{
struct eap_method *m, *last = NULL;
if (method == NULL || method->name == NULL ||
- method->version != EAP_SERVER_METHOD_INTERFACE_VERSION)
+ method->version != EAP_SERVER_METHOD_INTERFACE_VERSION) {
+ eap_server_method_free(method);
return -1;
+ }
for (m = eap_methods; m; m = m->next) {
if ((m->vendor == method->vendor &&
m->method == method->method) ||
- os_strcmp(m->name, method->name) == 0)
+ os_strcmp(m->name, method->name) == 0) {
+ eap_server_method_free(method);
return -2;
+ }
last = m;
}
diff --git a/contrib/wpa/src/eap_server/eap_server_mschapv2.c b/contrib/wpa/src/eap_server/eap_server_mschapv2.c
index 98d74e0..e9e03b0 100644
--- a/contrib/wpa/src/eap_server/eap_server_mschapv2.c
+++ b/contrib/wpa/src/eap_server/eap_server_mschapv2.c
@@ -71,13 +71,12 @@ static void * eap_mschapv2_init(struct eap_sm *sm)
}
if (sm->peer_challenge) {
- data->peer_challenge = os_malloc(CHALLENGE_LEN);
+ data->peer_challenge = os_memdup(sm->peer_challenge,
+ CHALLENGE_LEN);
if (data->peer_challenge == NULL) {
os_free(data);
return NULL;
}
- os_memcpy(data->peer_challenge, sm->peer_challenge,
- CHALLENGE_LEN);
}
return data;
@@ -552,9 +551,13 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (key == NULL)
return NULL;
/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
- get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
- get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
- MSCHAPV2_KEY_LEN, 1, 1);
+ if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0,
+ 1) < 0 ||
+ get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+ MSCHAPV2_KEY_LEN, 1, 1) < 0) {
+ os_free(key);
+ return NULL;
+ }
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
return key;
@@ -571,7 +574,6 @@ static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
int eap_server_mschapv2_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
@@ -588,8 +590,5 @@ int eap_server_mschapv2_register(void)
eap->getKey = eap_mschapv2_getKey;
eap->isSuccess = eap_mschapv2_isSuccess;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_pax.c b/contrib/wpa/src/eap_server/eap_server_pax.c
index 0e6b4a0..2e8c1a6 100644
--- a/contrib/wpa/src/eap_server/eap_server_pax.c
+++ b/contrib/wpa/src/eap_server/eap_server_pax.c
@@ -107,9 +107,14 @@ static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm,
data->rand.r.x, EAP_PAX_RAND_LEN);
pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
- eap_pax_mac(data->mac_id, (u8 *) "", 0,
- wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
- NULL, 0, NULL, 0, pos);
+ if (eap_pax_mac(data->mac_id, (u8 *) "", 0,
+ wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, pos) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to calculate ICV");
+ data->state = FAILURE;
+ wpabuf_free(req);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
return req;
@@ -144,18 +149,28 @@ static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
wpabuf_put_be16(req, EAP_PAX_MAC_LEN);
pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
- eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
- data->rand.r.y, EAP_PAX_RAND_LEN,
- (u8 *) data->cid, data->cid_len, NULL, 0, pos);
+ if (eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
+ data->rand.r.y, EAP_PAX_RAND_LEN,
+ (u8 *) data->cid, data->cid_len, NULL, 0, pos) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to calculate MAC");
+ data->state = FAILURE;
+ wpabuf_free(req);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
pos, EAP_PAX_MAC_LEN);
/* Optional ADE could be added here, if needed */
pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
- eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
- wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
- NULL, 0, NULL, 0, pos);
+ if (eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, pos) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to calculate ICV");
+ data->state = FAILURE;
+ wpabuf_free(req);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
return req;
@@ -190,7 +205,7 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
u8 icvbuf[EAP_PAX_ICV_LEN], *icv;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
- if (pos == NULL || len < sizeof(*resp)) {
+ if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
return TRUE;
}
@@ -264,11 +279,11 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
}
icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
- eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
- wpabuf_mhead(respData),
- wpabuf_len(respData) - EAP_PAX_ICV_LEN,
- NULL, 0, NULL, 0, icvbuf);
- if (os_memcmp_const(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
+ if (eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ wpabuf_mhead(respData),
+ wpabuf_len(respData) - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, icvbuf) < 0 ||
+ os_memcmp_const(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
@@ -327,13 +342,12 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
}
data->cid_len = cid_len;
os_free(data->cid);
- data->cid = os_malloc(data->cid_len);
+ data->cid = os_memdup(pos + 2, data->cid_len);
if (data->cid == NULL) {
wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for "
"CID");
return;
}
- os_memcpy(data->cid, pos + 2, data->cid_len);
pos += 2 + data->cid_len;
left -= 2 + data->cid_len;
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
@@ -396,11 +410,11 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
}
data->keys_set = 1;
- eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
- data->rand.r.x, EAP_PAX_RAND_LEN,
- data->rand.r.y, EAP_PAX_RAND_LEN,
- (u8 *) data->cid, data->cid_len, mac);
- if (os_memcmp_const(mac, pos, EAP_PAX_MAC_LEN) != 0) {
+ if (eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
+ data->rand.r.x, EAP_PAX_RAND_LEN,
+ data->rand.r.y, EAP_PAX_RAND_LEN,
+ (u8 *) data->cid, data->cid_len, mac) < 0 ||
+ os_memcmp_const(mac, pos, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
"PAX_STD-2");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
@@ -418,11 +432,11 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
return;
}
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
- eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
- wpabuf_head(respData),
- wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
- icvbuf);
- if (os_memcmp_const(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
+ if (eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ wpabuf_head(respData),
+ wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0,
+ NULL, 0, icvbuf) < 0 ||
+ os_memcmp_const(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
@@ -565,7 +579,6 @@ static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_pax_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
@@ -583,8 +596,5 @@ int eap_server_pax_register(void)
eap->get_emsk = eap_pax_get_emsk;
eap->getSessionId = eap_pax_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_peap.c b/contrib/wpa/src/eap_server/eap_server_peap.c
index 51062b0..92c0e5e 100644
--- a/contrib/wpa/src/eap_server/eap_server_peap.c
+++ b/contrib/wpa/src/eap_server/eap_server_peap.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -324,17 +324,30 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
{
u8 *tk;
u8 isk[32], imck[60];
+ int res;
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
* phase 1 of PEAP (based on TLS).
*/
tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
- EAP_TLS_KEY_LEN);
+ NULL, 0, EAP_TLS_KEY_LEN);
if (tk == NULL)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+ if (tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+ /* Fast-connect: IPMK|CMK = TK */
+ os_memcpy(data->ipmk, tk, 40);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
+ data->ipmk, 40);
+ os_memcpy(data->cmk, tk + 40, 20);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
+ data->cmk, 20);
+ os_free(tk);
+ return 0;
+ }
+
eap_peap_get_isk(data, isk, sizeof(isk));
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
@@ -346,9 +359,11 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
* in the end of the label just before ISK; is that just a typo?)
*/
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
- if (peap_prfplus(data->peap_version, tk, 40,
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+ res = peap_prfplus(data->peap_version, tk, 40,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ os_memset(isk, 0, sizeof(isk));
+ if (res < 0) {
os_free(tk);
return -1;
}
@@ -357,11 +372,11 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
os_free(tk);
- /* TODO: fast-connect: IPMK|CMK = TK */
os_memcpy(data->ipmk, imck, 40);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
os_memcpy(data->cmk, imck + 40, 20);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+ os_memset(imck, 0, sizeof(imck));
return 0;
}
@@ -745,7 +760,7 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
} else {
eap_peap_state(data, FAILURE);
}
-
+
} else if (status == EAP_TLV_RESULT_FAILURE) {
wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
"- requested %s", requested);
@@ -1267,8 +1282,9 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG,
"EAP-PEAP: Resuming previous session - skip Phase2");
- eap_peap_state(data, SUCCESS_REQ);
- tls_connection_set_success_data_resumed(data->ssl.conn);
+ eap_peap_req_success(sm, data);
+ if (data->state == SUCCESS_REQ)
+ tls_connection_set_success_data_resumed(data->ssl.conn);
}
@@ -1310,14 +1326,17 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
"key");
}
+ os_memset(csk, 0, sizeof(csk));
+
return eapKeyData;
}
/* TODO: PEAPv1 - different label in some cases */
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
- EAP_TLS_KEY_LEN);
+ "client EAP encryption", NULL, 0,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
+ os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
*len = EAP_TLS_KEY_LEN;
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
eapKeyData, EAP_TLS_KEY_LEN);
@@ -1329,6 +1348,40 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *eapKeyData, *emsk;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ if (data->crypto_binding_used) {
+ /* [MS-PEAP] does not define EMSK derivation */
+ return NULL;
+ }
+
+ /* TODO: PEAPv1 - different label in some cases */
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+ "client EAP encryption", NULL, 0,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (eapKeyData) {
+ emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (!emsk)
+ return NULL;
+ *len = EAP_EMSK_LEN;
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived EMSK",
+ emsk, EAP_EMSK_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive EMSK");
+ emsk = NULL;
+ }
+
+ return emsk;
+}
+
+
static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
@@ -1351,7 +1404,6 @@ static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_peap_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
@@ -1365,11 +1417,9 @@ int eap_server_peap_register(void)
eap->process = eap_peap_process;
eap->isDone = eap_peap_isDone;
eap->getKey = eap_peap_getKey;
+ eap->get_emsk = eap_peap_get_emsk;
eap->isSuccess = eap_peap_isSuccess;
eap->getSessionId = eap_peap_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_psk.c b/contrib/wpa/src/eap_server/eap_server_psk.c
index 12b5d25..0eab893 100644
--- a/contrib/wpa/src/eap_server/eap_server_psk.c
+++ b/contrib/wpa/src/eap_server/eap_server_psk.c
@@ -236,13 +236,12 @@ static void eap_psk_process_2(struct eap_sm *sm,
left -= sizeof(*resp);
os_free(data->id_p);
- data->id_p = os_malloc(left);
+ data->id_p = os_memdup(cpos, left);
if (data->id_p == NULL) {
wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for "
"ID_P");
return;
}
- os_memcpy(data->id_p, cpos, left);
data->id_p_len = left;
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P",
data->id_p, data->id_p_len);
@@ -371,10 +370,9 @@ static void eap_psk_process_4(struct eap_sm *sm,
pos += 16;
left -= 16;
- decrypted = os_malloc(left);
+ decrypted = os_memdup(pos, left);
if (decrypted == NULL)
return;
- os_memcpy(decrypted, pos, left);
if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
wpabuf_head(respData), 22, decrypted, left,
@@ -450,10 +448,9 @@ static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -468,10 +465,9 @@ static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
@@ -510,7 +506,6 @@ static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_psk_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
@@ -528,8 +523,5 @@ int eap_server_psk_register(void)
eap->get_emsk = eap_psk_get_emsk;
eap->getSessionId = eap_psk_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_pwd.c b/contrib/wpa/src/eap_server/eap_server_pwd.c
index cb83ff7..e720a28 100644
--- a/contrib/wpa/src/eap_server/eap_server_pwd.c
+++ b/contrib/wpa/src/eap_server/eap_server_pwd.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "crypto/sha256.h"
#include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
#include "eap_server/eap_i.h"
#include "eap_common/eap_pwd_common.h"
@@ -26,8 +27,11 @@ struct eap_pwd_data {
u8 *password;
size_t password_len;
int password_hash;
+ u8 *salt;
+ size_t salt_len;
u32 token;
u16 group_num;
+ u8 password_prep;
EAP_PWD_group *grp;
struct wpabuf *inbuf;
@@ -36,20 +40,18 @@ struct eap_pwd_data {
size_t out_frag_pos;
size_t mtu;
- BIGNUM *k;
- BIGNUM *private_value;
- BIGNUM *peer_scalar;
- BIGNUM *my_scalar;
- EC_POINT *my_element;
- EC_POINT *peer_element;
+ struct crypto_bignum *k;
+ struct crypto_bignum *private_value;
+ struct crypto_bignum *peer_scalar;
+ struct crypto_bignum *my_scalar;
+ struct crypto_ec_point *my_element;
+ struct crypto_ec_point *peer_element;
u8 my_confirm[SHA256_MAC_LEN];
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
u8 session_id[1 + SHA256_MAC_LEN];
-
- BN_CTX *bnctx;
};
@@ -116,13 +118,17 @@ static void * eap_pwd_init(struct eap_sm *sm)
os_memcpy(data->password, sm->user->password, data->password_len);
data->password_hash = sm->user->password_hash;
- data->bnctx = BN_CTX_new();
- if (data->bnctx == NULL) {
- wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
- bin_clear_free(data->password, data->password_len);
- bin_clear_free(data->id_server, data->id_server_len);
- os_free(data);
- return NULL;
+ data->salt_len = sm->user->salt_len;
+ if (data->salt_len) {
+ data->salt = os_memdup(sm->user->salt, sm->user->salt_len);
+ if (!data->salt) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Memory allocation of salt failed");
+ bin_clear_free(data->id_server, data->id_server_len);
+ bin_clear_free(data->password, data->password_len);
+ os_free(data);
+ return NULL;
+ }
}
data->in_frag_pos = data->out_frag_pos = 0;
@@ -138,21 +144,19 @@ static void eap_pwd_reset(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
- BN_clear_free(data->private_value);
- BN_clear_free(data->peer_scalar);
- BN_clear_free(data->my_scalar);
- BN_clear_free(data->k);
- BN_CTX_free(data->bnctx);
- EC_POINT_clear_free(data->my_element);
- EC_POINT_clear_free(data->peer_element);
+ crypto_bignum_deinit(data->private_value, 1);
+ crypto_bignum_deinit(data->peer_scalar, 1);
+ crypto_bignum_deinit(data->my_scalar, 1);
+ crypto_bignum_deinit(data->k, 1);
+ crypto_ec_point_deinit(data->my_element, 1);
+ crypto_ec_point_deinit(data->peer_element, 1);
bin_clear_free(data->id_peer, data->id_peer_len);
bin_clear_free(data->id_server, data->id_server_len);
bin_clear_free(data->password, data->password_len);
+ bin_clear_free(data->salt, data->salt_len);
if (data->grp) {
- EC_GROUP_free(data->grp->group);
- EC_POINT_clear_free(data->grp->pwe);
- BN_clear_free(data->grp->order);
- BN_clear_free(data->grp->prime);
+ crypto_ec_deinit(data->grp->group);
+ crypto_ec_point_deinit(data->grp->pwe, 1);
os_free(data->grp);
}
wpabuf_free(data->inbuf);
@@ -178,14 +182,52 @@ static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
return;
}
- /* an lfsr is good enough to generate unpredictable tokens */
- data->token = os_random();
+ if (os_get_random((u8 *) &data->token, sizeof(data->token)) < 0) {
+ wpabuf_free(data->outbuf);
+ data->outbuf = NULL;
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd (server): password",
+ data->password, data->password_len);
+ if (data->salt_len)
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd (server): salt",
+ data->salt, data->salt_len);
+
+ /*
+ * If this is a salted password then figure out how it was hashed
+ * based on the length.
+ */
+ if (data->salt_len) {
+ switch (data->password_len) {
+ case 20:
+ data->password_prep = EAP_PWD_PREP_SSHA1;
+ break;
+ case 32:
+ data->password_prep = EAP_PWD_PREP_SSHA256;
+ break;
+ case 64:
+ data->password_prep = EAP_PWD_PREP_SSHA512;
+ break;
+ default:
+ wpa_printf(MSG_INFO,
+ "EAP-pwd (server): bad size %d for salted password",
+ (int) data->password_len);
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+ } else {
+ /* Otherwise, figure out whether it's MS hashed or plain */
+ data->password_prep = data->password_hash ? EAP_PWD_PREP_MS :
+ EAP_PWD_PREP_NONE;
+ }
+
wpabuf_put_be16(data->outbuf, data->group_num);
wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
- wpabuf_put_u8(data->outbuf, data->password_hash ? EAP_PWD_PREP_MS :
- EAP_PWD_PREP_NONE);
+ wpabuf_put_u8(data->outbuf, data->password_prep);
wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
}
@@ -193,9 +235,9 @@ static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
static void eap_pwd_build_commit_req(struct eap_sm *sm,
struct eap_pwd_data *data, u8 id)
{
- BIGNUM *mask = NULL, *x = NULL, *y = NULL;
- u8 *scalar = NULL, *element = NULL;
- u16 offset;
+ struct crypto_bignum *mask = NULL;
+ u8 *scalar, *element;
+ size_t prime_len, order_len;
wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
/*
@@ -205,93 +247,62 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm,
if (data->out_frag_pos)
return;
- if (((data->private_value = BN_new()) == NULL) ||
- ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
- ((data->my_scalar = BN_new()) == NULL) ||
- ((mask = BN_new()) == NULL)) {
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
+ data->private_value = crypto_bignum_init();
+ data->my_element = crypto_ec_point_init(data->grp->group);
+ data->my_scalar = crypto_bignum_init();
+ mask = crypto_bignum_init();
+ if (!data->private_value || !data->my_element || !data->my_scalar ||
+ !mask) {
wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
"fail");
goto fin;
}
- if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
- BN_rand_range(mask, data->grp->order) != 1 ||
- BN_add(data->my_scalar, data->private_value, mask) != 1 ||
- BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
- data->bnctx) != 1) {
- wpa_printf(MSG_INFO,
- "EAP-pwd (server): unable to get randomness");
+ if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
+ data->my_scalar) < 0)
goto fin;
- }
- if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
- data->grp->pwe, mask, data->bnctx)) {
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
+ data->my_element) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
"fail");
eap_pwd_state(data, FAILURE);
goto fin;
}
- if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
- {
+ if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
"fail");
goto fin;
}
- BN_clear_free(mask);
- if (((x = BN_new()) == NULL) ||
- ((y = BN_new()) == NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
- "fail");
+ data->outbuf = wpabuf_alloc(2 * prime_len + order_len +
+ (data->salt ? 1 + data->salt_len : 0));
+ if (data->outbuf == NULL)
goto fin;
+
+ /* If we're doing salted password prep, add the salt */
+ if (data->salt_len) {
+ wpabuf_put_u8(data->outbuf, data->salt_len);
+ wpabuf_put_data(data->outbuf, data->salt, data->salt_len);
}
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+
+ /* We send the element as (x,y) followed by the scalar */
+ element = wpabuf_put(data->outbuf, 2 * prime_len);
+ scalar = wpabuf_put(data->outbuf, order_len);
+ crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
+ element + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
"fail");
goto fin;
}
- if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
- ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
- NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
- goto fin;
- }
-
- /*
- * bignums occupy as little memory as possible so one that is
- * sufficiently smaller than the prime or order might need pre-pending
- * with zeros.
- */
- os_memset(scalar, 0, BN_num_bytes(data->grp->order));
- os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, scalar + offset);
-
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, element + offset);
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
-
- data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
- BN_num_bytes(data->grp->order));
- if (data->outbuf == NULL)
- goto fin;
-
- /* We send the element as (x,y) followed by the scalar */
- wpabuf_put_data(data->outbuf, element,
- 2 * BN_num_bytes(data->grp->prime));
- wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
-
fin:
- os_free(scalar);
- os_free(element);
- BN_clear_free(x);
- BN_clear_free(y);
+ crypto_bignum_deinit(mask, 1);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
}
@@ -300,11 +311,10 @@ fin:
static void eap_pwd_build_confirm_req(struct eap_sm *sm,
struct eap_pwd_data *data, u8 id)
{
- BIGNUM *x = NULL, *y = NULL;
- struct crypto_hash *hash;
+ struct crypto_hash *hash = NULL;
u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
u16 grp;
- int offset;
+ size_t prime_len, order_len;
wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
/*
@@ -314,9 +324,12 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
if (data->out_frag_pos)
return;
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
/* Each component of the cruft will be at most as big as the prime */
- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+ cruft = os_malloc(prime_len * 2);
+ if (!cruft) {
wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
"fail");
goto fin;
@@ -336,64 +349,38 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
*
* First is k
*/
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
- BN_bn2bin(data->k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
/* server element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+ cruft + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
-
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* server scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* peer element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->peer_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft,
+ cruft + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
-
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* peer scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->peer_scalar);
- BN_bn2bin(data->peer_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* ciphersuite */
grp = htons(data->group_num);
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+ os_memset(cruft, 0, prime_len);
ptr = cruft;
os_memcpy(ptr, &grp, sizeof(u16));
ptr += sizeof(u16);
@@ -405,6 +392,7 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
/* all done with the random function */
eap_pwd_h_final(hash, conf);
+ hash = NULL;
os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
@@ -414,11 +402,10 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
- bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
- BN_clear_free(x);
- BN_clear_free(y);
+ bin_clear_free(cruft, prime_len * 2);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
+ eap_pwd_h_final(hash, NULL);
}
@@ -597,11 +584,16 @@ static void eap_pwd_process_id_resp(struct eap_sm *sm,
if ((data->group_num != be_to_host16(id->group_num)) ||
(id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
(os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
- (id->prf != EAP_PWD_DEFAULT_PRF)) {
+ (id->prf != EAP_PWD_DEFAULT_PRF) ||
+ (id->prep != data->password_prep)) {
wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
eap_pwd_state(data, FAILURE);
return;
}
+ if (data->id_peer || data->grp) {
+ wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated");
+ return;
+ }
data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
if (data->id_peer == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
@@ -612,14 +604,19 @@ static void eap_pwd_process_id_resp(struct eap_sm *sm,
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
data->id_peer, data->id_peer_len);
- data->grp = os_zalloc(sizeof(EAP_PWD_group));
+ data->grp = get_eap_pwd_group(data->group_num);
if (data->grp == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
"group");
return;
}
- if (data->password_hash) {
+ /*
+ * If it's PREP_MS then hash the password again, otherwise regardless
+ * of the prep the client is doing, the password we have is the one to
+ * use to generate the password element.
+ */
+ if (data->password_prep == EAP_PWD_PREP_MS) {
res = hash_nt_password_hash(data->password, pwhashhash);
if (res)
return;
@@ -642,7 +639,7 @@ static void eap_pwd_process_id_resp(struct eap_sm *sm,
return;
}
wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
- BN_num_bits(data->grp->prime));
+ (int) crypto_ec_prime_len_bits(data->grp->group));
eap_pwd_state(data, PWD_Commit_Req);
}
@@ -652,16 +649,15 @@ static void
eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
const u8 *payload, size_t payload_len)
{
- u8 *ptr;
- BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
- EC_POINT *K = NULL, *point = NULL;
+ const u8 *ptr;
+ struct crypto_ec_point *K = NULL;
int res = 0;
size_t prime_len, order_len;
wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
- prime_len = BN_num_bytes(data->grp->prime);
- order_len = BN_num_bytes(data->grp->order);
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
if (payload_len != 2 * prime_len + order_len) {
wpa_printf(MSG_INFO,
@@ -671,90 +667,63 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
}
- if (((data->peer_scalar = BN_new()) == NULL) ||
- ((data->k = BN_new()) == NULL) ||
- ((cofactor = BN_new()) == NULL) ||
- ((x = BN_new()) == NULL) ||
- ((y = BN_new()) == NULL) ||
- ((point = EC_POINT_new(data->grp->group)) == NULL) ||
- ((K = EC_POINT_new(data->grp->group)) == NULL) ||
- ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
+ data->k = crypto_bignum_init();
+ K = crypto_ec_point_init(data->grp->group);
+ if (!data->k || !K) {
wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
"fail");
goto fin;
}
- if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
- "cofactor for curve");
- goto fin;
- }
-
/* element, x then y, followed by scalar */
- ptr = (u8 *) payload;
- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
- ptr += BN_num_bytes(data->grp->prime);
- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
- ptr += BN_num_bytes(data->grp->prime);
- BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
- if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
- data->peer_element, x, y,
- data->bnctx)) {
+ ptr = payload;
+ data->peer_element = eap_pwd_get_element(data->grp, ptr);
+ if (!data->peer_element) {
wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
"fail");
goto fin;
}
+ ptr += prime_len * 2;
+ data->peer_scalar = eap_pwd_get_scalar(data->grp, ptr);
+ if (!data->peer_scalar) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+ "fail");
+ goto fin;
+ }
- /* check to ensure peer's element is not in a small sub-group */
- if (BN_cmp(cofactor, BN_value_one())) {
- if (!EC_POINT_mul(data->grp->group, point, NULL,
- data->peer_element, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
- "multiply peer element by order");
- goto fin;
- }
- if (EC_POINT_is_at_infinity(data->grp->group, point)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
- "is at infinity!\n");
- goto fin;
- }
+ /* detect reflection attacks */
+ if (crypto_bignum_cmp(data->my_scalar, data->peer_scalar) == 0 ||
+ crypto_ec_point_cmp(data->grp->group, data->my_element,
+ data->peer_element) == 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-PWD (server): detected reflection attack!");
+ goto fin;
}
/* compute the shared key, k */
- if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
- data->peer_scalar, data->bnctx)) ||
- (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
- data->bnctx)) ||
- (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
- data->bnctx))) {
+ if ((crypto_ec_point_mul(data->grp->group, data->grp->pwe,
+ data->peer_scalar, K) < 0) ||
+ (crypto_ec_point_add(data->grp->group, K, data->peer_element,
+ K) < 0) ||
+ (crypto_ec_point_mul(data->grp->group, K, data->private_value,
+ K) < 0)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
"fail");
goto fin;
}
- /* ensure that the shared key isn't in a small sub-group */
- if (BN_cmp(cofactor, BN_value_one())) {
- if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
- NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
- "multiply shared key point by order!\n");
- goto fin;
- }
- }
-
/*
- * This check is strictly speaking just for the case above where
+ * This check is strictly speaking just for the case where
* co-factor > 1 but it was suggested that even though this is probably
* never going to happen it is a simple and safe check "just to be
* sure" so let's be safe.
*/
- if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+ if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
"at infinity");
goto fin;
}
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
- NULL, data->bnctx)) {
+ if (crypto_ec_point_x(data->grp->group, K, data->k)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
"shared secret from secret point");
goto fin;
@@ -762,11 +731,7 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
res = 1;
fin:
- EC_POINT_clear_free(K);
- EC_POINT_clear_free(point);
- BN_clear_free(cofactor);
- BN_clear_free(x);
- BN_clear_free(y);
+ crypto_ec_point_deinit(K, 1);
if (res)
eap_pwd_state(data, PWD_Confirm_Req);
@@ -779,12 +744,14 @@ static void
eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
const u8 *payload, size_t payload_len)
{
- BIGNUM *x = NULL, *y = NULL;
- struct crypto_hash *hash;
+ struct crypto_hash *hash = NULL;
u32 cs;
u16 grp;
u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
- int offset;
+ size_t prime_len, order_len;
+
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
if (payload_len != SHA256_MAC_LEN) {
wpa_printf(MSG_INFO,
@@ -803,8 +770,8 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
*ptr = EAP_PWD_DEFAULT_PRF;
/* each component of the cruft will be at most as big as the prime */
- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+ cruft = os_malloc(prime_len * 2);
+ if (!cruft) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
goto fin;
}
@@ -818,66 +785,41 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
/* k */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
- BN_bn2bin(data->k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
/* peer element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->peer_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft,
+ cruft + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* peer scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->peer_scalar);
- BN_bn2bin(data->peer_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* server element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+ cruft + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
-
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* server scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* ciphersuite */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* all done */
eap_pwd_h_final(hash, conf);
+ hash = NULL;
ptr = (u8 *) payload;
if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
@@ -887,7 +829,7 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
}
wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
- if (compute_keys(data->grp, data->bnctx, data->k,
+ if (compute_keys(data->grp, data->k,
data->peer_scalar, data->my_scalar, conf,
data->my_confirm, &cs, data->msk, data->emsk,
data->session_id) < 0)
@@ -896,9 +838,8 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
eap_pwd_state(data, SUCCESS);
fin:
- bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
- BN_clear_free(x);
- BN_clear_free(y);
+ bin_clear_free(cruft, prime_len * 2);
+ eap_pwd_h_final(hash, NULL);
}
@@ -970,7 +911,13 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
/*
* the first and all intermediate fragments have the M bit set
*/
- if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
+ if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
+ if (!data->inbuf) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: No buffer for reassembly");
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
"attack detected! (%d+%d > %d)",
@@ -981,6 +928,8 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
}
wpabuf_put_data(data->inbuf, pos, len);
data->in_frag_pos += len;
+ }
+ if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
(int) len);
return;
@@ -989,9 +938,7 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
* last fragment won't have the M bit set (but we're obviously
* buffering fragments so that's how we know it's the last)
*/
- if (data->in_frag_pos) {
- wpabuf_put_data(data->inbuf, pos, len);
- data->in_frag_pos += len;
+ if (data->in_frag_pos && data->inbuf) {
pos = wpabuf_head_u8(data->inbuf);
len = data->in_frag_pos;
wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
@@ -1028,11 +975,10 @@ static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -1047,11 +993,10 @@ static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
@@ -1080,11 +1025,10 @@ static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- id = os_malloc(1 + SHA256_MAC_LEN);
+ id = os_memdup(data->session_id, 1 + SHA256_MAC_LEN);
if (id == NULL)
return NULL;
- os_memcpy(id, data->session_id, 1 + SHA256_MAC_LEN);
*len = 1 + SHA256_MAC_LEN;
return id;
@@ -1094,15 +1038,6 @@ static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_pwd_register(void)
{
struct eap_method *eap;
- int ret;
- struct timeval tp;
- struct timezone tz;
- u32 sr;
-
- sr = 0xdeaddada;
- (void) gettimeofday(&tp, &tz);
- sr ^= (tp.tv_sec ^ tp.tv_usec);
- srandom(sr);
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PWD,
@@ -1121,9 +1056,5 @@ int eap_server_pwd_register(void)
eap->isSuccess = eap_pwd_is_success;
eap->getSessionId = eap_pwd_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
-
diff --git a/contrib/wpa/src/eap_server/eap_server_sake.c b/contrib/wpa/src/eap_server/eap_server_sake.c
index de70777..2fc2c05 100644
--- a/contrib/wpa/src/eap_server/eap_server_sake.c
+++ b/contrib/wpa/src/eap_server/eap_server_sake.c
@@ -204,7 +204,7 @@ static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
{
wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
data->state = FAILURE;
- os_free(msg);
+ wpabuf_free(msg);
return NULL;
}
@@ -326,10 +326,9 @@ static void eap_sake_process_challenge(struct eap_sm *sm,
data->peerid = NULL;
data->peerid_len = 0;
if (attr.peerid) {
- data->peerid = os_malloc(attr.peerid_len);
+ data->peerid = os_memdup(attr.peerid, attr.peerid_len);
if (data->peerid == NULL)
return;
- os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
data->peerid_len = attr.peerid_len;
}
@@ -341,16 +340,25 @@ static void eap_sake_process_challenge(struct eap_sm *sm,
data->state = FAILURE;
return;
}
- eap_sake_derive_keys(sm->user->password,
- sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
- data->rand_s, data->rand_p,
- (u8 *) &data->tek, data->msk, data->emsk);
-
- eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
- data->peerid, data->peerid_len, 1,
- wpabuf_head(respData), wpabuf_len(respData),
- attr.mic_p, mic_p);
+ if (eap_sake_derive_keys(sm->user->password,
+ sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
+ data->rand_s, data->rand_p,
+ (u8 *) &data->tek, data->msk,
+ data->emsk) < 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to derive keys");
+ data->state = FAILURE;
+ return;
+ }
+
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ sm->server_id, sm->server_id_len,
+ data->peerid, data->peerid_len, 1,
+ wpabuf_head(respData), wpabuf_len(respData),
+ attr.mic_p, mic_p) < 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ data->state = FAILURE;
+ return;
+ }
if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
eap_sake_state(data, FAILURE);
@@ -383,11 +391,14 @@ static void eap_sake_process_confirm(struct eap_sm *sm,
return;
}
- eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
- data->peerid, data->peerid_len, 1,
- wpabuf_head(respData), wpabuf_len(respData),
- attr.mic_p, mic_p);
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ sm->server_id, sm->server_id_len,
+ data->peerid, data->peerid_len, 1,
+ wpabuf_head(respData), wpabuf_len(respData),
+ attr.mic_p, mic_p) < 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ return;
+ }
if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
eap_sake_state(data, FAILURE);
@@ -460,10 +471,9 @@ static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_MSK_LEN);
+ key = os_memdup(data->msk, EAP_MSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_MSK_LEN);
*len = EAP_MSK_LEN;
return key;
@@ -478,10 +488,9 @@ static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
@@ -520,7 +529,6 @@ static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_sake_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
@@ -538,8 +546,5 @@ int eap_server_sake_register(void)
eap->get_emsk = eap_sake_get_emsk;
eap->getSessionId = eap_sake_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_sim.c b/contrib/wpa/src/eap_server/eap_server_sim.c
index ddfb71c..1287827 100644
--- a/contrib/wpa/src/eap_server/eap_server_sim.c
+++ b/contrib/wpa/src/eap_server/eap_server_sim.c
@@ -535,6 +535,9 @@ skip_id_update:
goto failed;
}
+ if (data->permanent[0] == EAP_SIM_PERMANENT_PREFIX)
+ os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
+
identity_len = sm->identity_len;
while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
@@ -787,10 +790,9 @@ static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
+ key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
*len = EAP_SIM_KEYING_DATA_LEN;
return key;
}
@@ -804,10 +806,9 @@ static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = os_malloc(EAP_EMSK_LEN);
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
if (key == NULL)
return NULL;
- os_memcpy(key, data->emsk, EAP_EMSK_LEN);
*len = EAP_EMSK_LEN;
return key;
}
@@ -846,7 +847,6 @@ static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_sim_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
@@ -864,8 +864,5 @@ int eap_server_sim_register(void)
eap->get_emsk = eap_sim_get_emsk;
eap->getSessionId = eap_sim_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_tls.c b/contrib/wpa/src/eap_server/eap_server_tls.c
index bd18a4b..357e72a 100644
--- a/contrib/wpa/src/eap_server/eap_server_tls.c
+++ b/contrib/wpa/src/eap_server/eap_server_tls.c
@@ -22,6 +22,7 @@ struct eap_tls_data {
enum { START, CONTINUE, SUCCESS, FAILURE } state;
int established;
u8 eap_type;
+ int phase2;
};
@@ -85,6 +86,8 @@ static void * eap_tls_init(struct eap_sm *sm)
data->eap_type = EAP_TYPE_TLS;
+ data->phase2 = sm->init_phase2;
+
return data;
}
@@ -202,6 +205,20 @@ check_established:
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
eap_tls_state(data, SUCCESS);
eap_tls_valid_session(sm, data);
+ if (sm->serial_num) {
+ char user[128];
+ int user_len;
+
+ user_len = os_snprintf(user, sizeof(user), "cert-%s",
+ sm->serial_num);
+ if (eap_user_get(sm, (const u8 *) user, user_len,
+ data->phase2) < 0)
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: No user entry found based on the serial number of the client certificate ");
+ else
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Updated user entry based on the serial number of the client certificate ");
+ }
}
return res;
@@ -288,6 +305,8 @@ static void eap_tls_process(struct eap_sm *sm, void *priv,
"EAP-TLS: Resuming previous session");
eap_tls_state(data, SUCCESS);
tls_connection_set_success_data_resumed(data->ssl.conn);
+ /* TODO: Cache serial number with session and update EAP user
+ * information based on the cached serial number */
}
@@ -302,17 +321,23 @@ static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_tls_data *data = priv;
u8 *eapKeyData;
+ const char *label;
if (data->state != SUCCESS)
return NULL;
- eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
- EAP_TLS_KEY_LEN);
+ if (data->ssl.tls_v13)
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ else
+ label = "client EAP encryption";
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
+ NULL, 0,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
eapKeyData, EAP_TLS_KEY_LEN);
+ os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
} else {
wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
}
@@ -325,12 +350,17 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_tls_data *data = priv;
u8 *eapKeyData, *emsk;
+ const char *label;
if (data->state != SUCCESS)
return NULL;
- eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
+ if (data->ssl.tls_v13)
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ else
+ label = "client EAP encryption";
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
+ NULL, 0,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_malloc(EAP_EMSK_LEN);
@@ -375,7 +405,6 @@ static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_tls_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
@@ -393,10 +422,7 @@ int eap_server_tls_register(void)
eap->get_emsk = eap_tls_get_emsk;
eap->getSessionId = eap_tls_get_session_id;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
@@ -404,7 +430,6 @@ int eap_server_tls_register(void)
int eap_server_unauth_tls_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_UNAUTH_TLS,
@@ -423,10 +448,7 @@ int eap_server_unauth_tls_register(void)
eap->isSuccess = eap_tls_isSuccess;
eap->get_emsk = eap_tls_get_emsk;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
#endif /* EAP_SERVER_UNAUTH_TLS */
@@ -435,7 +457,6 @@ int eap_server_unauth_tls_register(void)
int eap_server_wfa_unauth_tls_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_WFA_NEW,
@@ -454,9 +475,6 @@ int eap_server_wfa_unauth_tls_register(void)
eap->isSuccess = eap_tls_isSuccess;
eap->get_emsk = eap_tls_get_emsk;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
#endif /* CONFIG_HS20 */
diff --git a/contrib/wpa/src/eap_server/eap_server_tls_common.c b/contrib/wpa/src/eap_server/eap_server_tls_common.c
index 05677b7..0eca0ff 100644
--- a/contrib/wpa/src/eap_server/eap_server_tls_common.c
+++ b/contrib/wpa/src/eap_server/eap_server_tls_common.c
@@ -47,7 +47,7 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer, int eap_type)
{
u8 session_ctx[8];
- unsigned int flags = 0;
+ unsigned int flags = sm->tls_flags;
if (sm->ssl_ctx == NULL) {
wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
@@ -107,7 +107,8 @@ void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- char *label, size_t len)
+ const char *label, const u8 *context,
+ size_t context_len, size_t len)
{
u8 *out;
@@ -115,8 +116,8 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
if (out == NULL)
return NULL;
- if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, 0,
- out, len)) {
+ if (tls_connection_export_key(sm->ssl_ctx, data->conn, label,
+ context, context_len, out, len)) {
os_free(out);
return NULL;
}
@@ -145,6 +146,29 @@ u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
struct tls_random keys;
u8 *out;
+ if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ u8 *id, *method_id;
+
+ /* Session-Id = <EAP-Type> || Method-Id
+ * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
+ * "", 64)
+ */
+ *len = 1 + 64;
+ id = os_malloc(*len);
+ if (!id)
+ return NULL;
+ method_id = eap_server_tls_derive_key(
+ sm, data, "EXPORTER_EAP_TLS_Method-Id", NULL, 0, 64);
+ if (!method_id) {
+ os_free(id);
+ return NULL;
+ }
+ id[0] = eap_type;
+ os_memcpy(id + 1, method_id, 64);
+ os_free(method_id);
+ return id;
+ }
+
if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
return NULL;
@@ -305,6 +329,8 @@ static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
{
+ char buf[20];
+
if (data->tls_out) {
/* This should not happen.. */
wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
@@ -327,6 +353,16 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
return -1;
}
+ if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
+ wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
+ data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
+ }
+
+ if (!sm->serial_num &&
+ tls_connection_established(sm->ssl_ctx, data->conn))
+ sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx,
+ data->conn);
+
return 0;
}
@@ -373,7 +409,7 @@ static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
if (data->tls_in &&
eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
return -1;
-
+
if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
*pos, end - *pos) < 0)
diff --git a/contrib/wpa/src/eap_server/eap_server_tnc.c b/contrib/wpa/src/eap_server/eap_server_tnc.c
index 21bd26f..b568558 100644
--- a/contrib/wpa/src/eap_server/eap_server_tnc.c
+++ b/contrib/wpa/src/eap_server/eap_server_tnc.c
@@ -554,7 +554,6 @@ static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
int eap_server_tnc_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
@@ -569,8 +568,5 @@ int eap_server_tnc_register(void)
eap->isDone = eap_tnc_isDone;
eap->isSuccess = eap_tnc_isSuccess;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_ttls.c b/contrib/wpa/src/eap_server/eap_server_ttls.c
index 53ffa1e..52bff8a 100644
--- a/contrib/wpa/src/eap_server/eap_server_ttls.c
+++ b/contrib/wpa/src/eap_server/eap_server_ttls.c
@@ -228,14 +228,13 @@ static int eap_ttls_avp_parse(struct wpabuf *buf, struct eap_ttls_avp *parse)
if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
if (parse->eap == NULL) {
- parse->eap = os_malloc(dlen);
+ parse->eap = os_memdup(dpos, dlen);
if (parse->eap == NULL) {
wpa_printf(MSG_WARNING, "EAP-TTLS: "
"failed to allocate memory "
"for Phase 2 EAP data");
goto fail;
}
- os_memcpy(parse->eap, dpos, dlen);
parse->eap_len = dlen;
} else {
u8 *neweap = os_realloc(parse->eap,
@@ -333,7 +332,7 @@ static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
struct eap_ttls_data *data, size_t len)
{
return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge",
- len);
+ NULL, 0, len);
}
@@ -372,7 +371,7 @@ static void eap_ttls_reset(struct eap_sm *sm, void *priv)
static struct wpabuf * eap_ttls_build_start(struct eap_sm *sm,
struct eap_ttls_data *data, u8 id)
-{
+{
struct wpabuf *req;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1,
@@ -666,11 +665,14 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
}
os_free(chal);
- if (sm->user->password_hash)
- challenge_response(challenge, sm->user->password, nt_response);
- else
- nt_challenge_response(challenge, sm->user->password,
- sm->user->password_len, nt_response);
+ if ((sm->user->password_hash &&
+ challenge_response(challenge, sm->user->password, nt_response)) ||
+ (!sm->user->password_hash &&
+ nt_challenge_response(challenge, sm->user->password,
+ sm->user->password_len, nt_response))) {
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
if (os_memcmp_const(nt_response, response + 2 + 24, 24) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
@@ -1051,12 +1053,11 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
}
os_free(sm->identity);
- sm->identity = os_malloc(parse.user_name_len);
+ sm->identity = os_memdup(parse.user_name, parse.user_name_len);
if (sm->identity == NULL) {
eap_ttls_state(data, FAILURE);
goto done;
}
- os_memcpy(sm->identity, parse.user_name, parse.user_name_len);
sm->identity_len = parse.user_name_len;
if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1)
!= 0) {
@@ -1267,7 +1268,7 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
return NULL;
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
+ "ttls keying material", NULL, 0,
EAP_TLS_KEY_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
@@ -1309,7 +1310,7 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
return NULL;
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
+ "ttls keying material", NULL, 0,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_malloc(EAP_EMSK_LEN);
@@ -1335,7 +1336,6 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
int eap_server_ttls_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
@@ -1353,8 +1353,5 @@ int eap_server_ttls_register(void)
eap->getSessionId = eap_ttls_get_session_id;
eap->get_emsk = eap_ttls_get_emsk;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_vendor_test.c b/contrib/wpa/src/eap_server/eap_server_vendor_test.c
index 30f600d..9639977 100644
--- a/contrib/wpa/src/eap_server/eap_server_vendor_test.c
+++ b/contrib/wpa/src/eap_server/eap_server_vendor_test.c
@@ -168,7 +168,6 @@ static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
int eap_server_vendor_test_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_ID, EAP_VENDOR_TYPE,
@@ -185,8 +184,5 @@ int eap_server_vendor_test_register(void)
eap->getKey = eap_vendor_test_getKey;
eap->isSuccess = eap_vendor_test_isSuccess;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_server_wsc.c b/contrib/wpa/src/eap_server/eap_server_wsc.c
index 9d9c28d..4a5cb98 100644
--- a/contrib/wpa/src/eap_server/eap_server_wsc.c
+++ b/contrib/wpa/src/eap_server/eap_server_wsc.c
@@ -257,7 +257,7 @@ static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
}
data->out_used = 0;
}
- /* pass through */
+ /* fall through */
case WAIT_FRAG_ACK:
return eap_wsc_build_msg(data, id);
case FRAG_ACK:
@@ -488,7 +488,6 @@ static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
int eap_server_wsc_register(void)
{
struct eap_method *eap;
- int ret;
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
@@ -505,8 +504,5 @@ int eap_server_wsc_register(void)
eap->isSuccess = eap_wsc_isSuccess;
eap->getTimeout = eap_wsc_getTimeout;
- ret = eap_server_method_register(eap);
- if (ret)
- eap_server_method_free(eap);
- return ret;
+ return eap_server_method_register(eap);
}
diff --git a/contrib/wpa/src/eap_server/eap_sim_db.c b/contrib/wpa/src/eap_server/eap_sim_db.c
index acf5435..d84c3d2 100644
--- a/contrib/wpa/src/eap_server/eap_sim_db.c
+++ b/contrib/wpa/src/eap_server/eap_sim_db.c
@@ -66,6 +66,7 @@ struct eap_sim_db_data {
struct eap_sim_pseudonym *pseudonyms;
struct eap_sim_reauth *reauths;
struct eap_sim_db_pending *pending;
+ unsigned int eap_sim_db_timeout;
#ifdef CONFIG_SQLITE
sqlite3 *sqlite_db;
char db_tmp_identity[100];
@@ -76,6 +77,10 @@ struct eap_sim_db_data {
};
+static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx);
+static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx);
+
+
#ifdef CONFIG_SQLITE
static int db_table_exists(sqlite3 *db, const char *name)
@@ -397,6 +402,57 @@ static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
}
+static void eap_sim_db_free_pending(struct eap_sim_db_data *data,
+ struct eap_sim_db_pending *entry)
+{
+ eloop_cancel_timeout(eap_sim_db_query_timeout, data, entry);
+ eloop_cancel_timeout(eap_sim_db_del_timeout, data, entry);
+ os_free(entry);
+}
+
+
+static void eap_sim_db_del_pending(struct eap_sim_db_data *data,
+ struct eap_sim_db_pending *entry)
+{
+ struct eap_sim_db_pending **pp = &data->pending;
+
+ while (*pp != NULL) {
+ if (*pp == entry) {
+ *pp = entry->next;
+ eap_sim_db_free_pending(data, entry);
+ return;
+ }
+ pp = &(*pp)->next;
+ }
+}
+
+
+static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx)
+{
+ struct eap_sim_db_data *data = eloop_ctx;
+ struct eap_sim_db_pending *entry = user_ctx;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Delete query timeout for %p", entry);
+ eap_sim_db_del_pending(data, entry);
+}
+
+
+static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx)
+{
+ struct eap_sim_db_data *data = eloop_ctx;
+ struct eap_sim_db_pending *entry = user_ctx;
+
+ /*
+ * Report failure and allow some time for EAP server to process it
+ * before deleting the query.
+ */
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Query timeout for %p", entry);
+ entry->state = FAILURE;
+ data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+ eloop_register_timeout(1, 0, eap_sim_db_del_timeout, data, entry);
+}
+
+
static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
const char *imsi, char *buf)
{
@@ -472,7 +528,7 @@ static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
parse_fail:
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
- os_free(entry);
+ eap_sim_db_free_pending(data, entry);
}
@@ -563,7 +619,7 @@ static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
parse_fail:
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
- os_free(entry);
+ eap_sim_db_free_pending(data, entry);
}
@@ -690,12 +746,13 @@ static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
/**
* eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
* @config: Configuration data (e.g., file name)
+ * @db_timeout: Database lookup timeout
* @get_complete_cb: Callback function for reporting availability of triplets
* @ctx: Context pointer for get_complete_cb
* Returns: Pointer to a private data structure or %NULL on failure
*/
struct eap_sim_db_data *
-eap_sim_db_init(const char *config,
+eap_sim_db_init(const char *config, unsigned int db_timeout,
void (*get_complete_cb)(void *ctx, void *session_ctx),
void *ctx)
{
@@ -709,6 +766,7 @@ eap_sim_db_init(const char *config,
data->sock = -1;
data->get_complete_cb = get_complete_cb;
data->ctx = ctx;
+ data->eap_sim_db_timeout = db_timeout;
data->fname = os_strdup(config);
if (data->fname == NULL)
goto fail;
@@ -796,7 +854,7 @@ void eap_sim_db_deinit(void *priv)
while (pending) {
prev_pending = pending;
pending = pending->next;
- os_free(prev_pending);
+ eap_sim_db_free_pending(data, prev_pending);
}
os_free(data);
@@ -833,11 +891,11 @@ static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
}
-static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
+static void eap_sim_db_expire_pending(struct eap_sim_db_data *data,
+ struct eap_sim_db_pending *entry)
{
- /* TODO: add limit for maximum length for pending list; remove latest
- * (i.e., last) entry from the list if the limit is reached; could also
- * use timeout to expire pending entries */
+ eloop_register_timeout(data->eap_sim_db_timeout, 0,
+ eap_sim_db_query_timeout, data, entry);
}
@@ -891,7 +949,7 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
if (entry->state == FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
"failure");
- os_free(entry);
+ eap_sim_db_free_pending(data, entry);
return EAP_SIM_DB_FAILURE;
}
@@ -911,7 +969,7 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
os_memcpy(sres, entry->u.sim.sres,
num_chal * EAP_SIM_SRES_LEN);
os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
- os_free(entry);
+ eap_sim_db_free_pending(data, entry);
return num_chal;
}
@@ -945,7 +1003,8 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
entry->cb_session_ctx = cb_session_ctx;
entry->state = PENDING;
eap_sim_db_add_pending(data, entry);
- eap_sim_db_expire_pending(data);
+ eap_sim_db_expire_pending(data, entry);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
return EAP_SIM_DB_PENDING;
}
@@ -1356,7 +1415,7 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
entry = eap_sim_db_get_pending(data, imsi, 1);
if (entry) {
if (entry->state == FAILURE) {
- os_free(entry);
+ eap_sim_db_free_pending(data, entry);
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
return EAP_SIM_DB_FAILURE;
}
@@ -1375,7 +1434,7 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
*res_len = entry->u.aka.res_len;
- os_free(entry);
+ eap_sim_db_free_pending(data, entry);
return 0;
}
@@ -1406,7 +1465,8 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
entry->cb_session_ctx = cb_session_ctx;
entry->state = PENDING;
eap_sim_db_add_pending(data, entry);
- eap_sim_db_expire_pending(data);
+ eap_sim_db_expire_pending(data, entry);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
return EAP_SIM_DB_PENDING;
}
diff --git a/contrib/wpa/src/eap_server/eap_sim_db.h b/contrib/wpa/src/eap_server/eap_sim_db.h
index 53a1a7c..ca900b9 100644
--- a/contrib/wpa/src/eap_server/eap_sim_db.h
+++ b/contrib/wpa/src/eap_server/eap_sim_db.h
@@ -31,7 +31,7 @@ enum eap_sim_db_method {
struct eap_sim_db_data;
struct eap_sim_db_data *
-eap_sim_db_init(const char *config,
+eap_sim_db_init(const char *config, unsigned int db_timeout,
void (*get_complete_cb)(void *ctx, void *session_ctx),
void *ctx);
diff --git a/contrib/wpa/src/eap_server/eap_tls_common.h b/contrib/wpa/src/eap_server/eap_tls_common.h
index dc943eb..0b04983 100644
--- a/contrib/wpa/src/eap_server/eap_tls_common.h
+++ b/contrib/wpa/src/eap_server/eap_tls_common.h
@@ -50,6 +50,11 @@ struct eap_ssl_data {
enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state;
struct wpabuf tmpbuf;
+
+ /**
+ * tls_v13 - Whether TLS v1.3 or newer is used
+ */
+ int tls_v13;
};
@@ -73,7 +78,8 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer, int eap_type);
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- char *label, size_t len);
+ const char *label, const u8 *context,
+ size_t context_len, size_t len);
u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
diff --git a/contrib/wpa/src/eap_server/ikev2.c b/contrib/wpa/src/eap_server/ikev2.c
index 632598f..0e9210e 100644
--- a/contrib/wpa/src/eap_server/ikev2.c
+++ b/contrib/wpa/src/eap_server/ikev2.c
@@ -133,7 +133,7 @@ static int ikev2_parse_transform(struct ikev2_initiator_data *data,
t = (const struct ikev2_transform *) pos;
transform_len = WPA_GET_BE16(t->transform_length);
- if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
+ if (transform_len < (int) sizeof(*t) || transform_len > end - pos) {
wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
transform_len);
return -1;
@@ -221,7 +221,7 @@ static int ikev2_parse_proposal(struct ikev2_initiator_data *data,
p = (const struct ikev2_proposal *) pos;
proposal_len = WPA_GET_BE16(p->proposal_length);
- if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
+ if (proposal_len < (int) sizeof(*p) || proposal_len > end - pos) {
wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
proposal_len);
return -1;
@@ -256,7 +256,7 @@ static int ikev2_parse_proposal(struct ikev2_initiator_data *data,
ppos = (const u8 *) (p + 1);
pend = pos + proposal_len;
- if (ppos + p->spi_size > pend) {
+ if (p->spi_size > pend - ppos) {
wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
"in proposal");
return -1;
@@ -544,10 +544,9 @@ static int ikev2_process_idr(struct ikev2_initiator_data *data,
}
os_free(data->IDr);
}
- data->IDr = os_malloc(idr_len);
+ data->IDr = os_memdup(idr, idr_len);
if (data->IDr == NULL)
return -1;
- os_memcpy(data->IDr, idr, idr_len);
data->IDr_len = idr_len;
data->IDr_type = id_type;
@@ -1147,10 +1146,9 @@ static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data)
return NULL;
} else {
os_free(data->shared_secret);
- data->shared_secret = os_malloc(secret_len);
+ data->shared_secret = os_memdup(secret, secret_len);
if (data->shared_secret == NULL)
return NULL;
- os_memcpy(data->shared_secret, secret, secret_len);
data->shared_secret_len = secret_len;
}
diff --git a/contrib/wpa/src/eap_server/tncs.c b/contrib/wpa/src/eap_server/tncs.c
index dc6f689..942a195 100644
--- a/contrib/wpa/src/eap_server/tncs.c
+++ b/contrib/wpa/src/eap_server/tncs.c
@@ -140,7 +140,7 @@ static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
/* TNCS functions that IMVs can call */
-TNC_Result TNC_TNCS_ReportMessageTypes(
+static TNC_Result TNC_TNCS_ReportMessageTypes(
TNC_IMVID imvID,
TNC_MessageTypeList supportedTypes,
TNC_UInt32 typeCount)
@@ -161,19 +161,17 @@ TNC_Result TNC_TNCS_ReportMessageTypes(
if (imv == NULL)
return TNC_RESULT_INVALID_PARAMETER;
os_free(imv->supported_types);
- imv->supported_types =
- os_malloc(typeCount * sizeof(TNC_MessageType));
+ imv->supported_types = os_memdup(supportedTypes,
+ typeCount * sizeof(TNC_MessageType));
if (imv->supported_types == NULL)
return TNC_RESULT_FATAL;
- os_memcpy(imv->supported_types, supportedTypes,
- typeCount * sizeof(TNC_MessageType));
imv->num_supported_types = typeCount;
return TNC_RESULT_SUCCESS;
}
-TNC_Result TNC_TNCS_SendMessage(
+static TNC_Result TNC_TNCS_SendMessage(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_BufferReference message,
@@ -222,7 +220,7 @@ TNC_Result TNC_TNCS_SendMessage(
}
-TNC_Result TNC_TNCS_RequestHandshakeRetry(
+static TNC_Result TNC_TNCS_RequestHandshakeRetry(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_RetryReason reason)
@@ -233,7 +231,7 @@ TNC_Result TNC_TNCS_RequestHandshakeRetry(
}
-TNC_Result TNC_TNCS_ProvideRecommendation(
+static TNC_Result TNC_TNCS_ProvideRecommendation(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_IMV_Action_Recommendation recommendation,
@@ -260,7 +258,7 @@ TNC_Result TNC_TNCS_ProvideRecommendation(
}
-TNC_Result TNC_TNCS_GetAttribute(
+static TNC_Result TNC_TNCS_GetAttribute(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_AttributeID attribureID,
@@ -274,7 +272,7 @@ TNC_Result TNC_TNCS_GetAttribute(
}
-TNC_Result TNC_TNCS_SetAttribute(
+static TNC_Result TNC_TNCS_SetAttribute(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_AttributeID attribureID,
@@ -287,7 +285,7 @@ TNC_Result TNC_TNCS_SetAttribute(
}
-TNC_Result TNC_TNCS_BindFunction(
+static TNC_Result TNC_TNCS_BindFunction(
TNC_IMVID imvID,
char *functionName,
void **pOutFunctionPointer)
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_sm.c b/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
index ff33d28..36074d3 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm.c
@@ -848,6 +848,7 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
eap_conf.server_id_len = eapol->conf.server_id_len;
eap_conf.erp = eapol->conf.erp;
eap_conf.tls_session_lifetime = eapol->conf.tls_session_lifetime;
+ eap_conf.tls_flags = eapol->conf.tls_flags;
sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
if (sm->eap == NULL) {
eapol_auth_free(sm);
@@ -866,10 +867,13 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
sm->radius_cui = wpabuf_alloc_copy(radius_cui,
os_strlen(radius_cui));
- sm->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo++;
- if (eapol->acct_multi_session_id_lo == 0)
- eapol->acct_multi_session_id_hi++;
- sm->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
+#ifndef CONFIG_NO_RADIUS
+ if (radius_gen_session_id((u8 *) &sm->acct_multi_session_id,
+ sizeof(sm->acct_multi_session_id)) < 0) {
+ eapol_auth_free(sm);
+ return NULL;
+ }
+#endif /* CONFIG_NO_RADIUS */
return sm;
}
@@ -884,6 +888,9 @@ void eapol_auth_free(struct eapol_state_machine *sm)
eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
if (sm->eap)
eap_server_sm_deinit(sm->eap);
+
+ wpabuf_free(sm->radius_cui);
+ os_free(sm->identity);
os_free(sm);
}
@@ -1191,30 +1198,27 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
dst->server_id = src->server_id;
dst->server_id_len = src->server_id_len;
if (src->eap_req_id_text) {
- dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
+ dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
+ src->eap_req_id_text_len);
if (dst->eap_req_id_text == NULL)
return -1;
- os_memcpy(dst->eap_req_id_text, src->eap_req_id_text,
- src->eap_req_id_text_len);
dst->eap_req_id_text_len = src->eap_req_id_text_len;
} else {
dst->eap_req_id_text = NULL;
dst->eap_req_id_text_len = 0;
}
if (src->pac_opaque_encr_key) {
- dst->pac_opaque_encr_key = os_malloc(16);
+ dst->pac_opaque_encr_key = os_memdup(src->pac_opaque_encr_key,
+ 16);
if (dst->pac_opaque_encr_key == NULL)
goto fail;
- os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
- 16);
} else
dst->pac_opaque_encr_key = NULL;
if (src->eap_fast_a_id) {
- dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
+ dst->eap_fast_a_id = os_memdup(src->eap_fast_a_id,
+ src->eap_fast_a_id_len);
if (dst->eap_fast_a_id == NULL)
goto fail;
- os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
- src->eap_fast_a_id_len);
dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
} else
dst->eap_fast_a_id = NULL;
@@ -1243,6 +1247,7 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
dst->erp_send_reauth_start = src->erp_send_reauth_start;
dst->erp = src->erp;
dst->tls_session_lifetime = src->tls_session_lifetime;
+ dst->tls_flags = src->tls_flags;
return 0;
@@ -1271,7 +1276,6 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
struct eapol_auth_cb *cb)
{
struct eapol_authenticator *eapol;
- struct os_time now;
eapol = os_zalloc(sizeof(*eapol));
if (eapol == NULL)
@@ -1300,12 +1304,6 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
eapol->cb.erp_get_key = cb->erp_get_key;
eapol->cb.erp_add_key = cb->erp_add_key;
- /* Acct-Multi-Session-Id should be unique over reboots. If reliable
- * clock is not available, this could be replaced with reboot counter,
- * etc. */
- os_get_time(&now);
- eapol->acct_multi_session_id_hi = now.sec;
-
return eapol;
}
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_sm.h b/contrib/wpa/src/eapol_auth/eapol_auth_sm.h
index e1974e4..44f3f31 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm.h
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm.h
@@ -28,6 +28,7 @@ struct eapol_auth_config {
char *erp_domain; /* a copy of this will be allocated */
int erp; /* Whether ERP is enabled on authentication server */
unsigned int tls_session_lifetime;
+ unsigned int tls_flags;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
diff --git a/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h b/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
index a29b49c..04386b2 100644
--- a/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
+++ b/contrib/wpa/src/eapol_auth/eapol_auth_sm_i.h
@@ -30,9 +30,6 @@ struct eapol_authenticator {
u8 *default_wep_key;
u8 default_wep_key_idx;
-
- u32 acct_multi_session_id_hi;
- u32 acct_multi_session_id_lo;
};
@@ -162,12 +159,6 @@ struct eapol_state_machine {
struct radius_class_data radius_class;
struct wpabuf *radius_cui; /* Chargeable-User-Identity */
- /* Keys for encrypting and signing EAPOL-Key frames */
- u8 *eapol_key_sign;
- size_t eapol_key_sign_len;
- u8 *eapol_key_crypt;
- size_t eapol_key_crypt_len;
-
struct eap_sm *eap;
Boolean initializing; /* in process of initializing state machines */
@@ -179,8 +170,7 @@ struct eapol_state_machine {
int remediation;
- u32 acct_multi_session_id_hi;
- u32 acct_multi_session_id_lo;
+ u64 acct_multi_session_id;
};
#endif /* EAPOL_AUTH_SM_I_H */
diff --git a/contrib/wpa/src/eapol_supp/eapol_supp_sm.c b/contrib/wpa/src/eapol_supp/eapol_supp_sm.c
index 09cf4f6..a0f27fd 100644
--- a/contrib/wpa/src/eapol_supp/eapol_supp_sm.c
+++ b/contrib/wpa/src/eapol_supp/eapol_supp_sm.c
@@ -16,6 +16,7 @@
#include "crypto/md5.h"
#include "common/eapol_common.h"
#include "eap_peer/eap.h"
+#include "eap_peer/eap_config.h"
#include "eap_peer/eap_proxy.h"
#include "eapol_supp_sm.h"
@@ -95,7 +96,7 @@ struct eapol_sm {
SUPP_BE_RECEIVE = 4,
SUPP_BE_RESPONSE = 5,
SUPP_BE_FAIL = 6,
- SUPP_BE_TIMEOUT = 7,
+ SUPP_BE_TIMEOUT = 7,
SUPP_BE_SUCCESS = 8
} SUPP_BE_state; /* dot1xSuppBackendPaeState */
/* Variables */
@@ -188,8 +189,9 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
}
if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
- eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
- sm);
+ if (eloop_register_timeout(1, 0, eapol_port_timers_tick,
+ eloop_ctx, sm) < 0)
+ sm->timer_tick_enabled = 0;
} else {
wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
sm->timer_tick_enabled = 0;
@@ -203,9 +205,9 @@ static void eapol_enable_timer_tick(struct eapol_sm *sm)
if (sm->timer_tick_enabled)
return;
wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
- sm->timer_tick_enabled = 1;
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
- eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+ if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
+ sm->timer_tick_enabled = 1;
}
@@ -250,6 +252,8 @@ SM_STATE(SUPP_PAE, CONNECTING)
if (sm->eapTriggerStart)
send_start = 1;
+ if (sm->ctx->preauth)
+ send_start = 1;
sm->eapTriggerStart = FALSE;
if (send_start) {
@@ -314,6 +318,16 @@ SM_STATE(SUPP_PAE, RESTART)
{
SM_ENTRY(SUPP_PAE, RESTART);
sm->eapRestart = TRUE;
+ if (sm->altAccept) {
+ /*
+ * Prevent EAP peer state machine from failing due to prior
+ * external EAP success notification (altSuccess=TRUE in the
+ * IDLE state could result in a transition to the FAILURE state.
+ */
+ wpa_printf(MSG_DEBUG, "EAPOL: Clearing prior altAccept TRUE");
+ sm->eapSuccess = FALSE;
+ sm->altAccept = FALSE;
+ }
}
@@ -480,9 +494,24 @@ SM_STATE(SUPP_BE, SUCCESS)
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
if (eap_proxy_key_available(sm->eap_proxy)) {
+ u8 *session_id, *emsk;
+ size_t session_id_len, emsk_len;
+
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
sm->replay_counter_valid = FALSE;
+
+ session_id = eap_proxy_get_eap_session_id(
+ sm->eap_proxy, &session_id_len);
+ emsk = eap_proxy_get_emsk(sm->eap_proxy, &emsk_len);
+ if (sm->config->erp && session_id && emsk) {
+ eap_peer_erp_init(sm->eap, session_id,
+ session_id_len, emsk,
+ emsk_len);
+ } else {
+ os_free(session_id);
+ bin_clear_free(emsk, emsk_len);
+ }
}
return;
}
@@ -887,6 +916,9 @@ static void eapol_sm_abortSupp(struct eapol_sm *sm)
wpabuf_free(sm->eapReqData);
sm->eapReqData = NULL;
eap_sm_abort(sm->eap);
+#ifdef CONFIG_EAP_PROXY
+ eap_proxy_sm_abort(sm->eap_proxy);
+#endif /* CONFIG_EAP_PROXY */
}
@@ -1988,7 +2020,17 @@ static void eapol_sm_notify_status(void *ctx, const char *status,
}
+static void eapol_sm_notify_eap_error(void *ctx, int error_code)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->eap_error_cb)
+ sm->ctx->eap_error_cb(sm->ctx->ctx, error_code);
+}
+
+
#ifdef CONFIG_EAP_PROXY
+
static void eapol_sm_eap_proxy_cb(void *ctx)
{
struct eapol_sm *sm = ctx;
@@ -1996,6 +2038,18 @@ static void eapol_sm_eap_proxy_cb(void *ctx)
if (sm->ctx->eap_proxy_cb)
sm->ctx->eap_proxy_cb(sm->ctx->ctx);
}
+
+
+static void
+eapol_sm_eap_proxy_notify_sim_status(void *ctx,
+ enum eap_proxy_sim_state sim_state)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->eap_proxy_notify_sim_status)
+ sm->ctx->eap_proxy_notify_sim_status(sm->ctx->ctx, sim_state);
+}
+
#endif /* CONFIG_EAP_PROXY */
@@ -2022,8 +2076,11 @@ static const struct eapol_callbacks eapol_cb =
eapol_sm_eap_param_needed,
eapol_sm_notify_cert,
eapol_sm_notify_status,
+ eapol_sm_notify_eap_error,
#ifdef CONFIG_EAP_PROXY
eapol_sm_eap_proxy_cb,
+ eapol_sm_eap_proxy_notify_sim_status,
+ eapol_sm_get_eap_proxy_imsi,
#endif /* CONFIG_EAP_PROXY */
eapol_sm_set_anon_id
};
@@ -2085,8 +2142,8 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
sm->initialize = FALSE;
eapol_sm_step(sm);
- sm->timer_tick_enabled = 1;
- eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+ if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
+ sm->timer_tick_enabled = 1;
return sm;
}
@@ -2131,16 +2188,16 @@ int eapol_sm_failed(struct eapol_sm *sm)
}
-int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
-{
#ifdef CONFIG_EAP_PROXY
+int eapol_sm_get_eap_proxy_imsi(void *ctx, int sim_num, char *imsi, size_t *len)
+{
+ struct eapol_sm *sm = ctx;
+
if (sm->eap_proxy == NULL)
return -1;
- return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
-#else /* CONFIG_EAP_PROXY */
- return -1;
-#endif /* CONFIG_EAP_PROXY */
+ return eap_proxy_get_imsi(sm->eap_proxy, sim_num, imsi, len);
}
+#endif /* CONFIG_EAP_PROXY */
void eapol_sm_erp_flush(struct eapol_sm *sm)
@@ -2148,3 +2205,56 @@ void eapol_sm_erp_flush(struct eapol_sm *sm)
if (sm)
eap_peer_erp_free_keys(sm->eap);
}
+
+
+struct wpabuf * eapol_sm_build_erp_reauth_start(struct eapol_sm *sm)
+{
+#ifdef CONFIG_ERP
+ if (!sm)
+ return NULL;
+ return eap_peer_build_erp_reauth_start(sm->eap, 0);
+#else /* CONFIG_ERP */
+ return NULL;
+#endif /* CONFIG_ERP */
+}
+
+
+void eapol_sm_process_erp_finish(struct eapol_sm *sm, const u8 *buf,
+ size_t len)
+{
+#ifdef CONFIG_ERP
+ if (!sm)
+ return;
+ eap_peer_finish(sm->eap, (const struct eap_hdr *) buf, len);
+#endif /* CONFIG_ERP */
+}
+
+
+int eapol_sm_update_erp_next_seq_num(struct eapol_sm *sm, u16 next_seq_num)
+{
+#ifdef CONFIG_ERP
+ if (!sm)
+ return -1;
+ return eap_peer_update_erp_next_seq_num(sm->eap, next_seq_num);
+#else /* CONFIG_ERP */
+ return -1;
+#endif /* CONFIG_ERP */
+}
+
+
+int eapol_sm_get_erp_info(struct eapol_sm *sm, struct eap_peer_config *config,
+ const u8 **username, size_t *username_len,
+ const u8 **realm, size_t *realm_len,
+ u16 *erp_next_seq_num, const u8 **rrk,
+ size_t *rrk_len)
+{
+#ifdef CONFIG_ERP
+ if (!sm)
+ return -1;
+ return eap_peer_get_erp_info(sm->eap, config, username, username_len,
+ realm, realm_len, erp_next_seq_num, rrk,
+ rrk_len);
+#else /* CONFIG_ERP */
+ return -1;
+#endif /* CONFIG_ERP */
+}
diff --git a/contrib/wpa/src/eapol_supp/eapol_supp_sm.h b/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
index 1309ff7..74f40bb 100644
--- a/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
+++ b/contrib/wpa/src/eapol_supp/eapol_supp_sm.h
@@ -271,12 +271,27 @@ struct eapol_ctx {
void (*status_cb)(void *ctx, const char *status,
const char *parameter);
+ /**
+ * eap_error_cb - Notification of EAP method error
+ * @ctx: Callback context (ctx)
+ * @error_code: EAP method error code
+ */
+ void (*eap_error_cb)(void *ctx, int error_code);
+
#ifdef CONFIG_EAP_PROXY
/**
* eap_proxy_cb - Callback signifying any updates from eap_proxy
* @ctx: eapol_ctx from eap_peer_sm_init() call
*/
void (*eap_proxy_cb)(void *ctx);
+
+ /**
+ * eap_proxy_notify_sim_status - Notification of SIM status change
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @status: One of enum value from sim_state
+ */
+ void (*eap_proxy_notify_sim_status)(void *ctx,
+ enum eap_proxy_sim_state sim_state);
#endif /* CONFIG_EAP_PROXY */
/**
@@ -328,7 +343,18 @@ void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
struct ext_password_data *ext);
int eapol_sm_failed(struct eapol_sm *sm);
void eapol_sm_erp_flush(struct eapol_sm *sm);
-int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len);
+struct wpabuf * eapol_sm_build_erp_reauth_start(struct eapol_sm *sm);
+void eapol_sm_process_erp_finish(struct eapol_sm *sm, const u8 *buf,
+ size_t len);
+int eapol_sm_get_eap_proxy_imsi(void *ctx, int sim_num, char *imsi,
+ size_t *len);
+int eapol_sm_update_erp_next_seq_num(struct eapol_sm *sm, u16 next_seq_num);
+int eapol_sm_get_erp_info(struct eapol_sm *sm, struct eap_peer_config *config,
+ const u8 **username, size_t *username_len,
+ const u8 **realm, size_t *realm_len,
+ u16 *erp_next_seq_num, const u8 **rrk,
+ size_t *rrk_len);
+
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
@@ -438,6 +464,28 @@ static inline int eapol_sm_failed(struct eapol_sm *sm)
static inline void eapol_sm_erp_flush(struct eapol_sm *sm)
{
}
+static inline struct wpabuf *
+eapol_sm_build_erp_reauth_start(struct eapol_sm *sm)
+{
+ return NULL;
+}
+static inline void eapol_sm_process_erp_finish(struct eapol_sm *sm,
+ const u8 *buf, size_t len)
+{
+}
+static inline int eapol_sm_update_erp_next_seq_num(struct eapol_sm *sm,
+ u16 next_seq_num)
+{
+ return -1;
+}
+static inline int
+eapol_sm_get_erp_info(struct eapol_sm *sm, struct eap_peer_config *config,
+ const u8 **username, size_t *username_len,
+ const u8 **realm, size_t *realm_len,
+ u16 *erp_next_seq_num, const u8 **rrk, size_t *rrk_len)
+{
+ return -1;
+}
#endif /* IEEE8021X_EAPOL */
#endif /* EAPOL_SUPP_SM_H */
diff --git a/contrib/wpa/src/fst/fst.c b/contrib/wpa/src/fst/fst.c
index 2880870..32cd941 100644
--- a/contrib/wpa/src/fst/fst.c
+++ b/contrib/wpa/src/fst/fst.c
@@ -15,6 +15,7 @@
#include "fst/fst_defs.h"
#include "fst/fst_ctrl_iface.h"
+static int fst_global_initialized = 0;
struct dl_list fst_global_ctrls_list;
@@ -106,6 +107,7 @@ int fst_global_init(void)
dl_list_init(&fst_global_groups_list);
dl_list_init(&fst_global_ctrls_list);
fst_session_global_init();
+ fst_global_initialized = 1;
return 0;
}
@@ -115,6 +117,9 @@ void fst_global_deinit(void)
struct fst_group *group;
struct fst_ctrl_handle *h;
+ if (!fst_global_initialized)
+ return;
+
fst_session_global_deinit();
while ((group = fst_first_group()) != NULL)
fst_group_delete(group);
@@ -122,6 +127,7 @@ void fst_global_deinit(void)
struct fst_ctrl_handle,
global_ctrls_lentry)))
fst_global_del_ctrl(h);
+ fst_global_initialized = 0;
}
@@ -160,7 +166,7 @@ void fst_global_del_ctrl(struct fst_ctrl_handle *h)
void fst_rx_action(struct fst_iface *iface, const struct ieee80211_mgmt *mgmt,
size_t len)
{
- if (fst_iface_is_connected(iface, mgmt->sa))
+ if (fst_iface_is_connected(iface, mgmt->sa, FALSE))
fst_session_on_action_rx(iface, mgmt, len);
else
wpa_printf(MSG_DEBUG,
diff --git a/contrib/wpa/src/fst/fst.h b/contrib/wpa/src/fst/fst.h
index 0c0e435..2967491 100644
--- a/contrib/wpa/src/fst/fst.h
+++ b/contrib/wpa/src/fst/fst.h
@@ -19,10 +19,18 @@
#define US_IN_MS 1000
#define LLT_UNIT_US 32 /* See 10.32.2.2 Transitioning between states */
-#define FST_LLT_MS_TO_VAL(m) (((u32) (m)) * US_IN_MS / LLT_UNIT_US)
-#define FST_LLT_VAL_TO_MS(v) (((u32) (v)) * LLT_UNIT_US / US_IN_MS)
-
-#define FST_MAX_LLT_MS FST_LLT_VAL_TO_MS(-1)
+/*
+ * These were originally
+ * #define FST_LLT_MS_TO_VAL(m) (((u32) (m)) * US_IN_MS / LLT_UNIT_US)
+ * #define FST_LLT_VAL_TO_MS(v) (((u32) (v)) * LLT_UNIT_US / US_IN_MS)
+ * #define FST_MAX_LLT_MS FST_LLT_VAL_TO_MS(-1)
+ * but those can overflow 32-bit unsigned integer, so use alternative defines
+ * to avoid undefined behavior with such overflow.
+ * LLT_UNIT_US/US_IN_MS = 32/1000 = 4/125
+ */
+#define FST_LLT_MS_TO_VAL(m) (((u32) (m)) * 125 / 4)
+#define FST_LLT_VAL_TO_MS(v) (((u32) (v)) * 4 / 125)
+#define FST_MAX_LLT_MS (((u32) -1) / 4)
#define FST_MAX_PRIO_VALUE ((u8) -1)
#define FST_MAX_GROUP_ID_LEN IFNAMSIZ
diff --git a/contrib/wpa/src/fst/fst_ctrl_aux.c b/contrib/wpa/src/fst/fst_ctrl_aux.c
index dc7b2a7..b632827 100644
--- a/contrib/wpa/src/fst/fst_ctrl_aux.c
+++ b/contrib/wpa/src/fst/fst_ctrl_aux.c
@@ -14,27 +14,28 @@
static const char *session_event_names[] = {
- [EVENT_FST_ESTABLISHED] FST_PVAL_EVT_TYPE_ESTABLISHED,
- [EVENT_FST_SETUP] FST_PVAL_EVT_TYPE_SETUP,
- [EVENT_FST_SESSION_STATE_CHANGED] FST_PVAL_EVT_TYPE_SESSION_STATE,
+ [EVENT_FST_ESTABLISHED] = FST_PVAL_EVT_TYPE_ESTABLISHED,
+ [EVENT_FST_SETUP] = FST_PVAL_EVT_TYPE_SETUP,
+ [EVENT_FST_SESSION_STATE_CHANGED] = FST_PVAL_EVT_TYPE_SESSION_STATE,
};
static const char *reason_names[] = {
- [REASON_TEARDOWN] FST_CS_PVAL_REASON_TEARDOWN,
- [REASON_SETUP] FST_CS_PVAL_REASON_SETUP,
- [REASON_SWITCH] FST_CS_PVAL_REASON_SWITCH,
- [REASON_STT] FST_CS_PVAL_REASON_STT,
- [REASON_REJECT] FST_CS_PVAL_REASON_REJECT,
- [REASON_ERROR_PARAMS] FST_CS_PVAL_REASON_ERROR_PARAMS,
- [REASON_RESET] FST_CS_PVAL_REASON_RESET,
- [REASON_DETACH_IFACE] FST_CS_PVAL_REASON_DETACH_IFACE,
+ [REASON_TEARDOWN] = FST_CS_PVAL_REASON_TEARDOWN,
+ [REASON_SETUP] = FST_CS_PVAL_REASON_SETUP,
+ [REASON_SWITCH] = FST_CS_PVAL_REASON_SWITCH,
+ [REASON_STT] = FST_CS_PVAL_REASON_STT,
+ [REASON_REJECT] = FST_CS_PVAL_REASON_REJECT,
+ [REASON_ERROR_PARAMS] = FST_CS_PVAL_REASON_ERROR_PARAMS,
+ [REASON_RESET] = FST_CS_PVAL_REASON_RESET,
+ [REASON_DETACH_IFACE] = FST_CS_PVAL_REASON_DETACH_IFACE,
};
static const char *session_state_names[] = {
- [FST_SESSION_STATE_INITIAL] FST_CS_PVAL_STATE_INITIAL,
- [FST_SESSION_STATE_SETUP_COMPLETION] FST_CS_PVAL_STATE_SETUP_COMPLETION,
- [FST_SESSION_STATE_TRANSITION_DONE] FST_CS_PVAL_STATE_TRANSITION_DONE,
- [FST_SESSION_STATE_TRANSITION_CONFIRMED]
+ [FST_SESSION_STATE_INITIAL] = FST_CS_PVAL_STATE_INITIAL,
+ [FST_SESSION_STATE_SETUP_COMPLETION] =
+ FST_CS_PVAL_STATE_SETUP_COMPLETION,
+ [FST_SESSION_STATE_TRANSITION_DONE] = FST_CS_PVAL_STATE_TRANSITION_DONE,
+ [FST_SESSION_STATE_TRANSITION_CONFIRMED] =
FST_CS_PVAL_STATE_TRANSITION_CONFIRMED,
};
diff --git a/contrib/wpa/src/fst/fst_ctrl_aux.h b/contrib/wpa/src/fst/fst_ctrl_aux.h
index e2133f5..0aff5d0 100644
--- a/contrib/wpa/src/fst/fst_ctrl_aux.h
+++ b/contrib/wpa/src/fst/fst_ctrl_aux.h
@@ -35,6 +35,17 @@ enum fst_event_type {
* more info */
};
+enum fst_reason {
+ REASON_TEARDOWN,
+ REASON_SETUP,
+ REASON_SWITCH,
+ REASON_STT,
+ REASON_REJECT,
+ REASON_ERROR_PARAMS,
+ REASON_RESET,
+ REASON_DETACH_IFACE,
+};
+
enum fst_initiator {
FST_INITIATOR_UNDEFINED,
FST_INITIATOR_LOCAL,
@@ -57,16 +68,7 @@ union fst_event_extra {
enum fst_session_state new_state;
union fst_session_state_switch_extra {
struct {
- enum fst_reason {
- REASON_TEARDOWN,
- REASON_SETUP,
- REASON_SWITCH,
- REASON_STT,
- REASON_REJECT,
- REASON_ERROR_PARAMS,
- REASON_RESET,
- REASON_DETACH_IFACE,
- } reason;
+ enum fst_reason reason;
u8 reject_code; /* REASON_REJECT */
/* REASON_SWITCH,
* REASON_TEARDOWN,
diff --git a/contrib/wpa/src/fst/fst_ctrl_iface.c b/contrib/wpa/src/fst/fst_ctrl_iface.c
index d090718..7df3362 100644
--- a/contrib/wpa/src/fst/fst_ctrl_iface.c
+++ b/contrib/wpa/src/fst/fst_ctrl_iface.c
@@ -49,7 +49,7 @@ static Boolean format_session_state_extra(const union fst_event_extra *extra,
if (ss->extra.to_initial.reject_code != WLAN_STATUS_SUCCESS)
os_snprintf(reject_str, sizeof(reject_str), "%u",
ss->extra.to_initial.reject_code);
- /* no break */
+ /* fall through */
case REASON_TEARDOWN:
case REASON_SWITCH:
switch (ss->extra.to_initial.initiator) {
@@ -648,9 +648,9 @@ static int list_groups(const char *cmd, char *buf, size_t buflen)
static const char * band_freq(enum mb_band_id band)
{
static const char *band_names[] = {
- [MB_BAND_ID_WIFI_2_4GHZ] "2.4GHZ",
- [MB_BAND_ID_WIFI_5GHZ] "5GHZ",
- [MB_BAND_ID_WIFI_60GHZ] "60GHZ",
+ [MB_BAND_ID_WIFI_2_4GHZ] = "2.4GHZ",
+ [MB_BAND_ID_WIFI_5GHZ] = "5GHZ",
+ [MB_BAND_ID_WIFI_60GHZ] = "60GHZ",
};
return fst_get_str_name(band, band_names, ARRAY_SIZE(band_names));
@@ -749,7 +749,7 @@ int fst_ctrl_iface_mb_info(const u8 *addr, char *buf, size_t buflen)
foreach_fst_group(g) {
foreach_fst_group_iface(g, f) {
- if (fst_iface_is_connected(f, addr)) {
+ if (fst_iface_is_connected(f, addr, TRUE)) {
ret += print_band(num++, f, addr,
buf + ret, buflen - ret);
}
diff --git a/contrib/wpa/src/fst/fst_defs.h b/contrib/wpa/src/fst/fst_defs.h
index 8ddcc61..5859f6f 100644
--- a/contrib/wpa/src/fst/fst_defs.h
+++ b/contrib/wpa/src/fst/fst_defs.h
@@ -34,7 +34,7 @@ enum session_type {
struct session_transition_ie {
u8 element_id;
u8 length;
- u32 fsts_id;
+ le32 fsts_id;
u8 session_control;
u8 new_band_id;
u8 new_band_setup;
@@ -47,7 +47,7 @@ struct session_transition_ie {
struct fst_setup_req {
u8 action;
u8 dialog_token;
- u32 llt;
+ le32 llt;
struct session_transition_ie stie;
/* Multi-band (optional) */
/* Wakeup Schedule (optional) */
@@ -70,18 +70,18 @@ struct fst_setup_res {
struct fst_ack_req {
u8 action;
u8 dialog_token;
- u32 fsts_id;
+ le32 fsts_id;
} STRUCT_PACKED;
struct fst_ack_res {
u8 action;
u8 dialog_token;
- u32 fsts_id;
+ le32 fsts_id;
} STRUCT_PACKED;
struct fst_tear_down {
u8 action;
- u32 fsts_id;
+ le32 fsts_id;
} STRUCT_PACKED;
#endif /* IEEE_80211_FST_DEFS_H */
diff --git a/contrib/wpa/src/fst/fst_group.c b/contrib/wpa/src/fst/fst_group.c
index f6c7be9..a4ae016 100644
--- a/contrib/wpa/src/fst/fst_group.c
+++ b/contrib/wpa/src/fst/fst_group.c
@@ -18,22 +18,6 @@
struct dl_list fst_global_groups_list;
-#ifndef HOSTAPD
-static Boolean fst_has_fst_peer(struct fst_iface *iface, Boolean *has_peer)
-{
- const u8 *bssid;
-
- bssid = fst_iface_get_bssid(iface);
- if (!bssid) {
- *has_peer = FALSE;
- return FALSE;
- }
-
- *has_peer = TRUE;
- return fst_iface_get_peer_mb_ie(iface, bssid) != NULL;
-}
-#endif /* HOSTAPD */
-
static void fst_dump_mb_ies(const char *group_id, const char *ifname,
struct wpabuf *mbies)
@@ -45,7 +29,7 @@ static void fst_dump_mb_ies(const char *group_id, const char *ifname,
const struct multi_band_ie *mbie =
(const struct multi_band_ie *) p;
WPA_ASSERT(mbie->eid == WLAN_EID_MULTI_BAND);
- WPA_ASSERT(2 + mbie->len >= sizeof(*mbie));
+ WPA_ASSERT(2U + mbie->len >= sizeof(*mbie));
fst_printf(MSG_WARNING,
"%s: %s: mb_ctrl=%u band_id=%u op_class=%u chan=%u bssid="
@@ -147,16 +131,6 @@ static struct wpabuf * fst_group_create_mb_ie(struct fst_group *g,
struct fst_iface *f;
unsigned int nof_mbies = 0;
unsigned int nof_ifaces_added = 0;
-#ifndef HOSTAPD
- Boolean has_peer;
- Boolean has_fst_peer;
-
- foreach_fst_group_iface(g, f) {
- has_fst_peer = fst_has_fst_peer(f, &has_peer);
- if (has_peer && !has_fst_peer)
- return NULL;
- }
-#endif /* HOSTAPD */
foreach_fst_group_iface(g, f) {
if (f == i)
@@ -222,43 +196,35 @@ static const u8 * fst_mbie_get_peer_addr(const struct multi_band_ie *mbie)
}
-static struct fst_iface *
-fst_group_get_new_iface_by_mbie_and_band_id(struct fst_group *g,
- const u8 *mb_ies_buff,
- size_t mb_ies_size,
- u8 band_id,
- u8 *iface_peer_addr)
+static const u8 * fst_mbie_get_peer_addr_for_band(const struct wpabuf *mbies,
+ u8 band_id)
{
- while (mb_ies_size >= 2) {
- const struct multi_band_ie *mbie =
- (const struct multi_band_ie *) mb_ies_buff;
-
- if (mbie->eid != WLAN_EID_MULTI_BAND ||
- (size_t) 2 + mbie->len < sizeof(*mbie))
- break;
+ const u8 *p = wpabuf_head(mbies);
+ size_t s = wpabuf_len(mbies);
- if (mbie->band_id == band_id) {
- struct fst_iface *iface;
+ while (s >= 2) {
+ const struct multi_band_ie *mbie =
+ (const struct multi_band_ie *) p;
- foreach_fst_group_iface(g, iface) {
- const u8 *peer_addr =
- fst_mbie_get_peer_addr(mbie);
+ if (mbie->eid != WLAN_EID_MULTI_BAND) {
+ fst_printf(MSG_INFO, "unexpected eid %d", mbie->eid);
+ return NULL;
+ }
- if (peer_addr &&
- fst_iface_is_connected(iface, peer_addr) &&
- band_id == fst_iface_get_band_id(iface)) {
- os_memcpy(iface_peer_addr, peer_addr,
- ETH_ALEN);
- return iface;
- }
- }
- break;
+ if (mbie->len < sizeof(*mbie) - 2 || mbie->len > s - 2) {
+ fst_printf(MSG_INFO, "invalid mbie len %d",
+ mbie->len);
+ return NULL;
}
- mb_ies_buff += 2 + mbie->len;
- mb_ies_size -= 2 + mbie->len;
+ if (mbie->band_id == band_id)
+ return fst_mbie_get_peer_addr(mbie);
+
+ p += 2 + mbie->len;
+ s -= 2 + mbie->len;
}
+ fst_printf(MSG_INFO, "mbie doesn't contain band %d", band_id);
return NULL;
}
@@ -295,78 +261,172 @@ u32 fst_group_assign_fsts_id(struct fst_group *g)
}
-static Boolean
-fst_group_does_iface_appear_in_other_mbies(struct fst_group *g,
- struct fst_iface *iface,
- struct fst_iface *other,
- u8 *peer_addr)
+/**
+ * fst_group_get_peer_other_connection_1 - Find peer's "other" connection
+ * (iface, MAC tuple) by using peer's MB IE on iface.
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ * "other" iface)
+ *
+ * This function parses peer's MB IE on iface. It looks for peer's MAC address
+ * on band_id (tmp_peer_addr). Next all interfaces are iterated to find an
+ * interface which correlates with band_id. If such interface is found, peer
+ * database is iterated to see if tmp_peer_addr is connected over it.
+ */
+static struct fst_iface *
+fst_group_get_peer_other_connection_1(struct fst_iface *iface,
+ const u8 *peer_addr, u8 band_id,
+ u8 *other_peer_addr)
{
- struct fst_get_peer_ctx *ctx;
- const u8 *addr;
- const u8 *iface_addr;
- enum mb_band_id iface_band_id;
+ const struct wpabuf *mbies;
+ struct fst_iface *other_iface;
+ const u8 *tmp_peer_addr;
- WPA_ASSERT(g == fst_iface_get_group(iface));
- WPA_ASSERT(g == fst_iface_get_group(other));
+ /* Get peer's MB IEs on iface */
+ mbies = fst_iface_get_peer_mb_ie(iface, peer_addr);
+ if (!mbies)
+ return NULL;
- iface_addr = fst_iface_get_addr(iface);
- iface_band_id = fst_iface_get_band_id(iface);
+ /* Get peer's MAC address on the "other" interface */
+ tmp_peer_addr = fst_mbie_get_peer_addr_for_band(mbies, band_id);
+ if (!tmp_peer_addr) {
+ fst_printf(MSG_INFO,
+ "couldn't extract other peer addr from mbies");
+ return NULL;
+ }
- addr = fst_iface_get_peer_first(other, &ctx, TRUE);
- for (; addr; addr = fst_iface_get_peer_next(other, &ctx, TRUE)) {
- const struct wpabuf *mbies;
- u8 other_iface_peer_addr[ETH_ALEN];
- struct fst_iface *other_new_iface;
+ fst_printf(MSG_DEBUG, "found other peer addr from mbies: " MACSTR,
+ MAC2STR(tmp_peer_addr));
- mbies = fst_iface_get_peer_mb_ie(other, addr);
- if (!mbies)
+ foreach_fst_group_iface(fst_iface_get_group(iface), other_iface) {
+ if (other_iface == iface ||
+ band_id != fst_iface_get_band_id(other_iface))
continue;
-
- other_new_iface = fst_group_get_new_iface_by_mbie_and_band_id(
- g, wpabuf_head(mbies), wpabuf_len(mbies),
- iface_band_id, other_iface_peer_addr);
- if (other_new_iface == iface &&
- os_memcmp(iface_addr, other_iface_peer_addr,
- ETH_ALEN) != 0) {
- os_memcpy(peer_addr, addr, ETH_ALEN);
- return TRUE;
+ if (fst_iface_is_connected(other_iface, tmp_peer_addr, FALSE)) {
+ os_memcpy(other_peer_addr, tmp_peer_addr, ETH_ALEN);
+ return other_iface;
}
}
- return FALSE;
+ return NULL;
}
-struct fst_iface *
-fst_group_find_new_iface_by_stie(struct fst_group *g,
- struct fst_iface *iface,
- const u8 *peer_addr,
- const struct session_transition_ie *stie,
- u8 *iface_peer_addr)
+/**
+ * fst_group_get_peer_other_connection_2 - Find peer's "other" connection
+ * (iface, MAC tuple) by using MB IEs of other peers.
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ * "other" iface)
+ *
+ * This function iterates all connection (other_iface, cur_peer_addr tuples).
+ * For each connection, MB IE (of cur_peer_addr on other_iface) is parsed and
+ * MAC address on iface's band_id is extracted (this_peer_addr).
+ * this_peer_addr is then compared to peer_addr. A match indicates we have
+ * found the "other" connection.
+ */
+static struct fst_iface *
+fst_group_get_peer_other_connection_2(struct fst_iface *iface,
+ const u8 *peer_addr, u8 band_id,
+ u8 *other_peer_addr)
{
- struct fst_iface *i;
+ u8 this_band_id = fst_iface_get_band_id(iface);
+ const u8 *cur_peer_addr, *this_peer_addr;
+ struct fst_get_peer_ctx *ctx;
+ struct fst_iface *other_iface;
+ const struct wpabuf *cur_mbie;
- foreach_fst_group_iface(g, i) {
- if (i == iface ||
- stie->new_band_id != fst_iface_get_band_id(i))
+ foreach_fst_group_iface(fst_iface_get_group(iface), other_iface) {
+ if (other_iface == iface ||
+ band_id != fst_iface_get_band_id(other_iface))
continue;
- if (fst_group_does_iface_appear_in_other_mbies(g, iface, i,
- iface_peer_addr))
- return i;
- break;
+ cur_peer_addr = fst_iface_get_peer_first(other_iface, &ctx,
+ TRUE);
+ for (; cur_peer_addr;
+ cur_peer_addr = fst_iface_get_peer_next(other_iface, &ctx,
+ TRUE)) {
+ cur_mbie = fst_iface_get_peer_mb_ie(other_iface,
+ cur_peer_addr);
+ if (!cur_mbie)
+ continue;
+ this_peer_addr = fst_mbie_get_peer_addr_for_band(
+ cur_mbie, this_band_id);
+ if (!this_peer_addr)
+ continue;
+ if (os_memcmp(this_peer_addr, peer_addr, ETH_ALEN) ==
+ 0) {
+ os_memcpy(other_peer_addr, cur_peer_addr,
+ ETH_ALEN);
+ return other_iface;
+ }
+ }
}
+
return NULL;
}
+/**
+ * fst_group_get_peer_other_connection - Find peer's "other" connection (iface,
+ * MAC tuple).
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ * "other" iface)
+ *
+ * This function is called upon receiving FST Setup Request from some peer who
+ * has peer_addr on iface. It searches for another connection of the same peer
+ * on different interface which correlates with band_id. MB IEs received from
+ * peer (on the two different interfaces) are used to identify same peer.
+ */
struct fst_iface *
-fst_group_get_new_iface_by_stie_and_mbie(
- struct fst_group *g, const u8 *mb_ies_buff, size_t mb_ies_size,
- const struct session_transition_ie *stie, u8 *iface_peer_addr)
+fst_group_get_peer_other_connection(struct fst_iface *iface,
+ const u8 *peer_addr, u8 band_id,
+ u8 *other_peer_addr)
{
- return fst_group_get_new_iface_by_mbie_and_band_id(
- g, mb_ies_buff, mb_ies_size, stie->new_band_id,
- iface_peer_addr);
+ struct fst_iface *other_iface;
+
+ fst_printf(MSG_DEBUG, "%s: %s:" MACSTR ", %d", __func__,
+ fst_iface_get_name(iface), MAC2STR(peer_addr), band_id);
+
+ /*
+ * Two search methods are used:
+ * 1. Use peer's MB IE on iface to extract peer's MAC address on
+ * "other" connection. Then check if such "other" connection exists.
+ * 2. Iterate peer database, examine each MB IE to see if it points to
+ * (iface, peer_addr) tuple
+ */
+
+ other_iface = fst_group_get_peer_other_connection_1(iface, peer_addr,
+ band_id,
+ other_peer_addr);
+ if (other_iface) {
+ fst_printf(MSG_DEBUG, "found by method #1. %s:" MACSTR,
+ fst_iface_get_name(other_iface),
+ MAC2STR(other_peer_addr));
+ return other_iface;
+ }
+
+ other_iface = fst_group_get_peer_other_connection_2(iface, peer_addr,
+ band_id,
+ other_peer_addr);
+ if (other_iface) {
+ fst_printf(MSG_DEBUG, "found by method #2. %s:" MACSTR,
+ fst_iface_get_name(other_iface),
+ MAC2STR(other_peer_addr));
+ return other_iface;
+ }
+
+ fst_printf(MSG_INFO, "%s: other connection not found", __func__);
+ return NULL;
}
diff --git a/contrib/wpa/src/fst/fst_group.h b/contrib/wpa/src/fst/fst_group.h
index 3a87c0b..00aee9c 100644
--- a/contrib/wpa/src/fst/fst_group.h
+++ b/contrib/wpa/src/fst/fst_group.h
@@ -48,15 +48,9 @@ Boolean fst_group_delete_if_empty(struct fst_group *group);
struct fst_iface * fst_group_get_iface_by_name(struct fst_group *g,
const char *ifname);
struct fst_iface *
-fst_group_find_new_iface_by_stie(struct fst_group *g,
- struct fst_iface *iface,
- const u8 *peer_addr,
- const struct session_transition_ie *stie,
- u8 *iface_peer_addr);
-struct fst_iface *
-fst_group_get_new_iface_by_stie_and_mbie(
- struct fst_group *g, const u8 *mb_ies_buff, size_t mb_ies_size,
- const struct session_transition_ie *stie, u8 *iface_peer_addr);
+fst_group_get_peer_other_connection(struct fst_iface *iface,
+ const u8 *peer_addr, u8 band_id,
+ u8 *other_peer_addr);
u8 fst_group_assign_dialog_token(struct fst_group *g);
u32 fst_group_assign_fsts_id(struct fst_group *g);
diff --git a/contrib/wpa/src/fst/fst_iface.c b/contrib/wpa/src/fst/fst_iface.c
index 5a92d2c..35e83cb 100644
--- a/contrib/wpa/src/fst/fst_iface.c
+++ b/contrib/wpa/src/fst/fst_iface.c
@@ -49,12 +49,13 @@ void fst_iface_delete(struct fst_iface *i)
}
-Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr)
+Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
+ Boolean mb_only)
{
struct fst_get_peer_ctx *ctx;
- const u8 *a = fst_iface_get_peer_first(iface, &ctx, TRUE);
+ const u8 *a = fst_iface_get_peer_first(iface, &ctx, mb_only);
- for (; a != NULL; a = fst_iface_get_peer_next(iface, &ctx, TRUE))
+ for (; a != NULL; a = fst_iface_get_peer_next(iface, &ctx, mb_only))
if (os_memcmp(addr, a, ETH_ALEN) == 0)
return TRUE;
diff --git a/contrib/wpa/src/fst/fst_iface.h b/contrib/wpa/src/fst/fst_iface.h
index 4670d89..cbaa7d8 100644
--- a/contrib/wpa/src/fst/fst_iface.h
+++ b/contrib/wpa/src/fst/fst_iface.h
@@ -106,7 +106,7 @@ static inline void fst_iface_update_mb_ie(struct fst_iface *i,
const u8 *addr,
const u8 *buf, size_t size)
{
- return i->iface_obj.update_mb_ie(i->iface_obj.ctx, addr, buf, size);
+ i->iface_obj.update_mb_ie(i->iface_obj.ctx, addr, buf, size);
}
static inline const u8 * fst_iface_get_peer_first(struct fst_iface *i,
@@ -123,7 +123,8 @@ static inline const u8 * fst_iface_get_peer_next(struct fst_iface *i,
return i->iface_obj.get_peer_next(i->iface_obj.ctx, ctx, mb_only);
}
-Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr);
+Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
+ Boolean mb_only);
void fst_iface_attach_mbie(struct fst_iface *i, struct wpabuf *mbie);
enum mb_band_id fst_iface_get_band_id(struct fst_iface *i);
diff --git a/contrib/wpa/src/fst/fst_session.c b/contrib/wpa/src/fst/fst_session.c
index 55fa694..a02a93e 100644
--- a/contrib/wpa/src/fst/fst_session.c
+++ b/contrib/wpa/src/fst/fst_session.c
@@ -44,7 +44,7 @@
#define FST_LLT_MS_DEFAULT 50
#define FST_ACTION_MAX_SUPPORTED FST_ACTION_ON_CHANNEL_TUNNEL
-const char * const fst_action_names[] = {
+static const char * const fst_action_names[] = {
[FST_ACTION_SETUP_REQUEST] = "Setup Request",
[FST_ACTION_SETUP_RESPONSE] = "Setup Response",
[FST_ACTION_TEAR_DOWN] = "Tear Down",
@@ -181,7 +181,8 @@ static void fst_session_timeout_handler(void *eloop_data, void *user_ctx)
static void fst_session_stt_arm(struct fst_session *s)
{
- eloop_register_timeout(0, TU_TO_US(FST_DEFAULT_SESSION_TIMEOUT_TU),
+ /* Action frames sometimes get delayed. Use relaxed timeout (2*) */
+ eloop_register_timeout(0, 2 * TU_TO_US(FST_DEFAULT_SESSION_TIMEOUT_TU),
fst_session_timeout_handler, NULL, s);
s->stt_armed = TRUE;
}
@@ -363,7 +364,6 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
struct fst_iface *new_iface = NULL;
struct fst_group *g;
u8 new_iface_peer_addr[ETH_ALEN];
- const struct wpabuf *peer_mbies;
size_t plen;
if (frame_len < IEEE80211_HDRLEN + 1 + sizeof(*req)) {
@@ -399,36 +399,18 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
MAC2STR(mgmt->sa));
}
- peer_mbies = fst_iface_get_peer_mb_ie(iface, mgmt->sa);
- if (peer_mbies) {
- new_iface = fst_group_get_new_iface_by_stie_and_mbie(
- g, wpabuf_head(peer_mbies), wpabuf_len(peer_mbies),
- &req->stie, new_iface_peer_addr);
- if (new_iface)
- fst_printf_iface(iface, MSG_INFO,
- "FST Request: new iface (%s:" MACSTR
- ") found by MB IEs",
- fst_iface_get_name(new_iface),
- MAC2STR(new_iface_peer_addr));
- }
-
- if (!new_iface) {
- new_iface = fst_group_find_new_iface_by_stie(
- g, iface, mgmt->sa, &req->stie,
- new_iface_peer_addr);
- if (new_iface)
- fst_printf_iface(iface, MSG_INFO,
- "FST Request: new iface (%s:" MACSTR
- ") found by others",
- fst_iface_get_name(new_iface),
- MAC2STR(new_iface_peer_addr));
- }
-
+ new_iface = fst_group_get_peer_other_connection(iface, mgmt->sa,
+ req->stie.new_band_id,
+ new_iface_peer_addr);
if (!new_iface) {
fst_printf_iface(iface, MSG_WARNING,
"FST Request dropped: new iface not found");
return;
}
+ fst_printf_iface(iface, MSG_INFO,
+ "FST Request: new iface (%s:" MACSTR ") found",
+ fst_iface_get_name(new_iface),
+ MAC2STR(new_iface_peer_addr));
s = fst_find_session_in_progress(mgmt->sa, g);
if (s) {
@@ -447,7 +429,9 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
* the initiator’s MAC address, in which case, the responder
* shall delete the received FST Setup Request.
*/
- if (os_memcmp(mgmt->da, mgmt->sa, ETH_ALEN) > 0) {
+ if (fst_session_is_ready_pending(s) &&
+ /* waiting for Setup Response */
+ os_memcmp(mgmt->da, mgmt->sa, ETH_ALEN) > 0) {
fst_printf_session(s, MSG_WARNING,
"FST Request dropped due to MAC comparison (our MAC is "
MACSTR ")",
@@ -455,23 +439,26 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
return;
}
- if (!fst_session_is_ready_pending(s)) {
- fst_printf_session(s, MSG_WARNING,
- "FST Request from " MACSTR
- " dropped due to inappropriate state %s",
- MAC2STR(mgmt->da),
- fst_session_state_name(s->state));
- return;
- }
+ /*
+ * State is SETUP_COMPLETION (either in transition or not) or
+ * TRANSITION_DONE (in transition).
+ * Setup Request arriving in this state could mean:
+ * 1. peer sent it before receiving our Setup Request (race
+ * condition)
+ * 2. peer didn't receive our Setup Response. Peer is retrying
+ * after STT timeout
+ * 3. peer's FST state machines are out of sync due to some
+ * other reason
+ *
+ * We will reset our session and create a new one instead.
+ */
+ fst_printf_session(s, MSG_WARNING,
+ "resetting due to FST request");
/*
* If FST Setup Request arrived with the same FSTS ID as one we
- * initialized before, it means the other side either didn't
- * receive our FST Request or skipped it for some reason (for
- * example, due to numerical MAC comparison).
- *
- * In this case, there's no need to tear down the session.
+ * initialized before, there's no need to tear down the session.
* Moreover, as FSTS ID is the same, the other side will
* associate this tear down with the session it initiated that
* will break the sync.
@@ -483,7 +470,6 @@ static void fst_session_handle_setup_request(struct fst_iface *iface,
"Skipping TearDown as the FST request has the same FSTS ID as initiated");
fst_session_set_state(s, FST_SESSION_STATE_INITIAL, &evext);
fst_session_stt_disarm(s);
- fst_printf_session(s, MSG_WARNING, "reset due to FST request");
}
s = fst_session_create(g);
@@ -521,7 +507,9 @@ static void fst_session_handle_setup_response(struct fst_session *s,
enum hostapd_hw_mode hw_mode;
u8 channel;
union fst_session_state_switch_extra evext = {
- .to_initial = {0},
+ .to_initial = {
+ .reject_code = 0,
+ },
};
if (iface != s->data.old_iface) {
@@ -768,8 +756,6 @@ struct fst_session * fst_session_create(struct fst_group *g)
struct fst_session *s;
u32 id;
- WPA_ASSERT(!is_zero_ether_addr(own_addr));
-
id = fst_find_free_session_id();
if (id == FST_INVALID_SESSION_ID) {
fst_printf(MSG_ERROR, "Cannot assign new session ID");
@@ -863,13 +849,15 @@ int fst_session_initiate_setup(struct fst_session *s)
return -EINVAL;
}
- if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr)) {
+ if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr,
+ FALSE)) {
fst_printf_session(s, MSG_ERROR,
"The preset old peer address is not connected");
return -EINVAL;
}
- if (!fst_iface_is_connected(s->data.new_iface, s->data.new_peer_addr)) {
+ if (!fst_iface_is_connected(s->data.new_iface, s->data.new_peer_addr,
+ FALSE)) {
fst_printf_session(s, MSG_ERROR,
"The preset new peer address is not connected");
return -EINVAL;
@@ -966,7 +954,8 @@ int fst_session_respond(struct fst_session *s, u8 status_code)
return -EINVAL;
}
- if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr)) {
+ if (!fst_iface_is_connected(s->data.old_iface,
+ s->data.old_peer_addr, FALSE)) {
fst_printf_session(s, MSG_ERROR,
"The preset peer address is not in the peer list");
return -EINVAL;
@@ -984,7 +973,7 @@ int fst_session_respond(struct fst_session *s, u8 status_code)
res.stie.length = sizeof(res.stie) - 2;
if (status_code == WLAN_STATUS_SUCCESS) {
- res.stie.fsts_id = s->data.fsts_id;
+ res.stie.fsts_id = host_to_le32(s->data.fsts_id);
res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
fst_iface_get_channel_info(s->data.new_iface, &hw_mode,
@@ -1458,7 +1447,7 @@ int fst_test_req_send_fst_response(const char *params)
res.stie.length = sizeof(res.stie) - 2;
if (res.status_code == WLAN_STATUS_SUCCESS) {
- res.stie.fsts_id = fsts_id;
+ res.stie.fsts_id = host_to_le32(fsts_id);
res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
fst_iface_get_channel_info(s.data.new_iface, &hw_mode,
@@ -1507,7 +1496,7 @@ int fst_test_req_send_ack_request(const char *params)
os_memset(&req, 0, sizeof(req));
req.action = FST_ACTION_ACK_REQUEST;
req.dialog_token = g->dialog_token;
- req.fsts_id = fsts_id;
+ req.fsts_id = host_to_le32(fsts_id);
return fst_session_send_action(&s, FALSE, &req, sizeof(req), NULL);
}
@@ -1535,7 +1524,7 @@ int fst_test_req_send_ack_response(const char *params)
os_memset(&res, 0, sizeof(res));
res.action = FST_ACTION_ACK_RESPONSE;
res.dialog_token = g->dialog_token;
- res.fsts_id = fsts_id;
+ res.fsts_id = host_to_le32(fsts_id);
return fst_session_send_action(&s, FALSE, &res, sizeof(res), NULL);
}
@@ -1562,7 +1551,7 @@ int fst_test_req_send_tear_down(const char *params)
os_memset(&td, 0, sizeof(td));
td.action = FST_ACTION_TEAR_DOWN;
- td.fsts_id = fsts_id;
+ td.fsts_id = host_to_le32(fsts_id);
return fst_session_send_action(&s, TRUE, &td, sizeof(td), NULL);
}
diff --git a/contrib/wpa/src/l2_packet/l2_packet.h b/contrib/wpa/src/l2_packet/l2_packet.h
index 2a45245..5387177 100644
--- a/contrib/wpa/src/l2_packet/l2_packet.h
+++ b/contrib/wpa/src/l2_packet/l2_packet.h
@@ -42,6 +42,7 @@ struct l2_ethhdr {
enum l2_packet_filter_type {
L2_PACKET_FILTER_DHCP,
L2_PACKET_FILTER_NDISC,
+ L2_PACKET_FILTER_PKTTYPE,
};
/**
diff --git a/contrib/wpa/src/l2_packet/l2_packet_privsep.c b/contrib/wpa/src/l2_packet/l2_packet_privsep.c
index e26ca20..ce86802 100644
--- a/contrib/wpa/src/l2_packet/l2_packet_privsep.c
+++ b/contrib/wpa/src/l2_packet/l2_packet_privsep.c
@@ -51,7 +51,7 @@ static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
return 0;
}
-
+
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
{
os_memcpy(addr, l2->own_addr, ETH_ALEN);
@@ -258,7 +258,7 @@ void l2_packet_deinit(struct l2_packet_data *l2)
unlink(l2->own_socket_path);
os_free(l2->own_socket_path);
}
-
+
os_free(l2);
}
diff --git a/contrib/wpa/src/p2p/p2p.c b/contrib/wpa/src/p2p/p2p.c
index 767706c..157bf89 100644
--- a/contrib/wpa/src/p2p/p2p.c
+++ b/contrib/wpa/src/p2p/p2p.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "eloop.h"
+#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
@@ -445,8 +446,9 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
static void p2p_copy_client_info(struct p2p_device *dev,
struct p2p_client_info *cli)
{
- os_memcpy(dev->info.device_name, cli->dev_name, cli->dev_name_len);
- dev->info.device_name[cli->dev_name_len] = '\0';
+ p2p_copy_filter_devname(dev->info.device_name,
+ sizeof(dev->info.device_name),
+ cli->dev_name, cli->dev_name_len);
dev->info.dev_capab = cli->dev_capab;
dev->info.config_methods = cli->config_methods;
os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8);
@@ -636,11 +638,11 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
end = ies + ies_len;
- for (pos = ies; pos + 1 < end; pos += len) {
+ for (pos = ies; end - pos > 1; pos += len) {
id = *pos++;
len = *pos++;
- if (pos + len > end)
+ if (len > end - pos)
break;
if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)
@@ -709,6 +711,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
struct p2p_message msg;
const u8 *p2p_dev_addr;
int wfd_changed;
+ int dev_name_changed;
int i;
struct os_reltime time_now;
@@ -786,11 +789,11 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
dev->oper_ssid_len = msg.ssid[1];
}
- if (msg.adv_service_instance && msg.adv_service_instance_len) {
- wpabuf_free(dev->info.p2ps_instance);
+ wpabuf_free(dev->info.p2ps_instance);
+ dev->info.p2ps_instance = NULL;
+ if (msg.adv_service_instance && msg.adv_service_instance_len)
dev->info.p2ps_instance = wpabuf_alloc_copy(
msg.adv_service_instance, msg.adv_service_instance_len);
- }
if (freq >= 2412 && freq <= 2484 && msg.ds_params &&
*msg.ds_params >= 1 && *msg.ds_params <= 14) {
@@ -819,6 +822,9 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
}
dev->info.level = level;
+ dev_name_changed = os_strncmp(dev->info.device_name, msg.device_name,
+ WPS_DEV_NAME_MAX_LEN) != 0;
+
p2p_copy_wps_info(p2p, dev, 0, &msg);
for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
@@ -837,9 +843,12 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
wfd_changed = p2p_compare_wfd_info(dev, &msg);
- if (msg.wfd_subelems) {
+ if (wfd_changed) {
wpabuf_free(dev->info.wfd_subelems);
- dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ if (msg.wfd_subelems)
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ else
+ dev->info.wfd_subelems = NULL;
}
if (scan_res) {
@@ -853,6 +862,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
p2p_update_peer_vendor_elems(dev, ies, ies_len);
if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
+ !dev_name_changed &&
(!msg.adv_service_instance ||
(dev->flags & P2P_DEV_P2PS_REPORTED)))
return 0;
@@ -1000,8 +1010,16 @@ static void p2p_search(struct p2p_data *p2p)
}
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
- if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
- (freq = p2p_get_next_prog_freq(p2p)) > 0) {
+ if (p2p->find_pending_full &&
+ (p2p->find_type == P2P_FIND_PROGRESSIVE ||
+ p2p->find_type == P2P_FIND_START_WITH_FULL)) {
+ type = P2P_SCAN_FULL;
+ p2p_dbg(p2p, "Starting search (pending full scan)");
+ p2p->find_pending_full = 0;
+ } else if ((p2p->find_type == P2P_FIND_PROGRESSIVE &&
+ (freq = p2p_get_next_prog_freq(p2p)) > 0) ||
+ (p2p->find_type == P2P_FIND_START_WITH_FULL &&
+ (freq = p2p->find_specified_freq) > 0)) {
type = P2P_SCAN_SOCIAL_PLUS_ONE;
p2p_dbg(p2p, "Starting search (+ freq %u)", freq);
} else {
@@ -1058,7 +1076,7 @@ static int p2p_run_after_scan(struct p2p_data *p2p)
p2p->after_scan_tx->bssid,
(u8 *) (p2p->after_scan_tx + 1),
p2p->after_scan_tx->len,
- p2p->after_scan_tx->wait_time);
+ p2p->after_scan_tx->wait_time, NULL);
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
return 1;
@@ -1154,21 +1172,20 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
u8 seek_count, const char **seek, int freq)
{
int res;
+ struct os_reltime start;
p2p_dbg(p2p, "Starting find (type=%d)", type);
- os_get_reltime(&p2p->find_start);
if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan is already running");
}
p2p_free_req_dev_types(p2p);
if (req_dev_types && num_req_dev_types) {
- p2p->req_dev_types = os_malloc(num_req_dev_types *
+ p2p->req_dev_types = os_memdup(req_dev_types,
+ num_req_dev_types *
WPS_DEV_TYPE_LEN);
if (p2p->req_dev_types == NULL)
return -1;
- os_memcpy(p2p->req_dev_types, req_dev_types,
- num_req_dev_types * WPS_DEV_TYPE_LEN);
p2p->num_req_dev_types = num_req_dev_types;
}
@@ -1220,9 +1237,19 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
p2p_clear_timeout(p2p);
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_find");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ p2p->find_pending_full = 0;
p2p->find_type = type;
+ if (freq != 2412 && freq != 2437 && freq != 2462 && freq != 60480)
+ p2p->find_specified_freq = freq;
+ else
+ p2p->find_specified_freq = 0;
p2p_device_clear_reported(p2p);
+ os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
p2p_set_state(p2p, P2P_SEARCH);
p2p->search_delay = search_delay;
p2p->in_search_delay = 0;
@@ -1231,12 +1258,13 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
if (timeout)
eloop_register_timeout(timeout, 0, p2p_find_timeout,
p2p, NULL);
+ os_get_reltime(&start);
switch (type) {
case P2P_FIND_START_WITH_FULL:
if (freq > 0) {
/*
* Start with the specified channel and then move to
- * social channels only scans.
+ * scans for social channels and this specific channel.
*/
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,
P2P_SCAN_SPECIFIC, freq,
@@ -1262,9 +1290,15 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
return -1;
}
+ if (!res)
+ p2p->find_start = start;
+
if (res != 0 && p2p->p2p_scan_running) {
p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
/* wait for the previous p2p_scan to complete */
+ if (type == P2P_FIND_PROGRESSIVE ||
+ (type == P2P_FIND_START_WITH_FULL && freq == 0))
+ p2p->find_pending_full = 1;
res = 0; /* do not report failure */
} else if (res != 0) {
p2p_dbg(p2p, "Failed to start p2p_scan");
@@ -1440,7 +1474,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
p2p->op_channel = p2p->cfg->op_channel;
} else if (p2p_channel_random_social(&p2p->cfg->channels,
&p2p->op_reg_class,
- &p2p->op_channel) == 0) {
+ &p2p->op_channel,
+ NULL, NULL) == 0) {
p2p_dbg(p2p, "Select random available social channel (op_class %u channel %u) as operating channel preference",
p2p->op_reg_class, p2p->op_channel);
} else {
@@ -1459,7 +1494,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
/**
- * p2p_prepare_channel - Select operating channel for GO Negotiation
+ * p2p_prepare_channel - Select operating channel for GO Negotiation or P2PS PD
* @p2p: P2P module context from p2p_init()
* @dev: Selected peer device
* @force_freq: Forced frequency in MHz or 0 if not forced
@@ -1468,9 +1503,9 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* Returns: 0 on success, -1 on failure (channel not supported for P2P)
*
* This function is used to do initial operating channel selection for GO
- * Negotiation prior to having received peer information. The selected channel
- * may be further optimized in p2p_reselect_channel() once the peer information
- * is available.
+ * Negotiation prior to having received peer information or for P2PS PD
+ * signalling. The selected channel may be further optimized in
+ * p2p_reselect_channel() once the peer information is available.
*/
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
unsigned int force_freq, unsigned int pref_freq, int go)
@@ -1826,6 +1861,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
p2p_clear_timeout(p2p);
p2p->ssid_set = 0;
peer->go_neg_req_sent = 0;
+ peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
peer->wps_method = WPS_NOT_READY;
peer->oob_pw_id = 0;
wpabuf_free(peer->go_neg_conf);
@@ -2028,8 +2064,23 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
dev = p2p_get_device(p2p, addr);
if (dev) {
- if (dev->country[0] == 0 && msg.listen_channel)
- os_memcpy(dev->country, msg.listen_channel, 3);
+ if (msg.listen_channel) {
+ int freq;
+
+ if (dev->country[0] == 0)
+ os_memcpy(dev->country, msg.listen_channel, 3);
+
+ freq = p2p_channel_to_freq(msg.listen_channel[3],
+ msg.listen_channel[4]);
+
+ if (freq > 0 && dev->listen_freq != freq) {
+ p2p_dbg(p2p,
+ "Updated peer " MACSTR " Listen channel (Probe Request): %d -> %d MHz",
+ MAC2STR(addr), dev->listen_freq, freq);
+ dev->listen_freq = freq;
+ }
+ }
+
os_get_reltime(&dev->last_seen);
p2p_parse_free(&msg);
return; /* already known */
@@ -2212,6 +2263,58 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
return buf;
}
+static int p2p_build_probe_resp_buf(struct p2p_data *p2p, struct wpabuf *buf,
+ struct wpabuf *ies,
+ const u8 *addr, int rx_freq)
+{
+ struct ieee80211_mgmt *resp;
+ u8 channel, op_class;
+
+ resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.probe_resp.variable));
+
+ resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_PROBE_RESP << 4));
+ os_memcpy(resp->da, addr, ETH_ALEN);
+ os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
+ resp->u.probe_resp.beacon_int = host_to_le16(100);
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ resp->u.probe_resp.capab_info =
+ host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
+ WLAN_CAPABILITY_PRIVACY |
+ WLAN_CAPABILITY_SHORT_SLOT_TIME);
+
+ wpabuf_put_u8(buf, WLAN_EID_SSID);
+ wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
+ wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+
+ wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
+ wpabuf_put_u8(buf, 8);
+ wpabuf_put_u8(buf, (60 / 5) | 0x80);
+ wpabuf_put_u8(buf, 90 / 5);
+ wpabuf_put_u8(buf, (120 / 5) | 0x80);
+ wpabuf_put_u8(buf, 180 / 5);
+ wpabuf_put_u8(buf, (240 / 5) | 0x80);
+ wpabuf_put_u8(buf, 360 / 5);
+ wpabuf_put_u8(buf, 480 / 5);
+ wpabuf_put_u8(buf, 540 / 5);
+
+ if (!rx_freq) {
+ channel = p2p->cfg->channel;
+ } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ p2p_err(p2p, "Failed to convert freq to channel");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, channel);
+
+ wpabuf_put_buf(buf, ies);
+
+ return 0;
+}
static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
{
@@ -2245,10 +2348,8 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
{
struct ieee802_11_elems elems;
struct wpabuf *buf;
- struct ieee80211_mgmt *resp;
struct p2p_message msg;
struct wpabuf *ies;
- u8 channel, op_class;
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
@@ -2360,7 +2461,7 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
if (msg.wps_attributes &&
!p2p_match_dev_type(p2p, msg.wps_attributes)) {
/* No match with Requested Device Type */
- p2p_dbg(p2p, "Probe Req requestred Device Type did not match - ignore it");
+ p2p_dbg(p2p, "Probe Req requested Device Type did not match - ignore it");
p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
@@ -2392,49 +2493,12 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
return P2P_PREQ_NOT_PROCESSED;
}
- resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
- u.probe_resp.variable));
-
- resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
- (WLAN_FC_STYPE_PROBE_RESP << 4));
- os_memcpy(resp->da, addr, ETH_ALEN);
- os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
- os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
- resp->u.probe_resp.beacon_int = host_to_le16(100);
- /* hardware or low-level driver will setup seq_ctrl and timestamp */
- resp->u.probe_resp.capab_info =
- host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
- WLAN_CAPABILITY_PRIVACY |
- WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- wpabuf_put_u8(buf, WLAN_EID_SSID);
- wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
- wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
-
- wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
- wpabuf_put_u8(buf, 8);
- wpabuf_put_u8(buf, (60 / 5) | 0x80);
- wpabuf_put_u8(buf, 90 / 5);
- wpabuf_put_u8(buf, (120 / 5) | 0x80);
- wpabuf_put_u8(buf, 180 / 5);
- wpabuf_put_u8(buf, (240 / 5) | 0x80);
- wpabuf_put_u8(buf, 360 / 5);
- wpabuf_put_u8(buf, 480 / 5);
- wpabuf_put_u8(buf, 540 / 5);
-
- if (!rx_freq) {
- channel = p2p->cfg->channel;
- } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ if (p2p_build_probe_resp_buf(p2p, buf, ies, addr, rx_freq)) {
wpabuf_free(ies);
wpabuf_free(buf);
return P2P_PREQ_NOT_PROCESSED;
}
- wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
- wpabuf_put_u8(buf, 1);
- wpabuf_put_u8(buf, channel);
-
- wpabuf_put_buf(buf, ies);
wpabuf_free(ies);
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
@@ -2448,12 +2512,18 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len,
- unsigned int rx_freq)
+ unsigned int rx_freq, int p2p_lo_started)
{
enum p2p_probe_req_status res;
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
+ if (p2p_lo_started) {
+ p2p_dbg(p2p,
+ "Probe Response is offloaded, do not reply Probe Request");
+ return P2P_PREQ_PROCESSED;
+ }
+
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
return res;
@@ -2781,6 +2851,7 @@ void p2p_service_flush_asp(struct p2p_data *p2p)
}
p2p->p2ps_adv_list = NULL;
+ p2ps_prov_free(p2p);
p2p_dbg(p2p, "All ASP advertisements flushed");
}
@@ -2942,9 +3013,9 @@ void p2p_deinit(struct p2p_data *p2p)
wpabuf_free(p2p->wfd_dev_info);
wpabuf_free(p2p->wfd_assoc_bssid);
wpabuf_free(p2p->wfd_coupled_sink_info);
+ wpabuf_free(p2p->wfd_r2_dev_info);
#endif /* CONFIG_WIFI_DISPLAY */
- eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
@@ -2959,7 +3030,6 @@ void p2p_deinit(struct p2p_data *p2p)
os_free(p2p->groups);
p2ps_prov_free(p2p);
wpabuf_free(p2p->sd_resp);
- os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
os_free(p2p->no_go_freq.range);
p2p_service_flush_asp(p2p);
@@ -2971,6 +3041,8 @@ void p2p_deinit(struct p2p_data *p2p)
void p2p_flush(struct p2p_data *p2p)
{
struct p2p_device *dev, *prev;
+
+ p2p_ext_listen(p2p, 0, 0);
p2p_stop_find(p2p);
dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
list) {
@@ -2981,6 +3053,10 @@ void p2p_flush(struct p2p_data *p2p)
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
p2p->ssid_set = 0;
+ p2ps_prov_free(p2p);
+ p2p_reset_pending_pd(p2p);
+ p2p->override_pref_op_class = 0;
+ p2p->override_pref_channel = 0;
}
@@ -3157,13 +3233,18 @@ int p2p_set_country(struct p2p_data *p2p, const char *country)
static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
{
+ int res;
+
if (dev->sd_pending_bcast_queries == 0) {
/* Initialize with total number of registered broadcast
* SD queries. */
dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
}
- if (p2p_start_sd(p2p, dev) == 0)
+ res = p2p_start_sd(p2p, dev);
+ if (res == -2)
+ return -2;
+ if (res == 0)
return 1;
if (dev->req_config_methods &&
@@ -3183,7 +3264,7 @@ static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
void p2p_continue_find(struct p2p_data *p2p)
{
struct p2p_device *dev;
- int found;
+ int found, res;
p2p_set_state(p2p, P2P_SEARCH);
@@ -3196,10 +3277,13 @@ void p2p_continue_find(struct p2p_data *p2p)
}
if (!found)
continue;
- if (p2p_pre_find_operation(p2p, dev) > 0) {
+ res = p2p_pre_find_operation(p2p, dev);
+ if (res > 0) {
p2p->last_p2p_find_oper = dev;
return;
}
+ if (res == -2)
+ goto skip_sd;
}
/*
@@ -3207,14 +3291,19 @@ void p2p_continue_find(struct p2p_data *p2p)
* iteration device.
*/
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (p2p_pre_find_operation(p2p, dev) > 0) {
+ res = p2p_pre_find_operation(p2p, dev);
+ if (res > 0) {
p2p->last_p2p_find_oper = dev;
return;
}
+ if (res == -2)
+ goto skip_sd;
if (dev == p2p->last_p2p_find_oper)
break;
}
+skip_sd:
+ os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
p2p_listen_in_find(p2p, 1);
}
@@ -3226,8 +3315,17 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success)
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (!success) {
- if (p2p->sd_peer)
+ if (p2p->sd_peer) {
+ if (is_zero_ether_addr(p2p->sd_query_no_ack)) {
+ os_memcpy(p2p->sd_query_no_ack,
+ p2p->sd_peer->info.p2p_device_addr,
+ ETH_ALEN);
+ p2p_dbg(p2p,
+ "First SD Query no-ACK in this search iteration: "
+ MACSTR, MAC2STR(p2p->sd_query_no_ack));
+ }
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ }
p2p->sd_peer = NULL;
if (p2p->state != P2P_IDLE)
p2p_continue_find(p2p);
@@ -3326,6 +3424,43 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
}
/*
+ * If after PD Request the peer doesn't expect to receive PD Response
+ * the PD Request ACK indicates a completion of the current PD. This
+ * happens only on the advertiser side sending the follow-on PD Request
+ * with the status different than 12 (Success: accepted by user).
+ */
+ if (p2p->p2ps_prov && !p2p->p2ps_prov->pd_seeker &&
+ p2p->p2ps_prov->status != P2P_SC_SUCCESS_DEFERRED) {
+ p2p_dbg(p2p, "P2PS PD completion on Follow-on PD Request ACK");
+
+ if (p2p->send_action_in_progress) {
+ p2p->send_action_in_progress = 0;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ }
+
+ p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+ if (p2p->cfg->p2ps_prov_complete) {
+ p2p->cfg->p2ps_prov_complete(
+ p2p->cfg->cb_ctx,
+ p2p->p2ps_prov->status,
+ p2p->p2ps_prov->adv_mac,
+ p2p->p2ps_prov->adv_mac,
+ p2p->p2ps_prov->session_mac,
+ NULL, p2p->p2ps_prov->adv_id,
+ p2p->p2ps_prov->session_id,
+ 0, 0, NULL, 0, 0, 0,
+ NULL, NULL, 0, 0, NULL, 0);
+ }
+
+ if (p2p->user_initiated_pd)
+ p2p_reset_pending_pd(p2p);
+
+ p2ps_prov_free(p2p);
+ return;
+ }
+
+ /*
* This postponing, of resetting pending_action_state, needs to be
* done only for user initiated PD requests and not internal ones.
*/
@@ -3399,9 +3534,11 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
* operation was started.
*/
p2p_dbg(p2p, "Ignore old scan result for " MACSTR
- " (rx_time=%u.%06u)",
+ " (rx_time=%u.%06u find_start=%u.%06u)",
MAC2STR(bssid), (unsigned int) rx_time->sec,
- (unsigned int) rx_time->usec);
+ (unsigned int) rx_time->usec,
+ (unsigned int) p2p->find_start.sec,
+ (unsigned int) p2p->find_start.usec);
return 0;
}
@@ -3426,7 +3563,8 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
}
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id,
+ unsigned int bands)
{
u8 dev_capab;
u8 *len;
@@ -3460,6 +3598,9 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period,
p2p->ext_listen_interval);
+ if (bands & BAND_60_GHZ)
+ p2p_buf_add_device_info(ies, p2p, NULL);
+
if (p2p->p2ps_seek && p2p->p2ps_seek_count)
p2p_buf_add_service_hash(ies, p2p);
@@ -3694,6 +3835,8 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
break;
case P2P_PENDING_INVITATION_RESPONSE:
p2p_invitation_resp_cb(p2p, success);
+ if (p2p->inv_status != P2P_SC_SUCCESS)
+ p2p_check_after_scan_tx_continuation(p2p);
break;
case P2P_PENDING_DEV_DISC_REQUEST:
p2p_dev_disc_req_cb(p2p, success);
@@ -3751,6 +3894,19 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
if (p2p->in_listen)
return 0; /* Internal timeout will trigger the next step */
+ if (p2p->state == P2P_WAIT_PEER_CONNECT && p2p->go_neg_peer &&
+ p2p->pending_listen_freq) {
+ /*
+ * Better wait a bit if the driver is unable to start
+ * offchannel operation for some reason to continue with
+ * P2P_WAIT_PEER_(IDLE/CONNECT) state transitions.
+ */
+ p2p_dbg(p2p,
+ "Listen operation did not seem to start - delay idle phase to avoid busy loop");
+ p2p_set_timeout(p2p, 0, 100000);
+ return 1;
+ }
+
if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
if (p2p->go_neg_peer->connect_reqs >= 120) {
p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
@@ -4613,9 +4769,12 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
- u8 *op_channel)
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list)
{
- return p2p_channel_random_social(&p2p->channels, op_class, op_channel);
+ return p2p_channel_random_social(&p2p->channels, op_class, op_channel,
+ avoid_list, disallow_list);
}
@@ -4695,11 +4854,10 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
struct p2p_channel *n;
if (pref_chan) {
- n = os_malloc(num_pref_chan * sizeof(struct p2p_channel));
+ n = os_memdup(pref_chan,
+ num_pref_chan * sizeof(struct p2p_channel));
if (n == NULL)
return -1;
- os_memcpy(n, pref_chan,
- num_pref_chan * sizeof(struct p2p_channel));
} else
n = NULL;
@@ -4815,6 +4973,8 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time)
{
+ int res, scheduled;
+
if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes");
if (p2p->after_scan_tx) {
@@ -4835,8 +4995,16 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
return 0;
}
- return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
- buf, len, wait_time);
+ res = p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
+ buf, len, wait_time, &scheduled);
+ if (res == 0 && scheduled && p2p->in_listen && freq > 0 &&
+ (unsigned int) p2p->drv_in_listen != freq) {
+ p2p_dbg(p2p,
+ "Stop listen on %d MHz to allow a frame to be sent immediately on %d MHz",
+ p2p->drv_in_listen, freq);
+ p2p_stop_listen_for_freq(p2p, freq);
+ }
+ return res;
}
@@ -5021,6 +5189,20 @@ int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
}
+int p2p_set_wfd_r2_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
+{
+ wpabuf_free(p2p->wfd_r2_dev_info);
+ if (elem) {
+ p2p->wfd_r2_dev_info = wpabuf_dup(elem);
+ if (p2p->wfd_r2_dev_info == NULL)
+ return -1;
+ } else
+ p2p->wfd_r2_dev_info = NULL;
+
+ return 0;
+}
+
+
int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem)
{
wpabuf_free(p2p->wfd_assoc_bssid);
@@ -5400,3 +5582,42 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
i, p2p->pref_freq_list[i]);
}
}
+
+
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+ u8 chan)
+{
+ p2p->override_pref_op_class = op_class;
+ p2p->override_pref_channel = chan;
+}
+
+
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+ unsigned int freq)
+{
+ struct wpabuf *ies, *buf;
+ u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ int ret;
+
+ ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
+ if (!ies) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: Failed to build Probe Response IEs");
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(200 + wpabuf_len(ies));
+ if (!buf) {
+ wpabuf_free(ies);
+ return NULL;
+ }
+
+ ret = p2p_build_probe_resp_buf(p2p, buf, ies, addr, freq);
+ wpabuf_free(ies);
+ if (ret) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/contrib/wpa/src/p2p/p2p.h b/contrib/wpa/src/p2p/p2p.h
index b4060be..425b037 100644
--- a/contrib/wpa/src/p2p/p2p.h
+++ b/contrib/wpa/src/p2p/p2p.h
@@ -31,7 +31,7 @@
/**
* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
*/
-#define P2P_MAX_REG_CLASSES 10
+#define P2P_MAX_REG_CLASSES 15
/**
* P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class
@@ -99,6 +99,15 @@ struct p2p_go_neg_results {
int vht;
+ u8 max_oper_chwidth;
+
+ unsigned int vht_center_freq2;
+
+ /**
+ * he - Indicates if IEEE 802.11ax HE is enabled
+ */
+ int he;
+
/**
* ssid - SSID of the group
*/
@@ -224,6 +233,16 @@ struct p2ps_provision {
u8 cpt_priority[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
/**
+ * force_freq - The only allowed channel frequency in MHz or 0.
+ */
+ unsigned int force_freq;
+
+ /**
+ * pref_freq - Preferred operating frequency in MHz or 0.
+ */
+ unsigned int pref_freq;
+
+ /**
* info - Vendor defined extra Provisioning information
*/
char info[0];
@@ -646,6 +665,8 @@ struct p2p_config {
* @buf: Frame body (starting from Category field)
* @len: Length of buf in octets
* @wait_time: How many msec to wait for a response frame
+ * @scheduled: Return value indicating whether the transmissions was
+ * scheduled to happen once the radio is available
* Returns: 0 on success, -1 on failure
*
* The Action frame may not be transmitted immediately and the status
@@ -656,7 +677,7 @@ struct p2p_config {
*/
int (*send_action)(void *ctx, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
- size_t len, unsigned int wait_time);
+ size_t len, unsigned int wait_time, int *scheduled);
/**
* send_action_done - Notify that Action frame sequence was completed
@@ -1024,6 +1045,8 @@ struct p2p_config {
* @ssid_len: Buffer for returning length of @ssid
* @group_iface: Buffer for returning whether a separate group interface
* would be used
+ * @freq: Variable for returning the current operating frequency of a
+ * currently running P2P GO.
* Returns: 1 if GO info found, 0 otherwise
*
* This is used to compose New Group settings (SSID, and intended
@@ -1031,7 +1054,8 @@ struct p2p_config {
* result in our being an autonomous GO.
*/
int (*get_go_info)(void *ctx, u8 *intended_addr,
- u8 *ssid, size_t *ssid_len, int *group_iface);
+ u8 *ssid, size_t *ssid_len, int *group_iface,
+ unsigned int *freq);
/**
* remove_stale_groups - Remove stale P2PS groups
@@ -1056,7 +1080,9 @@ struct p2p_config {
const u8 *persist_ssid,
size_t persist_ssid_size, int response_done,
int prov_start, const char *session_info,
- const u8 *feat_cap, size_t feat_cap_len);
+ const u8 *feat_cap, size_t feat_cap_len,
+ unsigned int freq, const u8 *group_ssid,
+ size_t group_ssid_len);
/**
* prov_disc_resp_cb - Callback for indicating completion of PD Response
@@ -1070,14 +1096,20 @@ struct p2p_config {
/**
* p2ps_group_capability - Determine group capability
+ * @ctx: Callback context from cb_ctx
+ * @incoming: Peer requested roles, expressed with P2PS_SETUP_* bitmap.
+ * @role: Local roles, expressed with P2PS_SETUP_* bitmap.
+ * @force_freq: Variable for returning forced frequency for the group.
+ * @pref_freq: Variable for returning preferred frequency for the group.
+ * Returns: P2PS_SETUP_* bitmap of group capability result.
*
- * This function can be used to determine group capability based on
- * information from P2PS PD exchange and the current state of ongoing
- * groups and driver capabilities.
- *
- * P2PS_SETUP_* bitmap is used as the parameters and return value.
+ * This function can be used to determine group capability and
+ * frequencies based on information from P2PS PD exchange and the
+ * current state of ongoing groups and driver capabilities.
*/
- u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role);
+ u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role,
+ unsigned int *force_freq,
+ unsigned int *pref_freq);
/**
* get_pref_freq_list - Get preferred frequency list for an interface
@@ -1530,12 +1562,13 @@ enum p2p_probe_req_status {
* @ie: Information elements from the Probe Request frame body
* @ie_len: Length of ie buffer in octets
* @rx_freq: Probe Request frame RX frequency
+ * @p2p_lo_started: Whether P2P Listen Offload is started
* Returns: value indicating the type and status of the probe request
*/
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len,
- unsigned int rx_freq);
+ unsigned int rx_freq, int p2p_lo_started);
/**
* p2p_rx_action - Report received Action frame
@@ -1691,6 +1724,12 @@ struct p2p_group_config {
int freq;
/**
+ * ip_addr_alloc - Whether IP address allocation within 4-way handshake
+ * is supported
+ */
+ int ip_addr_alloc;
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
@@ -1877,8 +1916,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
* @p2p: P2P module context from p2p_init()
* @ies: Buffer for writing P2P IE
* @dev_id: Device ID to search for or %NULL for any
+ * @bands: Frequency bands used in the scan (enum wpa_radio_work_band bitmap)
*/
-void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id);
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id,
+ unsigned int bands);
/**
* p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
@@ -1971,6 +2012,8 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
* @p2p: P2P config
* @op_class: Selected operating class
* @op_channel: Selected social channel
+ * @avoid_list: Channel ranges to try to avoid or %NULL
+ * @disallow_list: Channel ranges to discard or %NULL
* Returns: 0 on success, -1 on failure
*
* This function is used before p2p_init is called. A random social channel
@@ -1978,7 +2021,9 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
* returned on success.
*/
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
- u8 *op_channel);
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list);
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
u8 forced);
@@ -2100,6 +2145,16 @@ int p2p_client_limit_reached(struct p2p_group *group);
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
/**
+ * p2p_group_get_client_interface_addr - Get P2P Interface Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @dev_addr: P2P Device Address of the client
+ * Returns: P2P Interface Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group,
+ const u8 *dev_addr);
+
+/**
* p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group
* @group: P2P group context from p2p_group_init()
* @addr: P2P Interface Address of the client
@@ -2222,6 +2277,7 @@ int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_r2_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem);
int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
const struct wpabuf *elem);
@@ -2241,7 +2297,7 @@ struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
* discovery (p2p_find). A random number of 100 TU units is picked for each
* Listen state iteration from [min_disc_int,max_disc_int] range.
*
- * max_disc_tu can be used to futher limit the discoverable duration. However,
+ * max_disc_tu can be used to further limit the discoverable duration. However,
* it should be noted that use of this parameter is not recommended since it
* would not be compliant with the P2P specification.
*/
@@ -2329,6 +2385,8 @@ void p2p_expire_peers(struct p2p_data *p2p);
void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
const unsigned int *pref_freq_list,
unsigned int size);
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+ u8 chan);
/**
* p2p_group_get_common_freqs - Get the group common frequencies
@@ -2340,4 +2398,7 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
unsigned int *num);
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+ unsigned int freq);
+
#endif /* P2P_H */
diff --git a/contrib/wpa/src/p2p/p2p_build.c b/contrib/wpa/src/p2p/p2p_build.c
index 793d28b..63eb2e8 100644
--- a/contrib/wpa/src/p2p/p2p_build.c
+++ b/contrib/wpa/src/p2p/p2p_build.c
@@ -202,11 +202,11 @@ void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
if (peer && peer->wps_method != WPS_NOT_READY) {
if (peer->wps_method == WPS_PBC)
methods |= WPS_CONFIG_PUSHBUTTON;
+ else if (peer->wps_method == WPS_P2PS)
+ methods |= WPS_CONFIG_P2PS;
else if (peer->wps_method == WPS_PIN_DISPLAY ||
- peer->wps_method == WPS_PIN_KEYPAD) {
+ peer->wps_method == WPS_PIN_KEYPAD)
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
- methods |= WPS_CONFIG_P2PS;
- }
} else if (p2p->cfg->config_methods) {
methods |= p2p->cfg->config_methods &
(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
@@ -802,7 +802,7 @@ int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
wpabuf_put_be16(buf, p2p->cfg->config_methods);
}
- if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+ if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0)
return -1;
if (all_attr && p2p->cfg->num_sec_dev_types) {
diff --git a/contrib/wpa/src/p2p/p2p_go_neg.c b/contrib/wpa/src/p2p/p2p_go_neg.c
index 83b4356..65ab4b8 100644
--- a/contrib/wpa/src/p2p/p2p_go_neg.c
+++ b/contrib/wpa/src/p2p/p2p_go_neg.c
@@ -38,7 +38,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
{
const u8 *pos, *end;
struct p2p_channels *ch;
- size_t channels;
+ u8 channels;
struct p2p_channels intersection;
ch = &dev->channels;
@@ -58,14 +58,14 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
}
pos += 3;
- while (pos + 2 < end) {
+ while (end - pos > 2) {
struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
cl->reg_class = *pos++;
- if (pos + 1 + pos[0] > end) {
+ channels = *pos++;
+ if (channels > end - pos) {
p2p_info(p2p, "Invalid peer Channel List");
return -1;
}
- channels = *pos++;
cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ?
P2P_MAX_REG_CLASS_CHANNELS : channels;
os_memcpy(cl->channel, pos, cl->channels);
@@ -315,7 +315,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
group_capab);
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
- if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
+ if (p2p->override_pref_op_class) {
+ p2p_dbg(p2p, "Override operating channel preference");
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->override_pref_op_class,
+ p2p->override_pref_channel);
+ } else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
p2p_dbg(p2p, "Omit Operating Channel attribute");
} else {
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
@@ -384,7 +389,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
unsigned int i;
const int op_classes_5ghz[] = { 124, 125, 115, 0 };
const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
- const int op_classes_vht[] = { 128, 0 };
+ const int op_classes_vht[] = { 128, 129, 130, 0 };
if (p2p->own_freq_preference > 0 &&
p2p_freq_to_channel(p2p->own_freq_preference,
@@ -562,26 +567,11 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
* also supported by the peer device.
*/
for (i = 0; i < size && !found; i++) {
- /*
- * Make sure that the common frequency is:
- * 1. Supported by peer
- * 2. Allowed for P2P use.
- */
+ /* Make sure that the common frequency is supported by peer. */
oper_freq = freq_list[i];
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0) {
- p2p_dbg(p2p, "Unsupported frequency %u MHz", oper_freq);
- continue;
- }
- if (!p2p_channels_includes(&p2p->cfg->channels,
- op_class, op_channel) &&
- (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
- op_class, op_channel))) {
- p2p_dbg(p2p,
- "Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
- oper_freq, op_class, op_channel);
- break;
- }
+ &op_channel) < 0)
+ continue; /* cannot happen due to earlier check */
for (j = 0; j < msg->channel_list_len; j++) {
if (op_channel != msg->channel_list[j])
@@ -602,8 +592,7 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
oper_freq);
} else {
p2p_dbg(p2p,
- "None of our preferred channels are supported by peer!. Use: %d MHz for oper_channel",
- dev->oper_freq);
+ "None of our preferred channels are supported by peer!");
}
}
@@ -629,29 +618,9 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go,
msg->pref_freq_list[2 * j + 1]);
if (freq_list[i] != oper_freq)
continue;
-
- /*
- * Make sure that the found frequency is:
- * 1. Supported
- * 2. Allowed for P2P use.
- */
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0) {
- p2p_dbg(p2p, "Unsupported frequency %u MHz",
- oper_freq);
- continue;
- }
-
- if (!p2p_channels_includes(&p2p->cfg->channels,
- op_class, op_channel) &&
- (go ||
- !p2p_channels_includes(&p2p->cfg->cli_channels,
- op_class, op_channel))) {
- p2p_dbg(p2p,
- "Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
- oper_freq, op_class, op_channel);
- break;
- }
+ &op_channel) < 0)
+ continue; /* cannot happen */
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -666,9 +635,7 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go,
"Freq %d MHz is a common preferred channel for both peer and local, use it as operating channel",
oper_freq);
} else {
- p2p_dbg(p2p,
- "No common preferred channels found! Use: %d MHz for oper_channel",
- dev->oper_freq);
+ p2p_dbg(p2p, "No common preferred channels found!");
}
}
@@ -679,6 +646,8 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size;
unsigned int i;
u8 op_class, op_channel;
+ char txt[100], *pos, *end;
+ int res;
/*
* Use the preferred channel list from the driver only if there is no
@@ -694,6 +663,39 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size,
freq_list))
return;
+ /* Filter out frequencies that are not acceptable for P2P use */
+ i = 0;
+ while (i < size) {
+ if (p2p_freq_to_channel(freq_list[i], &op_class,
+ &op_channel) < 0 ||
+ (!p2p_channels_includes(&p2p->cfg->channels,
+ op_class, op_channel) &&
+ (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
+ op_class, op_channel)))) {
+ p2p_dbg(p2p,
+ "Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
+ freq_list[i], go);
+ if (size - i - 1 > 0)
+ os_memmove(&freq_list[i], &freq_list[i + 1], size - i - 1);
+ size--;
+ continue;
+ }
+
+ /* Preferred frequency is acceptable for P2P use */
+ i++;
+ }
+
+ pos = txt;
+ end = pos + sizeof(txt);
+ for (i = 0; i < size; i++) {
+ res = os_snprintf(pos, end - pos, " %u", freq_list[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
+ p2p_dbg(p2p, "Local driver frequency preference (size=%u):%s",
+ size, txt);
/*
* Check if peer's preference of operating channel is in
@@ -703,20 +705,14 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
if (freq_list[i] == (unsigned int) dev->oper_freq)
break;
}
- if (i != size) {
+ if (i != size &&
+ p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) {
/* Peer operating channel preference matches our preference */
- if (p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) <
- 0) {
- p2p_dbg(p2p,
- "Peer operating channel preference is unsupported frequency %u MHz",
- freq_list[i]);
- } else {
- p2p->op_reg_class = op_class;
- p2p->op_channel = op_channel;
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- return;
- }
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ os_memcpy(&p2p->channels, &p2p->cfg->channels,
+ sizeof(struct p2p_channels));
+ return;
}
p2p_dbg(p2p,
@@ -901,6 +897,14 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
return;
}
+ if (dev->go_neg_req_sent &&
+ (dev->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
+ p2p_dbg(p2p,
+ "Do not reply since peer is waiting for us to start a new GO Negotiation and GO Neg Request already sent");
+ p2p_parse_free(&msg);
+ return;
+ }
+
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
if (go < 0) {
p2p_dbg(p2p, "Incompatible GO Intent");
@@ -1052,7 +1056,7 @@ fail:
P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 500) < 0) {
+ wpabuf_head(resp), wpabuf_len(resp), 100) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
}
@@ -1260,6 +1264,11 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
dev->client_timeout = msg.config_timeout[1];
}
+ if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ }
+
if (!msg.operating_channel && !go) {
/*
* Note: P2P Client may omit Operating Channel attribute to
@@ -1386,7 +1395,7 @@ fail:
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
wpabuf_head(dev->go_neg_conf),
- wpabuf_len(dev->go_neg_conf), 200) < 0) {
+ wpabuf_len(dev->go_neg_conf), 50) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
p2p_go_neg_failed(p2p, -1);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
diff --git a/contrib/wpa/src/p2p/p2p_group.c b/contrib/wpa/src/p2p/p2p_group.c
index 0d66993..aa18af6 100644
--- a/contrib/wpa/src/p2p/p2p_group.c
+++ b/contrib/wpa/src/p2p/p2p_group.c
@@ -155,7 +155,8 @@ static void p2p_group_add_common_ies(struct p2p_group *group,
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (group->num_members >= group->cfg->max_clients)
group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT;
- group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
+ if (group->cfg->ip_addr_alloc)
+ group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
p2p_buf_add_capability(ie, dev_capab, group_capab);
}
@@ -296,14 +297,14 @@ static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
os_memset(zero_addr, 0, ETH_ALEN);
pos = wpabuf_head_u8(m->wfd_ie);
end = pos + wpabuf_len(m->wfd_ie);
- while (pos + 1 < end) {
+ while (end - pos >= 3) {
u8 id;
u16 len;
id = *pos++;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end)
+ if (len > end - pos)
break;
switch (id) {
@@ -366,6 +367,8 @@ wifi_display_build_go_ie(struct p2p_group *group)
return NULL;
if (group->p2p->wfd_dev_info)
wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info);
+ if (group->p2p->wfd_r2_dev_info)
+ wpabuf_put_buf(wfd_subelems, group->p2p->wfd_r2_dev_info);
if (group->p2p->wfd_assoc_bssid)
wpabuf_put_buf(wfd_subelems,
group->p2p->wfd_assoc_bssid);
@@ -849,6 +852,20 @@ static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group,
}
+const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group,
+ const u8 *dev_addr)
+{
+ struct p2p_group_member *m;
+
+ if (!group)
+ return NULL;
+ m = p2p_group_get_client(group, dev_addr);
+ if (m)
+ return m->addr;
+ return NULL;
+}
+
+
static struct p2p_group_member * p2p_group_get_client_iface(
struct p2p_group *group, const u8 *interface_addr)
{
@@ -924,7 +941,8 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr,
group->cfg->interface_addr,
group->cfg->interface_addr,
- wpabuf_head(req), wpabuf_len(req), 200) < 0)
+ wpabuf_head(req), wpabuf_len(req), 200, NULL)
+ < 0)
{
p2p_dbg(p2p, "Failed to send Action frame");
}
@@ -1097,7 +1115,7 @@ int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
struct p2p_device *dev;
dev = p2p_get_device(group->p2p, m->dev_addr);
- if (!dev)
+ if (!dev || dev->channels.reg_classes == 0)
continue;
p2p_channels_intersect(&intersect, &dev->channels, &res);
diff --git a/contrib/wpa/src/p2p/p2p_i.h b/contrib/wpa/src/p2p/p2p_i.h
index 0ce4058..d2c55c9 100644
--- a/contrib/wpa/src/p2p/p2p_i.h
+++ b/contrib/wpa/src/p2p/p2p_i.h
@@ -308,6 +308,18 @@ struct p2p_data {
*/
int num_p2p_sd_queries;
+ /**
+ * sd_query_no_ack - The first peer (Dev Addr) that did not ACK SD Query
+ *
+ * This is used to track the first peer that did not ACK an SD Query
+ * within a single P2P Search iteration. All zeros address means no such
+ * peer was yet seen. This information is used to allow a new Listen and
+ * Search phases to be once every pending SD Query has been sent once to
+ * each peer instead of looping all pending attempts continuously until
+ * running out of retry maximums.
+ */
+ u8 sd_query_no_ack[ETH_ALEN];
+
/* GO Negotiation data */
/**
@@ -425,9 +437,11 @@ struct p2p_data {
int inv_persistent;
enum p2p_discovery_type find_type;
+ int find_specified_freq;
unsigned int last_p2p_find_timeout;
u8 last_prog_scan_class;
u8 last_prog_scan_chan;
+ unsigned int find_pending_full:1;
int p2p_scan_running;
enum p2p_after_scan {
P2P_AFTER_SCAN_NOTHING,
@@ -533,6 +547,7 @@ struct p2p_data {
struct wpabuf *wfd_dev_info;
struct wpabuf *wfd_assoc_bssid;
struct wpabuf *wfd_coupled_sink_info;
+ struct wpabuf *wfd_r2_dev_info;
#endif /* CONFIG_WIFI_DISPLAY */
u16 authorized_oob_dev_pw_id;
@@ -541,6 +556,10 @@ struct p2p_data {
unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
unsigned int num_pref_freq;
+
+ /* Override option for preferred operating channel in GO Negotiation */
+ u8 override_pref_op_class;
+ u8 override_pref_channel;
};
/**
@@ -688,9 +707,13 @@ void p2p_channels_dump(struct p2p_data *p2p, const char *title,
int p2p_channel_select(struct p2p_channels *chans, const int *classes,
u8 *op_class, u8 *op_channel);
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
- u8 *op_channel);
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list);
/* p2p_parse.c */
+void p2p_copy_filter_devname(char *dst, size_t dst_len,
+ const void *src, size_t src_len);
int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg);
int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg);
int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg);
diff --git a/contrib/wpa/src/p2p/p2p_invitation.c b/contrib/wpa/src/p2p/p2p_invitation.c
index 108e5b7..77d662a 100644
--- a/contrib/wpa/src/p2p/p2p_invitation.c
+++ b/contrib/wpa/src/p2p/p2p_invitation.c
@@ -284,7 +284,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
if (!p2p_channels_includes(&intersection, reg_class, channel))
{
- p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
+ p2p_dbg(p2p, "forced freq %d MHz not in the supported channels intersection",
op_freq);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
@@ -418,7 +418,7 @@ fail:
p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
+ wpabuf_head(resp), wpabuf_len(resp), 50) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
}
@@ -488,7 +488,7 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
p2p->retry_invite_req &&
p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
- &p2p->op_channel) == 0) {
+ &p2p->op_channel, NULL, NULL) == 0) {
p2p->retry_invite_req = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
diff --git a/contrib/wpa/src/p2p/p2p_parse.c b/contrib/wpa/src/p2p/p2p_parse.c
index bd1e68b..5d2299c 100644
--- a/contrib/wpa/src/p2p/p2p_parse.c
+++ b/contrib/wpa/src/p2p/p2p_parse.c
@@ -15,11 +15,29 @@
#include "p2p_i.h"
+void p2p_copy_filter_devname(char *dst, size_t dst_len,
+ const void *src, size_t src_len)
+{
+ size_t i;
+
+ if (src_len >= dst_len)
+ src_len = dst_len - 1;
+ os_memcpy(dst, src, src_len);
+ dst[src_len] = '\0';
+ for (i = 0; i < src_len; i++) {
+ if (dst[i] == '\0')
+ break;
+ if (is_ctrl_char(dst[i]))
+ dst[i] = '_';
+ }
+}
+
+
static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
struct p2p_message *msg)
{
const u8 *pos;
- size_t i, nlen;
+ u16 nlen;
char devtype[WPS_DEV_TYPE_BUFSIZE];
switch (id) {
@@ -149,21 +167,14 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
pos += 2;
nlen = WPA_GET_BE16(pos);
pos += 2;
- if (data + len - pos < (int) nlen ||
- nlen > WPS_DEV_NAME_MAX_LEN) {
+ if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) {
wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
- "length %d (buf len %d)", (int) nlen,
+ "length %u (buf len %d)", nlen,
(int) (data + len - pos));
return -1;
}
- os_memcpy(msg->device_name, pos, nlen);
- msg->device_name[nlen] = '\0';
- for (i = 0; i < nlen; i++) {
- if (msg->device_name[i] == '\0')
- break;
- if (is_ctrl_char(msg->device_name[i]))
- msg->device_name[i] = '_';
- }
+ p2p_copy_filter_devname(msg->device_name,
+ sizeof(msg->device_name), pos, nlen);
wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR
" primary device type %s device name '%s' "
"config methods 0x%x",
@@ -637,49 +648,48 @@ int p2p_group_info_parse(const u8 *gi, size_t gi_len,
gend = gi + gi_len;
while (g < gend) {
struct p2p_client_info *cli;
- const u8 *t, *cend;
- int count;
+ const u8 *cend;
+ u16 count;
+ u8 len;
cli = &info->client[info->num_clients];
- cend = g + 1 + g[0];
- if (cend > gend)
+ len = *g++;
+ if (len > gend - g || len < 2 * ETH_ALEN + 1 + 2 + 8 + 1)
return -1; /* invalid data */
+ cend = g + len;
/* g at start of P2P Client Info Descriptor */
- /* t at Device Capability Bitmap */
- t = g + 1 + 2 * ETH_ALEN;
- if (t > cend)
- return -1; /* invalid data */
- cli->p2p_device_addr = g + 1;
- cli->p2p_interface_addr = g + 1 + ETH_ALEN;
- cli->dev_capab = t[0];
-
- if (t + 1 + 2 + 8 + 1 > cend)
- return -1; /* invalid data */
-
- cli->config_methods = WPA_GET_BE16(&t[1]);
- cli->pri_dev_type = &t[3];
-
- t += 1 + 2 + 8;
- /* t at Number of Secondary Device Types */
- cli->num_sec_dev_types = *t++;
- if (t + 8 * cli->num_sec_dev_types > cend)
+ cli->p2p_device_addr = g;
+ g += ETH_ALEN;
+ cli->p2p_interface_addr = g;
+ g += ETH_ALEN;
+ cli->dev_capab = *g++;
+
+ cli->config_methods = WPA_GET_BE16(g);
+ g += 2;
+ cli->pri_dev_type = g;
+ g += 8;
+
+ /* g at Number of Secondary Device Types */
+ len = *g++;
+ if (8 * len > cend - g)
return -1; /* invalid data */
- cli->sec_dev_types = t;
- t += 8 * cli->num_sec_dev_types;
+ cli->num_sec_dev_types = len;
+ cli->sec_dev_types = g;
+ g += 8 * len;
- /* t at Device Name in WPS TLV format */
- if (t + 2 + 2 > cend)
+ /* g at Device Name in WPS TLV format */
+ if (cend - g < 2 + 2)
return -1; /* invalid data */
- if (WPA_GET_BE16(t) != ATTR_DEV_NAME)
+ if (WPA_GET_BE16(g) != ATTR_DEV_NAME)
return -1; /* invalid Device Name TLV */
- t += 2;
- count = WPA_GET_BE16(t);
- t += 2;
- if (count > cend - t)
+ g += 2;
+ count = WPA_GET_BE16(g);
+ g += 2;
+ if (count > cend - g)
return -1; /* invalid Device Name TLV */
if (count >= WPS_DEV_NAME_MAX_LEN)
count = WPS_DEV_NAME_MAX_LEN;
- cli->dev_name = (const char *) t;
+ cli->dev_name = (const char *) g;
cli->dev_name_len = count;
g = cend;
diff --git a/contrib/wpa/src/p2p/p2p_pd.c b/contrib/wpa/src/p2p/p2p_pd.c
index 8900945..3994ec0 100644
--- a/contrib/wpa/src/p2p/p2p_pd.c
+++ b/contrib/wpa/src/p2p/p2p_pd.c
@@ -40,21 +40,31 @@ static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
}
-static void p2ps_add_new_group_info(struct p2p_data *p2p, struct wpabuf *buf)
+static void p2ps_add_new_group_info(struct p2p_data *p2p,
+ struct p2p_device *dev,
+ struct wpabuf *buf)
{
int found;
u8 intended_addr[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int group_iface;
+ unsigned int force_freq;
if (!p2p->cfg->get_go_info)
return;
found = p2p->cfg->get_go_info(
p2p->cfg->cb_ctx, intended_addr, ssid,
- &ssid_len, &group_iface);
+ &ssid_len, &group_iface, &force_freq);
if (found) {
+ if (force_freq > 0) {
+ p2p->p2ps_prov->force_freq = force_freq;
+ p2p->p2ps_prov->pref_freq = 0;
+
+ if (dev)
+ p2p_prepare_channel(p2p, dev, force_freq, 0, 0);
+ }
p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
ssid, ssid_len);
@@ -92,62 +102,62 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
size_t ssid_len;
u8 go_dev_addr[ETH_ALEN];
u8 intended_addr[ETH_ALEN];
+ int follow_on_req_fail = prov->status >= 0 &&
+ prov->status != P2P_SC_SUCCESS_DEFERRED;
/* If we might be explicite group owner, add GO details */
- if (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
- P2PS_SETUP_NEW))
- p2ps_add_new_group_info(p2p, buf);
+ if (!follow_on_req_fail &&
+ (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
+ p2ps_add_new_group_info(p2p, dev, buf);
if (prov->status >= 0)
p2p_buf_add_status(buf, (u8) prov->status);
else
prov->method = config_methods;
- if (p2p->cfg->get_persistent_group) {
- shared_group = p2p->cfg->get_persistent_group(
- p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, 0,
- go_dev_addr, ssid, &ssid_len, intended_addr);
- }
-
- /* Add Operating Channel if conncap includes GO */
- if (shared_group ||
- (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
- P2PS_SETUP_NEW))) {
- u8 tmp;
+ if (!follow_on_req_fail) {
+ if (p2p->cfg->get_persistent_group) {
+ shared_group = p2p->cfg->get_persistent_group(
+ p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
+ NULL, 0, go_dev_addr, ssid, &ssid_len,
+ intended_addr);
+ }
- p2p_go_select_channel(p2p, dev, &tmp);
+ if (shared_group ||
+ (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW)))
+ p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ &p2p->channels);
- if (p2p->op_reg_class && p2p->op_channel)
+ if ((shared_group && !is_zero_ether_addr(intended_addr)) ||
+ (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
p2p->op_reg_class,
p2p->op_channel);
- else
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
- p2p->cfg->op_reg_class,
- p2p->cfg->op_channel);
}
- p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->cfg->channels);
-
- if (prov->info[0])
+ if (prov->status < 0 && prov->info[0])
p2p_buf_add_session_info(buf, prov->info);
- p2p_buf_add_connection_capability(buf, prov->conncap);
+ if (!follow_on_req_fail)
+ p2p_buf_add_connection_capability(buf, prov->conncap);
p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac);
- if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
- prov->conncap ==
- (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
- prov->conncap ==
- (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
- /* Add Config Timeout */
- p2p_buf_add_config_timeout(buf, p2p->go_timeout,
- p2p->client_timeout);
- }
+ if (!follow_on_req_fail) {
+ if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
+ prov->conncap ==
+ (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
+ prov->conncap ==
+ (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
+ /* Add Config Timeout */
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+ p2p->client_timeout);
+ }
- p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
- p2p->cfg->channel);
+ p2p_buf_add_listen_channel(buf, p2p->cfg->country,
+ p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ }
p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac);
@@ -285,6 +295,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
u8 *len = p2p_buf_add_ie_hdr(buf);
struct p2ps_provision *prov = p2p->p2ps_prov;
u8 group_capab;
+ u8 conncap = 0;
+
+ if (status == P2P_SC_SUCCESS ||
+ status == P2P_SC_SUCCESS_DEFERRED)
+ conncap = prov->conncap;
if (!status && prov->status != -1)
status = prov->status;
@@ -301,7 +316,7 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
group_capab);
p2p_buf_add_device_info(buf, p2p, NULL);
- if (persist_ssid && p2p->cfg->get_persistent_group &&
+ if (persist_ssid && p2p->cfg->get_persistent_group && dev &&
(status == P2P_SC_SUCCESS ||
status == P2P_SC_SUCCESS_DEFERRED)) {
u8 ssid[SSID_MAX_LEN];
@@ -323,16 +338,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
}
}
- if (!persist && (prov->conncap & P2PS_SETUP_GROUP_OWNER))
- p2ps_add_new_group_info(p2p, buf);
+ if (!persist && (conncap & P2PS_SETUP_GROUP_OWNER))
+ p2ps_add_new_group_info(p2p, dev, buf);
/* Add Operating Channel if conncap indicates GO */
- if (persist || (prov->conncap & P2PS_SETUP_GROUP_OWNER)) {
- u8 tmp;
-
- if (dev)
- p2p_go_select_channel(p2p, dev, &tmp);
-
+ if (persist || (conncap & P2PS_SETUP_GROUP_OWNER)) {
if (p2p->op_reg_class && p2p->op_channel)
p2p_buf_add_operating_channel(
buf, p2p->cfg->country,
@@ -345,17 +355,20 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
p2p->cfg->op_channel);
}
- p2p_buf_add_channel_list(buf, p2p->cfg->country,
- &p2p->cfg->channels);
+ if (persist ||
+ (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
+ p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ &p2p->channels);
- if (!persist && (status == P2P_SC_SUCCESS ||
- status == P2P_SC_SUCCESS_DEFERRED))
- p2p_buf_add_connection_capability(buf, prov->conncap);
+ if (!persist && conncap)
+ p2p_buf_add_connection_capability(buf, conncap);
p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
- p2p_buf_add_config_timeout(buf, p2p->go_timeout,
- p2p->client_timeout);
+ if (persist ||
+ (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+ p2p->client_timeout);
p2p_buf_add_session_id(buf, prov->session_id,
prov->session_mac);
@@ -427,6 +440,117 @@ static u8 p2ps_own_preferred_cpt(const u8 *cpt_priority, u8 req_cpt_mask)
}
+/* Check if the message contains a valid P2PS PD Request */
+static int p2ps_validate_pd_req(struct p2p_data *p2p, struct p2p_message *msg,
+ const u8 *addr)
+{
+ u8 group_id = 0;
+ u8 intended_addr = 0;
+ u8 operating_channel = 0;
+ u8 channel_list = 0;
+ u8 config_timeout = 0;
+ u8 listen_channel = 0;
+
+#define P2PS_PD_REQ_CHECK(_val, _attr) \
+do { \
+ if ((_val) && !msg->_attr) { \
+ p2p_dbg(p2p, "Not P2PS PD Request. Missing %s", #_attr); \
+ return -1; \
+ } \
+} while (0)
+
+ P2PS_PD_REQ_CHECK(1, adv_id);
+ P2PS_PD_REQ_CHECK(1, session_id);
+ P2PS_PD_REQ_CHECK(1, session_mac);
+ P2PS_PD_REQ_CHECK(1, adv_mac);
+ P2PS_PD_REQ_CHECK(1, capability);
+ P2PS_PD_REQ_CHECK(1, p2p_device_info);
+ P2PS_PD_REQ_CHECK(1, feature_cap);
+
+ /*
+ * We don't need to check Connection Capability, Persistent Group,
+ * and related attributes for follow-on PD Request with a status
+ * other than SUCCESS_DEFERRED.
+ */
+ if (msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED)
+ return 0;
+
+ P2PS_PD_REQ_CHECK(1, conn_cap);
+
+ /*
+ * Note 1: A feature capability attribute structure can be changed
+ * in the future. The assumption is that such modifications are
+ * backward compatible, therefore we allow processing of msg.feature_cap
+ * exceeding the size of the p2ps_feature_capab structure.
+ * Note 2: Verification of msg.feature_cap_len below has to be changed
+ * to allow 2 byte feature capability processing if
+ * struct p2ps_feature_capab is extended to include additional fields
+ * and it affects the structure size.
+ */
+ if (msg->feature_cap_len < sizeof(struct p2ps_feature_capab)) {
+ p2p_dbg(p2p, "P2PS: Invalid feature capability len");
+ return -1;
+ }
+
+ switch (*msg->conn_cap) {
+ case P2PS_SETUP_NEW:
+ group_id = 1;
+ intended_addr = 1;
+ operating_channel = 1;
+ channel_list = 1;
+ config_timeout = 1;
+ listen_channel = 1;
+ break;
+ case P2PS_SETUP_CLIENT:
+ channel_list = 1;
+ listen_channel = 1;
+ break;
+ case P2PS_SETUP_GROUP_OWNER:
+ group_id = 1;
+ intended_addr = 1;
+ operating_channel = 1;
+ break;
+ case P2PS_SETUP_NEW | P2PS_SETUP_GROUP_OWNER:
+ group_id = 1;
+ operating_channel = 1;
+ intended_addr = 1;
+ channel_list = 1;
+ config_timeout = 1;
+ break;
+ case P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER:
+ group_id = 1;
+ intended_addr = 1;
+ operating_channel = 1;
+ channel_list = 1;
+ config_timeout = 1;
+ break;
+ default:
+ p2p_dbg(p2p, "Invalid P2PS PD connection capability");
+ return -1;
+ }
+
+ if (msg->persistent_dev) {
+ channel_list = 1;
+ config_timeout = 1;
+ if (os_memcmp(msg->persistent_dev, addr, ETH_ALEN) == 0) {
+ intended_addr = 1;
+ operating_channel = 1;
+ }
+ }
+
+ P2PS_PD_REQ_CHECK(group_id, group_id);
+ P2PS_PD_REQ_CHECK(intended_addr, intended_addr);
+ P2PS_PD_REQ_CHECK(operating_channel, operating_channel);
+ P2PS_PD_REQ_CHECK(channel_list, channel_list);
+ P2PS_PD_REQ_CHECK(config_timeout, config_timeout);
+ P2PS_PD_REQ_CHECK(listen_channel, listen_channel);
+
+#undef P2PS_PD_REQ_CHECK
+
+ return 0;
+}
+
+
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
@@ -440,14 +564,16 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
u8 conncap = P2PS_SETUP_NEW;
u8 auto_accept = 0;
u32 session_id = 0;
- u8 session_mac[ETH_ALEN];
- u8 adv_mac[ETH_ALEN];
+ u8 session_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ u8 adv_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
const u8 *group_mac;
int passwd_id = DEV_PW_DEFAULT;
u16 config_methods;
u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
struct p2ps_feature_capab resp_fcap = { 0, 0 };
- struct p2ps_feature_capab *req_fcap;
+ struct p2ps_feature_capab *req_fcap = NULL;
+ u8 remote_conncap;
+ u16 method;
if (p2p_parse(data, len, &msg))
return;
@@ -466,300 +592,431 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
0)) {
p2p_dbg(p2p, "Provision Discovery Request add device failed "
MACSTR, MAC2STR(sa));
+ goto out;
+ }
+
+ if (!dev) {
+ dev = p2p_get_device(p2p, sa);
+ if (!dev) {
+ p2p_dbg(p2p,
+ "Provision Discovery device not found "
+ MACSTR, MAC2STR(sa));
+ goto out;
+ }
}
} else if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
}
- if (msg.adv_id)
- allowed_config_methods |= WPS_CONFIG_P2PS;
- else
+ if (!msg.adv_id) {
allowed_config_methods |= WPS_CONFIG_PUSHBUTTON;
+ if (!(msg.wps_config_methods & allowed_config_methods)) {
+ p2p_dbg(p2p,
+ "Unsupported Config Methods in Provision Discovery Request");
+ goto out;
+ }
- if (!(msg.wps_config_methods & allowed_config_methods)) {
- p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
- goto out;
- }
+ /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
+ if (msg.group_id) {
+ size_t i;
- /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
- if (!msg.adv_id && msg.group_id) {
- size_t i;
- for (i = 0; i < p2p->num_groups; i++) {
- if (p2p_group_is_group_id_match(p2p->groups[i],
- msg.group_id,
- msg.group_id_len))
- break;
+ for (i = 0; i < p2p->num_groups; i++) {
+ if (p2p_group_is_group_id_match(
+ p2p->groups[i],
+ msg.group_id, msg.group_id_len))
+ break;
+ }
+ if (i == p2p->num_groups) {
+ p2p_dbg(p2p,
+ "PD request for unknown P2P Group ID - reject");
+ goto out;
+ }
}
- if (i == p2p->num_groups) {
- p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
+ } else {
+ allowed_config_methods |= WPS_CONFIG_P2PS;
+
+ /*
+ * Set adv_id here, so in case of an error, a P2PS PD Response
+ * will be sent.
+ */
+ adv_id = WPA_GET_LE32(msg.adv_id);
+ if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) {
+ reject = P2P_SC_FAIL_INVALID_PARAMS;
goto out;
}
- }
- if (dev) {
- dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
- P2P_DEV_PD_PEER_KEYPAD |
- P2P_DEV_PD_PEER_P2PS);
+ req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
- /* Remove stale persistent groups */
- if (p2p->cfg->remove_stale_groups) {
- p2p->cfg->remove_stale_groups(
- p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
- msg.persistent_dev,
- msg.persistent_ssid, msg.persistent_ssid_len);
+ os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
+ os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+
+ session_id = WPA_GET_LE32(msg.session_id);
+
+ if (msg.conn_cap)
+ conncap = *msg.conn_cap;
+
+ /*
+ * We need to verify a P2PS config methog in an initial PD
+ * request or in a follow-on PD request with the status
+ * SUCCESS_DEFERRED.
+ */
+ if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) &&
+ !(msg.wps_config_methods & allowed_config_methods)) {
+ p2p_dbg(p2p,
+ "Unsupported Config Methods in Provision Discovery Request");
+ goto out;
}
+
+ /*
+ * TODO: since we don't support multiple PD, reject PD request
+ * if we are in the middle of P2PS PD with some other peer
+ */
}
+
+ dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
+ P2P_DEV_PD_PEER_KEYPAD |
+ P2P_DEV_PD_PEER_P2PS);
+
if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
p2p_dbg(p2p, "Peer " MACSTR
" requested us to show a PIN on display", MAC2STR(sa));
- if (dev)
- dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
+ dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
passwd_id = DEV_PW_USER_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
p2p_dbg(p2p, "Peer " MACSTR
" requested us to write its PIN using keypad",
MAC2STR(sa));
- if (dev)
- dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
+ dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
} else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
MAC2STR(sa));
- if (dev)
- dev->flags |= P2P_DEV_PD_PEER_P2PS;
+ dev->flags |= P2P_DEV_PD_PEER_P2PS;
passwd_id = DEV_PW_P2PS_DEFAULT;
}
- reject = P2P_SC_SUCCESS;
+ /* Remove stale persistent groups */
+ if (p2p->cfg->remove_stale_groups) {
+ p2p->cfg->remove_stale_groups(
+ p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
+ msg.persistent_dev,
+ msg.persistent_ssid, msg.persistent_ssid_len);
+ }
- os_memset(session_mac, 0, ETH_ALEN);
- os_memset(adv_mac, 0, ETH_ALEN);
+ reject = P2P_SC_SUCCESS;
- /* Note 1: A feature capability attribute structure can be changed
- * in the future. The assumption is that such modifications are
- * backwards compatible, therefore we allow processing of
- * msg.feature_cap exceeding the size of the p2ps_feature_capab
- * structure.
- * Note 2: Vverification of msg.feature_cap_len below has to be changed
- * to allow 2 byte feature capability processing if struct
- * p2ps_feature_capab is extended to include additional fields and it
- * affects the structure size.
+ /*
+ * End of a legacy P2P PD Request processing, from this point continue
+ * with P2PS one.
*/
- if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac &&
- msg.feature_cap && msg.feature_cap_len >= sizeof(*req_fcap) &&
- (msg.status || msg.conn_cap)) {
- u8 remote_conncap;
+ if (!msg.adv_id)
+ goto out;
- req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
+ remote_conncap = conncap;
- os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
- os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+ if (!msg.status) {
+ unsigned int forced_freq, pref_freq;
- session_id = WPA_GET_LE32(msg.session_id);
- adv_id = WPA_GET_LE32(msg.adv_id);
-
- if (!msg.status)
- p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
+ if (os_memcmp(p2p->cfg->dev_addr, msg.adv_mac, ETH_ALEN)) {
+ p2p_dbg(p2p,
+ "P2PS PD adv mac does not match the local one");
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ goto out;
+ }
- p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv);
+ p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
+ if (!p2ps_adv) {
+ p2p_dbg(p2p, "P2PS PD invalid adv_id=0x%X", adv_id);
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ goto out;
+ }
+ p2p_dbg(p2p, "adv_id: 0x%X, p2ps_adv: %p", adv_id, p2ps_adv);
- if (msg.conn_cap)
- conncap = *msg.conn_cap;
- remote_conncap = conncap;
+ auto_accept = p2ps_adv->auto_accept;
+ conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
+ conncap, auto_accept,
+ &forced_freq,
+ &pref_freq);
- if (p2ps_adv) {
- auto_accept = p2ps_adv->auto_accept;
- conncap = p2p->cfg->p2ps_group_capability(
- p2p->cfg->cb_ctx, conncap, auto_accept);
+ p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
+ auto_accept, remote_conncap, conncap);
- p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
- auto_accept, remote_conncap, conncap);
+ p2p_prepare_channel(p2p, dev, forced_freq, pref_freq, 0);
- resp_fcap.cpt =
- p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
+ resp_fcap.cpt = p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
req_fcap->cpt);
+ p2p_dbg(p2p, "cpt: service:0x%x remote:0x%x result:0x%x",
+ p2ps_adv->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
+
+ if (!resp_fcap.cpt) {
+ p2p_dbg(p2p,
+ "Incompatible P2PS feature capability CPT bitmask");
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ } else if (p2ps_adv->config_methods &&
+ !(msg.wps_config_methods &
+ p2ps_adv->config_methods)) {
p2p_dbg(p2p,
- "cpt: service:0x%x remote:0x%x result:0x%x",
- p2ps_adv->cpt_mask, req_fcap->cpt,
- resp_fcap.cpt);
+ "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
+ p2ps_adv->config_methods,
+ msg.wps_config_methods);
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ } else if (!p2ps_adv->state) {
+ p2p_dbg(p2p, "P2PS state unavailable");
+ reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+ } else if (!conncap) {
+ p2p_dbg(p2p, "Conncap resolution failed");
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ }
- if (!resp_fcap.cpt) {
- p2p_dbg(p2p,
- "Incompatible P2PS feature capability CPT bitmask");
- reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- } else if (p2ps_adv->config_methods &&
- !(msg.wps_config_methods &
- p2ps_adv->config_methods)) {
- p2p_dbg(p2p,
- "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
- p2ps_adv->config_methods,
- msg.wps_config_methods);
- reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- } else if (!p2ps_adv->state) {
- p2p_dbg(p2p, "P2PS state unavailable");
- reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
- } else if (!conncap) {
- p2p_dbg(p2p, "Conncap resolution failed");
- reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- }
+ if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+ p2p_dbg(p2p, "Keypad - always defer");
+ auto_accept = 0;
+ }
- if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
- p2p_dbg(p2p, "Keypad - always defer");
- auto_accept = 0;
+ if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
+ msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
+ msg.channel_list && msg.channel_list_len &&
+ p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0) {
+ p2p_dbg(p2p,
+ "No common channels - force deferred flow");
+ auto_accept = 0;
+ }
+
+ if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) ||
+ msg.persistent_dev) && msg.operating_channel) {
+ struct p2p_channels intersect;
+
+ /*
+ * There are cases where only the operating channel is
+ * provided. This requires saving the channel as the
+ * supported channel list, and verifying that it is
+ * supported.
+ */
+ if (dev->channels.reg_classes == 0 ||
+ !p2p_channels_includes(&dev->channels,
+ msg.operating_channel[3],
+ msg.operating_channel[4])) {
+ struct p2p_channels *ch = &dev->channels;
+
+ os_memset(ch, 0, sizeof(*ch));
+ ch->reg_class[0].reg_class =
+ msg.operating_channel[3];
+ ch->reg_class[0].channel[0] =
+ msg.operating_channel[4];
+ ch->reg_class[0].channels = 1;
+ ch->reg_classes = 1;
}
- if (auto_accept || reject != P2P_SC_SUCCESS) {
- struct p2ps_provision *tmp;
-
- if (reject == P2P_SC_SUCCESS && !conncap) {
- reject =
- P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- }
-
- if (p2ps_setup_p2ps_prov(
- p2p, adv_id, session_id,
- msg.wps_config_methods,
- session_mac, adv_mac) < 0) {
- reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
- goto out;
- }
-
- tmp = p2p->p2ps_prov;
- if (conncap) {
- tmp->conncap = conncap;
- tmp->status = P2P_SC_SUCCESS;
- } else {
- tmp->conncap = auto_accept;
- tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- }
-
- if (reject != P2P_SC_SUCCESS)
- goto out;
+ p2p_channels_intersect(&p2p->channels, &dev->channels,
+ &intersect);
+
+ if (intersect.reg_classes == 0) {
+ p2p_dbg(p2p,
+ "No common channels - force deferred flow");
+ auto_accept = 0;
}
- } else if (!msg.status) {
- reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- goto out;
}
- if (!msg.status && !auto_accept &&
- (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
+ if (auto_accept || reject != P2P_SC_SUCCESS) {
struct p2ps_provision *tmp;
- if (!conncap) {
- reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- goto out;
- }
-
if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
msg.wps_config_methods,
session_mac, adv_mac) < 0) {
reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
goto out;
}
+
tmp = p2p->p2ps_prov;
- reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
- tmp->status = reject;
+ tmp->force_freq = forced_freq;
+ tmp->pref_freq = pref_freq;
+ if (conncap) {
+ tmp->conncap = conncap;
+ tmp->status = P2P_SC_SUCCESS;
+ } else {
+ tmp->conncap = auto_accept;
+ tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ }
+
+ if (reject != P2P_SC_SUCCESS)
+ goto out;
}
+ }
- if (msg.status) {
- if (*msg.status &&
- *msg.status != P2P_SC_SUCCESS_DEFERRED) {
- reject = *msg.status;
- } else if (*msg.status == P2P_SC_SUCCESS_DEFERRED &&
- p2p->p2ps_prov) {
- u16 method = p2p->p2ps_prov->method;
+ if (!msg.status && !auto_accept &&
+ (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
+ struct p2ps_provision *tmp;
- conncap = p2p->cfg->p2ps_group_capability(
- p2p->cfg->cb_ctx, remote_conncap,
- p2p->p2ps_prov->conncap);
+ if (!conncap) {
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ goto out;
+ }
- p2p_dbg(p2p,
- "Conncap: local:%d remote:%d result:%d",
- p2p->p2ps_prov->conncap,
- remote_conncap, conncap);
+ if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
+ msg.wps_config_methods,
+ session_mac, adv_mac) < 0) {
+ reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+ goto out;
+ }
+ tmp = p2p->p2ps_prov;
+ reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+ tmp->status = reject;
+ }
- resp_fcap.cpt = p2ps_own_preferred_cpt(
- p2p->p2ps_prov->cpt_priority,
- req_fcap->cpt);
+ /* Not a P2PS Follow-on PD */
+ if (!msg.status)
+ goto out;
- p2p_dbg(p2p,
- "cpt: local:0x%x remote:0x%x result:0x%x",
- p2p->p2ps_prov->cpt_mask,
- req_fcap->cpt, resp_fcap.cpt);
+ if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) {
+ reject = *msg.status;
+ goto out;
+ }
- /*
- * Ensure that if we asked for PIN originally,
- * our method is consistent with original
- * request.
- */
- if (method & WPS_CONFIG_DISPLAY)
- method = WPS_CONFIG_KEYPAD;
- else if (method & WPS_CONFIG_KEYPAD)
- method = WPS_CONFIG_DISPLAY;
-
- if (!conncap ||
- !(msg.wps_config_methods & method)) {
- /*
- * Reject this "Deferred Accept*
- * if incompatible conncap or method
- */
- reject =
- P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- } else if (!resp_fcap.cpt) {
- p2p_dbg(p2p,
- "Incompatible P2PS feature capability CPT bitmask");
- reject =
- P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
- } else {
- reject = P2P_SC_SUCCESS;
- }
-
- p2p->p2ps_prov->status = reject;
- p2p->p2ps_prov->conncap = conncap;
- }
- }
+ if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
+ goto out;
+
+ if (p2p->p2ps_prov->adv_id != adv_id ||
+ os_memcmp(p2p->p2ps_prov->adv_mac, msg.adv_mac, ETH_ALEN)) {
+ p2p_dbg(p2p,
+ "P2PS Follow-on PD with mismatch Advertisement ID/MAC");
+ goto out;
+ }
+
+ if (p2p->p2ps_prov->session_id != session_id ||
+ os_memcmp(p2p->p2ps_prov->session_mac, msg.session_mac, ETH_ALEN)) {
+ p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC");
+ goto out;
+ }
+
+ method = p2p->p2ps_prov->method;
+
+ conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
+ remote_conncap,
+ p2p->p2ps_prov->conncap,
+ &p2p->p2ps_prov->force_freq,
+ &p2p->p2ps_prov->pref_freq);
+
+ resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority,
+ req_fcap->cpt);
+
+ p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x",
+ p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
+
+ p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
+ p2p->p2ps_prov->pref_freq, 0);
+
+ /*
+ * Ensure that if we asked for PIN originally, our method is consistent
+ * with original request.
+ */
+ if (method & WPS_CONFIG_DISPLAY)
+ method = WPS_CONFIG_KEYPAD;
+ else if (method & WPS_CONFIG_KEYPAD)
+ method = WPS_CONFIG_DISPLAY;
+
+ if (!conncap || !(msg.wps_config_methods & method)) {
+ /*
+ * Reject this "Deferred Accept*
+ * if incompatible conncap or method
+ */
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ } else if (!resp_fcap.cpt) {
+ p2p_dbg(p2p,
+ "Incompatible P2PS feature capability CPT bitmask");
+ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
+ } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
+ msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
+ msg.channel_list && msg.channel_list_len &&
+ p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0) {
+ p2p_dbg(p2p,
+ "No common channels in Follow-On Provision Discovery Request");
+ reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ } else {
+ reject = P2P_SC_SUCCESS;
+ }
+
+ dev->oper_freq = 0;
+ if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) {
+ u8 tmp;
+
+ if (msg.operating_channel)
+ dev->oper_freq =
+ p2p_channel_to_freq(msg.operating_channel[3],
+ msg.operating_channel[4]);
+
+ if ((conncap & P2PS_SETUP_GROUP_OWNER) &&
+ p2p_go_select_channel(p2p, dev, &tmp) < 0)
+ reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
}
+ p2p->p2ps_prov->status = reject;
+ p2p->p2ps_prov->conncap = conncap;
+
out:
if (reject == P2P_SC_SUCCESS ||
reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
config_methods = msg.wps_config_methods;
else
config_methods = 0;
- resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, reject,
- config_methods, adv_id,
- msg.group_id, msg.group_id_len,
- msg.persistent_ssid,
- msg.persistent_ssid_len,
- (const u8 *) &resp_fcap,
- sizeof(resp_fcap));
- if (resp == NULL) {
- p2p_parse_free(&msg);
- return;
- }
- p2p_dbg(p2p, "Sending Provision Discovery Response");
- if (rx_freq > 0)
- freq = rx_freq;
- else
- freq = p2p_channel_to_freq(p2p->cfg->reg_class,
- p2p->cfg->channel);
- if (freq < 0) {
- p2p_dbg(p2p, "Unknown regulatory class/channel");
+
+ /*
+ * Send PD Response for an initial PD Request or for follow-on
+ * PD Request with P2P_SC_SUCCESS_DEFERRED status.
+ */
+ if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) {
+ resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token,
+ reject, config_methods, adv_id,
+ msg.group_id, msg.group_id_len,
+ msg.persistent_ssid,
+ msg.persistent_ssid_len,
+ (const u8 *) &resp_fcap,
+ sizeof(resp_fcap));
+ if (!resp) {
+ p2p_parse_free(&msg);
+ return;
+ }
+ p2p_dbg(p2p, "Sending Provision Discovery Response");
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
+ wpabuf_free(resp);
+ p2p_parse_free(&msg);
+ return;
+ }
+ p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
+ if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
+ p2p->cfg->dev_addr,
+ wpabuf_head(resp), wpabuf_len(resp),
+ 50) < 0)
+ p2p_dbg(p2p, "Failed to send Action frame");
+ else
+ p2p->send_action_in_progress = 1;
+
wpabuf_free(resp);
+ }
+
+ if (!dev) {
p2p_parse_free(&msg);
return;
}
- p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
- if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
- p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
- p2p_dbg(p2p, "Failed to send Action frame");
- } else
- p2p->send_action_in_progress = 1;
- wpabuf_free(resp);
+ freq = 0;
+ if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) {
+ freq = p2p_channel_to_freq(p2p->op_reg_class,
+ p2p->op_channel);
+ if (freq < 0)
+ freq = 0;
+ }
if (!p2p->cfg->p2ps_prov_complete) {
/* Don't emit anything */
@@ -771,7 +1028,8 @@ out:
NULL, adv_id, session_id,
0, 0, msg.persistent_ssid,
msg.persistent_ssid_len,
- 0, 0, NULL, NULL, 0);
+ 0, 0, NULL, NULL, 0, freq,
+ NULL, 0);
} else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
p2p->p2ps_prov) {
p2p->p2ps_prov->status = reject;
@@ -784,7 +1042,8 @@ out:
session_id, conncap, 0,
msg.persistent_ssid,
msg.persistent_ssid_len, 0,
- 0, NULL, NULL, 0);
+ 0, NULL, NULL, 0, freq,
+ NULL, 0);
else
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
*msg.status,
@@ -796,7 +1055,8 @@ out:
msg.persistent_ssid_len, 0,
0, NULL,
(const u8 *) &resp_fcap,
- sizeof(resp_fcap));
+ sizeof(resp_fcap), freq,
+ NULL, 0);
} else if (msg.status && p2p->p2ps_prov) {
p2p->p2ps_prov->status = P2P_SC_SUCCESS;
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa,
@@ -807,7 +1067,7 @@ out:
msg.persistent_ssid_len,
0, 0, NULL,
(const u8 *) &resp_fcap,
- sizeof(resp_fcap));
+ sizeof(resp_fcap), freq, NULL, 0);
} else if (msg.status) {
} else if (auto_accept && reject == P2P_SC_SUCCESS) {
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
@@ -818,7 +1078,11 @@ out:
msg.persistent_ssid_len,
0, 0, NULL,
(const u8 *) &resp_fcap,
- sizeof(resp_fcap));
+ sizeof(resp_fcap), freq,
+ msg.group_id ?
+ msg.group_id + ETH_ALEN : NULL,
+ msg.group_id ?
+ msg.group_id_len - ETH_ALEN : 0);
} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
(!msg.session_info || !msg.session_info_len)) {
p2p->p2ps_prov->method = msg.wps_config_methods;
@@ -831,7 +1095,7 @@ out:
msg.persistent_ssid_len,
0, 1, NULL,
(const u8 *) &resp_fcap,
- sizeof(resp_fcap));
+ sizeof(resp_fcap), freq, NULL, 0);
} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
size_t buf_len = msg.session_info_len;
char *buf = os_malloc(2 * buf_len + 1);
@@ -848,7 +1112,8 @@ out:
session_id, conncap, passwd_id,
msg.persistent_ssid, msg.persistent_ssid_len,
0, 1, buf,
- (const u8 *) &resp_fcap, sizeof(resp_fcap));
+ (const u8 *) &resp_fcap, sizeof(resp_fcap),
+ freq, NULL, 0);
os_free(buf);
}
@@ -898,7 +1163,10 @@ out:
msg.group_id, msg.group_id_len);
}
- if (dev && reject == P2P_SC_SUCCESS) {
+ if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+ p2ps_prov_free(p2p);
+
+ if (reject == P2P_SC_SUCCESS) {
switch (config_methods) {
case WPS_CONFIG_DISPLAY:
dev->wps_prov_info = WPS_CONFIG_KEYPAD;
@@ -1084,6 +1352,9 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
" with no pending request", MAC2STR(sa));
p2p_parse_free(&msg);
return;
+ } else if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
}
if (dev->dialog_token != msg.dialog_token) {
@@ -1148,17 +1419,71 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
passwd_id = DEV_PW_P2PS_DEFAULT;
}
- if ((msg.conn_cap || msg.persistent_dev) &&
- (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
+ if ((status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
p2p->p2ps_prov) {
+ dev->oper_freq = 0;
+
+ /*
+ * Save the reported channel list and operating frequency.
+ * Note that the specification mandates that the responder
+ * should include in the channel list only channels reported by
+ * the initiator, so this is only a sanity check, and if this
+ * fails the flow would continue, although it would probably
+ * fail. Same is true for the operating channel.
+ */
+ if (msg.channel_list && msg.channel_list_len &&
+ p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0)
+ p2p_dbg(p2p, "P2PS PD Response - no common channels");
+
+ if (msg.operating_channel) {
+ if (p2p_channels_includes(&p2p->channels,
+ msg.operating_channel[3],
+ msg.operating_channel[4]) &&
+ p2p_channels_includes(&dev->channels,
+ msg.operating_channel[3],
+ msg.operating_channel[4])) {
+ dev->oper_freq =
+ p2p_channel_to_freq(
+ msg.operating_channel[3],
+ msg.operating_channel[4]);
+ } else {
+ p2p_dbg(p2p,
+ "P2PS PD Response - invalid operating channel");
+ }
+ }
+
if (p2p->cfg->p2ps_prov_complete) {
+ int freq = 0;
+
+ if (conncap == P2PS_SETUP_GROUP_OWNER) {
+ u8 tmp;
+
+ /*
+ * Re-select the operating channel as it is
+ * possible that original channel is no longer
+ * valid. This should not really fail.
+ */
+ if (p2p_go_select_channel(p2p, dev, &tmp) < 0)
+ p2p_dbg(p2p,
+ "P2PS PD channel selection failed");
+
+ freq = p2p_channel_to_freq(p2p->op_reg_class,
+ p2p->op_channel);
+ if (freq < 0)
+ freq = 0;
+ }
+
p2p->cfg->p2ps_prov_complete(
p2p->cfg->cb_ctx, status, sa, adv_mac,
p2p->p2ps_prov->session_mac,
group_mac, adv_id, p2p->p2ps_prov->session_id,
conncap, passwd_id, msg.persistent_ssid,
msg.persistent_ssid_len, 1, 0, NULL,
- msg.feature_cap, msg.feature_cap_len);
+ msg.feature_cap, msg.feature_cap_len, freq,
+ msg.group_id ? msg.group_id + ETH_ALEN : NULL,
+ msg.group_id ? msg.group_id_len - ETH_ALEN : 0);
}
p2ps_prov_free(p2p);
} else if (status != P2P_SC_SUCCESS &&
@@ -1169,7 +1494,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
p2p->cfg->cb_ctx, status, sa, adv_mac,
p2p->p2ps_prov->session_mac,
group_mac, adv_id, p2p->p2ps_prov->session_id,
- 0, 0, NULL, 0, 1, 0, NULL, NULL, 0);
+ 0, 0, NULL, 0, 1, 0, NULL, NULL, 0, 0, NULL, 0);
p2ps_prov_free(p2p);
}
@@ -1259,7 +1584,7 @@ out:
report_config_methods);
if (p2p->state == P2P_PD_DURING_FIND) {
- p2p_clear_timeout(p2p);
+ p2p_stop_listen_for_freq(p2p, 0);
p2p_continue_find(p2p);
}
}
@@ -1318,6 +1643,10 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
"Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x",
p2p->p2ps_prov->method, p2p->p2ps_prov->status,
dev->req_config_methods);
+
+ if (p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
+ p2p->p2ps_prov->pref_freq, 1) < 0)
+ return -1;
}
req = p2p_build_prov_disc_req(p2p, dev, join);
diff --git a/contrib/wpa/src/p2p/p2p_sd.c b/contrib/wpa/src/p2p/p2p_sd.c
index 1a2af04..b9e753f 100644
--- a/contrib/wpa/src/p2p/p2p_sd.c
+++ b/contrib/wpa/src/p2p/p2p_sd.c
@@ -28,11 +28,11 @@ static int wfd_wsd_supported(struct wpabuf *wfd)
pos = wpabuf_head(wfd);
end = pos + wpabuf_len(wfd);
- while (pos + 3 <= end) {
+ while (end - pos >= 3) {
subelem = *pos++;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end)
+ if (len > end - pos)
break;
if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
@@ -288,6 +288,14 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
query = p2p_pending_sd_req(p2p, dev);
if (query == NULL)
return -1;
+ if (p2p->state == P2P_SEARCH &&
+ os_memcmp(p2p->sd_query_no_ack, dev->info.p2p_device_addr,
+ ETH_ALEN) == 0) {
+ p2p_dbg(p2p, "Do not start Service Discovery with " MACSTR
+ " due to it being the first no-ACK peer in this search iteration",
+ MAC2STR(dev->info.p2p_device_addr));
+ return -2;
+ }
p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
MAC2STR(dev->info.p2p_device_addr));
@@ -355,11 +363,11 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
pos++;
slen = *pos++;
- next = pos + slen;
- if (next > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
return;
}
+ next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -370,16 +378,16 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Request */
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end)
+ if (slen > end - pos)
return;
end = pos + slen;
/* ANQP Query Request */
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -389,7 +397,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end || slen < 3 + 1) {
+ if (slen > end - pos || slen < 3 + 1) {
p2p_dbg(p2p, "Invalid ANQP Query Request length");
return;
}
@@ -401,7 +409,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
}
pos += 4;
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
@@ -417,9 +425,17 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
u8 dialog_token, const struct wpabuf *resp_tlvs)
{
struct wpabuf *resp;
+ size_t max_len;
+ unsigned int wait_time = 200;
+
+ /*
+ * In the 60 GHz, we have a smaller maximum frame length for management
+ * frames.
+ */
+ max_len = (freq > 56160) ? 928 : 1400;
/* TODO: fix the length limit to match with the maximum frame length */
- if (wpabuf_len(resp_tlvs) > 1400) {
+ if (wpabuf_len(resp_tlvs) > max_len) {
p2p_dbg(p2p, "SD response long enough to require fragmentation");
if (p2p->sd_resp) {
/*
@@ -445,6 +461,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
1, p2p->srv_update_indic, NULL);
} else {
p2p_dbg(p2p, "SD response fits in initial response");
+ wait_time = 0; /* no more SD frames in the sequence */
resp = p2p_build_sd_response(dialog_token,
WLAN_STATUS_SUCCESS, 0,
p2p->srv_update_indic, resp_tlvs);
@@ -455,7 +472,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
+ wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
@@ -512,11 +529,11 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos++;
slen = *pos++;
- next = pos + slen;
- if (next > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
return;
}
+ next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -527,14 +544,14 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Response */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
p2p_dbg(p2p, "Too short Query Response");
return;
}
slen = WPA_GET_LE16(pos);
pos += 2;
p2p_dbg(p2p, "Query Response Length: %d", slen);
- if (pos + slen > end) {
+ if (slen > end - pos) {
p2p_dbg(p2p, "Not enough Query Response data");
return;
}
@@ -552,7 +569,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
}
/* ANQP Query Response */
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -562,7 +579,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end || slen < 3 + 1) {
+ if (slen > end - pos || slen < 3 + 1) {
p2p_dbg(p2p, "Invalid ANQP Query Response length");
return;
}
@@ -574,7 +591,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
}
pos += 4;
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
@@ -606,8 +623,9 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
{
struct wpabuf *resp;
u8 dialog_token;
- size_t frag_len;
+ size_t frag_len, max_len;
int more = 0;
+ unsigned int wait_time = 200;
wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
if (len < 1)
@@ -630,9 +648,14 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
return;
}
+ /*
+ * In the 60 GHz, we have a smaller maximum frame length for management
+ * frames.
+ */
+ max_len = (rx_freq > 56160) ? 928 : 1400;
frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
- if (frag_len > 1400) {
- frag_len = 1400;
+ if (frag_len > max_len) {
+ frag_len = max_len;
more = 1;
}
resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,
@@ -655,12 +678,13 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "All fragments of SD response sent");
wpabuf_free(p2p->sd_resp);
p2p->sd_resp = NULL;
+ wait_time = 0; /* no more SD frames in the sequence */
}
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
+ wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
@@ -727,11 +751,11 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos++;
slen = *pos++;
- next = pos + slen;
- if (next > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
return;
}
+ next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -742,14 +766,14 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos = next;
/* Query Response */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
p2p_dbg(p2p, "Too short Query Response");
return;
}
slen = WPA_GET_LE16(pos);
pos += 2;
p2p_dbg(p2p, "Query Response Length: %d", slen);
- if (pos + slen > end) {
+ if (slen > end - pos) {
p2p_dbg(p2p, "Not enough Query Response data");
return;
}
@@ -768,7 +792,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
}
/* ANQP Query Response */
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@@ -783,7 +807,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Invalid ANQP Query Response length");
return;
}
- if (pos + 4 > end)
+ if (end - pos < 4)
return;
if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
@@ -793,7 +817,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
}
pos += 4;
- if (pos + 2 > end)
+ if (end - pos < 2)
return;
p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
diff --git a/contrib/wpa/src/p2p/p2p_utils.c b/contrib/wpa/src/p2p/p2p_utils.c
index 2e2aa8a..1a62a44 100644
--- a/contrib/wpa/src/p2p/p2p_utils.c
+++ b/contrib/wpa/src/p2p/p2p_utils.c
@@ -413,17 +413,30 @@ int p2p_channel_select(struct p2p_channels *chans, const int *classes,
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
- u8 *op_channel)
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list)
{
u8 chan[4];
unsigned int num_channels = 0;
- /* Try to find available social channels from 2.4 GHz */
- if (p2p_channels_includes(chans, 81, 1))
+ /* Try to find available social channels from 2.4 GHz.
+ * If the avoid_list includes any of the 2.4 GHz social channels, that
+ * channel is not allowed by p2p_channels_includes() rules. However, it
+ * is assumed to allow minimal traffic for P2P negotiation, so allow it
+ * here for social channel selection unless explicitly disallowed in the
+ * disallow_list. */
+ if (p2p_channels_includes(chans, 81, 1) ||
+ (freq_range_list_includes(avoid_list, 2412) &&
+ !freq_range_list_includes(disallow_list, 2412)))
chan[num_channels++] = 1;
- if (p2p_channels_includes(chans, 81, 6))
+ if (p2p_channels_includes(chans, 81, 6) ||
+ (freq_range_list_includes(avoid_list, 2437) &&
+ !freq_range_list_includes(disallow_list, 2437)))
chan[num_channels++] = 6;
- if (p2p_channels_includes(chans, 81, 11))
+ if (p2p_channels_includes(chans, 81, 11) ||
+ (freq_range_list_includes(avoid_list, 2462) &&
+ !freq_range_list_includes(disallow_list, 2462)))
chan[num_channels++] = 11;
/* Try to find available social channels from 60 GHz */
diff --git a/contrib/wpa/src/pae/ieee802_1x_cp.c b/contrib/wpa/src/pae/ieee802_1x_cp.c
index cf43c59..1c4dc3e 100644
--- a/contrib/wpa/src/pae/ieee802_1x_cp.c
+++ b/contrib/wpa/src/pae/ieee802_1x_cp.c
@@ -20,7 +20,7 @@
#define STATE_MACHINE_DATA struct ieee802_1x_cp_sm
#define STATE_MACHINE_DEBUG_PREFIX "CP"
-static u8 default_cs_id[] = CS_ID_GCM_AES_128;
+static u64 default_cs_id = CS_ID_GCM_AES_128;
/* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
@@ -38,14 +38,12 @@ struct ieee802_1x_cp_sm {
/* Logon -> CP */
enum connect_type connect;
- u8 *authorization_data;
/* KaY -> CP */
Boolean chgd_server; /* clear by CP */
Boolean elected_self;
- u8 *authorization_data1;
enum confidentiality_offset cipher_offset;
- u8 *cipher_suite;
+ u64 cipher_suite;
Boolean new_sak; /* clear by CP */
struct ieee802_1x_mka_ki distributed_ki;
u8 distributed_an;
@@ -71,7 +69,7 @@ struct ieee802_1x_cp_sm {
Boolean replay_protect;
u32 replay_window;
- u8 *current_cipher_suite;
+ u64 current_cipher_suite;
enum confidentiality_offset confidentiality_offset;
Boolean controlled_port_enabled;
@@ -97,8 +95,7 @@ static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx,
static int changed_cipher(struct ieee802_1x_cp_sm *sm)
{
return sm->confidentiality_offset != sm->cipher_offset ||
- os_memcmp(sm->current_cipher_suite, sm->cipher_suite,
- CS_ID_LEN) != 0;
+ sm->current_cipher_suite != sm->cipher_suite;
}
@@ -160,6 +157,7 @@ SM_STATE(CP, ALLOWED)
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -178,6 +176,7 @@ SM_STATE(CP, AUTHENTICATED)
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -185,21 +184,17 @@ SM_STATE(CP, AUTHENTICATED)
SM_STATE(CP, SECURED)
{
- struct ieee802_1x_cp_conf conf;
-
SM_ENTRY(CP, SECURED);
sm->chgd_server = FALSE;
- ieee802_1x_kay_cp_conf(sm->kay, &conf);
- sm->protect_frames = conf.protect;
- sm->replay_protect = conf.replay_protect;
- sm->validate_frames = conf.validate;
+ sm->protect_frames = sm->kay->macsec_protect;
+ sm->replay_protect = sm->kay->macsec_replay_protect;
+ sm->validate_frames = sm->kay->macsec_validate;
- /* NOTE: now no other than default cipher suiter(AES-GCM-128) */
- os_memcpy(sm->current_cipher_suite, sm->cipher_suite, CS_ID_LEN);
- secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite,
- CS_ID_LEN);
+ /* NOTE: now no other than default cipher suite (AES-GCM-128) */
+ sm->current_cipher_suite = sm->cipher_suite;
+ secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
sm->confidentiality_offset = sm->cipher_offset;
@@ -208,6 +203,7 @@ SM_STATE(CP, SECURED)
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -218,6 +214,10 @@ SM_STATE(CP, RECEIVE)
SM_ENTRY(CP, RECEIVE);
/* RECEIVE state machine not keep with Figure 12-2 in
* IEEE Std 802.1X-2010 */
+ if (sm->oki) {
+ ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ os_free(sm->oki);
+ }
sm->oki = sm->lki;
sm->oan = sm->lan;
sm->otx = sm->ltx;
@@ -322,8 +322,11 @@ SM_STATE(CP, RETIRE)
SM_ENTRY(CP, RETIRE);
/* RETIRE state machine not keep with Figure 12-2 in
* IEEE Std 802.1X-2010 */
- os_free(sm->oki);
- sm->oki = NULL;
+ if (sm->oki) {
+ ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ os_free(sm->oki);
+ sm->oki = NULL;
+ }
sm->orx = FALSE;
sm->otx = FALSE;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
@@ -385,7 +388,8 @@ SM_STEP(CP)
if (!sm->elected_self)
SM_ENTER(CP, READY);
if (sm->elected_self &&
- (sm->all_receiving || !sm->transmit_when))
+ (sm->all_receiving || !sm->controlled_port_enabled ||
+ !sm->transmit_when))
SM_ENTER(CP, TRANSMIT);
break;
@@ -408,8 +412,8 @@ SM_STEP(CP)
case CP_READY:
if (sm->new_sak || changed_connect(sm))
- SM_ENTER(CP, RECEIVE);
- if (sm->server_transmitting)
+ SM_ENTER(CP, ABANDON);
+ if (sm->server_transmitting || !sm->controlled_port_enabled)
SM_ENTER(CP, TRANSMIT);
break;
case CP_ABANDON:
@@ -428,9 +432,7 @@ SM_STEP(CP)
/**
* ieee802_1x_cp_sm_init -
*/
-struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(
- struct ieee802_1x_kay *kay,
- struct ieee802_1x_cp_conf *pcp_conf)
+struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay)
{
struct ieee802_1x_cp_sm *sm;
@@ -446,10 +448,10 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(
sm->chgd_server = FALSE;
- sm->protect_frames = pcp_conf->protect;
- sm->validate_frames = pcp_conf->validate;
- sm->replay_protect = pcp_conf->replay_protect;
- sm->replay_window = pcp_conf->replay_window;
+ sm->protect_frames = kay->macsec_protect;
+ sm->validate_frames = kay->macsec_validate;
+ sm->replay_protect = kay->macsec_replay_protect;
+ sm->replay_window = kay->macsec_replay_window;
sm->controlled_port_enabled = FALSE;
@@ -460,35 +462,25 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(
sm->orx = FALSE;
sm->otx = FALSE;
- sm->cipher_suite = os_zalloc(CS_ID_LEN);
- sm->current_cipher_suite = os_zalloc(CS_ID_LEN);
- if (!sm->cipher_suite || !sm->current_cipher_suite) {
- wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__);
- os_free(sm->cipher_suite);
- os_free(sm->current_cipher_suite);
- os_free(sm);
- return NULL;
- }
- os_memcpy(sm->current_cipher_suite, default_cs_id, CS_ID_LEN);
- os_memcpy(sm->cipher_suite, default_cs_id, CS_ID_LEN);
+ sm->current_cipher_suite = default_cs_id;
+ sm->cipher_suite = default_cs_id;
sm->cipher_offset = CONFIDENTIALITY_OFFSET_0;
sm->confidentiality_offset = sm->cipher_offset;
sm->transmit_delay = MKA_LIFE_TIME;
sm->retire_delay = MKA_SAK_RETIRE_TIME;
sm->CP_state = CP_BEGIN;
sm->changed = FALSE;
- sm->authorization_data = NULL;
wpa_printf(MSG_DEBUG, "CP: state machine created");
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
- SM_ENTER(CP, INIT);
SM_STEP_RUN(CP);
return sm;
@@ -530,9 +522,6 @@ void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm)
eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
os_free(sm->lki);
os_free(sm->oki);
- os_free(sm->cipher_suite);
- os_free(sm->current_cipher_suite);
- os_free(sm->authorization_data);
os_free(sm);
}
@@ -603,25 +592,12 @@ void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status)
/**
- * ieee802_1x_cp_set_authorizationdata -
- */
-void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len)
-{
- struct ieee802_1x_cp_sm *sm = cp_ctx;
- os_free(sm->authorization_data);
- sm->authorization_data = os_zalloc(len);
- if (sm->authorization_data)
- os_memcpy(sm->authorization_data, pdata, len);
-}
-
-
-/**
* ieee802_1x_cp_set_ciphersuite -
*/
-void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, void *pid)
+void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
- os_memcpy(sm->cipher_suite, pid, CS_ID_LEN);
+ sm->cipher_suite = cs;
}
diff --git a/contrib/wpa/src/pae/ieee802_1x_cp.h b/contrib/wpa/src/pae/ieee802_1x_cp.h
index 773c930..a357b27 100644
--- a/contrib/wpa/src/pae/ieee802_1x_cp.h
+++ b/contrib/wpa/src/pae/ieee802_1x_cp.h
@@ -16,17 +16,7 @@ struct ieee802_1x_cp_sm;
struct ieee802_1x_kay;
struct ieee802_1x_mka_ki;
-struct ieee802_1x_cp_conf {
- Boolean protect;
- Boolean replay_protect;
- enum validate_frames validate;
- u32 replay_window;
-};
-
-
-struct ieee802_1x_cp_sm *
-ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay,
- struct ieee802_1x_cp_conf *pcp_conf);
+struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay);
void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm);
void ieee802_1x_cp_sm_step(void *cp_ctx);
void ieee802_1x_cp_connect_pending(void *cp_ctx);
@@ -35,8 +25,7 @@ void ieee802_1x_cp_connect_authenticated(void *cp_ctx);
void ieee802_1x_cp_connect_secure(void *cp_ctx);
void ieee802_1x_cp_signal_chgdserver(void *cp_ctx);
void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len);
-void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, void *pid);
+void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs);
void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset);
void ieee802_1x_cp_signal_newsak(void *cp_ctx);
void ieee802_1x_cp_set_distributedki(void *cp_ctx,
diff --git a/contrib/wpa/src/pae/ieee802_1x_kay.c b/contrib/wpa/src/pae/ieee802_1x_kay.c
index ef74430..b4455c8 100644
--- a/contrib/wpa/src/pae/ieee802_1x_kay.c
+++ b/contrib/wpa/src/pae/ieee802_1x_kay.c
@@ -1,5 +1,5 @@
/*
- * IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
+ * IEEE 802.1X-2010 Key Agreement Protocol of PAE state machine
* Copyright (c) 2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
@@ -27,8 +27,13 @@
#define DEFAULT_ICV_LEN 16
#define MAX_ICV_LEN 32 /* 32 bytes, 256 bits */
+#define MAX_MISSING_SAK_USE 10 /* Accept up to 10 inbound MKPDUs without
+ * SAK-USE before dropping */
+
#define PENDING_PN_EXHAUSTION 0xC0000000
+#define MKA_ALIGN_LENGTH(len) (((len) + 0x3) & ~0x3)
+
/* IEEE Std 802.1X-2010, Table 9-1 - MKA Algorithm Agility */
#define MKA_ALGO_AGILITY_2009 { 0x00, 0x80, 0xC2, 0x01 }
static u8 mka_algo_agility[4] = MKA_ALGO_AGILITY_2009;
@@ -37,12 +42,17 @@ static u8 mka_algo_agility[4] = MKA_ALGO_AGILITY_2009;
static struct macsec_ciphersuite cipher_suite_tbl[] = {
/* GCM-AES-128 */
{
- CS_ID_GCM_AES_128,
- CS_NAME_GCM_AES_128,
- MACSEC_CAP_INTEG_AND_CONF_0_30_50,
- 16,
-
- 0 /* index */
+ .id = CS_ID_GCM_AES_128,
+ .name = CS_NAME_GCM_AES_128,
+ .capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
+ .sak_len = DEFAULT_SA_KEY_LEN,
+ },
+ /* GCM-AES-256 */
+ {
+ .id = CS_ID_GCM_AES_256,
+ .name = CS_NAME_GCM_AES_256,
+ .capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
+ .sak_len = 32,
},
};
#define CS_TABLE_SIZE (ARRAY_SIZE(cipher_suite_tbl))
@@ -50,16 +60,15 @@ static struct macsec_ciphersuite cipher_suite_tbl[] = {
static struct mka_alg mka_alg_tbl[] = {
{
- MKA_ALGO_AGILITY_2009,
- /* 128-bit CAK, KEK, ICK, ICV */
- 16, 16, 16, 16,
- ieee802_1x_cak_128bits_aes_cmac,
- ieee802_1x_ckn_128bits_aes_cmac,
- ieee802_1x_kek_128bits_aes_cmac,
- ieee802_1x_ick_128bits_aes_cmac,
- ieee802_1x_icv_128bits_aes_cmac,
-
- 1, /* index */
+ .parameter = MKA_ALGO_AGILITY_2009,
+
+ .icv_len = DEFAULT_ICV_LEN,
+
+ .cak_trfm = ieee802_1x_cak_aes_cmac,
+ .ckn_trfm = ieee802_1x_ckn_aes_cmac,
+ .kek_trfm = ieee802_1x_kek_aes_cmac,
+ .ick_trfm = ieee802_1x_ick_aes_cmac,
+ .icv_hash = ieee802_1x_icv_aes_cmac,
},
};
#define MKA_ALG_TABLE_SIZE (ARRAY_SIZE(mka_alg_tbl))
@@ -73,16 +82,6 @@ static int is_ki_equal(struct ieee802_1x_mka_ki *ki1,
}
-struct mka_param_body_handler {
- int (*body_tx)(struct ieee802_1x_mka_participant *participant,
- struct wpabuf *buf);
- int (*body_rx)(struct ieee802_1x_mka_participant *participant,
- const u8 *mka_msg, size_t msg_len);
- int (*body_length)(struct ieee802_1x_mka_participant *participant);
- Boolean (*body_present)(struct ieee802_1x_mka_participant *participant);
-};
-
-
static void set_mka_param_body_len(void *body, unsigned int len)
{
struct ieee802_1x_mka_hdr *hdr = body;
@@ -98,13 +97,41 @@ static unsigned int get_mka_param_body_len(const void *body)
}
-static int get_mka_param_body_type(const void *body)
+static u8 get_mka_param_body_type(const void *body)
{
const struct ieee802_1x_mka_hdr *hdr = body;
return hdr->type;
}
+static const char * mi_txt(const u8 *mi)
+{
+ static char txt[MI_LEN * 2 + 1];
+
+ wpa_snprintf_hex(txt, sizeof(txt), mi, MI_LEN);
+ return txt;
+}
+
+
+static const char * sci_txt(const struct ieee802_1x_mka_sci *sci)
+{
+ static char txt[ETH_ALEN * 3 + 1 + 5 + 1];
+
+ os_snprintf(txt, sizeof(txt), MACSTR "@%u",
+ MAC2STR(sci->addr), be_to_host16(sci->port));
+ return txt;
+}
+
+
+static const char * algo_agility_txt(const u8 *algo_agility)
+{
+ static char txt[4 * 2 + 1];
+
+ wpa_snprintf_hex(txt, sizeof(txt), algo_agility, 4);
+ return txt;
+}
+
+
/**
* ieee802_1x_mka_dump_basic_body -
*/
@@ -116,26 +143,25 @@ ieee802_1x_mka_dump_basic_body(struct ieee802_1x_mka_basic_body *body)
if (!body)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-8 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_DEBUG, "*** MKA Basic Parameter set ***");
- wpa_printf(MSG_DEBUG, "\tVersion.......: %d", body->version);
- wpa_printf(MSG_DEBUG, "\tPriority......: %d", body->priority);
- wpa_printf(MSG_DEBUG, "\tKeySvr........: %d", body->key_server);
- wpa_printf(MSG_DEBUG, "\tMACSecDesired.: %d", body->macsec_desired);
- wpa_printf(MSG_DEBUG, "\tMACSecCapable.: %d", body->macsec_capbility);
- wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
- wpa_printf(MSG_DEBUG, "\tSCI MAC.......: " MACSTR,
- MAC2STR(body->actor_sci.addr));
- wpa_printf(MSG_DEBUG, "\tSCI Port .....: %d",
- be_to_host16(body->actor_sci.port));
- wpa_hexdump(MSG_DEBUG, "\tMember Id.....:",
- body->actor_mi, sizeof(body->actor_mi));
- wpa_printf(MSG_DEBUG, "\tMessage Number: %d",
+ wpa_printf(MSG_DEBUG, "MKA Basic Parameter Set");
+ wpa_printf(MSG_DEBUG, "\tMKA Version Identifier: %d", body->version);
+ wpa_printf(MSG_DEBUG, "\tKey Server Priority: %d", body->priority);
+ wpa_printf(MSG_DEBUG, "\tKey Server: %d", body->key_server);
+ wpa_printf(MSG_DEBUG, "\tMACsec Desired: %d", body->macsec_desired);
+ wpa_printf(MSG_DEBUG, "\tMACsec Capability: %d",
+ body->macsec_capability);
+ wpa_printf(MSG_DEBUG, "\tParameter set body length: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "\tSCI: %s", sci_txt(&body->actor_sci));
+ wpa_printf(MSG_DEBUG, "\tActor's Member Identifier: %s",
+ mi_txt(body->actor_mi));
+ wpa_printf(MSG_DEBUG, "\tActor's Message Number: %d",
be_to_host32(body->actor_mn));
- wpa_hexdump(MSG_DEBUG, "\tAlgo Agility..:",
- body->algo_agility, sizeof(body->algo_agility));
- wpa_hexdump_ascii(MSG_DEBUG, "\tCAK Name......:", body->ckn,
- body_len + MKA_HDR_LEN - sizeof(*body));
+ wpa_printf(MSG_DEBUG, "\tAlgorithm Agility: %s",
+ algo_agility_txt(body->algo_agility));
+ wpa_hexdump(MSG_DEBUG, "\tCAK Name", body->ckn,
+ body_len + MKA_HDR_LEN - sizeof(*body));
}
@@ -148,25 +174,26 @@ ieee802_1x_mka_dump_peer_body(struct ieee802_1x_mka_peer_body *body)
size_t body_len;
size_t i;
u8 *mi;
- u32 mn;
+ be32 mn;
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-9 */
body_len = get_mka_param_body_len(body);
if (body->type == MKA_LIVE_PEER_LIST) {
- wpa_printf(MSG_DEBUG, "*** Live Peer List ***");
- wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
+ wpa_printf(MSG_DEBUG, "Live Peer List parameter set");
+ wpa_printf(MSG_DEBUG, "\tBody Length: %zu", body_len);
} else if (body->type == MKA_POTENTIAL_PEER_LIST) {
- wpa_printf(MSG_DEBUG, "*** Potential Live Peer List ***");
- wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
+ wpa_printf(MSG_DEBUG, "Potential Peer List parameter set");
+ wpa_printf(MSG_DEBUG, "\tBody Length: %zu", body_len);
}
for (i = 0; i < body_len; i += MI_LEN + sizeof(mn)) {
mi = body->peer + i;
os_memcpy(&mn, mi + MI_LEN, sizeof(mn));
- wpa_hexdump_ascii(MSG_DEBUG, "\tMember Id.....:", mi, MI_LEN);
- wpa_printf(MSG_DEBUG, "\tMessage Number: %d", be_to_host32(mn));
+ wpa_printf(MSG_DEBUG, "\tMember Id: %s Message Number: %d",
+ mi_txt(mi), be_to_host32(mn));
}
}
@@ -182,18 +209,20 @@ ieee802_1x_mka_dump_dist_sak_body(struct ieee802_1x_mka_dist_sak_body *body)
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-11 and 11-12 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_INFO, "*** Distributed SAK ***");
- wpa_printf(MSG_INFO, "\tDistributed AN........: %d", body->dan);
- wpa_printf(MSG_INFO, "\tConfidentiality Offset: %d",
+ wpa_printf(MSG_DEBUG, "Distributed SAK parameter set");
+ wpa_printf(MSG_DEBUG, "\tDistributed AN........: %d", body->dan);
+ wpa_printf(MSG_DEBUG, "\tConfidentiality Offset: %d",
body->confid_offset);
- wpa_printf(MSG_INFO, "\tBody Length...........: %d", (int) body_len);
+ wpa_printf(MSG_DEBUG, "\tBody Length...........: %zu", body_len);
if (!body_len)
return;
- wpa_printf(MSG_INFO, "\tKey Number............: %d",
+ wpa_printf(MSG_DEBUG, "\tKey Number............: %d",
be_to_host32(body->kn));
- wpa_hexdump(MSG_INFO, "\tAES Key Wrap of SAK...:", body->sak, 24);
+ /* TODO: Other than GCM-AES-128 case: MACsec Cipher Suite */
+ wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", body->sak, 24);
}
@@ -214,33 +243,32 @@ ieee802_1x_mka_dump_sak_use_body(struct ieee802_1x_mka_sak_use_body *body)
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-10 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_DEBUG, "*** MACsec SAK Use ***");
+ wpa_printf(MSG_DEBUG, "MACsec SAK Use parameter set");
wpa_printf(MSG_DEBUG, "\tLatest Key AN....: %d", body->lan);
wpa_printf(MSG_DEBUG, "\tLatest Key Tx....: %s", yes_no(body->ltx));
wpa_printf(MSG_DEBUG, "\tLatest Key Rx....: %s", yes_no(body->lrx));
- wpa_printf(MSG_DEBUG, "\tOld Key AN....: %d", body->oan);
- wpa_printf(MSG_DEBUG, "\tOld Key Tx....: %s", yes_no(body->otx));
- wpa_printf(MSG_DEBUG, "\tOld Key Rx....: %s", yes_no(body->orx));
- wpa_printf(MSG_DEBUG, "\tPlain Key Tx....: %s", yes_no(body->ptx));
- wpa_printf(MSG_DEBUG, "\tPlain Key Rx....: %s", yes_no(body->prx));
+ wpa_printf(MSG_DEBUG, "\tOld Key AN.......: %d", body->oan);
+ wpa_printf(MSG_DEBUG, "\tOld Key Tx.......: %s", yes_no(body->otx));
+ wpa_printf(MSG_DEBUG, "\tOld Key Rx.......: %s", yes_no(body->orx));
+ wpa_printf(MSG_DEBUG, "\tPlain Tx.........: %s", yes_no(body->ptx));
+ wpa_printf(MSG_DEBUG, "\tPlain Rx.........: %s", yes_no(body->prx));
wpa_printf(MSG_DEBUG, "\tDelay Protect....: %s",
yes_no(body->delay_protect));
wpa_printf(MSG_DEBUG, "\tBody Length......: %d", body_len);
if (!body_len)
return;
- wpa_hexdump(MSG_DEBUG, "\tKey Server MI....:",
- body->lsrv_mi, sizeof(body->lsrv_mi));
+ wpa_printf(MSG_DEBUG, "\tKey Server MI....: %s", mi_txt(body->lsrv_mi));
wpa_printf(MSG_DEBUG, "\tKey Number.......: %u",
be_to_host32(body->lkn));
wpa_printf(MSG_DEBUG, "\tLowest PN........: %u",
be_to_host32(body->llpn));
- wpa_hexdump_ascii(MSG_DEBUG, "\tOld Key Server MI....:",
- body->osrv_mi, sizeof(body->osrv_mi));
- wpa_printf(MSG_DEBUG, "\tOld Key Number.......: %u",
+ wpa_printf(MSG_DEBUG, "\tOld Key Server MI: %s", mi_txt(body->osrv_mi));
+ wpa_printf(MSG_DEBUG, "\tOld Key Number...: %u",
be_to_host32(body->okn));
- wpa_printf(MSG_DEBUG, "\tOld Lowest PN........: %u",
+ wpa_printf(MSG_DEBUG, "\tOld Lowest PN....: %u",
be_to_host32(body->olpn));
}
@@ -249,13 +277,15 @@ ieee802_1x_mka_dump_sak_use_body(struct ieee802_1x_mka_sak_use_body *body)
* ieee802_1x_kay_get_participant -
*/
static struct ieee802_1x_mka_participant *
-ieee802_1x_kay_get_participant(struct ieee802_1x_kay *kay, const u8 *ckn)
+ieee802_1x_kay_get_participant(struct ieee802_1x_kay *kay, const u8 *ckn,
+ size_t len)
{
struct ieee802_1x_mka_participant *participant;
dl_list_for_each(participant, &kay->participant_list,
struct ieee802_1x_mka_participant, list) {
- if (os_memcmp(participant->ckn.name, ckn,
+ if (participant->ckn.len == len &&
+ os_memcmp(participant->ckn.name, ckn,
participant->ckn.len) == 0)
return participant;
}
@@ -280,7 +310,7 @@ ieee802_1x_kay_get_principal_participant(struct ieee802_1x_kay *kay)
return participant;
}
- wpa_printf(MSG_DEBUG, "KaY: principal participant is not founded");
+ wpa_printf(MSG_DEBUG, "KaY: principal participant is not found");
return NULL;
}
@@ -300,36 +330,46 @@ static struct ieee802_1x_kay_peer * get_peer_mi(struct dl_list *peers,
/**
- * ieee802_1x_kay_is_in_potential_peer
+ * ieee802_1x_kay_get_potential_peer
*/
-static Boolean
-ieee802_1x_kay_is_in_potential_peer(
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_get_potential_peer(
struct ieee802_1x_mka_participant *participant, const u8 *mi)
{
- return get_peer_mi(&participant->potential_peers, mi) != NULL;
+ return get_peer_mi(&participant->potential_peers, mi);
}
/**
- * ieee802_1x_kay_is_in_live_peer
+ * ieee802_1x_kay_get_live_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_get_live_peer(struct ieee802_1x_mka_participant *participant,
+ const u8 *mi)
+{
+ return get_peer_mi(&participant->live_peers, mi);
+}
+
+
+/**
+ * ieee802_1x_kay_is_in_potential_peer
*/
static Boolean
-ieee802_1x_kay_is_in_live_peer(
+ieee802_1x_kay_is_in_potential_peer(
struct ieee802_1x_mka_participant *participant, const u8 *mi)
{
- return get_peer_mi(&participant->live_peers, mi) != NULL;
+ return ieee802_1x_kay_get_potential_peer(participant, mi) != NULL;
}
/**
- * ieee802_1x_kay_is_in_peer
+ * ieee802_1x_kay_is_in_live_peer
*/
static Boolean
-ieee802_1x_kay_is_in_peer(struct ieee802_1x_mka_participant *participant,
- const u8 *mi)
+ieee802_1x_kay_is_in_live_peer(
+ struct ieee802_1x_mka_participant *participant, const u8 *mi)
{
- return ieee802_1x_kay_is_in_live_peer(participant, mi) ||
- ieee802_1x_kay_is_in_potential_peer(participant, mi);
+ return ieee802_1x_kay_get_live_peer(participant, mi) != NULL;
}
@@ -342,22 +382,11 @@ ieee802_1x_kay_get_peer(struct ieee802_1x_mka_participant *participant,
{
struct ieee802_1x_kay_peer *peer;
- peer = get_peer_mi(&participant->live_peers, mi);
+ peer = ieee802_1x_kay_get_live_peer(participant, mi);
if (peer)
return peer;
- return get_peer_mi(&participant->potential_peers, mi);
-}
-
-
-/**
- * ieee802_1x_kay_get_live_peer
- */
-static struct ieee802_1x_kay_peer *
-ieee802_1x_kay_get_live_peer(struct ieee802_1x_mka_participant *participant,
- const u8 *mi)
-{
- return get_peer_mi(&participant->live_peers, mi);
+ return ieee802_1x_kay_get_potential_peer(participant, mi);
}
@@ -366,18 +395,41 @@ ieee802_1x_kay_get_live_peer(struct ieee802_1x_mka_participant *participant,
*/
static struct macsec_ciphersuite *
ieee802_1x_kay_get_cipher_suite(struct ieee802_1x_mka_participant *participant,
- u8 *cs_id)
+ const u8 *cs_id, unsigned int *idx)
{
unsigned int i;
+ u64 cs;
+ be64 _cs;
+
+ os_memcpy(&_cs, cs_id, CS_ID_LEN);
+ cs = be_to_host64(_cs);
for (i = 0; i < CS_TABLE_SIZE; i++) {
- if (os_memcmp(cipher_suite_tbl[i].id, cs_id, CS_ID_LEN) == 0)
- break;
+ if (cipher_suite_tbl[i].id == cs) {
+ *idx = i;
+ return &cipher_suite_tbl[i];
+ }
}
- if (i >= CS_TABLE_SIZE)
- return NULL;
- return &cipher_suite_tbl[i];
+ return NULL;
+}
+
+
+u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci)
+{
+ struct ieee802_1x_mka_sci tmp;
+
+ os_memcpy(tmp.addr, sci->addr, ETH_ALEN);
+ tmp.port = sci->port;
+
+ return *((u64 *) &tmp);
+}
+
+
+static Boolean sci_equal(const struct ieee802_1x_mka_sci *a,
+ const struct ieee802_1x_mka_sci *b)
+{
+ return os_memcmp(a, b, sizeof(struct ieee802_1x_mka_sci)) == 0;
}
@@ -392,13 +444,13 @@ ieee802_1x_kay_get_peer_sci(struct ieee802_1x_mka_participant *participant,
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
- if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
+ if (sci_equal(&peer->sci, sci))
return peer;
}
dl_list_for_each(peer, &participant->potential_peers,
struct ieee802_1x_kay_peer, list) {
- if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
+ if (sci_equal(&peer->sci, sci))
return peer;
}
@@ -406,6 +458,8 @@ ieee802_1x_kay_get_peer_sci(struct ieee802_1x_mka_participant *participant,
}
+static void ieee802_1x_kay_use_data_key(struct data_key *pkey);
+
/**
* ieee802_1x_kay_init_receive_sa -
*/
@@ -424,6 +478,7 @@ ieee802_1x_kay_init_receive_sa(struct receive_sc *psc, u8 an, u32 lowest_pn,
return NULL;
}
+ ieee802_1x_kay_use_data_key(key);
psa->pkey = key;
psa->lowest_pn = lowest_pn;
psa->next_pn = lowest_pn;
@@ -435,22 +490,25 @@ ieee802_1x_kay_init_receive_sa(struct receive_sc *psc, u8 an, u32 lowest_pn,
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
- "KaY: Create receive SA(AN: %d lowest_pn: %u of SC(channel: %d)",
- (int) an, lowest_pn, psc->channel);
+ "KaY: Create receive SA(an: %hhu lowest_pn: %u) of SC",
+ an, lowest_pn);
return psa;
}
+static void ieee802_1x_kay_deinit_data_key(struct data_key *pkey);
+
/**
* ieee802_1x_kay_deinit_receive_sa -
*/
static void ieee802_1x_kay_deinit_receive_sa(struct receive_sa *psa)
{
+ ieee802_1x_kay_deinit_data_key(psa->pkey);
psa->pkey = NULL;
wpa_printf(MSG_DEBUG,
- "KaY: Delete receive SA(an: %d) of SC(channel: %d)",
- psa->an, psa->sc->channel);
+ "KaY: Delete receive SA(an: %hhu) of SC",
+ psa->an);
dl_list_del(&psa->list);
os_free(psa);
}
@@ -460,8 +518,7 @@ static void ieee802_1x_kay_deinit_receive_sa(struct receive_sa *psa)
* ieee802_1x_kay_init_receive_sc -
*/
static struct receive_sc *
-ieee802_1x_kay_init_receive_sc(const struct ieee802_1x_mka_sci *psci,
- int channel)
+ieee802_1x_kay_init_receive_sc(const struct ieee802_1x_mka_sci *psci)
{
struct receive_sc *psc;
@@ -475,19 +532,27 @@ ieee802_1x_kay_init_receive_sc(const struct ieee802_1x_mka_sci *psci,
}
os_memcpy(&psc->sci, psci, sizeof(psc->sci));
- psc->channel = channel;
os_get_time(&psc->created_time);
psc->receiving = FALSE;
dl_list_init(&psc->sa_list);
- wpa_printf(MSG_DEBUG, "KaY: Create receive SC(channel: %d)", channel);
- wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)psci, sizeof(*psci));
+ wpa_printf(MSG_DEBUG, "KaY: Create receive SC: SCI %s",
+ sci_txt(&psc->sci));
return psc;
}
+static void ieee802_1x_delete_receive_sa(struct ieee802_1x_kay *kay,
+ struct receive_sa *sa)
+{
+ secy_disable_receive_sa(kay, sa);
+ secy_delete_receive_sa(kay, sa);
+ ieee802_1x_kay_deinit_receive_sa(sa);
+}
+
+
/**
* ieee802_1x_kay_deinit_receive_sc -
**/
@@ -497,31 +562,31 @@ ieee802_1x_kay_deinit_receive_sc(
{
struct receive_sa *psa, *pre_sa;
- wpa_printf(MSG_DEBUG, "KaY: Delete receive SC(channel: %d)",
- psc->channel);
+ wpa_printf(MSG_DEBUG, "KaY: Delete receive SC");
dl_list_for_each_safe(psa, pre_sa, &psc->sa_list, struct receive_sa,
- list) {
- secy_disable_receive_sa(participant->kay, psa);
- ieee802_1x_kay_deinit_receive_sa(psa);
- }
+ list)
+ ieee802_1x_delete_receive_sa(participant->kay, psa);
+
dl_list_del(&psc->list);
+ secy_delete_receive_sc(participant->kay, psc);
os_free(psc);
}
-/**
- * ieee802_1x_kay_create_live_peer
- */
+static void ieee802_1x_kay_dump_peer(struct ieee802_1x_kay_peer *peer)
+{
+ wpa_printf(MSG_DEBUG, "\tMI: %s MN: %d SCI: %s",
+ mi_txt(peer->mi), peer->mn, sci_txt(&peer->sci));
+}
+
+
static struct ieee802_1x_kay_peer *
-ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
- u8 *mi, u32 mn)
+ieee802_1x_kay_create_peer(const u8 *mi, u32 mn)
{
struct ieee802_1x_kay_peer *peer;
- struct receive_sc *rxsc;
- u32 sc_ch = 0;
peer = os_zalloc(sizeof(*peer));
- if (peer == NULL) {
+ if (!peer) {
wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
return NULL;
}
@@ -530,24 +595,45 @@ ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
peer->sak_used = FALSE;
+ peer->missing_sak_use_count = 0;
+
+ return peer;
+}
+
+
+/**
+ * ieee802_1x_kay_create_live_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
+ const u8 *mi, u32 mn)
+{
+ struct ieee802_1x_kay_peer *peer;
+ struct receive_sc *rxsc;
+
+ peer = ieee802_1x_kay_create_peer(mi, mn);
+ if (!peer)
+ return NULL;
+
os_memcpy(&peer->sci, &participant->current_peer_sci,
sizeof(peer->sci));
- dl_list_add(&participant->live_peers, &peer->list);
-
- secy_get_available_receive_sc(participant->kay, &sc_ch);
- rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
- if (!rxsc)
+ rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci);
+ if (!rxsc) {
+ os_free(peer);
return NULL;
+ }
+ if (secy_create_receive_sc(participant->kay, rxsc)) {
+ os_free(rxsc);
+ os_free(peer);
+ return NULL;
+ }
+ dl_list_add(&participant->live_peers, &peer->list);
dl_list_add(&participant->rxsc_list, &rxsc->list);
- secy_create_receive_sc(participant->kay, rxsc);
wpa_printf(MSG_DEBUG, "KaY: Live peer created");
- wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
- wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
- wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
- wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+ ieee802_1x_kay_dump_peer(peer);
return peer;
}
@@ -562,24 +648,14 @@ ieee802_1x_kay_create_potential_peer(
{
struct ieee802_1x_kay_peer *peer;
- peer = os_zalloc(sizeof(*peer));
- if (peer == NULL) {
- wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
+ peer = ieee802_1x_kay_create_peer(mi, mn);
+ if (!peer)
return NULL;
- }
-
- os_memcpy(peer->mi, mi, MI_LEN);
- peer->mn = mn;
- peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
- peer->sak_used = FALSE;
dl_list_add(&participant->potential_peers, &peer->list);
- wpa_printf(MSG_DEBUG, "KaY: potential peer created");
- wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
- wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
- wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
- wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+ wpa_printf(MSG_DEBUG, "KaY: Potential peer created");
+ ieee802_1x_kay_dump_peer(peer);
return peer;
}
@@ -594,36 +670,33 @@ ieee802_1x_kay_move_live_peer(struct ieee802_1x_mka_participant *participant,
{
struct ieee802_1x_kay_peer *peer;
struct receive_sc *rxsc;
- u32 sc_ch = 0;
- dl_list_for_each(peer, &participant->potential_peers,
- struct ieee802_1x_kay_peer, list) {
- if (os_memcmp(peer->mi, mi, MI_LEN) == 0)
- break;
- }
+ peer = ieee802_1x_kay_get_potential_peer(participant, mi);
+ if (!peer)
+ return NULL;
+
+ rxsc = ieee802_1x_kay_init_receive_sc(&participant->current_peer_sci);
+ if (!rxsc)
+ return NULL;
os_memcpy(&peer->sci, &participant->current_peer_sci,
sizeof(peer->sci));
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
- wpa_printf(MSG_DEBUG, "KaY: move potential peer to live peer");
- wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
- wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
- wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
- wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+ wpa_printf(MSG_DEBUG, "KaY: Move potential peer to live peer");
+ ieee802_1x_kay_dump_peer(peer);
dl_list_del(&peer->list);
- dl_list_add_tail(&participant->live_peers, &peer->list);
-
- secy_get_available_receive_sc(participant->kay, &sc_ch);
-
- rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
- if (!rxsc)
+ if (secy_create_receive_sc(participant->kay, rxsc)) {
+ wpa_printf(MSG_ERROR, "KaY: Can't create SC, discard peer");
+ os_free(rxsc);
+ os_free(peer);
return NULL;
+ }
+ dl_list_add_tail(&participant->live_peers, &peer->list);
dl_list_add(&participant->rxsc_list, &rxsc->list);
- secy_create_receive_sc(participant->kay, rxsc);
return peer;
}
@@ -651,7 +724,7 @@ ieee802_1x_mka_basic_body_length(struct ieee802_1x_mka_participant *participant)
length = sizeof(struct ieee802_1x_mka_basic_body);
length += participant->ckn.len;
- return (length + 0x3) & ~0x3;
+ return MKA_ALIGN_LENGTH(length);
}
@@ -665,29 +738,32 @@ ieee802_1x_mka_encode_basic_body(
{
struct ieee802_1x_mka_basic_body *body;
struct ieee802_1x_kay *kay = participant->kay;
- unsigned int length = ieee802_1x_mka_basic_body_length(participant);
+ unsigned int length = sizeof(struct ieee802_1x_mka_basic_body);
- body = wpabuf_put(buf, length);
+ length += participant->ckn.len;
+ body = wpabuf_put(buf, MKA_ALIGN_LENGTH(length));
body->version = kay->mka_version;
body->priority = kay->actor_priority;
+ /* The Key Server flag is set if and only if the participant has not
+ * decided that another participant is or will be the Key Server. */
if (participant->is_elected)
body->key_server = participant->is_key_server;
else
body->key_server = participant->can_be_key_server;
body->macsec_desired = kay->macsec_desired;
- body->macsec_capbility = kay->macsec_capable;
+ body->macsec_capability = kay->macsec_capable;
set_mka_param_body_len(body, length - MKA_HDR_LEN);
os_memcpy(body->actor_sci.addr, kay->actor_sci.addr,
sizeof(kay->actor_sci.addr));
- body->actor_sci.port = host_to_be16(kay->actor_sci.port);
+ body->actor_sci.port = kay->actor_sci.port;
os_memcpy(body->actor_mi, participant->mi, sizeof(body->actor_mi));
participant->mn = participant->mn + 1;
body->actor_mn = host_to_be32(participant->mn);
- os_memcpy(body->algo_agility, participant->kay->algo_agility,
+ os_memcpy(body->algo_agility, kay->algo_agility,
sizeof(body->algo_agility));
os_memcpy(body->ckn, participant->ckn.name, participant->ckn.len);
@@ -698,6 +774,17 @@ ieee802_1x_mka_encode_basic_body(
}
+static Boolean
+reset_participant_mi(struct ieee802_1x_mka_participant *participant)
+{
+ if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ return FALSE;
+ participant->mn = 0;
+
+ return TRUE;
+}
+
+
/**
* ieee802_1x_mka_decode_basic_body -
*/
@@ -708,73 +795,110 @@ ieee802_1x_mka_decode_basic_body(struct ieee802_1x_kay *kay, const u8 *mka_msg,
struct ieee802_1x_mka_participant *participant;
const struct ieee802_1x_mka_basic_body *body;
struct ieee802_1x_kay_peer *peer;
+ size_t ckn_len;
+ size_t body_len;
body = (const struct ieee802_1x_mka_basic_body *) mka_msg;
if (body->version > MKA_VERSION_ID) {
wpa_printf(MSG_DEBUG,
- "KaY: peer's version(%d) greater than mka current version(%d)",
+ "KaY: Peer's version(%d) greater than MKA current version(%d)",
body->version, MKA_VERSION_ID);
}
if (kay->is_obliged_key_server && body->key_server) {
- wpa_printf(MSG_DEBUG, "I must be as key server");
+ wpa_printf(MSG_DEBUG, "KaY: I must be key server - ignore MKPDU claiming to be from a key server");
return NULL;
}
- participant = ieee802_1x_kay_get_participant(kay, body->ckn);
+ body_len = get_mka_param_body_len(body);
+ if (body_len < sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN) {
+ wpa_printf(MSG_DEBUG, "KaY: Too small body length %zu",
+ body_len);
+ return NULL;
+ }
+ ckn_len = body_len -
+ (sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN);
+ participant = ieee802_1x_kay_get_participant(kay, body->ckn, ckn_len);
if (!participant) {
- wpa_printf(MSG_DEBUG, "Peer is not included in my CA");
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer is not included in my CA - ignore MKPDU");
return NULL;
}
/* If the peer's MI is my MI, I will choose new MI */
if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
- if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ if (!reset_participant_mi(participant))
return NULL;
- participant->mn = 0;
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer using my MI - selected a new random MI: %s",
+ mi_txt(participant->mi));
}
os_memcpy(participant->current_peer_id.mi, body->actor_mi, MI_LEN);
- participant->current_peer_id.mn = be_to_host32(body->actor_mn);
+ participant->current_peer_id.mn = body->actor_mn;
os_memcpy(participant->current_peer_sci.addr, body->actor_sci.addr,
sizeof(participant->current_peer_sci.addr));
- participant->current_peer_sci.port = be_to_host16(body->actor_sci.port);
+ participant->current_peer_sci.port = body->actor_sci.port;
/* handler peer */
peer = ieee802_1x_kay_get_peer(participant, body->actor_mi);
if (!peer) {
- /* Check duplicated SCI */
- /* TODO: What policy should be applied to detect duplicated SCI
- * is active attacker or a valid peer whose MI is be changed?
+ /* Check duplicated SCI
+ *
+ * A duplicated SCI indicates either an active attacker or
+ * a valid peer whose MI is being changed. The latter scenario
+ * is more likely because to have gotten this far the received
+ * MKPDU must have had a valid ICV, indicating the peer holds
+ * the same CAK as our participant.
+ *
+ * Before creating a new peer object for the new MI we must
+ * clean up the resources (SCs and SAs) associated with the
+ * old peer. An easy way to do this is to ignore MKPDUs with
+ * the new MI's for now and just wait for the old peer to
+ * time out and clean itself up (within MKA_LIFE_TIME).
+ *
+ * This method is preferable to deleting the old peer here
+ * and now and continuing on with processing because if this
+ * MKPDU is from an attacker it's better to ignore the MKPDU
+ * than to process it (and delete a valid peer as well).
*/
peer = ieee802_1x_kay_get_peer_sci(participant,
&body->actor_sci);
if (peer) {
+ time_t new_expire;
+
wpa_printf(MSG_WARNING,
- "KaY: duplicated SCI detected, Maybe active attacker");
- dl_list_del(&peer->list);
- os_free(peer);
+ "KaY: duplicated SCI detected - maybe active attacker or peer selected new MI - ignore MKPDU");
+ /* Reduce timeout to speed up this process but left the
+ * chance for old one to prove aliveness. */
+ new_expire = time(NULL) + MKA_HELLO_TIME * 1.5 / 1000;
+ if (peer->expire > new_expire)
+ peer->expire = new_expire;
+ return NULL;
}
peer = ieee802_1x_kay_create_potential_peer(
participant, body->actor_mi,
be_to_host32(body->actor_mn));
- if (!peer)
+ if (!peer) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: No potential peer entry found - ignore MKPDU");
return NULL;
+ }
peer->macsec_desired = body->macsec_desired;
- peer->macsec_capbility = body->macsec_capbility;
+ peer->macsec_capability = body->macsec_capability;
peer->is_key_server = (Boolean) body->key_server;
peer->key_server_priority = body->priority;
} else if (peer->mn < be_to_host32(body->actor_mn)) {
peer->mn = be_to_host32(body->actor_mn);
- peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
peer->macsec_desired = body->macsec_desired;
- peer->macsec_capbility = body->macsec_capbility;
+ peer->macsec_capability = body->macsec_capability;
peer->is_key_server = (Boolean) body->key_server;
peer->key_server_priority = body->priority;
} else {
- wpa_printf(MSG_WARNING, "KaY: The peer MN have received");
+ wpa_printf(MSG_WARNING,
+ "KaY: The peer MN did not increase - ignore MKPDU");
return NULL;
}
@@ -807,7 +931,7 @@ ieee802_1x_mka_get_live_peer_length(
struct ieee802_1x_kay_peer, list)
len += sizeof(struct ieee802_1x_mka_peer_id);
- return (len + 0x3) & ~0x3;
+ return MKA_ALIGN_LENGTH(len);
}
@@ -836,7 +960,6 @@ ieee802_1x_mka_encode_live_peer_body(
sizeof(struct ieee802_1x_mka_peer_id));
os_memcpy(body_peer->mi, peer->mi, MI_LEN);
body_peer->mn = host_to_be32(peer->mn);
- body_peer++;
}
ieee802_1x_mka_dump_peer_body(body);
@@ -868,7 +991,7 @@ ieee802_1x_mka_get_potential_peer_length(
struct ieee802_1x_kay_peer, list)
len += sizeof(struct ieee802_1x_mka_peer_id);
- return (len + 0x3) & ~0x3;
+ return MKA_ALIGN_LENGTH(len);
}
@@ -897,7 +1020,6 @@ ieee802_1x_mka_encode_potential_peer_body(
sizeof(struct ieee802_1x_mka_peer_id));
os_memcpy(body_peer->mi, peer->mi, MI_LEN);
body_peer->mn = host_to_be32(peer->mn);
- body_peer++;
}
ieee802_1x_mka_dump_peer_body(body);
@@ -912,62 +1034,61 @@ static Boolean
ieee802_1x_mka_i_in_peerlist(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len)
{
- Boolean included = FALSE;
struct ieee802_1x_mka_hdr *hdr;
size_t body_len;
size_t left_len;
- int body_type;
- u32 peer_mn;
- const u8 *peer_mi;
+ u8 body_type;
const u8 *pos;
size_t i;
- pos = mka_msg;
- left_len = msg_len;
- while (left_len > (MKA_HDR_LEN + DEFAULT_ICV_LEN)) {
+ for (pos = mka_msg, left_len = msg_len;
+ left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
+ left_len -= MKA_ALIGN_LENGTH(body_len) + MKA_HDR_LEN,
+ pos += MKA_ALIGN_LENGTH(body_len) + MKA_HDR_LEN) {
hdr = (struct ieee802_1x_mka_hdr *) pos;
body_len = get_mka_param_body_len(hdr);
body_type = get_mka_param_body_type(hdr);
- if (body_type != MKA_LIVE_PEER_LIST &&
- body_type != MKA_POTENTIAL_PEER_LIST)
- goto SKIP_PEER;
-
- ieee802_1x_mka_dump_peer_body(
- (struct ieee802_1x_mka_peer_body *)pos);
-
- if (left_len < (MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN)) {
+ if (left_len < (MKA_HDR_LEN + MKA_ALIGN_LENGTH(body_len) + DEFAULT_ICV_LEN)) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Peer Packet Body Length (%d bytes) is less than the Parameter Set Header Length (%d bytes) + the Parameter Set Body Length (%d bytes) + %d bytes of ICV",
- (int) left_len, (int) MKA_HDR_LEN,
- (int) body_len, DEFAULT_ICV_LEN);
- goto SKIP_PEER;
+ "KaY: MKA Peer Packet Body Length (%zu bytes) is less than the Parameter Set Header Length (%zu bytes) + the Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+ left_len, MKA_HDR_LEN,
+ MKA_ALIGN_LENGTH(body_len),
+ DEFAULT_ICV_LEN);
+ return FALSE;
}
+ if (body_type != MKA_LIVE_PEER_LIST &&
+ body_type != MKA_POTENTIAL_PEER_LIST)
+ continue;
+
if ((body_len % 16) != 0) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Peer Packet Body Length (%d bytes) should multiple of 16 octets",
- (int) body_len);
- goto SKIP_PEER;
+ "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+ body_len);
+ continue;
}
- for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
- peer_mi = MKA_HDR_LEN + pos + i;
- os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
- peer_mn = be_to_host32(peer_mn);
- if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0 &&
- peer_mn == participant->mn) {
- included = TRUE;
- break;
+ ieee802_1x_mka_dump_peer_body(
+ (struct ieee802_1x_mka_peer_body *)pos);
+
+ for (i = 0; i < body_len;
+ i += sizeof(struct ieee802_1x_mka_peer_id)) {
+ const struct ieee802_1x_mka_peer_id *peer_mi;
+
+ peer_mi = (const struct ieee802_1x_mka_peer_id *)
+ (pos + MKA_HDR_LEN + i);
+ if (os_memcmp(peer_mi->mi, participant->mi,
+ MI_LEN) == 0) {
+ u32 mn = be_to_host32(peer_mi->mn);
+
+ wpa_printf(MSG_DEBUG,
+ "KaY: My MI - received MN %u, most recently transmitted MN %u",
+ mn, participant->mn);
+ if (mn == participant->mn)
+ return TRUE;
}
}
-
- if (included)
- return TRUE;
-
-SKIP_PEER:
- left_len -= body_len + MKA_HDR_LEN;
- pos += body_len + MKA_HDR_LEN;
}
return FALSE;
@@ -984,8 +1105,6 @@ static int ieee802_1x_mka_decode_live_peer_body(
const struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_kay_peer *peer;
size_t body_len;
- u32 peer_mn;
- const u8 *peer_mi;
size_t i;
Boolean is_included;
@@ -994,36 +1113,39 @@ static int ieee802_1x_mka_decode_live_peer_body(
hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
body_len = get_mka_param_body_len(hdr);
+ if (body_len % 16 != 0) {
+ wpa_printf(MSG_ERROR,
+ "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+ body_len);
+ return -1;
+ }
- for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
- peer_mi = MKA_HDR_LEN + peer_msg + i;
- os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
- peer_mn = be_to_host32(peer_mn);
+ for (i = 0; i < body_len; i += sizeof(struct ieee802_1x_mka_peer_id)) {
+ const struct ieee802_1x_mka_peer_id *peer_mi;
+ u32 peer_mn;
+
+ peer_mi = (const struct ieee802_1x_mka_peer_id *)
+ (peer_msg + MKA_HDR_LEN + i);
+ peer_mn = be_to_host32(peer_mi->mn);
/* it is myself */
if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
/* My message id is used by other participant */
- if (peer_mn > participant->mn) {
- if (os_get_random(participant->mi,
- sizeof(participant->mi)) < 0)
- wpa_printf(MSG_DEBUG,
- "KaY: Could not update mi");
- participant->mn = 0;
- }
+ if (peer_mn > participant->mn &&
+ !reset_participant_mi(participant))
+ wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
continue;
}
+
if (!is_included)
continue;
- peer = ieee802_1x_kay_get_peer(participant, peer_mi);
- if (NULL != peer) {
+ peer = ieee802_1x_kay_get_peer(participant, peer_mi->mi);
+ if (peer) {
peer->mn = peer_mn;
- peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
- } else {
- if (!ieee802_1x_kay_create_potential_peer(
- participant, peer_mi, peer_mn)) {
- return -1;
- }
+ } else if (!ieee802_1x_kay_create_potential_peer(
+ participant, peer_mi->mi, peer_mn)) {
+ return -1;
}
}
@@ -1039,30 +1161,33 @@ ieee802_1x_mka_decode_potential_peer_body(
struct ieee802_1x_mka_participant *participant,
const u8 *peer_msg, size_t msg_len)
{
- struct ieee802_1x_mka_hdr *hdr;
+ const struct ieee802_1x_mka_hdr *hdr;
size_t body_len;
- u32 peer_mn;
- const u8 *peer_mi;
size_t i;
- hdr = (struct ieee802_1x_mka_hdr *) peer_msg;
+ hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
body_len = get_mka_param_body_len(hdr);
+ if (body_len % 16 != 0) {
+ wpa_printf(MSG_ERROR,
+ "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+ body_len);
+ return -1;
+ }
+
+ for (i = 0; i < body_len; i += sizeof(struct ieee802_1x_mka_peer_id)) {
+ const struct ieee802_1x_mka_peer_id *peer_mi;
+ u32 peer_mn;
- for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
- peer_mi = MKA_HDR_LEN + peer_msg + i;
- os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
- peer_mn = be_to_host32(peer_mn);
+ peer_mi = (struct ieee802_1x_mka_peer_id *)
+ (peer_msg + MKA_HDR_LEN + i);
+ peer_mn = be_to_host32(peer_mi->mn);
/* it is myself */
if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
/* My message id is used by other participant */
- if (peer_mn > participant->mn) {
- if (os_get_random(participant->mi,
- sizeof(participant->mi)) < 0)
- wpa_printf(MSG_DEBUG,
- "KaY: Could not update mi");
- participant->mn = 0;
- }
+ if (peer_mn > participant->mn &&
+ !reset_participant_mi(participant))
+ wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
continue;
}
}
@@ -1078,10 +1203,7 @@ static Boolean
ieee802_1x_mka_sak_use_body_present(
struct ieee802_1x_mka_participant *participant)
{
- if (participant->to_use_sak)
- return TRUE;
- else
- return FALSE;
+ return participant->to_use_sak;
}
@@ -1096,37 +1218,44 @@ ieee802_1x_mka_get_sak_use_length(
if (participant->kay->macsec_desired && participant->advised_desired)
length = sizeof(struct ieee802_1x_mka_sak_use_body);
- else
- length = MKA_HDR_LEN;
- length = (length + 0x3) & ~0x3;
-
- return length;
+ return MKA_ALIGN_LENGTH(length);
}
/**
- *
+ * ieee802_1x_mka_get_lpn
*/
static u32
ieee802_1x_mka_get_lpn(struct ieee802_1x_mka_participant *principal,
struct ieee802_1x_mka_ki *ki)
{
- struct receive_sa *rxsa;
- struct receive_sc *rxsc;
+ struct transmit_sa *txsa;
u32 lpn = 0;
- dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
- dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list)
- {
- if (is_ki_equal(&rxsa->pkey->key_identifier, ki)) {
- secy_get_receive_lowest_pn(principal->kay,
- rxsa);
-
- lpn = lpn > rxsa->lowest_pn ?
- lpn : rxsa->lowest_pn;
- break;
- }
+ dl_list_for_each(txsa, &principal->txsc->sa_list,
+ struct transmit_sa, list) {
+ if (is_ki_equal(&txsa->pkey->key_identifier, ki)) {
+ /* Per IEEE Std 802.1X-2010, Clause 9, "Each SecY uses
+ * MKA to communicate the lowest PN used for
+ * transmission with the SAK within the last two
+ * seconds". Achieve this 2 second delay by setting the
+ * lpn using the transmit next PN (i.e., txsa->next_pn)
+ * that was read last time here (i.e., mka_hello_time
+ * 2 seconds ago).
+ *
+ * The lowest acceptable PN is the same as the last
+ * transmitted PN, which is one less than the next
+ * transmit PN.
+ *
+ * NOTE: This method only works if mka_hello_time is 2s.
+ */
+ lpn = (txsa->next_pn > 0) ? (txsa->next_pn - 1) : 0;
+
+ /* Now read the current transmit next PN for use next
+ * time through. */
+ secy_get_transmit_next_pn(principal->kay, txsa);
+ break;
}
}
@@ -1146,11 +1275,12 @@ ieee802_1x_mka_encode_sak_use_body(
struct wpabuf *buf)
{
struct ieee802_1x_mka_sak_use_body *body;
+ struct ieee802_1x_kay *kay = participant->kay;
unsigned int length;
u32 pn = 1;
length = ieee802_1x_mka_get_sak_use_length(participant);
- body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_sak_use_body));
+ body = wpabuf_put(buf, length);
body->type = MKA_SAK_USE;
set_mka_param_body_len(body, length - MKA_HDR_LEN);
@@ -1165,10 +1295,11 @@ ieee802_1x_mka_encode_sak_use_body(
return 0;
}
- /* data protect, lowest accept packet number */
- body->delay_protect = participant->kay->macsec_replay_protect;
+ /* data delay protect */
+ body->delay_protect = kay->mka_hello_time <= MKA_BOUNDED_HELLO_TIME;
+ /* lowest accept packet number */
pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
- if (pn > participant->kay->pn_exhaustion) {
+ if (pn > kay->pn_exhaustion) {
wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
if (participant->is_key_server)
participant->new_sak = TRUE;
@@ -1179,20 +1310,12 @@ ieee802_1x_mka_encode_sak_use_body(
body->olpn = host_to_be32(pn);
/* plain tx, plain rx */
- if (participant->kay->macsec_protect)
- body->ptx = FALSE;
- else
- body->ptx = TRUE;
-
- if (participant->kay->macsec_validate == Strict)
- body->prx = FALSE;
- else
- body->prx = TRUE;
+ body->ptx = !kay->macsec_protect;
+ body->prx = kay->macsec_validate != Strict;
/* latest key: rx, tx, key server member identifier key number */
body->lan = participant->lan;
- os_memcpy(body->lsrv_mi, participant->lki.mi,
- sizeof(body->lsrv_mi));
+ os_memcpy(body->lsrv_mi, participant->lki.mi, sizeof(body->lsrv_mi));
body->lkn = host_to_be32(participant->lki.kn);
body->lrx = participant->lrx;
body->ltx = participant->ltx;
@@ -1213,16 +1336,11 @@ ieee802_1x_mka_encode_sak_use_body(
/* set CP's variable */
if (body->ltx) {
- if (!participant->kay->tx_enable)
- participant->kay->tx_enable = TRUE;
-
- if (!participant->kay->port_enable)
- participant->kay->port_enable = TRUE;
- }
- if (body->lrx) {
- if (!participant->kay->rx_enable)
- participant->kay->rx_enable = TRUE;
+ kay->tx_enable = TRUE;
+ kay->port_enable = TRUE;
}
+ if (body->lrx)
+ kay->rx_enable = TRUE;
ieee802_1x_mka_dump_sak_use_body(body);
return 0;
@@ -1240,13 +1358,15 @@ ieee802_1x_mka_decode_sak_use_body(
struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay_peer *peer;
- struct transmit_sa *txsa;
+ struct receive_sc *rxsc;
+ struct receive_sa *rxsa;
struct data_key *sa_key = NULL;
size_t body_len;
struct ieee802_1x_mka_ki ki;
u32 lpn;
Boolean all_receiving;
- Boolean founded;
+ Boolean found;
+ struct ieee802_1x_kay *kay = participant->kay;
if (!participant->principal) {
wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
@@ -1255,7 +1375,9 @@ ieee802_1x_mka_decode_sak_use_body(
peer = ieee802_1x_kay_get_live_peer(participant,
participant->current_peer_id.mi);
if (!peer) {
- wpa_printf(MSG_WARNING, "KaY: the peer is not my live peer");
+ wpa_printf(MSG_WARNING,
+ "KaY: The peer (%s) is not my live peer - ignore MACsec SAK Use parameter set",
+ mi_txt(participant->current_peer_id.mi));
return -1;
}
@@ -1266,8 +1388,8 @@ ieee802_1x_mka_decode_sak_use_body(
if ((body_len != 0) && (body_len < 40)) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 0, 40, or more octets",
- (int) body_len);
+ "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 0, 40, or more octets",
+ body_len);
return -1;
}
@@ -1288,38 +1410,37 @@ ieee802_1x_mka_decode_sak_use_body(
/* check latest key is valid */
if (body->ltx || body->lrx) {
- founded = FALSE;
+ found = FALSE;
os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
- ki.kn = ntohl(body->lkn);
+ ki.kn = be_to_host32(body->lkn);
dl_list_for_each(sa_key, &participant->sak_list,
struct data_key, list) {
if (is_ki_equal(&sa_key->key_identifier, &ki)) {
- founded = TRUE;
+ found = TRUE;
break;
}
}
- if (!founded) {
- wpa_printf(MSG_WARNING, "KaY: Latest key is invalid");
+ if (!found) {
+ wpa_printf(MSG_INFO, "KaY: Latest key is invalid");
return -1;
}
if (os_memcmp(participant->lki.mi, body->lsrv_mi,
sizeof(participant->lki.mi)) == 0 &&
- ntohl(body->lkn) == participant->lki.kn &&
+ be_to_host32(body->lkn) == participant->lki.kn &&
body->lan == participant->lan) {
peer->sak_used = TRUE;
}
if (body->ltx && peer->is_key_server) {
- ieee802_1x_cp_set_servertransmitting(
- participant->kay->cp, TRUE);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(kay->cp);
}
}
- /* check old key is valid */
- if (body->otx || body->orx) {
+ /* check old key is valid (but only if we remember our old key) */
+ if (participant->oki.kn != 0 && (body->otx || body->orx)) {
if (os_memcmp(participant->oki.mi, body->osrv_mi,
sizeof(participant->oki.mi)) != 0 ||
- ntohl(body->okn) != participant->oki.kn ||
+ be_to_host32(body->okn) != participant->oki.kn ||
body->oan != participant->oan) {
wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
return -1;
@@ -1327,9 +1448,10 @@ ieee802_1x_mka_decode_sak_use_body(
}
/* TODO: how to set the MACsec hardware when delay_protect is true */
- if (body->delay_protect && (!ntohl(body->llpn) || !ntohl(body->olpn))) {
+ if (body->delay_protect &&
+ (!be_to_host32(body->llpn) || !be_to_host32(body->olpn))) {
wpa_printf(MSG_WARNING,
- "KaY: Lowest packet number should greater than 0 when delay_protect is TRUE");
+ "KaY: Lowest packet number should be greater than 0 when delay_protect is TRUE");
return -1;
}
@@ -1344,39 +1466,54 @@ ieee802_1x_mka_decode_sak_use_body(
}
if (all_receiving) {
participant->to_dist_sak = FALSE;
- ieee802_1x_cp_set_allreceiving(participant->kay->cp, TRUE);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(kay->cp);
}
- /* if i'm key server, and detects peer member pn exhaustion, rekey.*/
- lpn = ntohl(body->llpn);
- if (lpn > participant->kay->pn_exhaustion) {
+ /* if I'm key server, and detects peer member pn exhaustion, rekey. */
+ lpn = be_to_host32(body->llpn);
+ if (lpn > kay->pn_exhaustion) {
if (participant->is_key_server) {
participant->new_sak = TRUE;
wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
}
}
- founded = FALSE;
- dl_list_for_each(txsa, &participant->txsc->sa_list,
- struct transmit_sa, list) {
- if (sa_key != NULL && txsa->pkey == sa_key) {
- founded = TRUE;
- break;
+ if (sa_key)
+ sa_key->next_pn = lpn;
+ found = FALSE;
+ dl_list_for_each(rxsc, &participant->rxsc_list, struct receive_sc,
+ list) {
+ dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa,
+ list) {
+ if (sa_key && rxsa->pkey == sa_key) {
+ found = TRUE;
+ break;
+ }
}
+ if (found)
+ break;
}
- if (!founded) {
- wpa_printf(MSG_WARNING, "KaY: Can't find txsa");
+ if (!found) {
+ wpa_printf(MSG_WARNING, "KaY: Can't find rxsa");
return -1;
}
- /* FIXME: Secy creates txsa with default npn. If MKA detected Latest Key
- * npn is larger than txsa's npn, set it to txsa.
- */
- secy_get_transmit_next_pn(participant->kay, txsa);
- if (lpn > txsa->next_pn) {
- secy_set_transmit_next_pn(participant->kay, txsa);
- wpa_printf(MSG_INFO, "KaY: update lpn =0x%x", lpn);
+ if (body->delay_protect) {
+ secy_get_receive_lowest_pn(participant->kay, rxsa);
+ if (lpn > rxsa->lowest_pn) {
+ /* Delay protect window (communicated via MKA) is
+ * tighter than SecY's current replay protect window,
+ * so tell SecY the new (and higher) lpn. */
+ rxsa->lowest_pn = lpn;
+ secy_set_receive_lowest_pn(participant->kay, rxsa);
+ wpa_printf(MSG_DEBUG, "KaY: update lpn =0x%x", lpn);
+ }
+ /* FIX: Delay protection for olpn not implemented.
+ * Note that Old Key is only active for MKA_SAK_RETIRE_TIME
+ * (3 seconds) and delay protection does allow PN's within
+ * a 2 seconds window, so olpn would be a lot of work for
+ * just 1 second's worth of protection. */
}
return 0;
@@ -1390,10 +1527,8 @@ static Boolean
ieee802_1x_mka_dist_sak_body_present(
struct ieee802_1x_mka_participant *participant)
{
- if (!participant->to_dist_sak || !participant->new_key)
- return FALSE;
-
- return TRUE;
+ return participant->is_key_server && participant->to_dist_sak &&
+ participant->new_key;
}
@@ -1404,21 +1539,18 @@ static int
ieee802_1x_mka_get_dist_sak_length(
struct ieee802_1x_mka_participant *participant)
{
- int length;
- int cs_index = participant->kay->macsec_csindex;
+ int length = MKA_HDR_LEN;
+ unsigned int cs_index = participant->kay->macsec_csindex;
- if (participant->advised_desired) {
+ if (participant->advised_desired && cs_index < CS_TABLE_SIZE) {
length = sizeof(struct ieee802_1x_mka_dist_sak_body);
if (cs_index != DEFAULT_CS_INDEX)
length += CS_ID_LEN;
length += cipher_suite_tbl[cs_index].sak_len + 8;
- } else {
- length = MKA_HDR_LEN;
}
- length = (length + 0x3) & ~0x3;
- return length;
+ return MKA_ALIGN_LENGTH(length);
}
@@ -1433,7 +1565,7 @@ ieee802_1x_mka_encode_dist_sak_body(
struct ieee802_1x_mka_dist_sak_body *body;
struct data_key *sak;
unsigned int length;
- int cs_index;
+ unsigned int cs_index;
int sak_pos;
length = ieee802_1x_mka_get_dist_sak_length(participant);
@@ -1447,16 +1579,26 @@ ieee802_1x_mka_encode_dist_sak_body(
}
sak = participant->new_key;
+ if (!sak) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: No SAK available to build Distributed SAK parameter set");
+ return -1;
+ }
body->confid_offset = sak->confidentiality_offset;
body->dan = sak->an;
body->kn = host_to_be32(sak->key_identifier.kn);
cs_index = participant->kay->macsec_csindex;
sak_pos = 0;
+ if (cs_index >= CS_TABLE_SIZE)
+ return -1;
if (cs_index != DEFAULT_CS_INDEX) {
- os_memcpy(body->sak, cipher_suite_tbl[cs_index].id, CS_ID_LEN);
+ be64 cs;
+
+ cs = host_to_be64(cipher_suite_tbl[cs_index].id);
+ os_memcpy(body->sak, &cs, CS_ID_LEN);
sak_pos = CS_ID_LEN;
}
- if (aes_wrap(participant->kek.key, 16,
+ if (aes_wrap(participant->kek.key, participant->kek.len,
cipher_suite_tbl[cs_index].sak_len / 8,
sak->key, body->sak + sak_pos)) {
wpa_printf(MSG_ERROR, "KaY: AES wrap failed");
@@ -1472,39 +1614,14 @@ ieee802_1x_mka_encode_dist_sak_body(
/**
* ieee802_1x_kay_init_data_key -
*/
-static struct data_key *
-ieee802_1x_kay_init_data_key(const struct key_conf *conf)
+static void ieee802_1x_kay_init_data_key(struct data_key *pkey)
{
- struct data_key *pkey;
-
- if (!conf)
- return NULL;
-
- pkey = os_zalloc(sizeof(*pkey));
- if (pkey == NULL) {
- wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
- return NULL;
- }
-
- pkey->key = os_zalloc(conf->key_len);
- if (pkey->key == NULL) {
- wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
- os_free(pkey);
- return NULL;
- }
-
- os_memcpy(pkey->key, conf->key, conf->key_len);
- os_memcpy(&pkey->key_identifier, &conf->ki,
- sizeof(pkey->key_identifier));
- pkey->confidentiality_offset = conf->offset;
- pkey->an = conf->an;
- pkey->transmits = conf->tx;
- pkey->receives = conf->rx;
+ pkey->transmits = TRUE;
+ pkey->receives = TRUE;
os_get_time(&pkey->created_time);
+ pkey->next_pn = 1;
pkey->user = 1;
-
- return pkey;
}
@@ -1521,19 +1638,18 @@ ieee802_1x_mka_decode_dist_sak_body(
struct ieee802_1x_kay_peer *peer;
struct macsec_ciphersuite *cs;
size_t body_len;
- struct key_conf *conf;
struct data_key *sa_key = NULL;
- struct ieee802_1x_mka_ki sak_ki;
int sak_len;
u8 *wrap_sak;
u8 *unwrap_sak;
+ struct ieee802_1x_kay *kay = participant->kay;
hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
body_len = get_mka_param_body_len(hdr);
if ((body_len != 0) && (body_len != 28) && (body_len < 36)) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 0, 28, 36, or more octets",
- (int) body_len);
+ "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 0, 28, 36, or more octets",
+ body_len);
return -1;
}
@@ -1544,11 +1660,11 @@ ieee802_1x_mka_decode_dist_sak_body(
}
if (participant->is_key_server) {
wpa_printf(MSG_ERROR,
- "KaY: I can't accept the distributed SAK as myself is key server ");
+ "KaY: Reject distributed SAK since I'm a key server");
return -1;
}
- if (!participant->kay->macsec_desired ||
- participant->kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
+ if (!kay->macsec_desired ||
+ kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
wpa_printf(MSG_ERROR,
"KaY: I am not MACsec-desired or without MACsec capable");
return -1;
@@ -1561,28 +1677,29 @@ ieee802_1x_mka_decode_dist_sak_body(
"KaY: The key server is not in my live peers list");
return -1;
}
- if (os_memcmp(&participant->kay->key_server_sci,
- &peer->sci, sizeof(struct ieee802_1x_mka_sci)) != 0) {
+ if (!sci_equal(&kay->key_server_sci, &peer->sci)) {
wpa_printf(MSG_ERROR, "KaY: The key server is not elected");
return -1;
}
+
if (body_len == 0) {
- participant->kay->authenticated = TRUE;
- participant->kay->secured = FALSE;
- participant->kay->failed = FALSE;
+ kay->authenticated = TRUE;
+ kay->secured = FALSE;
+ kay->failed = FALSE;
participant->advised_desired = FALSE;
- ieee802_1x_cp_connect_authenticated(participant->kay->cp);
- ieee802_1x_cp_sm_step(participant->kay->cp);
- wpa_printf(MSG_WARNING, "KaY:The Key server advise no MACsec");
- participant->to_use_sak = TRUE;
+ ieee802_1x_cp_connect_authenticated(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ wpa_printf(MSG_WARNING, "KaY: The Key server advise no MACsec");
+ participant->to_use_sak = FALSE;
return 0;
}
+
participant->advised_desired = TRUE;
- participant->kay->authenticated = FALSE;
- participant->kay->secured = TRUE;
- participant->kay->failed = FALSE;
- ieee802_1x_cp_connect_secure(participant->kay->cp);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ kay->authenticated = FALSE;
+ kay->secured = TRUE;
+ kay->failed = FALSE;
+ ieee802_1x_cp_connect_secure(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
body = (struct ieee802_1x_mka_dist_sak_body *)mka_msg;
ieee802_1x_mka_dump_dist_sak_body(body);
@@ -1591,16 +1708,22 @@ ieee802_1x_mka_decode_dist_sak_body(
if (os_memcmp(sa_key->key_identifier.mi,
participant->current_peer_id.mi, MI_LEN) == 0 &&
sa_key->key_identifier.kn == be_to_host32(body->kn)) {
- wpa_printf(MSG_WARNING, "KaY:The Key has installed");
+ wpa_printf(MSG_DEBUG,
+ "KaY: SAK has already been installed - do not set it again");
return 0;
}
}
+
if (body_len == 28) {
sak_len = DEFAULT_SA_KEY_LEN;
wrap_sak = body->sak;
- participant->kay->macsec_csindex = DEFAULT_CS_INDEX;
+ kay->macsec_csindex = DEFAULT_CS_INDEX;
+ cs = &cipher_suite_tbl[kay->macsec_csindex];
} else {
- cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak);
+ unsigned int idx;
+
+ cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak,
+ &idx);
if (!cs) {
wpa_printf(MSG_ERROR,
"KaY: I can't support the Cipher Suite advised by key server");
@@ -1608,7 +1731,7 @@ ieee802_1x_mka_decode_dist_sak_body(
}
sak_len = cs->sak_len;
wrap_sak = body->sak + CS_ID_LEN;
- participant->kay->macsec_csindex = cs->index;
+ kay->macsec_csindex = idx;
}
unwrap_sak = os_zalloc(sak_len);
@@ -1616,70 +1739,47 @@ ieee802_1x_mka_decode_dist_sak_body(
wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
return -1;
}
- if (aes_unwrap(participant->kek.key, 16, sak_len >> 3, wrap_sak,
- unwrap_sak)) {
+ if (aes_unwrap(participant->kek.key, participant->kek.len,
+ sak_len >> 3, wrap_sak, unwrap_sak)) {
wpa_printf(MSG_ERROR, "KaY: AES unwrap failed");
os_free(unwrap_sak);
return -1;
}
- wpa_hexdump(MSG_DEBUG, "\tAES Key Unwrap of SAK:", unwrap_sak, sak_len);
-
- conf = os_zalloc(sizeof(*conf));
- if (!conf) {
- wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
- os_free(unwrap_sak);
- return -1;
- }
- conf->key_len = sak_len;
+ wpa_hexdump_key(MSG_DEBUG, "\tAES Key Unwrap of SAK.:",
+ unwrap_sak, sak_len);
- conf->key = os_zalloc(conf->key_len);
- if (!conf->key) {
- wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+ sa_key = os_zalloc(sizeof(*sa_key));
+ if (!sa_key) {
os_free(unwrap_sak);
- os_free(conf);
return -1;
}
- os_memcpy(conf->key, unwrap_sak, conf->key_len);
+ os_memcpy(&sa_key->key_identifier.mi, &participant->current_peer_id.mi,
+ MI_LEN);
+ sa_key->key_identifier.kn = be_to_host32(body->kn);
- os_memcpy(&sak_ki.mi, &participant->current_peer_id.mi,
- sizeof(sak_ki.mi));
- sak_ki.kn = be_to_host32(body->kn);
+ sa_key->key = unwrap_sak;
+ sa_key->key_len = sak_len;
- os_memcpy(conf->ki.mi, sak_ki.mi, MI_LEN);
- conf->ki.kn = sak_ki.kn;
- conf->an = body->dan;
- conf->offset = body->confid_offset;
- conf->rx = TRUE;
- conf->tx = TRUE;
-
- sa_key = ieee802_1x_kay_init_data_key(conf);
- if (!sa_key) {
- os_free(unwrap_sak);
- os_free(conf->key);
- os_free(conf);
- return -1;
- }
+ sa_key->confidentiality_offset = body->confid_offset;
+ sa_key->an = body->dan;
+ ieee802_1x_kay_init_data_key(sa_key);
+ ieee802_1x_kay_use_data_key(sa_key);
dl_list_add(&participant->sak_list, &sa_key->list);
- ieee802_1x_cp_set_ciphersuite(
- participant->kay->cp,
- cipher_suite_tbl[participant->kay->macsec_csindex].id);
- ieee802_1x_cp_sm_step(participant->kay->cp);
- ieee802_1x_cp_set_offset(participant->kay->cp, body->confid_offset);
- ieee802_1x_cp_sm_step(participant->kay->cp);
- ieee802_1x_cp_set_distributedki(participant->kay->cp, &sak_ki);
- ieee802_1x_cp_set_distributedan(participant->kay->cp, body->dan);
- ieee802_1x_cp_signal_newsak(participant->kay->cp);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ ieee802_1x_cp_set_ciphersuite(kay->cp, cs->id);
+ ieee802_1x_cp_sm_step(kay->cp);
+ ieee802_1x_cp_set_offset(kay->cp, body->confid_offset);
+ ieee802_1x_cp_sm_step(kay->cp);
+ ieee802_1x_cp_set_distributedki(kay->cp, &sa_key->key_identifier);
+ ieee802_1x_cp_set_distributedan(kay->cp, body->dan);
+ ieee802_1x_cp_signal_newsak(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ kay->rcvd_keys++;
participant->to_use_sak = TRUE;
- os_free(unwrap_sak);
- os_free(conf->key);
- os_free(conf);
-
return 0;
}
@@ -1702,10 +1802,15 @@ ieee802_1x_mka_get_icv_length(struct ieee802_1x_mka_participant *participant)
{
int length;
- length = sizeof(struct ieee802_1x_mka_icv_body);
+ /* Determine if we need space for the ICV Indicator */
+ if (mka_alg_tbl[participant->kay->mka_algindex].icv_len !=
+ DEFAULT_ICV_LEN)
+ length = sizeof(struct ieee802_1x_mka_icv_body);
+ else
+ length = 0;
length += mka_alg_tbl[participant->kay->mka_algindex].icv_len;
- return (length + 0x3) & ~0x3;
+ return MKA_ALIGN_LENGTH(length);
}
@@ -1721,24 +1826,24 @@ ieee802_1x_mka_encode_icv_body(struct ieee802_1x_mka_participant *participant,
u8 cmac[MAX_ICV_LEN];
length = ieee802_1x_mka_get_icv_length(participant);
- if (length != DEFAULT_ICV_LEN) {
+ if (mka_alg_tbl[participant->kay->mka_algindex].icv_len !=
+ DEFAULT_ICV_LEN) {
+ wpa_printf(MSG_DEBUG, "KaY: ICV Indicator");
body = wpabuf_put(buf, MKA_HDR_LEN);
body->type = MKA_ICV_INDICATOR;
- set_mka_param_body_len(body, length - MKA_HDR_LEN);
+ length -= MKA_HDR_LEN;
+ set_mka_param_body_len(body, length);
}
if (mka_alg_tbl[participant->kay->mka_algindex].icv_hash(
- participant->ick.key, wpabuf_head(buf), buf->used, cmac)) {
- wpa_printf(MSG_ERROR, "KaY, omac1_aes_128 failed");
+ participant->ick.key, participant->ick.len,
+ wpabuf_head(buf), wpabuf_len(buf), cmac)) {
+ wpa_printf(MSG_ERROR, "KaY: failed to calculate ICV");
return -1;
}
+ wpa_hexdump(MSG_DEBUG, "KaY: ICV", cmac, length);
- if (length != DEFAULT_ICV_LEN) {
- os_memcpy(wpabuf_put(buf, length - MKA_HDR_LEN), cmac,
- length - MKA_HDR_LEN);
- } else {
- os_memcpy(wpabuf_put(buf, length), cmac, length);
- }
+ os_memcpy(wpabuf_put(buf, length), cmac, length);
return 0;
}
@@ -1746,25 +1851,25 @@ ieee802_1x_mka_encode_icv_body(struct ieee802_1x_mka_participant *participant,
/**
* ieee802_1x_mka_decode_icv_body -
*/
-static u8 *
+static const u8 *
ieee802_1x_mka_decode_icv_body(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len)
{
- struct ieee802_1x_mka_hdr *hdr;
- struct ieee802_1x_mka_icv_body *body;
+ const struct ieee802_1x_mka_hdr *hdr;
+ const struct ieee802_1x_mka_icv_body *body;
size_t body_len;
size_t left_len;
- int body_type;
+ u8 body_type;
const u8 *pos;
pos = mka_msg;
left_len = msg_len;
- while (left_len > (MKA_HDR_LEN + DEFAULT_ICV_LEN)) {
- hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ while (left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN) {
+ hdr = (const struct ieee802_1x_mka_hdr *) pos;
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
body_type = get_mka_param_body_type(hdr);
- if (left_len < (body_len + MKA_HDR_LEN))
+ if (left_len < body_len + MKA_HDR_LEN)
break;
if (body_type != MKA_ICV_INDICATOR) {
@@ -1773,16 +1878,15 @@ ieee802_1x_mka_decode_icv_body(struct ieee802_1x_mka_participant *participant,
continue;
}
- body = (struct ieee802_1x_mka_icv_body *)pos;
+ body = (const struct ieee802_1x_mka_icv_body *) pos;
if (body_len
- < mka_alg_tbl[participant->kay->mka_algindex].icv_len) {
+ < mka_alg_tbl[participant->kay->mka_algindex].icv_len)
return NULL;
- }
return body->icv;
}
- return (u8 *) (mka_msg + msg_len - DEFAULT_ICV_LEN);
+ return mka_msg + msg_len - DEFAULT_ICV_LEN;
}
@@ -1801,8 +1905,8 @@ ieee802_1x_mka_decode_dist_cak_body(
body_len = get_mka_param_body_len(hdr);
if (body_len < 28) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 28 or more octets",
- (int) body_len);
+ "KaY: MKA Use CAK Packet Body Length (%zu bytes) should be 28 or more octets",
+ body_len);
return -1;
}
@@ -1825,8 +1929,8 @@ ieee802_1x_mka_decode_kmd_body(
body_len = get_mka_param_body_len(hdr);
if (body_len < 5) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 5 or more octets",
- (int) body_len);
+ "KaY: MKA Use KMD Packet Body Length (%zu bytes) should be 5 or more octets",
+ body_len);
return -1;
}
@@ -1845,85 +1949,105 @@ static int ieee802_1x_mka_decode_announce_body(
}
-static struct mka_param_body_handler mak_body_handler[] = {
- /* basic parameter set */
+struct mka_param_body_handler {
+ int (*body_tx)(struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *buf);
+ int (*body_rx)(struct ieee802_1x_mka_participant *participant,
+ const u8 *mka_msg, size_t msg_len);
+ int (*body_length)(struct ieee802_1x_mka_participant *participant);
+ Boolean (*body_present)(struct ieee802_1x_mka_participant *participant);
+};
+
+
+static struct mka_param_body_handler mka_body_handler[] = {
+ /* Basic parameter set */
{
- ieee802_1x_mka_encode_basic_body,
- NULL,
- ieee802_1x_mka_basic_body_length,
- ieee802_1x_mka_basic_body_present
+ .body_tx = ieee802_1x_mka_encode_basic_body,
+ .body_rx = NULL,
+ .body_length = ieee802_1x_mka_basic_body_length,
+ .body_present = ieee802_1x_mka_basic_body_present
},
- /* live peer list parameter set */
+ /* Live Peer List parameter set */
{
- ieee802_1x_mka_encode_live_peer_body,
- ieee802_1x_mka_decode_live_peer_body,
- ieee802_1x_mka_get_live_peer_length,
- ieee802_1x_mka_live_peer_body_present
+ .body_tx = ieee802_1x_mka_encode_live_peer_body,
+ .body_rx = ieee802_1x_mka_decode_live_peer_body,
+ .body_length = ieee802_1x_mka_get_live_peer_length,
+ .body_present = ieee802_1x_mka_live_peer_body_present
},
- /* potential peer list parameter set */
+ /* Potential Peer List parameter set */
{
- ieee802_1x_mka_encode_potential_peer_body,
- ieee802_1x_mka_decode_potential_peer_body,
- ieee802_1x_mka_get_potential_peer_length,
- ieee802_1x_mka_potential_peer_body_present
+ .body_tx = ieee802_1x_mka_encode_potential_peer_body,
+ .body_rx = ieee802_1x_mka_decode_potential_peer_body,
+ .body_length = ieee802_1x_mka_get_potential_peer_length,
+ .body_present = ieee802_1x_mka_potential_peer_body_present
},
- /* sak use parameter set */
+ /* MACsec SAK Use parameter set */
{
- ieee802_1x_mka_encode_sak_use_body,
- ieee802_1x_mka_decode_sak_use_body,
- ieee802_1x_mka_get_sak_use_length,
- ieee802_1x_mka_sak_use_body_present
+ .body_tx = ieee802_1x_mka_encode_sak_use_body,
+ .body_rx = ieee802_1x_mka_decode_sak_use_body,
+ .body_length = ieee802_1x_mka_get_sak_use_length,
+ .body_present = ieee802_1x_mka_sak_use_body_present
},
- /* distribute sak parameter set */
+ /* Distributed SAK parameter set */
{
- ieee802_1x_mka_encode_dist_sak_body,
- ieee802_1x_mka_decode_dist_sak_body,
- ieee802_1x_mka_get_dist_sak_length,
- ieee802_1x_mka_dist_sak_body_present
+ .body_tx = ieee802_1x_mka_encode_dist_sak_body,
+ .body_rx = ieee802_1x_mka_decode_dist_sak_body,
+ .body_length = ieee802_1x_mka_get_dist_sak_length,
+ .body_present = ieee802_1x_mka_dist_sak_body_present
},
- /* distribute cak parameter set */
+ /* Distribute CAK parameter set */
{
- NULL,
- ieee802_1x_mka_decode_dist_cak_body,
- NULL,
- NULL
+ .body_tx = NULL,
+ .body_rx = ieee802_1x_mka_decode_dist_cak_body,
+ .body_length = NULL,
+ .body_present = NULL
},
- /* kmd parameter set */
+ /* KMD parameter set */
{
- NULL,
- ieee802_1x_mka_decode_kmd_body,
- NULL,
- NULL
+ .body_tx = NULL,
+ .body_rx = ieee802_1x_mka_decode_kmd_body,
+ .body_length = NULL,
+ .body_present = NULL
},
- /* announce parameter set */
+ /* Announcement parameter set */
{
- NULL,
- ieee802_1x_mka_decode_announce_body,
- NULL,
- NULL
+ .body_tx = NULL,
+ .body_rx = ieee802_1x_mka_decode_announce_body,
+ .body_length = NULL,
+ .body_present = NULL
},
- /* icv parameter set */
+ /* ICV Indicator parameter set */
{
- ieee802_1x_mka_encode_icv_body,
- NULL,
- ieee802_1x_mka_get_icv_length,
- ieee802_1x_mka_icv_body_present
+ .body_tx = ieee802_1x_mka_encode_icv_body,
+ .body_rx = NULL,
+ .body_length = ieee802_1x_mka_get_icv_length,
+ .body_present = ieee802_1x_mka_icv_body_present
},
};
/**
- * ieee802_1x_kay_deinit_data_key -
+ * ieee802_1x_kay_use_data_key - Take reference on a key
*/
-void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
+static void ieee802_1x_kay_use_data_key(struct data_key *pkey)
+{
+ pkey->user++;
+}
+
+
+/**
+ * ieee802_1x_kay_deinit_data_key - Release reference on a key and
+ * free if there are no remaining users
+ */
+static void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
{
if (!pkey)
return;
@@ -1932,7 +2056,6 @@ void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
if (pkey->user > 1)
return;
- dl_list_del(&pkey->list);
os_free(pkey->key);
os_free(pkey);
}
@@ -1945,11 +2068,13 @@ static int
ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
{
struct data_key *sa_key = NULL;
- struct key_conf *conf;
struct ieee802_1x_kay_peer *peer;
struct ieee802_1x_kay *kay = participant->kay;
int ctx_len, ctx_offset;
u8 *context;
+ unsigned int key_len;
+ u8 *key;
+ struct macsec_ciphersuite *cs;
/* check condition for generating a fresh SAK:
* must have one live peer
@@ -1958,7 +2083,7 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
*/
if (dl_list_empty(&participant->live_peers)) {
wpa_printf(MSG_ERROR,
- "KaY: Live peers list must not empty when generating fresh SAK");
+ "KaY: Live peers list must not be empty when generating fresh SAK");
return -1;
}
@@ -1972,44 +2097,33 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
*/
if ((time(NULL) - kay->dist_time) < MKA_LIFE_TIME / 1000) {
wpa_printf(MSG_ERROR,
- "KaY: Life time have not elapsed since prior SAK distributed");
- return -1;
- }
-
- conf = os_zalloc(sizeof(*conf));
- if (!conf) {
- wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+ "KaY: Life time has not elapsed since prior SAK distributed");
return -1;
}
- conf->key_len = cipher_suite_tbl[kay->macsec_csindex].sak_len;
- conf->key = os_zalloc(conf->key_len);
- if (!conf->key) {
- os_free(conf);
+ cs = &cipher_suite_tbl[kay->macsec_csindex];
+ key_len = cs->sak_len;
+ key = os_zalloc(key_len);
+ if (!key) {
wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
return -1;
}
- ctx_len = conf->key_len + sizeof(kay->dist_kn);
+ ctx_len = key_len + sizeof(kay->dist_kn);
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list)
ctx_len += sizeof(peer->mi);
ctx_len += sizeof(participant->mi);
context = os_zalloc(ctx_len);
- if (!context) {
- os_free(conf->key);
- os_free(conf);
- return -1;
- }
+ if (!context)
+ goto fail;
+
ctx_offset = 0;
- if (os_get_random(context + ctx_offset, conf->key_len) < 0) {
- os_free(context);
- os_free(conf->key);
- os_free(conf);
- return -1;
- }
- ctx_offset += conf->key_len;
+ if (os_get_random(context + ctx_offset, key_len) < 0)
+ goto fail;
+
+ ctx_offset += key_len;
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
os_memcpy(context + ctx_offset, peer->mi, sizeof(peer->mi));
@@ -2020,46 +2134,49 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
ctx_offset += sizeof(participant->mi);
os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn));
- if (conf->key_len == 16) {
- ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
- context, ctx_len, conf->key);
- } else if (conf->key_len == 32) {
- ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
- context, ctx_len, conf->key);
+ if (key_len == 16 || key_len == 32) {
+ if (ieee802_1x_sak_aes_cmac(participant->cak.key,
+ participant->cak.len,
+ context, ctx_len,
+ key, key_len)) {
+ wpa_printf(MSG_ERROR, "KaY: Failed to generate SAK");
+ goto fail;
+ }
} else {
- wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
- os_free(conf->key);
- os_free(conf);
- os_free(context);
- return -1;
+ wpa_printf(MSG_ERROR, "KaY: SAK Length(%u) not supported",
+ key_len);
+ goto fail;
}
- wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK",
- conf->key, conf->key_len);
-
- os_memcpy(conf->ki.mi, participant->mi, MI_LEN);
- conf->ki.kn = participant->kay->dist_kn;
- conf->an = participant->kay->dist_an;
- conf->offset = kay->macsec_confidentiality;
- conf->rx = TRUE;
- conf->tx = TRUE;
+ wpa_hexdump_key(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
+ os_free(context);
+ context = NULL;
- sa_key = ieee802_1x_kay_init_data_key(conf);
+ sa_key = os_zalloc(sizeof(*sa_key));
if (!sa_key) {
- os_free(conf->key);
- os_free(conf);
- os_free(context);
- return -1;
+ wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+ goto fail;
}
+
+ sa_key->key = key;
+ sa_key->key_len = key_len;
+ os_memcpy(sa_key->key_identifier.mi, participant->mi, MI_LEN);
+ sa_key->key_identifier.kn = kay->dist_kn;
+
+ sa_key->confidentiality_offset = kay->macsec_confidentiality;
+ sa_key->an = kay->dist_an;
+ ieee802_1x_kay_init_data_key(sa_key);
+
participant->new_key = sa_key;
+ ieee802_1x_kay_use_data_key(sa_key);
dl_list_add(&participant->sak_list, &sa_key->list);
- ieee802_1x_cp_set_ciphersuite(participant->kay->cp,
- cipher_suite_tbl[kay->macsec_csindex].id);
+
+ ieee802_1x_cp_set_ciphersuite(kay->cp, cs->id);
ieee802_1x_cp_sm_step(kay->cp);
- ieee802_1x_cp_set_offset(kay->cp, conf->offset);
+ ieee802_1x_cp_set_offset(kay->cp, kay->macsec_confidentiality);
ieee802_1x_cp_sm_step(kay->cp);
- ieee802_1x_cp_set_distributedki(kay->cp, &conf->ki);
- ieee802_1x_cp_set_distributedan(kay->cp, conf->an);
+ ieee802_1x_cp_set_distributedki(kay->cp, &sa_key->key_identifier);
+ ieee802_1x_cp_set_distributedan(kay->cp, sa_key->an);
ieee802_1x_cp_signal_newsak(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
@@ -2067,17 +2184,31 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
struct ieee802_1x_kay_peer, list)
peer->sak_used = FALSE;
- participant->kay->dist_kn++;
- participant->kay->dist_an++;
- if (participant->kay->dist_an > 3)
- participant->kay->dist_an = 0;
+ kay->dist_kn++;
+ kay->dist_an++;
+ if (kay->dist_an > 3)
+ kay->dist_an = 0;
- participant->kay->dist_time = time(NULL);
+ kay->dist_time = time(NULL);
- os_free(conf->key);
- os_free(conf);
- os_free(context);
return 0;
+
+fail:
+ os_free(key);
+ os_free(context);
+ return -1;
+}
+
+
+static int compare_priorities(const struct ieee802_1x_kay_peer *peer,
+ const struct ieee802_1x_kay_peer *other)
+{
+ if (peer->key_server_priority < other->key_server_priority)
+ return -1;
+ if (other->key_server_priority < peer->key_server_priority)
+ return 1;
+
+ return os_memcmp(peer->sci.addr, other->sci.addr, ETH_ALEN);
}
@@ -2092,7 +2223,7 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
struct ieee802_1x_kay_peer *key_server = NULL;
struct ieee802_1x_kay *kay = participant->kay;
Boolean i_is_key_server;
- int i;
+ int priority_comparison;
if (participant->is_obliged_key_server) {
participant->new_sak = TRUE;
@@ -2112,47 +2243,32 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
continue;
}
- if (peer->key_server_priority <
- key_server->key_server_priority) {
+ if (compare_priorities(peer, key_server) < 0)
key_server = peer;
- } else if (peer->key_server_priority ==
- key_server->key_server_priority) {
- for (i = 0; i < 6; i++) {
- if (peer->sci.addr[i] <
- key_server->sci.addr[i])
- key_server = peer;
- }
- }
}
/* elect the key server between me and the above elected peer */
i_is_key_server = FALSE;
if (key_server && participant->can_be_key_server) {
- if (kay->actor_priority
- < key_server->key_server_priority) {
+ struct ieee802_1x_kay_peer tmp;
+
+ tmp.key_server_priority = kay->actor_priority;
+ os_memcpy(&tmp.sci, &kay->actor_sci, sizeof(tmp.sci));
+ priority_comparison = compare_priorities(&tmp, key_server);
+ if (priority_comparison < 0) {
i_is_key_server = TRUE;
- } else if (kay->actor_priority
- == key_server->key_server_priority) {
- for (i = 0; i < 6; i++) {
- if (kay->actor_sci.addr[i]
- < key_server->sci.addr[i]) {
- i_is_key_server = TRUE;
- }
- }
+ } else if (priority_comparison == 0) {
+ wpa_printf(MSG_WARNING,
+ "KaY: Cannot elect key server between me and peer, duplicate MAC detected");
+ key_server = NULL;
}
- }
-
- if (!key_server && !i_is_key_server) {
- participant->principal = FALSE;
- participant->is_key_server = FALSE;
- participant->is_elected = FALSE;
- return 0;
+ } else if (participant->can_be_key_server) {
+ i_is_key_server = TRUE;
}
if (i_is_key_server) {
ieee802_1x_cp_set_electedself(kay->cp, TRUE);
- if (os_memcmp(&kay->key_server_sci, &kay->actor_sci,
- sizeof(kay->key_server_sci))) {
+ if (!sci_equal(&kay->key_server_sci, &kay->actor_sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
}
@@ -2160,19 +2276,19 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
participant->is_key_server = TRUE;
participant->principal = TRUE;
participant->new_sak = TRUE;
- wpa_printf(MSG_DEBUG, "KaY: I is elected as key server");
+ wpa_printf(MSG_DEBUG, "KaY: I am elected as key server");
participant->to_dist_sak = FALSE;
participant->is_elected = TRUE;
os_memcpy(&kay->key_server_sci, &kay->actor_sci,
sizeof(kay->key_server_sci));
kay->key_server_priority = kay->actor_priority;
- }
-
- if (key_server) {
+ } else if (key_server) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer %s was elected as the key server",
+ mi_txt(key_server->mi));
ieee802_1x_cp_set_electedself(kay->cp, FALSE);
- if (os_memcmp(&kay->key_server_sci, &key_server->sci,
- sizeof(kay->key_server_sci))) {
+ if (!sci_equal(&kay->key_server_sci, &key_server->sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
}
@@ -2184,6 +2300,10 @@ ieee802_1x_kay_elect_key_server(struct ieee802_1x_mka_participant *participant)
os_memcpy(&kay->key_server_sci, &key_server->sci,
sizeof(kay->key_server_sci));
kay->key_server_priority = key_server->key_server_priority;
+ } else {
+ participant->principal = FALSE;
+ participant->is_key_server = FALSE;
+ participant->is_elected = FALSE;
}
return 0;
@@ -2226,11 +2346,11 @@ ieee802_1x_kay_decide_macsec_use(
if (!peer->macsec_desired)
continue;
- if (peer->macsec_capbility == MACSEC_CAP_NOT_IMPLEMENTED)
+ if (peer->macsec_capability == MACSEC_CAP_NOT_IMPLEMENTED)
continue;
- less_capability = (less_capability < peer->macsec_capbility) ?
- less_capability : peer->macsec_capbility;
+ less_capability = (less_capability < peer->macsec_capability) ?
+ less_capability : peer->macsec_capability;
has_peer = TRUE;
}
@@ -2285,16 +2405,24 @@ ieee802_1x_kay_encode_mkpdu(struct ieee802_1x_mka_participant *participant,
os_memcpy(ether_hdr->src, participant->kay->actor_sci.addr,
sizeof(ether_hdr->dest));
ether_hdr->ethertype = host_to_be16(ETH_P_EAPOL);
+ wpa_printf(MSG_DEBUG, "KaY: Ethernet header: DA=" MACSTR " SA=" MACSTR
+ " Ethertype=0x%x",
+ MAC2STR(ether_hdr->dest), MAC2STR(ether_hdr->src),
+ be_to_host16(ether_hdr->ethertype));
eapol_hdr = wpabuf_put(pbuf, sizeof(*eapol_hdr));
eapol_hdr->version = EAPOL_VERSION;
eapol_hdr->type = IEEE802_1X_TYPE_EAPOL_MKA;
- eapol_hdr->length = host_to_be16(pbuf->size - pbuf->used);
-
- for (i = 0; i < ARRAY_SIZE(mak_body_handler); i++) {
- if (mak_body_handler[i].body_present &&
- mak_body_handler[i].body_present(participant)) {
- if (mak_body_handler[i].body_tx(participant, pbuf))
+ eapol_hdr->length = host_to_be16(wpabuf_tailroom(pbuf));
+ wpa_printf(MSG_DEBUG,
+ "KaY: Common EAPOL PDU structure: Protocol Version=%u Packet Type=%u Packet Body Length=%u",
+ eapol_hdr->version, eapol_hdr->type,
+ be_to_host16(eapol_hdr->length));
+
+ for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
+ if (mka_body_handler[i].body_present &&
+ mka_body_handler[i].body_present(participant)) {
+ if (mka_body_handler[i].body_tx(participant, pbuf))
return -1;
}
}
@@ -2302,6 +2430,7 @@ ieee802_1x_kay_encode_mkpdu(struct ieee802_1x_mka_participant *participant,
return 0;
}
+
/**
* ieee802_1x_participant_send_mkpdu -
*/
@@ -2314,12 +2443,13 @@ ieee802_1x_participant_send_mkpdu(
size_t length = 0;
unsigned int i;
- wpa_printf(MSG_DEBUG, "KaY: to enpacket and send the MKPDU");
+ wpa_printf(MSG_DEBUG, "KaY: Encode and send an MKPDU (ifname=%s)",
+ kay->if_name);
length += sizeof(struct ieee802_1x_hdr) + sizeof(struct ieee8023_hdr);
- for (i = 0; i < ARRAY_SIZE(mak_body_handler); i++) {
- if (mak_body_handler[i].body_present &&
- mak_body_handler[i].body_present(participant))
- length += mak_body_handler[i].body_length(participant);
+ for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
+ if (mka_body_handler[i].body_present &&
+ mka_body_handler[i].body_present(participant))
+ length += mka_body_handler[i].body_length(participant);
}
buf = wpabuf_alloc(length);
@@ -2329,10 +2459,11 @@ ieee802_1x_participant_send_mkpdu(
}
if (ieee802_1x_kay_encode_mkpdu(participant, buf)) {
- wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail!");
+ wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail");
return -1;
}
+ wpa_hexdump_buf(MSG_MSGDUMP, "KaY: Outgoing MKPDU", buf);
l2_packet_send(kay->l2_mka, NULL, 0, wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
@@ -2344,6 +2475,16 @@ ieee802_1x_participant_send_mkpdu(
static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa);
+
+static void ieee802_1x_delete_transmit_sa(struct ieee802_1x_kay *kay,
+ struct transmit_sa *sa)
+{
+ secy_disable_transmit_sa(kay, sa);
+ secy_delete_transmit_sa(kay, sa);
+ ieee802_1x_kay_deinit_transmit_sa(sa);
+}
+
+
/**
* ieee802_1x_participant_timer -
*/
@@ -2359,28 +2500,19 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
kay = participant->kay;
+ wpa_printf(MSG_DEBUG, "KaY: Participant timer (ifname=%s)",
+ kay->if_name);
if (participant->cak_life) {
- if (now > participant->cak_life) {
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = TRUE;
- ieee802_1x_kay_delete_mka(kay, &participant->ckn);
- return;
- }
+ if (now > participant->cak_life)
+ goto delete_mka;
}
/* should delete MKA instance if there are not live peers
* when the MKA life elapsed since its creating */
if (participant->mka_life) {
if (dl_list_empty(&participant->live_peers)) {
- if (now > participant->mka_life) {
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = TRUE;
- ieee802_1x_kay_delete_mka(kay,
- &participant->ckn);
- return;
- }
+ if (now > participant->mka_life)
+ goto delete_mka;
} else {
participant->mka_life = 0;
}
@@ -2397,9 +2529,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
dl_list_for_each_safe(rxsc, pre_rxsc,
&participant->rxsc_list,
struct receive_sc, list) {
- if (os_memcmp(&rxsc->sci, &peer->sci,
- sizeof(rxsc->sci)) == 0) {
- secy_delete_receive_sc(kay, rxsc);
+ if (sci_equal(&rxsc->sci, &peer->sci)) {
ieee802_1x_kay_deinit_receive_sc(
participant, rxsc);
}
@@ -2416,7 +2546,13 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
participant->advised_capability =
MACSEC_CAP_NOT_IMPLEMENTED;
participant->to_use_sak = FALSE;
- kay->authenticated = TRUE;
+ participant->ltx = FALSE;
+ participant->lrx = FALSE;
+ participant->otx = FALSE;
+ participant->orx = FALSE;
+ participant->is_key_server = FALSE;
+ participant->is_elected = FALSE;
+ kay->authenticated = FALSE;
kay->secured = FALSE;
kay->failed = FALSE;
kay->ltx_kn = 0;
@@ -2430,11 +2566,10 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
dl_list_for_each_safe(txsa, pre_txsa,
&participant->txsc->sa_list,
struct transmit_sa, list) {
- secy_disable_transmit_sa(kay, txsa);
- ieee802_1x_kay_deinit_transmit_sa(txsa);
+ ieee802_1x_delete_transmit_sa(kay, txsa);
}
- ieee802_1x_cp_connect_authenticated(kay->cp);
+ ieee802_1x_cp_connect_pending(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
} else {
ieee802_1x_kay_elect_key_server(participant);
@@ -2454,21 +2589,30 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
}
}
- if (participant->new_sak) {
+ if (participant->new_sak && participant->is_key_server) {
if (!ieee802_1x_kay_generate_new_sak(participant))
participant->to_dist_sak = TRUE;
participant->new_sak = FALSE;
}
- if (participant->retry_count < MAX_RETRY_CNT) {
+ if (participant->retry_count < MAX_RETRY_CNT ||
+ participant->mode == PSK) {
ieee802_1x_participant_send_mkpdu(participant);
participant->retry_count++;
}
- eloop_register_timeout(MKA_HELLO_TIME / 1000, 0,
+ eloop_register_timeout(kay->mka_hello_time / 1000, 0,
ieee802_1x_participant_timer,
participant, NULL);
+
+ return;
+
+delete_mka:
+ kay->authenticated = FALSE;
+ kay->secured = FALSE;
+ kay->failed = TRUE;
+ ieee802_1x_kay_delete_mka(kay, &participant->ckn);
}
@@ -2497,6 +2641,7 @@ ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
psa->confidentiality = FALSE;
psa->an = an;
+ ieee802_1x_kay_use_data_key(key);
psa->pkey = key;
psa->next_pn = next_PN;
psa->sc = psc;
@@ -2506,8 +2651,8 @@ ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
- "KaY: Create transmit SA(an: %d, next_PN: %u) of SC(channel: %d)",
- (int) an, next_PN, psc->channel);
+ "KaY: Create transmit SA(an: %hhu, next_pn: %u) of SC",
+ an, next_PN);
return psa;
}
@@ -2518,10 +2663,11 @@ ieee802_1x_kay_init_transmit_sa(struct transmit_sc *psc, u8 an, u32 next_PN,
*/
static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa)
{
+ ieee802_1x_kay_deinit_data_key(psa->pkey);
psa->pkey = NULL;
wpa_printf(MSG_DEBUG,
- "KaY: Delete transmit SA(an: %d) of SC(channel: %d)",
- psa->an, psa->sc->channel);
+ "KaY: Delete transmit SA(an: %hhu) of SC",
+ psa->an);
dl_list_del(&psa->list);
os_free(psa);
}
@@ -2531,8 +2677,7 @@ static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa)
* init_transmit_sc -
*/
static struct transmit_sc *
-ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci,
- int channel)
+ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci)
{
struct transmit_sc *psc;
@@ -2542,7 +2687,6 @@ ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci,
return NULL;
}
os_memcpy(&psc->sci, sci, sizeof(psc->sci));
- psc->channel = channel;
os_get_time(&psc->created_time);
psc->transmitting = FALSE;
@@ -2550,8 +2694,8 @@ ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci,
psc->enciphering_sa = FALSE;
dl_list_init(&psc->sa_list);
- wpa_printf(MSG_DEBUG, "KaY: Create transmit SC(channel: %d)", channel);
- wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)sci , sizeof(*sci));
+ wpa_printf(MSG_DEBUG, "KaY: Create transmit SC - SCI: %s",
+ sci_txt(&psc->sci));
return psc;
}
@@ -2566,14 +2710,11 @@ ieee802_1x_kay_deinit_transmit_sc(
{
struct transmit_sa *psa, *tmp;
- wpa_printf(MSG_DEBUG, "KaY: Delete transmit SC(channel: %d)",
- psc->channel);
- dl_list_for_each_safe(psa, tmp, &psc->sa_list, struct transmit_sa,
- list) {
- secy_disable_transmit_sa(participant->kay, psa);
- ieee802_1x_kay_deinit_transmit_sa(psa);
- }
+ wpa_printf(MSG_DEBUG, "KaY: Delete transmit SC");
+ dl_list_for_each_safe(psa, tmp, &psc->sa_list, struct transmit_sa, list)
+ ieee802_1x_delete_transmit_sa(participant->kay, psa);
+ secy_delete_transmit_sc(participant->kay, psc);
os_free(psc);
}
@@ -2650,6 +2791,32 @@ int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
}
+static struct transmit_sa * lookup_txsa_by_an(struct transmit_sc *txsc, u8 an)
+{
+ struct transmit_sa *txsa;
+
+ dl_list_for_each(txsa, &txsc->sa_list, struct transmit_sa, list) {
+ if (txsa->an == an)
+ return txsa;
+ }
+
+ return NULL;
+}
+
+
+static struct receive_sa * lookup_rxsa_by_an(struct receive_sc *rxsc, u8 an)
+{
+ struct receive_sa *rxsa;
+
+ dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list) {
+ if (rxsa->an == an)
+ return rxsa;
+ }
+
+ return NULL;
+}
+
+
/**
* ieee802_1x_kay_create_sas -
*/
@@ -2679,11 +2846,14 @@ int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
}
}
if (!latest_sak) {
- wpa_printf(MSG_ERROR, "lki related sak not found");
+ wpa_printf(MSG_ERROR, "KaY: lki related sak not found");
return -1;
}
dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
+ while ((rxsa = lookup_rxsa_by_an(rxsc, latest_sak->an)) != NULL)
+ ieee802_1x_delete_receive_sa(kay, rxsa);
+
rxsa = ieee802_1x_kay_init_receive_sa(rxsc, latest_sak->an, 1,
latest_sak);
if (!rxsa)
@@ -2692,8 +2862,14 @@ int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
secy_create_receive_sa(kay, rxsa);
}
+ while ((txsa = lookup_txsa_by_an(principal->txsc, latest_sak->an)) !=
+ NULL)
+ ieee802_1x_delete_transmit_sa(kay, txsa);
+
txsa = ieee802_1x_kay_init_transmit_sa(principal->txsc, latest_sak->an,
- 1, latest_sak);
+ latest_sak->next_pn ?
+ latest_sak->next_pn : 1,
+ latest_sak);
if (!txsa)
return -1;
@@ -2725,20 +2901,16 @@ int ieee802_1x_kay_delete_sas(struct ieee802_1x_kay *kay,
/* remove the transmit sa */
dl_list_for_each_safe(txsa, pre_txsa, &principal->txsc->sa_list,
struct transmit_sa, list) {
- if (is_ki_equal(&txsa->pkey->key_identifier, ki)) {
- secy_disable_transmit_sa(kay, txsa);
- ieee802_1x_kay_deinit_transmit_sa(txsa);
- }
+ if (is_ki_equal(&txsa->pkey->key_identifier, ki))
+ ieee802_1x_delete_transmit_sa(kay, txsa);
}
/* remove the receive sa */
dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
dl_list_for_each_safe(rxsa, pre_rxsa, &rxsc->sa_list,
struct receive_sa, list) {
- if (is_ki_equal(&rxsa->pkey->key_identifier, ki)) {
- secy_disable_receive_sa(kay, rxsa);
- ieee802_1x_kay_deinit_receive_sa(rxsa);
- }
+ if (is_ki_equal(&rxsa->pkey->key_identifier, ki))
+ ieee802_1x_delete_receive_sa(kay, rxsa);
}
}
@@ -2746,11 +2918,12 @@ int ieee802_1x_kay_delete_sas(struct ieee802_1x_kay *kay,
dl_list_for_each_safe(sa_key, pre_key, &principal->sak_list,
struct data_key, list) {
if (is_ki_equal(&sa_key->key_identifier, ki)) {
+ if (principal->new_key == sa_key)
+ principal->new_key = NULL;
+ dl_list_del(&sa_key->list);
ieee802_1x_kay_deinit_data_key(sa_key);
break;
}
- if (principal->new_key == sa_key)
- principal->new_key = NULL;
}
return 0;
@@ -2827,7 +3000,7 @@ int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay)
if (!principal)
return -1;
- if (principal->retry_count < MAX_RETRY_CNT) {
+ if (principal->retry_count < MAX_RETRY_CNT || principal->mode == PSK) {
ieee802_1x_participant_send_mkpdu(principal);
principal->retry_count++;
}
@@ -2837,40 +3010,9 @@ int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay)
/**
- * ieee802_1x_kay_cp_conf -
- */
-int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
- struct ieee802_1x_cp_conf *pconf)
-{
- pconf->protect = kay->macsec_protect;
- pconf->replay_protect = kay->macsec_replay_protect;
- pconf->validate = kay->macsec_validate;
-
- return 0;
-}
-
-
-/**
- * ieee802_1x_kay_alloc_cp_sm -
- */
-static struct ieee802_1x_cp_sm *
-ieee802_1x_kay_alloc_cp_sm(struct ieee802_1x_kay *kay)
-{
- struct ieee802_1x_cp_conf conf;
-
- os_memset(&conf, 0, sizeof(conf));
- conf.protect = kay->macsec_protect;
- conf.replay_protect = kay->macsec_replay_protect;
- conf.validate = kay->macsec_validate;
- conf.replay_window = kay->macsec_replay_window;
-
- return ieee802_1x_cp_sm_init(kay, &conf);
-}
-
-
-/**
* ieee802_1x_kay_mkpdu_sanity_check -
- * sanity check specified in clause 11.11.2 of IEEE802.1X-2010
+ * Sanity checks specified in IEEE Std 802.1X-2010, 11.11.2 (Validation of
+ * MKPDUs)
*/
static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
const u8 *buf, size_t len)
@@ -2882,57 +3024,90 @@ static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
size_t mka_msg_len;
struct ieee802_1x_mka_participant *participant;
size_t body_len;
+ size_t ckn_len;
u8 icv[MAX_ICV_LEN];
- u8 *msg_icv;
+ const u8 *msg_icv;
+ /* len > eth+eapol header already verified in kay_l2_receive();
+ * likewise, eapol_hdr->length validated there */
eth_hdr = (struct ieee8023_hdr *) buf;
eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
mka_hdr = (struct ieee802_1x_mka_hdr *) (eapol_hdr + 1);
- /* destination address should be not individual address */
+ wpa_printf(MSG_DEBUG, "KaY: Ethernet header: DA=" MACSTR " SA=" MACSTR
+ " Ethertype=0x%x",
+ MAC2STR(eth_hdr->dest), MAC2STR(eth_hdr->src),
+ be_to_host16(eth_hdr->ethertype));
+
+ /* the destination address shall not be an individual address */
if (os_memcmp(eth_hdr->dest, pae_group_addr, ETH_ALEN) != 0) {
- wpa_printf(MSG_MSGDUMP,
+ wpa_printf(MSG_DEBUG,
"KaY: ethernet destination address is not PAE group address");
return -1;
}
- /* MKPDU should not less than 32 octets */
+ wpa_printf(MSG_DEBUG,
+ "KaY: Common EAPOL PDU structure: Protocol Version=%u Packet Type=%u Packet Body Length=%u",
+ eapol_hdr->version, eapol_hdr->type,
+ be_to_host16(eapol_hdr->length));
+
+ /* MKPDU shall not be less than 32 octets */
mka_msg_len = be_to_host16(eapol_hdr->length);
if (mka_msg_len < 32) {
- wpa_printf(MSG_MSGDUMP, "KaY: MKPDU is less than 32 octets");
+ wpa_printf(MSG_DEBUG, "KaY: MKPDU is less than 32 octets");
return -1;
}
- /* MKPDU should multiple 4 octets */
+ /* MKPDU shall be a multiple of 4 octets */
if ((mka_msg_len % 4) != 0) {
- wpa_printf(MSG_MSGDUMP,
+ wpa_printf(MSG_DEBUG,
"KaY: MKPDU is not multiple of 4 octets");
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "KaY: EAPOL-MKA Packet Body (MKPDU)",
+ mka_hdr, mka_msg_len);
+
+ /* Room for body_len already verified in kay_l2_receive() */
body = (struct ieee802_1x_mka_basic_body *) mka_hdr;
- ieee802_1x_mka_dump_basic_body(body);
body_len = get_mka_param_body_len(body);
/* EAPOL-MKA body should comprise basic parameter set and ICV */
if (mka_msg_len < MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN) {
wpa_printf(MSG_ERROR,
- "KaY: Received EAPOL-MKA Packet Body Length (%d bytes) is less than the Basic Parameter Set Header Length (%d bytes) + the Basic Parameter Set Body Length (%d bytes) + %d bytes of ICV",
- (int) mka_msg_len, (int) MKA_HDR_LEN,
- (int) body_len, DEFAULT_ICV_LEN);
+ "KaY: Received EAPOL-MKA Packet Body Length (%zu bytes) is less than the Basic Parameter Set Header Length (%zu bytes) + the Basic Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+ mka_msg_len, MKA_HDR_LEN,
+ body_len, DEFAULT_ICV_LEN);
return -1;
}
+ if (body_len < sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN) {
+ wpa_printf(MSG_DEBUG, "KaY: Too small body length %zu",
+ body_len);
+ return -1;
+ }
+ ckn_len = body_len -
+ (sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN);
+ if (ckn_len < 1 || ckn_len > MAX_CKN_LEN) {
+ wpa_printf(MSG_WARNING,
+ "KaY: Received EAPOL-MKA CKN Length (%zu bytes) is out of range (<= %u bytes)",
+ ckn_len, MAX_CKN_LEN);
+ return -1;
+ }
+
+ ieee802_1x_mka_dump_basic_body(body);
+
/* CKN should be owned by I */
- participant = ieee802_1x_kay_get_participant(kay, body->ckn);
+ participant = ieee802_1x_kay_get_participant(kay, body->ckn, ckn_len);
if (!participant) {
- wpa_printf(MSG_DEBUG, "CKN is not included in my CA");
+ wpa_printf(MSG_DEBUG, "KaY: CKN is not included in my CA");
return -1;
}
/* algorithm agility check */
if (os_memcmp(body->algo_agility, mka_algo_agility,
sizeof(body->algo_agility)) != 0) {
- wpa_printf(MSG_ERROR,
- "KaY: peer's algorithm agility not supported for me");
+ wpa_printf(MSG_INFO,
+ "KaY: Peer's algorithm agility (%s) not supported",
+ algo_agility_txt(body->algo_agility));
return -1;
}
@@ -2942,25 +3117,29 @@ static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
* its size, not the fixed length 16 octets, indicated by the EAPOL
* packet body length.
*/
- if (mka_alg_tbl[kay->mka_algindex].icv_hash(
- participant->ick.key,
+ if (len < mka_alg_tbl[kay->mka_algindex].icv_len ||
+ mka_alg_tbl[kay->mka_algindex].icv_hash(
+ participant->ick.key, participant->ick.len,
buf, len - mka_alg_tbl[kay->mka_algindex].icv_len, icv)) {
- wpa_printf(MSG_ERROR, "KaY: omac1_aes_128 failed");
+ wpa_printf(MSG_ERROR, "KaY: Failed to calculate ICV");
return -1;
}
- msg_icv = ieee802_1x_mka_decode_icv_body(participant, (u8 *) mka_hdr,
- mka_msg_len);
- if (msg_icv) {
- if (os_memcmp_const(msg_icv, icv,
- mka_alg_tbl[kay->mka_algindex].icv_len) !=
- 0) {
- wpa_printf(MSG_ERROR,
- "KaY: Computed ICV is not equal to Received ICV");
+ msg_icv = ieee802_1x_mka_decode_icv_body(participant,
+ (const u8 *) mka_hdr,
+ mka_msg_len);
+ if (!msg_icv) {
+ wpa_printf(MSG_WARNING, "KaY: No ICV in MKPDU - ignore it");
return -1;
- }
- } else {
- wpa_printf(MSG_ERROR, "KaY: No ICV");
+ }
+ wpa_hexdump(MSG_DEBUG, "KaY: Received ICV",
+ msg_icv, mka_alg_tbl[kay->mka_algindex].icv_len);
+ if (os_memcmp_const(msg_icv, icv,
+ mka_alg_tbl[kay->mka_algindex].icv_len) != 0) {
+ wpa_printf(MSG_WARNING,
+ "KaY: Computed ICV is not equal to Received ICV");
+ wpa_hexdump(MSG_DEBUG, "KaY: Calculated ICV",
+ icv, mka_alg_tbl[kay->mka_algindex].icv_len);
return -1;
}
@@ -2976,14 +3155,19 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
{
struct ieee802_1x_mka_participant *participant;
struct ieee802_1x_mka_hdr *hdr;
+ struct ieee802_1x_kay_peer *peer;
size_t body_len;
size_t left_len;
- int body_type;
+ u8 body_type;
int i;
const u8 *pos;
- Boolean my_included;
Boolean handled[256];
+ Boolean bad_sak_use = FALSE; /* Error detected while processing SAK Use
+ * parameter set */
+ Boolean i_in_peerlist, is_in_live_peer, is_in_potential_peer;
+ wpa_printf(MSG_DEBUG, "KaY: Decode received MKPDU (ifname=%s)",
+ kay->if_name);
if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
return -1;
@@ -2997,33 +3181,39 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
/* to skip basic parameter set */
hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
+ if (left_len < body_len + MKA_HDR_LEN)
+ return -1;
pos += body_len + MKA_HDR_LEN;
left_len -= body_len + MKA_HDR_LEN;
/* check i am in the peer's peer list */
- my_included = ieee802_1x_mka_i_in_peerlist(participant, pos, left_len);
- if (my_included) {
+ i_in_peerlist = ieee802_1x_mka_i_in_peerlist(participant, pos,
+ left_len);
+ is_in_live_peer = ieee802_1x_kay_is_in_live_peer(
+ participant, participant->current_peer_id.mi);
+ wpa_printf(MSG_DEBUG, "KaY: i_in_peerlist=%s is_in_live_peer=%s",
+ yes_no(i_in_peerlist), yes_no(is_in_live_peer));
+ if (i_in_peerlist && !is_in_live_peer) {
/* accept the peer as live peer */
- if (!ieee802_1x_kay_is_in_peer(
- participant,
- participant->current_peer_id.mi)) {
- if (!ieee802_1x_kay_create_live_peer(
+ is_in_potential_peer = ieee802_1x_kay_is_in_potential_peer(
+ participant, participant->current_peer_id.mi);
+ if (is_in_potential_peer) {
+ if (!ieee802_1x_kay_move_live_peer(
participant,
participant->current_peer_id.mi,
- participant->current_peer_id.mn))
+ be_to_host32(participant->
+ current_peer_id.mn)))
+ return -1;
+ } else if (!ieee802_1x_kay_create_live_peer(
+ participant, participant->current_peer_id.mi,
+ be_to_host32(participant->
+ current_peer_id.mn))) {
return -1;
- ieee802_1x_kay_elect_key_server(participant);
- ieee802_1x_kay_decide_macsec_use(participant);
- }
- if (ieee802_1x_kay_is_in_potential_peer(
- participant, participant->current_peer_id.mi)) {
- ieee802_1x_kay_move_live_peer(
- participant, participant->current_peer_id.mi,
- participant->current_peer_id.mn);
- ieee802_1x_kay_elect_key_server(participant);
- ieee802_1x_kay_decide_macsec_use(participant);
}
+
+ ieee802_1x_kay_elect_key_server(participant);
+ ieee802_1x_kay_decide_macsec_use(participant);
}
/*
@@ -3034,9 +3224,11 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
handled[i] = FALSE;
handled[0] = TRUE;
- while (left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN) {
+ for (; left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
+ pos += body_len + MKA_HDR_LEN,
+ left_len -= body_len + MKA_HDR_LEN) {
hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
body_type = get_mka_param_body_type(hdr);
if (body_type == MKA_ICV_INDICATOR)
@@ -3044,28 +3236,107 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
if (left_len < (MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN)) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Peer Packet Body Length (%d bytes) is less than the Parameter Set Header Length (%d bytes) + the Parameter Set Body Length (%d bytes) + %d bytes of ICV",
- (int) left_len, (int) MKA_HDR_LEN,
- (int) body_len, DEFAULT_ICV_LEN);
- goto next_para_set;
+ "KaY: MKA Peer Packet Body Length (%zu bytes) is less than the Parameter Set Header Length (%zu bytes) + the Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+ left_len, MKA_HDR_LEN,
+ body_len, DEFAULT_ICV_LEN);
+ return -1;
}
- if (handled[body_type])
- goto next_para_set;
+ if (handled[body_type]) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: Ignore duplicated body type %u",
+ body_type);
+ continue;
+ }
handled[body_type] = TRUE;
- if (mak_body_handler[body_type].body_rx) {
- mak_body_handler[body_type].body_rx
- (participant, pos, left_len);
+ if (body_type < ARRAY_SIZE(mka_body_handler) &&
+ mka_body_handler[body_type].body_rx) {
+ if (mka_body_handler[body_type].body_rx
+ (participant, pos, left_len) != 0) {
+ /* Handle parameter set failure */
+ if (body_type != MKA_SAK_USE) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: decode of parameter set type (%d) failed",
+ body_type);
+ return -1;
+ }
+
+ /* Ideally DIST-SAK should be processed before
+ * SAK-USE. Unfortunately IEEE Std 802.1X-2010,
+ * 11.11.3 (Encoding MKPDUs) states SAK-USE(3)
+ * must always be encoded before DIST-SAK(4).
+ * Rather than redesigning mka_body_handler so
+ * that it somehow processes DIST-SAK before
+ * SAK-USE, just ignore SAK-USE failures if
+ * DIST-SAK is also present in this MKPDU. */
+ bad_sak_use = TRUE;
+ }
} else {
wpa_printf(MSG_ERROR,
- "The type %d not supported in this MKA version %d",
+ "KaY: The body type %d is not supported in this MKA version %d",
body_type, MKA_VERSION_ID);
}
+ }
+
+ if (bad_sak_use && !handled[MKA_DISTRIBUTED_SAK]) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: decode of parameter set type (%d) failed",
+ MKA_SAK_USE);
+ if (!reset_participant_mi(participant))
+ wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
+ else
+ wpa_printf(MSG_DEBUG,
+ "KaY: Selected a new random MI: %s",
+ mi_txt(participant->mi));
+ return -1;
+ }
+
+ /* Detect missing parameter sets */
+ peer = ieee802_1x_kay_get_live_peer(participant,
+ participant->current_peer_id.mi);
+ if (peer) {
+ /* MKPDU is from live peer */
+ if (!handled[MKA_SAK_USE]) {
+ /* Once a live peer starts sending SAK-USE, it should be
+ * sent every time. */
+ if (peer->sak_used) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: Live Peer stopped sending SAK-USE");
+ return -1;
+ }
+
+ /* Live peer is probably hung if it hasn't sent SAK-USE
+ * after a reasonable number of MKPDUs. Drop the MKPDU,
+ * which will eventually force an timeout. */
+ if (++peer->missing_sak_use_count >
+ MAX_MISSING_SAK_USE) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: Live Peer not sending SAK-USE");
+ return -1;
+ }
+ } else {
+ peer->missing_sak_use_count = 0;
+
+ /* Only update live peer watchdog after successful
+ * decode of all parameter sets */
+ peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+ }
+ } else {
+ /* MKPDU is from new or potential peer */
+ peer = ieee802_1x_kay_get_peer(participant,
+ participant->current_peer_id.mi);
+ if (!peer) {
+ wpa_printf(MSG_DEBUG, "KaY: No peer entry found");
+ return -1;
+ }
-next_para_set:
- pos += body_len + MKA_HDR_LEN;
- left_len -= body_len + MKA_HDR_LEN;
+ /* Do not update potential peer watchdog. Per IEEE Std
+ * 802.1X-2010, 9.4.3, potential peers need to show liveness by
+ * including our MI/MN in their transmitted MKPDU (within
+ * potential or live parameter sets). Whena potential peer does
+ * include our MI/MN in an MKPDU, we respond by moving the peer
+ * from 'potential_peers' to 'live_peers'. */
}
kay->active = TRUE;
@@ -3083,6 +3354,9 @@ static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf,
struct ieee802_1x_kay *kay = ctx;
struct ieee8023_hdr *eth_hdr;
struct ieee802_1x_hdr *eapol_hdr;
+ size_t calc_len;
+
+ /* IEEE Std 802.1X-2010, 11.4 (Validation of received EAPOL PDUs) */
/* must contain at least ieee8023_hdr + ieee802_1x_hdr */
if (len < sizeof(*eth_hdr) + sizeof(*eapol_hdr)) {
@@ -3093,26 +3367,35 @@ static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf,
eth_hdr = (struct ieee8023_hdr *) buf;
eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
- if (len != sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
- ntohs(eapol_hdr->length)) {
- wpa_printf(MSG_MSGDUMP, "KAY: EAPOL MPDU is invalid: (%lu-%lu)",
+ calc_len = sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
+ be_to_host16(eapol_hdr->length);
+ if (len < calc_len) {
+ wpa_printf(MSG_MSGDUMP, "KaY: EAPOL MPDU is invalid: (received len %lu, calculated len %lu, EAPOL length %u)",
(unsigned long) len,
- (unsigned long) ntohs(eapol_hdr->length));
+ (unsigned long) calc_len,
+ be_to_host16(eapol_hdr->length));
return;
}
+ if (len > calc_len) {
+ wpa_hexdump(MSG_DEBUG,
+ "KaY: Ignore extra octets following the Packey Body field",
+ &buf[calc_len], len - calc_len);
+ len = calc_len;
+ }
if (eapol_hdr->version < EAPOL_VERSION) {
wpa_printf(MSG_MSGDUMP, "KaY: version %d does not support MKA",
eapol_hdr->version);
return;
}
- if (ntohs(eth_hdr->ethertype) != ETH_P_PAE ||
+ if (be_to_host16(eth_hdr->ethertype) != ETH_P_PAE ||
eapol_hdr->type != IEEE802_1X_TYPE_EAPOL_MKA)
- return;
+ return; /* ignore other EAPOL types silently here */
- wpa_hexdump(MSG_DEBUG, "RX EAPOL-MKA: ", buf, len);
+ wpa_hexdump(MSG_DEBUG, "KaY: RX EAPOL-MKA", buf, len);
if (dl_list_empty(&kay->participant_list)) {
- wpa_printf(MSG_ERROR, "KaY: no MKA participant instance");
+ wpa_printf(MSG_ERROR,
+ "KaY: No MKA participant instance - ignore EAPOL-MKA");
return;
}
@@ -3125,13 +3408,18 @@ static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf,
*/
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
- const char *ifname, const u8 *addr)
+ Boolean macsec_replay_protect, u32 macsec_replay_window,
+ u16 port, u8 priority, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
+ wpa_printf(MSG_DEBUG, "KaY: Initialize - ifname=%s addr=" MACSTR
+ " port=%u priority=%u",
+ ifname, MAC2STR(addr), port, priority);
kay = os_zalloc(sizeof(*kay));
if (!kay) {
wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
+ os_free(ctx);
return NULL;
}
@@ -3147,8 +3435,10 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
os_memcpy(kay->actor_sci.addr, addr, ETH_ALEN);
- kay->actor_sci.port = 0x0001;
- kay->actor_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
+ kay->actor_sci.port = host_to_be16(port ? port : 0x0001);
+ wpa_printf(MSG_DEBUG, "KaY: Generated SCI: %s",
+ sci_txt(&kay->actor_sci));
+ kay->actor_priority = priority;
/* While actor acts as a key server, shall distribute sakey */
kay->dist_kn = 1;
@@ -3165,38 +3455,52 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
dl_list_init(&kay->participant_list);
- if (policy == DO_NOT_SECURE) {
+ if (policy != DO_NOT_SECURE &&
+ secy_get_capability(kay, &kay->macsec_capable) < 0)
+ goto error;
+
+ if (policy == DO_NOT_SECURE ||
+ kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
kay->macsec_desired = FALSE;
kay->macsec_protect = FALSE;
+ kay->macsec_encrypt = FALSE;
kay->macsec_validate = Disabled;
kay->macsec_replay_protect = FALSE;
kay->macsec_replay_window = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
+ kay->mka_hello_time = MKA_HELLO_TIME;
} else {
- kay->macsec_capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
kay->macsec_desired = TRUE;
kay->macsec_protect = TRUE;
+ if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF &&
+ policy == SHOULD_ENCRYPT) {
+ kay->macsec_encrypt = TRUE;
+ kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
+ } else { /* SHOULD_SECURE */
+ kay->macsec_encrypt = FALSE;
+ kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
+ }
kay->macsec_validate = Strict;
- kay->macsec_replay_protect = FALSE;
- kay->macsec_replay_window = 0;
- kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
+ kay->macsec_replay_protect = macsec_replay_protect;
+ kay->macsec_replay_window = macsec_replay_window;
+ kay->mka_hello_time = MKA_HELLO_TIME;
}
wpa_printf(MSG_DEBUG, "KaY: state machine created");
/* Initialize the SecY must be prio to CP, as CP will control SecY */
- secy_init_macsec(kay);
- secy_get_available_transmit_sc(kay, &kay->sc_ch);
+ if (secy_init_macsec(kay) < 0) {
+ wpa_printf(MSG_DEBUG, "KaY: Could not initialize MACsec");
+ goto error;
+ }
wpa_printf(MSG_DEBUG, "KaY: secy init macsec done");
/* init CP */
- kay->cp = ieee802_1x_kay_alloc_cp_sm(kay);
- if (kay->cp == NULL) {
- ieee802_1x_kay_deinit(kay);
- return NULL;
- }
+ kay->cp = ieee802_1x_cp_sm_init(kay);
+ if (kay->cp == NULL)
+ goto error;
if (policy == DO_NOT_SECURE) {
ieee802_1x_cp_connect_authenticated(kay->cp);
@@ -3207,12 +3511,15 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
if (kay->l2_mka == NULL) {
wpa_printf(MSG_WARNING,
"KaY: Failed to initialize L2 packet processing for MKA packet");
- ieee802_1x_kay_deinit(kay);
- return NULL;
+ goto error;
}
}
return kay;
+
+error:
+ ieee802_1x_kay_deinit(kay);
+ return NULL;
}
@@ -3249,28 +3556,47 @@ ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay)
}
+static const char * mode_txt(enum mka_created_mode mode)
+{
+ switch (mode) {
+ case PSK:
+ return "PSK";
+ case EAP_EXCHANGE:
+ return "EAP";
+ }
+
+ return "?";
+}
+
+
/**
* ieee802_1x_kay_create_mka -
*/
struct ieee802_1x_mka_participant *
-ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
- struct mka_key *cak, u32 life,
+ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
+ const struct mka_key_name *ckn,
+ const struct mka_key *cak, u32 life,
enum mka_created_mode mode, Boolean is_authenticator)
{
struct ieee802_1x_mka_participant *participant;
unsigned int usecs;
+ wpa_printf(MSG_DEBUG,
+ "KaY: Create MKA (ifname=%s mode=%s authenticator=%s)",
+ kay->if_name, mode_txt(mode), yes_no(is_authenticator));
+
if (!kay || !ckn || !cak) {
wpa_printf(MSG_ERROR, "KaY: ckn or cak is null");
return NULL;
}
- if (cak->len != mka_alg_tbl[kay->mka_algindex].cak_len) {
- wpa_printf(MSG_ERROR, "KaY: CAK length not follow key schema");
+ if (cak->len != 16 && cak->len != 32) {
+ wpa_printf(MSG_ERROR, "KaY: Unexpected CAK length %u",
+ (unsigned int) cak->len);
return NULL;
}
if (ckn->len > MAX_CKN_LEN) {
- wpa_printf(MSG_ERROR, "KaY: CKN is out of range(<=32 bytes)");
+ wpa_printf(MSG_ERROR, "KaY: CKN is out of range (>32 bytes)");
return NULL;
}
if (!kay->enable) {
@@ -3286,8 +3612,12 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
participant->ckn.len = ckn->len;
os_memcpy(participant->ckn.name, ckn->name, ckn->len);
+ wpa_hexdump(MSG_DEBUG, "KaY: CKN", participant->ckn.name,
+ participant->ckn.len);
participant->cak.len = cak->len;
os_memcpy(participant->cak.key, cak->key, cak->len);
+ wpa_hexdump_key(MSG_DEBUG, "KaY: CAK", participant->cak.key,
+ participant->cak.len);
if (life)
participant->cak_life = life + time(NULL);
@@ -3314,7 +3644,7 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
default:
participant->is_obliged_key_server = FALSE;
participant->can_be_key_server = TRUE;
- participant->is_key_server = FALSE;
+ participant->is_key_server = TRUE;
participant->is_elected = FALSE;
break;
}
@@ -3335,9 +3665,10 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
participant->retry_count = 0;
participant->kay = kay;
- if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ if (!reset_participant_mi(participant))
goto fail;
- participant->mn = 0;
+ wpa_printf(MSG_DEBUG, "KaY: Selected random MI: %s",
+ mi_txt(participant->mi));
participant->lrx = FALSE;
participant->ltx = FALSE;
@@ -3349,50 +3680,62 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
dl_list_init(&participant->sak_list);
participant->new_key = NULL;
dl_list_init(&participant->rxsc_list);
- participant->txsc = ieee802_1x_kay_init_transmit_sc(&kay->actor_sci,
- kay->sc_ch);
+ participant->txsc = ieee802_1x_kay_init_transmit_sc(&kay->actor_sci);
secy_cp_control_protect_frames(kay, kay->macsec_protect);
secy_cp_control_replay(kay, kay->macsec_replay_protect,
kay->macsec_replay_window);
- secy_create_transmit_sc(kay, participant->txsc);
+ if (secy_create_transmit_sc(kay, participant->txsc))
+ goto fail;
/* to derive KEK from CAK and CKN */
- participant->kek.len = mka_alg_tbl[kay->mka_algindex].kek_len;
+ participant->kek.len = participant->cak.len;
if (mka_alg_tbl[kay->mka_algindex].kek_trfm(participant->cak.key,
+ participant->cak.len,
participant->ckn.name,
participant->ckn.len,
- participant->kek.key)) {
- wpa_printf(MSG_ERROR, "KaY: Derived KEK failed");
+ participant->kek.key,
+ participant->kek.len)) {
+ wpa_printf(MSG_ERROR, "KaY: KEK derivation failed");
goto fail;
}
wpa_hexdump_key(MSG_DEBUG, "KaY: Derived KEK",
participant->kek.key, participant->kek.len);
/* to derive ICK from CAK and CKN */
- participant->ick.len = mka_alg_tbl[kay->mka_algindex].ick_len;
+ participant->ick.len = participant->cak.len;
if (mka_alg_tbl[kay->mka_algindex].ick_trfm(participant->cak.key,
+ participant->cak.len,
participant->ckn.name,
participant->ckn.len,
- participant->ick.key)) {
- wpa_printf(MSG_ERROR, "KaY: Derived ICK failed");
+ participant->ick.key,
+ participant->ick.len)) {
+ wpa_printf(MSG_ERROR, "KaY: ICK derivation failed");
goto fail;
}
wpa_hexdump_key(MSG_DEBUG, "KaY: Derived ICK",
participant->ick.key, participant->ick.len);
dl_list_add(&kay->participant_list, &participant->list);
- wpa_hexdump(MSG_DEBUG, "KaY: Participant created:",
- ckn->name, ckn->len);
- usecs = os_random() % (MKA_HELLO_TIME * 1000);
+ usecs = os_random() % (kay->mka_hello_time * 1000);
eloop_register_timeout(0, usecs, ieee802_1x_participant_timer,
participant, NULL);
- participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
- usecs / 1000000;
+
+ /* Disable MKA lifetime for PSK mode.
+ * The peer(s) can take a long time to come up, because we
+ * create a "standby" MKA, and we need it to remain live until
+ * some peer appears.
+ */
+ if (mode != PSK) {
+ participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
+ usecs / 1000000;
+ }
+ participant->mode = mode;
return participant;
fail:
+ os_free(participant->txsc);
os_free(participant);
return NULL;
}
@@ -3415,13 +3758,14 @@ ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn)
wpa_printf(MSG_DEBUG, "KaY: participant removed");
/* get the participant */
- participant = ieee802_1x_kay_get_participant(kay, ckn->name);
+ participant = ieee802_1x_kay_get_participant(kay, ckn->name, ckn->len);
if (!participant) {
wpa_hexdump(MSG_DEBUG, "KaY: participant is not found",
ckn->name, ckn->len);
return;
}
+ eloop_cancel_timeout(ieee802_1x_participant_timer, participant, NULL);
dl_list_del(&participant->list);
/* remove live peer */
@@ -3445,16 +3789,13 @@ ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn)
sak = dl_list_entry(participant->sak_list.next,
struct data_key, list);
dl_list_del(&sak->list);
- os_free(sak->key);
- os_free(sak);
+ ieee802_1x_kay_deinit_data_key(sak);
}
while (!dl_list_empty(&participant->rxsc_list)) {
rxsc = dl_list_entry(participant->rxsc_list.next,
struct receive_sc, list);
- secy_delete_receive_sc(kay, rxsc);
ieee802_1x_kay_deinit_receive_sc(participant, rxsc);
}
- secy_delete_transmit_sc(kay, participant->txsc);
ieee802_1x_kay_deinit_transmit_sc(participant, participant->txsc);
os_memset(&participant->cak, 0, sizeof(participant->cak));
@@ -3476,7 +3817,7 @@ void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
if (!kay || !ckn)
return;
- participant = ieee802_1x_kay_get_participant(kay, ckn->name);
+ participant = ieee802_1x_kay_get_participant(kay, ckn->name, ckn->len);
if (!participant)
return;
@@ -3510,14 +3851,16 @@ ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay)
* ieee802_1x_kay_change_cipher_suite -
*/
int
-ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
+ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
+ unsigned int cs_index)
{
struct ieee802_1x_mka_participant *participant;
+ enum macsec_cap secy_cap;
if (!kay)
return -1;
- if ((unsigned int) cs_index >= CS_TABLE_SIZE) {
+ if (cs_index >= CS_TABLE_SIZE) {
wpa_printf(MSG_ERROR,
"KaY: Configured cipher suite index is out of range");
return -1;
@@ -3531,6 +3874,12 @@ ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
kay->macsec_csindex = cs_index;
kay->macsec_capable = cipher_suite_tbl[kay->macsec_csindex].capable;
+ if (secy_get_capability(kay, &secy_cap) < 0)
+ return -3;
+
+ if (kay->macsec_capable > secy_cap)
+ kay->macsec_capable = secy_cap;
+
participant = ieee802_1x_kay_get_principal_participant(kay);
if (participant) {
wpa_printf(MSG_INFO, "KaY: Cipher Suite changed");
@@ -3539,3 +3888,210 @@ ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
return 0;
}
+
+
+#ifdef CONFIG_CTRL_IFACE
+
+/**
+ * ieee802_1x_kay_get_status - Get IEEE 802.1X KaY status details
+ * @sm: Pointer to KaY allocated with ieee802_1x_kay_init()
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @verbose: Whether to include verbose status information
+ * Returns: Number of bytes written to buf.
+ *
+ * Query KaY status information. This function fills in a text area with current
+ * status information. If the buffer (buf) is not large enough, status
+ * information will be truncated to fit the buffer.
+ */
+int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
+ size_t buflen)
+{
+ char *pos, *end;
+ int res, count;
+ struct ieee802_1x_mka_participant *p;
+
+ if (!kay)
+ return 0;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos,
+ "PAE KaY status=%s\n"
+ "Authenticated=%s\n"
+ "Secured=%s\n"
+ "Failed=%s\n"
+ "Actor Priority=%u\n"
+ "Key Server Priority=%u\n"
+ "Is Key Server=%s\n"
+ "Number of Keys Distributed=%u\n"
+ "Number of Keys Received=%u\n"
+ "MKA Hello Time=%u\n",
+ kay->active ? "Active" : "Not-Active",
+ kay->authenticated ? "Yes" : "No",
+ kay->secured ? "Yes" : "No",
+ kay->failed ? "Yes" : "No",
+ kay->actor_priority,
+ kay->key_server_priority,
+ kay->is_key_server ? "Yes" : "No",
+ kay->dist_kn - 1,
+ kay->rcvd_keys,
+ kay->mka_hello_time);
+ if (os_snprintf_error(buflen, res))
+ return 0;
+ pos += res;
+
+ res = os_snprintf(pos, end - pos,
+ "actor_sci=%s\n", sci_txt(&kay->actor_sci));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos += res;
+
+ res = os_snprintf(pos, end - pos,
+ "key_server_sci=%s\n", sci_txt(&kay->key_server_sci));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos += res;
+
+ count = 0;
+ dl_list_for_each(p, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ char *pos2 = pos;
+
+ res = os_snprintf(pos2, end - pos2, "participant_idx=%d\nckn=",
+ count);
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ count++;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, p->ckn.name,
+ p->ckn.len);
+
+ res = os_snprintf(pos2, end - pos2,
+ "\nmi=%s\n"
+ "mn=%u\n"
+ "active=%s\n"
+ "participant=%s\n"
+ "retain=%s\n"
+ "live_peers=%u\n"
+ "potential_peers=%u\n"
+ "is_key_server=%s\n"
+ "is_elected=%s\n",
+ mi_txt(p->mi), p->mn,
+ yes_no(p->active),
+ yes_no(p->participant),
+ yes_no(p->retain),
+ dl_list_len(&p->live_peers),
+ dl_list_len(&p->potential_peers),
+ yes_no(p->is_key_server),
+ yes_no(p->is_elected));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ pos = pos2;
+ }
+
+ return pos - buf;
+}
+
+
+static const char * true_false(Boolean val)
+{
+ return val ? "true" : "false";
+}
+
+
+static const char * activate_control_txt(enum activate_ctrl activate)
+{
+ switch (activate) {
+ case DEFAULT:
+ return "default";
+ case DISABLED:
+ return "disabled";
+ case ON_OPER_UP:
+ return "onOperUp";
+ case ALWAYS:
+ return "always";
+ }
+
+ return "?";
+}
+
+
+static char * mka_mib_peer(struct dl_list *peers, Boolean live, char *buf,
+ char *end)
+{
+ char *pos = buf;
+ struct ieee802_1x_kay_peer *p;
+ int res;
+
+ dl_list_for_each(p, peers, struct ieee802_1x_kay_peer, list) {
+ res = os_snprintf(pos, end - pos,
+ "ieee8021XKayMkaPeerListMI=%s\n"
+ "ieee8021XKayMkaPeerListMN=%u\n"
+ "ieee8021XKayMkaPeerListType=%u\n"
+ "ieee8021XKayMkaPeerListSCI=%s\n",
+ mi_txt(p->mi),
+ p->mn,
+ live ? 1 : 2,
+ sci_txt(&p->sci));
+ if (os_snprintf_error(end - pos, res))
+ return pos;
+ pos += res;
+ }
+
+ return pos;
+}
+
+
+int ieee802_1x_kay_get_mib(struct ieee802_1x_kay *kay, char *buf,
+ size_t buflen)
+{
+ char *pos, *end;
+ int res;
+ struct ieee802_1x_mka_participant *p;
+
+ if (!kay)
+ return 0;
+
+ pos = buf;
+ end = buf + buflen;
+
+ dl_list_for_each(p, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ char *pos2 = pos;
+
+ res = os_snprintf(pos2, end - pos2, "ieee8021XKayMkaPartCKN=");
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, p->ckn.name,
+ p->ckn.len);
+
+ res = os_snprintf(pos2, end - pos2,
+ "\nieee8021XKayMkaPartCached=%s\n"
+ "ieee8021XKayMkaPartActive=%s\n"
+ "ieee8021XKayMkaPartRetain=%s\n"
+ "ieee8021XKayMkaPartActivateControl=%s\n"
+ "ieee8021XKayMkaPartPrincipal=%s\n",
+ true_false(p->cached),
+ true_false(p->active),
+ true_false(p->retain),
+ activate_control_txt(p->activate),
+ true_false(p->principal));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ pos = pos2;
+
+ pos = mka_mib_peer(&p->live_peers, TRUE, pos, end);
+ pos = mka_mib_peer(&p->potential_peers, FALSE, pos, end);
+ }
+
+ return pos - buf;
+}
+
+#endif /* CONFIG_CTRL_IFACE */
diff --git a/contrib/wpa/src/pae/ieee802_1x_kay.h b/contrib/wpa/src/pae/ieee802_1x_kay.h
index 064417e..3367d3a 100644
--- a/contrib/wpa/src/pae/ieee802_1x_kay.h
+++ b/contrib/wpa/src/pae/ieee802_1x_kay.h
@@ -14,17 +14,23 @@
#include "common/ieee802_1x_defs.h"
struct macsec_init_params;
-struct ieee802_1x_cp_conf;
-#define MI_LEN 12
+#define MI_LEN 12 /* 96-bit Member Identifier */
#define MAX_KEY_LEN 32 /* 32 bytes, 256 bits */
#define MAX_CKN_LEN 32 /* 32 bytes, 256 bits */
/* MKA timer, unit: millisecond */
#define MKA_HELLO_TIME 2000
+#define MKA_BOUNDED_HELLO_TIME 500
#define MKA_LIFE_TIME 6000
#define MKA_SAK_RETIRE_TIME 3000
+/**
+ * struct ieee802_1x_mka_ki - Key Identifier (KI)
+ * @mi: Key Server's Member Identifier
+ * @kn: Key Number, assigned by the Key Server
+ * IEEE 802.1X-2010 9.8 SAK generation, distribution, and selection
+ */
struct ieee802_1x_mka_ki {
u8 mi[MI_LEN];
u32 kn;
@@ -32,8 +38,8 @@ struct ieee802_1x_mka_ki {
struct ieee802_1x_mka_sci {
u8 addr[ETH_ALEN];
- u16 port;
-};
+ be16 port;
+} STRUCT_PACKED;
struct mka_key {
u8 key[MAX_KEY_LEN];
@@ -48,8 +54,84 @@ struct mka_key_name {
enum mka_created_mode {
PSK,
EAP_EXCHANGE,
- DISTRIBUTED,
- CACHED,
+};
+
+struct data_key {
+ u8 *key;
+ int key_len;
+ struct ieee802_1x_mka_ki key_identifier;
+ enum confidentiality_offset confidentiality_offset;
+ u8 an;
+ Boolean transmits;
+ Boolean receives;
+ struct os_time created_time;
+ u32 next_pn;
+
+ /* not defined data */
+ Boolean rx_latest;
+ Boolean tx_latest;
+
+ int user;
+
+ struct dl_list list;
+};
+
+/* TransmitSC in IEEE Std 802.1AE-2006, Figure 10-6 */
+struct transmit_sc {
+ struct ieee802_1x_mka_sci sci; /* const SCI sci */
+ Boolean transmitting; /* bool transmitting (read only) */
+
+ struct os_time created_time; /* Time createdTime */
+
+ u8 encoding_sa; /* AN encodingSA (read only) */
+ u8 enciphering_sa; /* AN encipheringSA (read only) */
+
+ /* not defined data */
+ struct dl_list list;
+ struct dl_list sa_list;
+};
+
+/* TransmitSA in IEEE Std 802.1AE-2006, Figure 10-6 */
+struct transmit_sa {
+ Boolean in_use; /* bool inUse (read only) */
+ u32 next_pn; /* PN nextPN (read only) */
+ struct os_time created_time; /* Time createdTime */
+
+ Boolean enable_transmit; /* bool EnableTransmit */
+
+ u8 an;
+ Boolean confidentiality;
+ struct data_key *pkey;
+
+ struct transmit_sc *sc;
+ struct dl_list list; /* list entry in struct transmit_sc::sa_list */
+};
+
+/* ReceiveSC in IEEE Std 802.1AE-2006, Figure 10-6 */
+struct receive_sc {
+ struct ieee802_1x_mka_sci sci; /* const SCI sci */
+ Boolean receiving; /* bool receiving (read only) */
+
+ struct os_time created_time; /* Time createdTime */
+
+ struct dl_list list;
+ struct dl_list sa_list;
+};
+
+/* ReceiveSA in IEEE Std 802.1AE-2006, Figure 10-6 */
+struct receive_sa {
+ Boolean enable_receive; /* bool enableReceive */
+ Boolean in_use; /* bool inUse (read only) */
+
+ u32 next_pn; /* PN nextPN (read only) */
+ u32 lowest_pn; /* PN lowestPN (read only) */
+ u8 an;
+ struct os_time created_time;
+
+ struct data_key *pkey;
+ struct receive_sc *sc; /* list entry in struct receive_sc::sa_list */
+
+ struct dl_list list;
};
struct ieee802_1x_kay_ctx {
@@ -59,34 +141,31 @@ struct ieee802_1x_kay_ctx {
/* abstract wpa driver interface */
int (*macsec_init)(void *ctx, struct macsec_init_params *params);
int (*macsec_deinit)(void *ctx);
+ int (*macsec_get_capability)(void *priv, enum macsec_cap *cap);
int (*enable_protect_frames)(void *ctx, Boolean enabled);
+ int (*enable_encrypt)(void *ctx, Boolean enabled);
int (*set_replay_protect)(void *ctx, Boolean enabled, u32 window);
- int (*set_current_cipher_suite)(void *ctx, const u8 *cs, size_t cs_len);
+ int (*set_current_cipher_suite)(void *ctx, u64 cs);
int (*enable_controlled_port)(void *ctx, Boolean enabled);
- int (*get_receive_lowest_pn)(void *ctx, u32 channel, u8 an,
- u32 *lowest_pn);
- int (*get_transmit_next_pn)(void *ctx, u32 channel, u8 an,
- u32 *next_pn);
- int (*set_transmit_next_pn)(void *ctx, u32 channel, u8 an, u32 next_pn);
- int (*get_available_receive_sc)(void *ctx, u32 *channel);
- int (*create_receive_sc)(void *ctx, u32 channel,
- struct ieee802_1x_mka_sci *sci,
+ int (*get_receive_lowest_pn)(void *ctx, struct receive_sa *sa);
+ int (*get_transmit_next_pn)(void *ctx, struct transmit_sa *sa);
+ int (*set_transmit_next_pn)(void *ctx, struct transmit_sa *sa);
+ int (*set_receive_lowest_pn)(void *ctx, struct receive_sa *sa);
+ int (*create_receive_sc)(void *ctx, struct receive_sc *sc,
enum validate_frames vf,
enum confidentiality_offset co);
- int (*delete_receive_sc)(void *ctx, u32 channel);
- int (*create_receive_sa)(void *ctx, u32 channel, u8 an, u32 lowest_pn,
- const u8 *sak);
- int (*enable_receive_sa)(void *ctx, u32 channel, u8 an);
- int (*disable_receive_sa)(void *ctx, u32 channel, u8 an);
- int (*get_available_transmit_sc)(void *ctx, u32 *channel);
- int (*create_transmit_sc)(void *ctx, u32 channel,
- const struct ieee802_1x_mka_sci *sci,
+ int (*delete_receive_sc)(void *ctx, struct receive_sc *sc);
+ int (*create_receive_sa)(void *ctx, struct receive_sa *sa);
+ int (*delete_receive_sa)(void *ctx, struct receive_sa *sa);
+ int (*enable_receive_sa)(void *ctx, struct receive_sa *sa);
+ int (*disable_receive_sa)(void *ctx, struct receive_sa *sa);
+ int (*create_transmit_sc)(void *ctx, struct transmit_sc *sc,
enum confidentiality_offset co);
- int (*delete_transmit_sc)(void *ctx, u32 channel);
- int (*create_transmit_sa)(void *ctx, u32 channel, u8 an, u32 next_pn,
- Boolean confidentiality, const u8 *sak);
- int (*enable_transmit_sa)(void *ctx, u32 channel, u8 an);
- int (*disable_transmit_sa)(void *ctx, u32 channel, u8 an);
+ int (*delete_transmit_sc)(void *ctx, struct transmit_sc *sc);
+ int (*create_transmit_sa)(void *ctx, struct transmit_sa *sa);
+ int (*delete_transmit_sa)(void *ctx, struct transmit_sa *sa);
+ int (*enable_transmit_sa)(void *ctx, struct transmit_sa *sa);
+ int (*disable_transmit_sa)(void *ctx, struct transmit_sa *sa);
};
struct ieee802_1x_kay {
@@ -105,10 +184,12 @@ struct ieee802_1x_kay {
enum macsec_cap macsec_capable;
Boolean macsec_desired;
Boolean macsec_protect;
+ Boolean macsec_encrypt;
Boolean macsec_replay_protect;
u32 macsec_replay_window;
enum validate_frames macsec_validate;
enum confidentiality_offset macsec_confidentiality;
+ u32 mka_hello_time;
u32 ltx_kn;
u8 ltx_an;
@@ -126,16 +207,16 @@ struct ieee802_1x_kay {
Boolean is_obliged_key_server;
char if_name[IFNAMSIZ];
- int macsec_csindex; /* MACsec cipher suite table index */
+ unsigned int macsec_csindex; /* MACsec cipher suite table index */
int mka_algindex; /* MKA alg table index */
u32 dist_kn;
+ u32 rcvd_keys;
u8 dist_an;
time_t dist_time;
u8 mka_version;
u8 algo_agility[4];
- u32 sc_ch;
u32 pn_exhaustion;
Boolean port_enable;
@@ -154,14 +235,18 @@ struct ieee802_1x_kay {
};
+u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci);
+
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
- const char *ifname, const u8 *addr);
+ Boolean macsec_replay_protect, u32 macsec_replay_window,
+ u16 port, u8 priority, const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
- struct mka_key_name *ckn, struct mka_key *cak,
+ const struct mka_key_name *ckn,
+ const struct mka_key *cak,
u32 life, enum mka_created_mode mode,
Boolean is_authenticator);
void ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay,
@@ -171,7 +256,7 @@ void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
Boolean status);
int ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay);
int ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
- int cs_index);
+ unsigned int cs_index);
int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki, u8 lan,
@@ -188,7 +273,9 @@ int ieee802_1x_kay_enable_tx_sas(struct ieee802_1x_kay *kay,
int ieee802_1x_kay_enable_rx_sas(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki);
int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay);
-int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
- struct ieee802_1x_cp_conf *pconf);
+int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
+ size_t buflen);
+int ieee802_1x_kay_get_mib(struct ieee802_1x_kay *kay, char *buf,
+ size_t buflen);
#endif /* IEEE802_1X_KAY_H */
diff --git a/contrib/wpa/src/pae/ieee802_1x_kay_i.h b/contrib/wpa/src/pae/ieee802_1x_kay_i.h
index bdad3a5..f9cd3f4 100644
--- a/contrib/wpa/src/pae/ieee802_1x_kay_i.h
+++ b/contrib/wpa/src/pae/ieee802_1x_kay_i.h
@@ -15,7 +15,7 @@
#define MKA_VERSION_ID 1
-/* IEEE Std 802.1X-2010, 11.11.1, Table 11-7 */
+/* IEEE Std 802.1X-2010, 11.11.1, Table 11-7 (MKPDU parameter sets) */
enum mka_packet_type {
MKA_BASIC_PARAMETER_SET = MKA_VERSION_ID,
MKA_LIVE_PEER_LIST = 1,
@@ -38,8 +38,8 @@ struct ieee802_1x_kay;
struct ieee802_1x_mka_peer_id {
u8 mi[MI_LEN];
- u32 mn;
-};
+ be32 mn;
+} STRUCT_PACKED;
struct ieee802_1x_kay_peer {
struct ieee802_1x_mka_sci sci;
@@ -49,127 +49,35 @@ struct ieee802_1x_kay_peer {
Boolean is_key_server;
u8 key_server_priority;
Boolean macsec_desired;
- enum macsec_cap macsec_capbility;
+ enum macsec_cap macsec_capability;
Boolean sak_used;
- struct dl_list list;
-};
-
-struct key_conf {
- u8 *key;
- struct ieee802_1x_mka_ki ki;
- enum confidentiality_offset offset;
- u8 an;
- Boolean tx;
- Boolean rx;
- int key_len; /* unit: byte */
-};
-
-struct data_key {
- u8 *key;
- int key_len;
- struct ieee802_1x_mka_ki key_identifier;
- enum confidentiality_offset confidentiality_offset;
- u8 an;
- Boolean transmits;
- Boolean receives;
- struct os_time created_time;
- u32 next_pn;
-
- /* not defined data */
- Boolean rx_latest;
- Boolean tx_latest;
-
- int user; /* FIXME: to indicate if it can be delete safely */
-
- struct dl_list list;
-};
-
-/* TransmitSC in IEEE Std 802.1AE-2006, Figure 10-6 */
-struct transmit_sc {
- struct ieee802_1x_mka_sci sci; /* const SCI sci */
- Boolean transmitting; /* bool transmitting (read only) */
-
- struct os_time created_time; /* Time createdTime */
-
- u8 encoding_sa; /* AN encodingSA (read only) */
- u8 enciphering_sa; /* AN encipheringSA (read only) */
-
- /* not defined data */
- unsigned int channel;
-
- struct dl_list list;
- struct dl_list sa_list;
-};
-
-/* TransmitSA in IEEE Std 802.1AE-2006, Figure 10-6 */
-struct transmit_sa {
- Boolean in_use; /* bool inUse (read only) */
- u32 next_pn; /* PN nextPN (read only) */
- struct os_time created_time; /* Time createdTime */
-
- Boolean enable_transmit; /* bool EnableTransmit */
-
- u8 an;
- Boolean confidentiality;
- struct data_key *pkey;
-
- struct transmit_sc *sc;
- struct dl_list list; /* list entry in struct transmit_sc::sa_list */
-};
-
-/* ReceiveSC in IEEE Std 802.1AE-2006, Figure 10-6 */
-struct receive_sc {
- struct ieee802_1x_mka_sci sci; /* const SCI sci */
- Boolean receiving; /* bool receiving (read only) */
-
- struct os_time created_time; /* Time createdTime */
-
- unsigned int channel;
-
- struct dl_list list;
- struct dl_list sa_list;
-};
-
-/* ReceiveSA in IEEE Std 802.1AE-2006, Figure 10-6 */
-struct receive_sa {
- Boolean enable_receive; /* bool enableReceive */
- Boolean in_use; /* bool inUse (read only) */
-
- u32 next_pn; /* PN nextPN (read only) */
- u32 lowest_pn; /* PN lowestPN (read only) */
- u8 an;
- struct os_time created_time;
-
- struct data_key *pkey;
- struct receive_sc *sc; /* list entry in struct receive_sc::sa_list */
-
+ int missing_sak_use_count;
struct dl_list list;
};
struct macsec_ciphersuite {
- u8 id[CS_ID_LEN];
+ u64 id;
char name[32];
enum macsec_cap capable;
int sak_len; /* unit: byte */
-
- u32 index;
};
struct mka_alg {
u8 parameter[4];
- size_t cak_len;
- size_t kek_len;
- size_t ick_len;
size_t icv_len;
- int (*cak_trfm)(const u8 *msk, const u8 *mac1, const u8 *mac2, u8 *cak);
- int (*ckn_trfm)(const u8 *msk, const u8 *mac1, const u8 *mac2,
- const u8 *sid, size_t sid_len, u8 *ckn);
- int (*kek_trfm)(const u8 *cak, const u8 *ckn, size_t ckn_len, u8 *kek);
- int (*ick_trfm)(const u8 *cak, const u8 *ckn, size_t ckn_len, u8 *ick);
- int (*icv_hash)(const u8 *ick, const u8 *msg, size_t msg_len, u8 *icv);
-
- int index; /* index for configuring */
+ int (*cak_trfm)(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes);
+ int (*ckn_trfm)(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid, size_t sid_len, u8 *ckn);
+ int (*kek_trfm)(const u8 *cak, size_t cak_bytes,
+ const u8 *ckn, size_t ckn_len,
+ u8 *kek, size_t kek_bytes);
+ int (*ick_trfm)(const u8 *cak, size_t cak_bytes,
+ const u8 *ckn, size_t ckn_len,
+ u8 *ick, size_t ick_bytes);
+ int (*icv_hash)(const u8 *ick, size_t ick_bytes,
+ const u8 *msg, size_t msg_len, u8 *icv);
};
#define DEFAULT_MKA_ALG_INDEX 0
@@ -185,8 +93,9 @@ struct ieee802_1x_mka_participant {
Boolean active;
Boolean participant;
Boolean retain;
+ enum mka_created_mode mode;
- enum { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
+ enum activate_ctrl { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
/* used for active participant */
Boolean principal;
@@ -222,8 +131,10 @@ struct ieee802_1x_mka_participant {
u8 mi[MI_LEN];
u32 mn;
+ /* Current peer MI and SCI during MKPDU processing */
struct ieee802_1x_mka_peer_id current_peer_id;
struct ieee802_1x_mka_sci current_peer_sci;
+
time_t cak_life;
time_t mka_life;
Boolean to_dist_sak;
@@ -241,179 +152,274 @@ struct ieee802_1x_mka_participant {
struct ieee802_1x_mka_hdr {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
- u32 reserve:8;
+ u8 reserve;
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 reserve1:4;
+ u8 length:4;
+ u8 reserve1:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 reserve1:4;
- u32 length:4;
+ u8 reserve1:4;
+ u8 length:4;
#else
#error "Please fix <bits/endian.h>"
#endif
/* octet 4 */
- u32 length1:8;
-};
+ u8 length1;
+} STRUCT_PACKED;
#define MKA_HDR_LEN sizeof(struct ieee802_1x_mka_hdr)
+/**
+ * struct ieee802_1x_mka_basic_body - Basic Parameter Set (Figure 11-8)
+ * @version: MKA Version Identifier
+ * @priority: Key Server Priority
+ * @length: Parameter set body length
+ * @macsec_capability: MACsec capability, as defined in ieee802_1x_defs.h
+ * @macsec_desired: the participant wants MACsec to be used to protect frames
+ * (9.6.1)
+ * @key_server: the participant has not decided that another participant is or
+ * will be the key server (9.5.1)
+ * @length1: Parameter set body length (cont)
+ * @actor_mi: Actor's Member Identifier
+ * @actor_mn: Actor's Message Number
+ * @algo_agility: Algorithm Agility parameter
+ * @ckn: CAK Name
+ */
struct ieee802_1x_mka_basic_body {
/* octet 1 */
- u32 version:8;
+ u8 version;
/* octet 2 */
- u32 priority:8;
+ u8 priority;
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 macsec_capbility:2;
- u32 macsec_desired:1;
- u32 key_server:1;
+ u8 length:4;
+ u8 macsec_capability:2;
+ u8 macsec_desired:1;
+ u8 key_server:1;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 key_server:1;
- u32 macsec_desired:1;
- u32 macsec_capbility:2;
- u32 length:4;
+ u8 key_server:1;
+ u8 macsec_desired:1;
+ u8 macsec_capability:2;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
struct ieee802_1x_mka_sci actor_sci;
u8 actor_mi[MI_LEN];
- u32 actor_mn;
+ be32 actor_mn;
u8 algo_agility[4];
- /* followed by CAK Name*/
+ /* followed by CAK Name */
u8 ckn[0];
-};
-
+} STRUCT_PACKED;
+
+/**
+ * struct ieee802_1x_mka_peer_body - Live Peer List and Potential Peer List
+ * parameter sets (Figure 11-9)
+ * @type: Parameter set type (1 or 2)
+ * @length: Parameter set body length
+ * @length1: Parameter set body length (cont)
+ * @peer: array of (MI, MN) pairs
+ */
struct ieee802_1x_mka_peer_body {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
- u32 reserve:8;
+ u8 reserve;
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 reserve1:4;
+ u8 length:4;
+ u8 reserve1:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 reserve1:4;
- u32 length:4;
+ u8 reserve1:4;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
- u8 peer[0];
/* followed by Peers */
-};
-
+ u8 peer[0];
+} STRUCT_PACKED;
+
+/**
+ * struct ieee802_1x_mka_sak_use_body - MACsec SAK Use parameter set (Figure
+ * 11-10)
+ * @type: MKA message type
+ * @lan: latest key AN
+ * @ltx: latest key TX
+ * @lrx: latest key RX
+ * @oan: old key AN
+ * @otx: old key TX
+ * @orx: old key RX
+ * @ptx: plain TX, ie protectFrames is False
+ * @prx: plain RX, ie validateFrames is not Strict
+ * @delay_protect: True if LPNs are being reported sufficiently frequently to
+ * allow the recipient to provide data delay protection. If False, the LPN
+ * can be reported as zero.
+ * @lsrv_mi: latest key server MI
+ * @lkn: latest key number (together with MI, form the KI)
+ * @llpn: latest lowest acceptable PN (LPN)
+ * @osrv_mi: old key server MI
+ * @okn: old key number (together with MI, form the KI)
+ * @olpn: old lowest acceptable PN (LPN)
+ */
struct ieee802_1x_mka_sak_use_body {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 orx:1;
- u32 otx:1;
- u32 oan:2;
- u32 lrx:1;
- u32 ltx:1;
- u32 lan:2;
+ u8 orx:1;
+ u8 otx:1;
+ u8 oan:2;
+ u8 lrx:1;
+ u8 ltx:1;
+ u8 lan:2;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 lan:2;
- u32 ltx:1;
- u32 lrx:1;
- u32 oan:2;
- u32 otx:1;
- u32 orx:1;
+ u8 lan:2;
+ u8 ltx:1;
+ u8 lrx:1;
+ u8 oan:2;
+ u8 otx:1;
+ u8 orx:1;
#endif
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 delay_protect:1;
- u32 reserve:1;
- u32 prx:1;
- u32 ptx:1;
+ u8 length:4;
+ u8 delay_protect:1;
+ u8 reserve:1;
+ u8 prx:1;
+ u8 ptx:1;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 ptx:1;
- u32 prx:1;
- u32 reserve:1;
- u32 delay_protect:1;
- u32 length:4;
+ u8 ptx:1;
+ u8 prx:1;
+ u8 reserve:1;
+ u8 delay_protect:1;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
/* octet 5 - 16 */
u8 lsrv_mi[MI_LEN];
/* octet 17 - 20 */
- u32 lkn;
+ be32 lkn;
/* octet 21 - 24 */
- u32 llpn;
+ be32 llpn;
/* octet 25 - 36 */
u8 osrv_mi[MI_LEN];
/* octet 37 - 40 */
- u32 okn;
+ be32 okn;
/* octet 41 - 44 */
- u32 olpn;
-};
-
-
+ be32 olpn;
+} STRUCT_PACKED;
+
+/**
+ * struct ieee802_1x_mka_dist_sak_body - Distributed SAK parameter set
+ * (GCM-AES-128, Figure 11-11)
+ * @type: Parameter set type (4)
+ * @length: Parameter set body length
+ * @length1: Parameter set body length (cont)
+ * Total parameter body length values:
+ * - 0 for plain text
+ * - 28 for GCM-AES-128
+ * - 36 or more for other cipher suites
+ * @confid_offset: confidentiality offset, as defined in ieee802_1x_defs.h
+ * @dan: distributed AN (0 for plain text)
+ * @kn: Key Number
+ * @sak: AES Key Wrap of SAK (see 9.8)
+ */
struct ieee802_1x_mka_dist_sak_body {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 reserve:4;
- u32 confid_offset:2;
- u32 dan:2;
+ u8 reserve:4;
+ u8 confid_offset:2;
+ u8 dan:2;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 dan:2;
- u32 confid_offset:2;
- u32 reserve:4;
+ u8 dan:2;
+ u8 confid_offset:2;
+ u8 reserve:4;
#endif
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 reserve1:4;
+ u8 length:4;
+ u8 reserve1:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 reserve1:4;
- u32 length:4;
+ u8 reserve1:4;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
/* octet 5 - 8 */
- u32 kn;
+ be32 kn;
/* for GCM-AES-128: octet 9-32: SAK
* for other cipher suite: octet 9-16: cipher suite id, octet 17-: SAK
*/
u8 sak[0];
-};
+} STRUCT_PACKED;
+
+/**
+ * struct ieee802_1x_mka_dist_cak_body - Distributed CAK parameter set (Figure
+ * 11-13)
+ * @type: Parameter set type (5)
+ * @length: Parameter set body length
+ * @length1: Parameter set body length (cont)
+ * Total parameter body length values:
+ * - 0 for plain text
+ * - 28 for GCM-AES-128
+ * - 36 or more for other cipher suites
+ * @cak: AES Key Wrap of CAK (see 9.8)
+ * @ckn: CAK Name
+ */
+struct ieee802_1x_mka_dist_cak_body {
+ /* octet 1 */
+ u8 type;
+ /* octet 2 */
+ u8 reserve;
+ /* octet 3 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u8 length:4;
+ u8 reserve1:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u8 reserve1:4;
+ u8 length:4;
+#endif
+ /* octet 4 */
+ u8 length1;
+ /* octet 5 - 28 */
+ u8 cak[24];
+
+ /* followed by CAK Name, 29- */
+ u8 ckn[0];
+} STRUCT_PACKED;
struct ieee802_1x_mka_icv_body {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
- u32 reserve:8;
+ u8 reserve;
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 reserve1:4;
+ u8 length:4;
+ u8 reserve1:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 reserve1:4;
- u32 length:4;
+ u8 reserve1:4;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
/* octet 5 - */
u8 icv[0];
-};
+} STRUCT_PACKED;
#endif /* IEEE802_1X_KAY_I_H */
diff --git a/contrib/wpa/src/pae/ieee802_1x_key.c b/contrib/wpa/src/pae/ieee802_1x_key.c
index 9a8d923..d63ca7f 100644
--- a/contrib/wpa/src/pae/ieee802_1x_key.c
+++ b/contrib/wpa/src/pae/ieee802_1x_key.c
@@ -31,8 +31,9 @@ static void joint_two_mac(const u8 *mac1, const u8 *mac2, u8 *out)
/* IEEE Std 802.1X-2010, 6.2.1 KDF */
-static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context,
- int ctx_bits, int ret_bits, u8 *ret)
+static int aes_kdf(const u8 *kdk, size_t kdk_bits,
+ const char *label, const u8 *context,
+ int ctx_bits, int ret_bits, u8 *ret)
{
const int h = 128;
const int r = 8;
@@ -40,6 +41,9 @@ static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context,
int lab_len, ctx_len, ret_len, buf_len;
u8 *buf;
+ if (kdk_bits != 128 && kdk_bits != 256)
+ return -1;
+
lab_len = os_strlen(label);
ctx_len = (ctx_bits + 7) / 8;
ret_len = ((ret_bits & 0xffff) + 7) / 8;
@@ -60,8 +64,14 @@ static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context,
WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
for (i = 0; i < n; i++) {
+ int res;
+
buf[0] = (u8) (i + 1);
- if (omac1_aes_128(kdk, buf, buf_len, ret)) {
+ if (kdk_bits == 128)
+ res = omac1_aes_128(kdk, buf, buf_len, ret);
+ else
+ res = omac1_aes_256(kdk, buf, buf_len, ret);
+ if (res) {
os_free(buf);
return -1;
}
@@ -72,33 +82,32 @@ static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context,
}
-/********** AES-CMAC-128 **********/
/**
- * ieee802_1x_cak_128bits_aes_cmac
+ * ieee802_1x_cak_aes_cmac
*
* IEEE Std 802.1X-2010, 6.2.2
* CAK = KDF(Key, Label, mac1 | mac2, CAKlength)
*/
-int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, u8 *cak)
+int ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes)
{
u8 context[2 * ETH_ALEN];
joint_two_mac(mac1, mac2, context);
- return aes_kdf_128(msk, "IEEE8021 EAP CAK",
- context, sizeof(context) * 8, 128, cak);
+ return aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CAK",
+ context, sizeof(context) * 8, 8 * cak_bytes, cak);
}
/**
- * ieee802_1x_ckn_128bits_aes_cmac
+ * ieee802_1x_ckn_aes_cmac
*
* IEEE Std 802.1X-2010, 6.2.2
* CKN = KDF(Key, Label, ID | mac1 | mac2, CKNlength)
*/
-int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, const u8 *sid,
- size_t sid_bytes, u8 *ckn)
+int ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid,
+ size_t sid_bytes, u8 *ckn)
{
int res;
u8 *context;
@@ -112,21 +121,21 @@ int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
os_memcpy(context, sid, sid_bytes);
joint_two_mac(mac1, mac2, context + sid_bytes);
- res = aes_kdf_128(msk, "IEEE8021 EAP CKN", context, ctx_len * 8,
- 128, ckn);
+ res = aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CKN",
+ context, ctx_len * 8, 128, ckn);
os_free(context);
return res;
}
/**
- * ieee802_1x_kek_128bits_aes_cmac
+ * ieee802_1x_kek_aes_cmac
*
* IEEE Std 802.1X-2010, 9.3.3
* KEK = KDF(Key, Label, Keyid, KEKLength)
*/
-int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *kek)
+int ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *kek, size_t kek_bytes)
{
u8 context[16];
@@ -134,19 +143,20 @@ int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
os_memset(context, 0, sizeof(context));
os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
- return aes_kdf_128(cak, "IEEE8021 KEK", context, sizeof(context) * 8,
- 128, kek);
+ return aes_kdf(cak, 8 * cak_bytes, "IEEE8021 KEK",
+ context, sizeof(context) * 8,
+ 8 * kek_bytes, kek);
}
/**
- * ieee802_1x_ick_128bits_aes_cmac
+ * ieee802_1x_ick_aes_cmac
*
* IEEE Std 802.1X-2010, 9.3.3
* ICK = KDF(Key, Label, Keyid, ICKLength)
*/
-int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *ick)
+int ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *ick, size_t ick_bytes)
{
u8 context[16];
@@ -154,22 +164,32 @@ int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
os_memset(context, 0, sizeof(context));
os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
- return aes_kdf_128(cak, "IEEE8021 ICK", context, sizeof(context) * 8,
- 128, ick);
+ return aes_kdf(cak, 8 *cak_bytes, "IEEE8021 ICK",
+ context, sizeof(context) * 8,
+ 8 * ick_bytes, ick);
}
/**
- * ieee802_1x_icv_128bits_aes_cmac
+ * ieee802_1x_icv_aes_cmac
*
* IEEE Std 802.1X-2010, 9.4.1
* ICV = AES-CMAC(ICK, M, 128)
*/
-int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
- size_t msg_bytes, u8 *icv)
+int ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
+ size_t msg_bytes, u8 *icv)
{
- if (omac1_aes_128(ick, msg, msg_bytes, icv)) {
- wpa_printf(MSG_ERROR, "MKA: omac1_aes_128 failed");
+ int res;
+
+ if (ick_bytes == 16)
+ res = omac1_aes_128(ick, msg, msg_bytes, icv);
+ else if (ick_bytes == 32)
+ res = omac1_aes_256(ick, msg, msg_bytes, icv);
+ else
+ return -1;
+ if (res) {
+ wpa_printf(MSG_ERROR,
+ "MKA: AES-CMAC failed for ICV calculation");
return -1;
}
return 0;
@@ -177,13 +197,14 @@ int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
/**
- * ieee802_1x_sak_128bits_aes_cmac
+ * ieee802_1x_sak_aes_cmac
*
* IEEE Std 802.1X-2010, 9.8.1
* SAK = KDF(Key, Label, KS-nonce | MI-value list | KN, SAKLength)
*/
-int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
- size_t ctx_bytes, u8 *sak)
+int ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
+ size_t ctx_bytes, u8 *sak, size_t sak_bytes)
{
- return aes_kdf_128(cak, "IEEE8021 SAK", ctx, ctx_bytes * 8, 128, sak);
+ return aes_kdf(cak, cak_bytes * 8, "IEEE8021 SAK", ctx, ctx_bytes * 8,
+ sak_bytes * 8, sak);
}
diff --git a/contrib/wpa/src/pae/ieee802_1x_key.h b/contrib/wpa/src/pae/ieee802_1x_key.h
index ea318ea..1f9058d 100644
--- a/contrib/wpa/src/pae/ieee802_1x_key.h
+++ b/contrib/wpa/src/pae/ieee802_1x_key.h
@@ -9,18 +9,18 @@
#ifndef IEEE802_1X_KEY_H
#define IEEE802_1X_KEY_H
-int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, u8 *cak);
-int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, const u8 *sid,
- size_t sid_bytes, u8 *ckn);
-int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *kek);
-int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *ick);
-int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
- size_t msg_bytes, u8 *icv);
-int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
- size_t ctx_bytes, u8 *sak);
+int ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes);
+int ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid,
+ size_t sid_bytes, u8 *ckn);
+int ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *kek, size_t kek_bytes);
+int ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *ick, size_t ick_bytes);
+int ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
+ size_t msg_bytes, u8 *icv);
+int ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
+ size_t ctx_bytes, u8 *sak, size_t sak_bytes);
#endif /* IEEE802_1X_KEY_H */
diff --git a/contrib/wpa/src/pae/ieee802_1x_secy_ops.c b/contrib/wpa/src/pae/ieee802_1x_secy_ops.c
index fbe05dc..84ee42b 100644
--- a/contrib/wpa/src/pae/ieee802_1x_secy_ops.c
+++ b/contrib/wpa/src/pae/ieee802_1x_secy_ops.c
@@ -45,6 +45,26 @@ int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean enabled)
}
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->enable_encrypt) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy enable_encrypt operation not supported");
+ return -1;
+ }
+
+ return ops->enable_encrypt(ops->ctx, enabled);
+}
+
+
int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
{
struct ieee802_1x_kay_ctx *ops;
@@ -65,8 +85,7 @@ int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
}
-int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
- const u8 *cs, size_t cs_len)
+int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs)
{
struct ieee802_1x_kay_ctx *ops;
@@ -82,7 +101,7 @@ int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
return -1;
}
- return ops->set_current_cipher_suite(ops->ctx, cs, cs_len);
+ return ops->set_current_cipher_suite(ops->ctx, cs);
}
@@ -114,6 +133,26 @@ int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean enabled)
}
+int secy_get_capability(struct ieee802_1x_kay *kay, enum macsec_cap *cap)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->macsec_get_capability) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy macsec_get_capability operation not supported");
+ return -1;
+ }
+
+ return ops->macsec_get_capability(ops->ctx, cap);
+}
+
+
int secy_get_receive_lowest_pn(struct ieee802_1x_kay *kay,
struct receive_sa *rxsa)
{
@@ -131,10 +170,7 @@ int secy_get_receive_lowest_pn(struct ieee802_1x_kay *kay,
return -1;
}
- return ops->get_receive_lowest_pn(ops->ctx,
- rxsa->sc->channel,
- rxsa->an,
- &rxsa->lowest_pn);
+ return ops->get_receive_lowest_pn(ops->ctx, rxsa);
}
@@ -151,14 +187,11 @@ int secy_get_transmit_next_pn(struct ieee802_1x_kay *kay,
ops = kay->ctx;
if (!ops || !ops->get_transmit_next_pn) {
wpa_printf(MSG_ERROR,
- "KaY: secy get_receive_lowest_pn operation not supported");
+ "KaY: secy get_transmit_next_pn operation not supported");
return -1;
}
- return ops->get_transmit_next_pn(ops->ctx,
- txsa->sc->channel,
- txsa->an,
- &txsa->next_pn);
+ return ops->get_transmit_next_pn(ops->ctx, txsa);
}
@@ -175,34 +208,32 @@ int secy_set_transmit_next_pn(struct ieee802_1x_kay *kay,
ops = kay->ctx;
if (!ops || !ops->set_transmit_next_pn) {
wpa_printf(MSG_ERROR,
- "KaY: secy get_receive_lowest_pn operation not supported");
+ "KaY: secy set_transmit_next_pn operation not supported");
return -1;
}
- return ops->set_transmit_next_pn(ops->ctx,
- txsa->sc->channel,
- txsa->an,
- txsa->next_pn);
+ return ops->set_transmit_next_pn(ops->ctx, txsa);
}
-int secy_get_available_receive_sc(struct ieee802_1x_kay *kay, u32 *channel)
+int secy_set_receive_lowest_pn(struct ieee802_1x_kay *kay,
+ struct receive_sa *rxsa)
{
struct ieee802_1x_kay_ctx *ops;
- if (!kay) {
+ if (!kay || !rxsa) {
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
return -1;
}
ops = kay->ctx;
- if (!ops || !ops->get_available_receive_sc) {
+ if (!ops || !ops->set_receive_lowest_pn) {
wpa_printf(MSG_ERROR,
- "KaY: secy get_available_receive_sc operation not supported");
+ "KaY: secy set_receive_lowest_pn operation not supported");
return -1;
}
- return ops->get_available_receive_sc(ops->ctx, channel);
+ return ops->set_receive_lowest_pn(ops->ctx, rxsa);
}
@@ -222,8 +253,7 @@ int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc)
return -1;
}
- return ops->create_receive_sc(ops->ctx, rxsc->channel, &rxsc->sci,
- kay->vf, kay->co);
+ return ops->create_receive_sc(ops->ctx, rxsc, kay->vf, kay->co);
}
@@ -243,7 +273,7 @@ int secy_delete_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc)
return -1;
}
- return ops->delete_receive_sc(ops->ctx, rxsc->channel);
+ return ops->delete_receive_sc(ops->ctx, rxsc);
}
@@ -263,12 +293,11 @@ int secy_create_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
return -1;
}
- return ops->create_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an,
- rxsa->lowest_pn, rxsa->pkey->key);
+ return ops->create_receive_sa(ops->ctx, rxsa);
}
-int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
+int secy_delete_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
{
struct ieee802_1x_kay_ctx *ops;
@@ -278,19 +307,17 @@ int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
}
ops = kay->ctx;
- if (!ops || !ops->enable_receive_sa) {
+ if (!ops || !ops->delete_receive_sa) {
wpa_printf(MSG_ERROR,
- "KaY: secy enable_receive_sa operation not supported");
+ "KaY: secy delete_receive_sa operation not supported");
return -1;
}
- rxsa->enable_receive = TRUE;
-
- return ops->enable_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an);
+ return ops->delete_receive_sa(ops->ctx, rxsa);
}
-int secy_disable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
+int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
{
struct ieee802_1x_kay_ctx *ops;
@@ -300,35 +327,37 @@ int secy_disable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
}
ops = kay->ctx;
- if (!ops || !ops->disable_receive_sa) {
+ if (!ops || !ops->enable_receive_sa) {
wpa_printf(MSG_ERROR,
- "KaY: secy disable_receive_sa operation not supported");
+ "KaY: secy enable_receive_sa operation not supported");
return -1;
}
- rxsa->enable_receive = FALSE;
+ rxsa->enable_receive = TRUE;
- return ops->disable_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an);
+ return ops->enable_receive_sa(ops->ctx, rxsa);
}
-int secy_get_available_transmit_sc(struct ieee802_1x_kay *kay, u32 *channel)
+int secy_disable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
{
struct ieee802_1x_kay_ctx *ops;
- if (!kay) {
+ if (!kay || !rxsa) {
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
return -1;
}
ops = kay->ctx;
- if (!ops || !ops->get_available_transmit_sc) {
+ if (!ops || !ops->disable_receive_sa) {
wpa_printf(MSG_ERROR,
- "KaY: secy get_available_transmit_sc operation not supported");
+ "KaY: secy disable_receive_sa operation not supported");
return -1;
}
- return ops->get_available_transmit_sc(ops->ctx, channel);
+ rxsa->enable_receive = FALSE;
+
+ return ops->disable_receive_sa(ops->ctx, rxsa);
}
@@ -349,8 +378,7 @@ int secy_create_transmit_sc(struct ieee802_1x_kay *kay,
return -1;
}
- return ops->create_transmit_sc(ops->ctx, txsc->channel, &txsc->sci,
- kay->co);
+ return ops->create_transmit_sc(ops->ctx, txsc, kay->co);
}
@@ -371,7 +399,7 @@ int secy_delete_transmit_sc(struct ieee802_1x_kay *kay,
return -1;
}
- return ops->delete_transmit_sc(ops->ctx, txsc->channel);
+ return ops->delete_transmit_sc(ops->ctx, txsc);
}
@@ -392,9 +420,28 @@ int secy_create_transmit_sa(struct ieee802_1x_kay *kay,
return -1;
}
- return ops->create_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an,
- txsa->next_pn, txsa->confidentiality,
- txsa->pkey->key);
+ return ops->create_transmit_sa(ops->ctx, txsa);
+}
+
+
+int secy_delete_transmit_sa(struct ieee802_1x_kay *kay,
+ struct transmit_sa *txsa)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !txsa) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->delete_transmit_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy delete_transmit_sa operation not supported");
+ return -1;
+ }
+
+ return ops->delete_transmit_sa(ops->ctx, txsa);
}
@@ -417,7 +464,7 @@ int secy_enable_transmit_sa(struct ieee802_1x_kay *kay,
txsa->enable_transmit = TRUE;
- return ops->enable_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an);
+ return ops->enable_transmit_sa(ops->ctx, txsa);
}
@@ -440,7 +487,7 @@ int secy_disable_transmit_sa(struct ieee802_1x_kay *kay,
txsa->enable_transmit = FALSE;
- return ops->disable_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an);
+ return ops->disable_transmit_sa(ops->ctx, txsa);
}
diff --git a/contrib/wpa/src/pae/ieee802_1x_secy_ops.h b/contrib/wpa/src/pae/ieee802_1x_secy_ops.h
index 295b823..2d112ba 100644
--- a/contrib/wpa/src/pae/ieee802_1x_secy_ops.h
+++ b/contrib/wpa/src/pae/ieee802_1x_secy_ops.h
@@ -13,10 +13,6 @@
#include "common/ieee802_1x_defs.h"
struct ieee802_1x_kay_conf;
-struct receive_sa;
-struct transmit_sa;
-struct receive_sc;
-struct transmit_sc;
int secy_init_macsec(struct ieee802_1x_kay *kay);
int secy_deinit_macsec(struct ieee802_1x_kay *kay);
@@ -25,35 +21,39 @@ int secy_deinit_macsec(struct ieee802_1x_kay *kay);
int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
enum validate_frames vf);
int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean flag);
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled);
int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean flag, u32 win);
-int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
- const u8 *cs, size_t cs_len);
+int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs);
int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
enum confidentiality_offset co);
int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean flag);
/****** KaY -> SecY *******/
+int secy_get_capability(struct ieee802_1x_kay *kay, enum macsec_cap *cap);
int secy_get_receive_lowest_pn(struct ieee802_1x_kay *kay,
struct receive_sa *rxsa);
int secy_get_transmit_next_pn(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
int secy_set_transmit_next_pn(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
-int secy_get_available_receive_sc(struct ieee802_1x_kay *kay, u32 *channel);
+int secy_set_receive_lowest_pn(struct ieee802_1x_kay *kay,
+ struct receive_sa *txsa);
int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc);
int secy_delete_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc);
int secy_create_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
+int secy_delete_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
int secy_disable_receive_sa(struct ieee802_1x_kay *kay,
struct receive_sa *rxsa);
-int secy_get_available_transmit_sc(struct ieee802_1x_kay *kay, u32 *channel);
int secy_create_transmit_sc(struct ieee802_1x_kay *kay,
struct transmit_sc *txsc);
int secy_delete_transmit_sc(struct ieee802_1x_kay *kay,
struct transmit_sc *txsc);
int secy_create_transmit_sa(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
+int secy_delete_transmit_sa(struct ieee802_1x_kay *kay,
+ struct transmit_sa *txsa);
int secy_enable_transmit_sa(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
int secy_disable_transmit_sa(struct ieee802_1x_kay *kay,
diff --git a/contrib/wpa/src/radius/radius.c b/contrib/wpa/src/radius/radius.c
index 1ebfd11..07240ea 100644
--- a/contrib/wpa/src/radius/radius.c
+++ b/contrib/wpa/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2011-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -173,6 +173,8 @@ static const struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
{ RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
{ RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP },
{ RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
@@ -208,12 +210,13 @@ static const struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
+ { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_EGRESS_VLANID, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
@@ -247,6 +250,8 @@ static const struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_WLAN_REASON_CODE, "WLAN-Reason-Code",
+ RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher",
RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher",
@@ -535,7 +540,8 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
- size_t secret_len)
+ size_t secret_len,
+ int require_message_authenticator)
{
const u8 *addr[4];
size_t len[4];
@@ -574,7 +580,11 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
}
if (attr == NULL) {
- /* Message-Authenticator is MAY; not required */
+ if (require_message_authenticator) {
+ wpa_printf(MSG_WARNING,
+ "Missing Message-Authenticator attribute in RADIUS message");
+ return 1;
+ }
return 0;
}
@@ -623,6 +633,9 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
size_t buf_needed;
struct radius_attr_hdr *attr;
+ if (TEST_FAIL())
+ return NULL;
+
if (data_len > RADIUS_MAX_ATTR_LEN) {
wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
(unsigned long) data_len);
@@ -703,7 +716,7 @@ struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
attr = (struct radius_attr_hdr *) pos;
- if (pos + attr->length > end || attr->length < sizeof(*attr))
+ if (attr->length > end - pos || attr->length < sizeof(*attr))
goto fail;
/* TODO: check that attr->length is suitable for attr->type */
@@ -815,8 +828,9 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
os_memcpy(msg->hdr->authenticator, req_auth,
sizeof(msg->hdr->authenticator));
}
- hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
- wpabuf_len(msg->buf), auth);
+ if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), auth) < 0)
+ return 1;
os_memcpy(attr + 1, orig, MD5_MAC_LEN);
if (req_auth) {
os_memcpy(msg->hdr->authenticator, orig_authenticator,
@@ -859,8 +873,8 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
addr[3] = secret;
len[3] = secret_len;
- md5_vector(4, addr, len, hash);
- if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+ if (md5_vector(4, addr, len, hash) < 0 ||
+ os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "Response Authenticator invalid!");
return 1;
}
@@ -892,25 +906,11 @@ int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
/* Create Request Authenticator. The value should be unique over the lifetime
* of the shared secret between authenticator and authentication server.
- * Use one-way MD5 hash calculated from current timestamp and some data given
- * by the caller. */
-void radius_msg_make_authenticator(struct radius_msg *msg,
- const u8 *data, size_t len)
+ */
+int radius_msg_make_authenticator(struct radius_msg *msg)
{
- struct os_time tv;
- long int l;
- const u8 *addr[3];
- size_t elen[3];
-
- os_get_time(&tv);
- l = os_random();
- addr[0] = (u8 *) &tv;
- elen[0] = sizeof(tv);
- addr[1] = data;
- elen[1] = len;
- addr[2] = (u8 *) &l;
- elen[2] = sizeof(l);
- md5_vector(3, addr, elen, msg->hdr->authenticator);
+ return os_get_random((u8 *) &msg->hdr->authenticator,
+ sizeof(msg->hdr->authenticator));
}
@@ -965,10 +965,9 @@ static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
}
len = vhdr->vendor_length - sizeof(*vhdr);
- data = os_malloc(len);
+ data = os_memdup(pos + sizeof(*vhdr), len);
if (data == NULL)
return NULL;
- os_memcpy(data, pos + sizeof(*vhdr), len);
if (alen)
*alen = len;
return data;
@@ -1028,7 +1027,10 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
addr[1] = pos - MD5_MAC_LEN;
elen[1] = MD5_MAC_LEN;
}
- md5_vector(first ? 3 : 2, addr, elen, hash);
+ if (md5_vector(first ? 3 : 2, addr, elen, hash) < 0) {
+ os_free(plain);
+ return NULL;
+ }
first = 0;
for (i = 0; i < MD5_MAC_LEN; i++)
@@ -1042,12 +1044,11 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
return NULL;
}
- res = os_malloc(plain[0]);
+ res = os_memdup(plain + 1, plain[0]);
if (res == NULL) {
os_free(plain);
return NULL;
}
- os_memcpy(res, plain + 1, plain[0]);
if (reslen)
*reslen = plain[0];
os_free(plain);
@@ -1210,7 +1211,11 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg,
vhdr = (struct radius_attr_vendor *) pos;
vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
pos = (u8 *) (vhdr + 1);
- salt = os_random() | 0x8000;
+ if (os_get_random((u8 *) &salt, sizeof(salt)) < 0) {
+ os_free(buf);
+ return 0;
+ }
+ salt |= 0x8000;
WPA_PUT_BE16(pos, salt);
pos += 2;
encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
@@ -1422,12 +1427,30 @@ struct radius_tunnel_attrs {
};
+static int cmp_int(const void *a, const void *b)
+{
+ int x, y;
+
+ x = *((int *) a);
+ y = *((int *) b);
+ return (x - y);
+}
+
+
/**
* radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
+ * The k tagged vlans found are sorted by vlan_id and stored in the first k
+ * items of tagged.
+ *
* @msg: RADIUS message
- * Returns: VLAN ID for the first tunnel configuration or 0 if none is found
+ * @untagged: Pointer to store untagged vid
+ * @numtagged: Size of tagged
+ * @tagged: Pointer to store tagged list
+ *
+ * Returns: 0 if neither tagged nor untagged configuration is found, 1 otherwise
*/
-int radius_msg_get_vlanid(struct radius_msg *msg)
+int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
+ int *tagged)
{
struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
size_t i;
@@ -1435,8 +1458,12 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
const u8 *data;
char buf[10];
size_t dlen;
+ int j, taggedidx = 0, vlan_id;
os_memset(&tunnel, 0, sizeof(tunnel));
+ for (j = 0; j < numtagged; j++)
+ tagged[j] = 0;
+ *untagged = 0;
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
@@ -1473,21 +1500,44 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
break;
os_memcpy(buf, data, dlen);
buf[dlen] = '\0';
+ vlan_id = atoi(buf);
+ if (vlan_id <= 0)
+ break;
tun->tag_used++;
- tun->vlanid = atoi(buf);
+ tun->vlanid = vlan_id;
+ break;
+ case RADIUS_ATTR_EGRESS_VLANID: /* RFC 4675 */
+ if (attr->length != 6)
+ break;
+ vlan_id = WPA_GET_BE24(data + 1);
+ if (vlan_id <= 0)
+ break;
+ if (data[0] == 0x32)
+ *untagged = vlan_id;
+ else if (data[0] == 0x31 && tagged &&
+ taggedidx < numtagged)
+ tagged[taggedidx++] = vlan_id;
break;
}
}
+ /* Use tunnel with the lowest tag for untagged VLAN id */
for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
tun = &tunnel[i];
if (tun->tag_used &&
tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
- tun->vlanid > 0)
- return tun->vlanid;
+ tun->vlanid > 0) {
+ *untagged = tun->vlanid;
+ break;
+ }
}
+ if (taggedidx)
+ qsort(tagged, taggedidx, sizeof(int), cmp_int);
+
+ if (*untagged > 0 || taggedidx)
+ return 1;
return 0;
}
@@ -1547,10 +1597,9 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
goto out;
/* alloc writable memory for decryption */
- buf = os_malloc(fdlen);
+ buf = os_memdup(fdata, fdlen);
if (buf == NULL)
goto out;
- os_memcpy(buf, fdata, fdlen);
buflen = fdlen;
/* init pointers */
@@ -1637,12 +1686,11 @@ int radius_copy_class(struct radius_class_data *dst,
dst->count = 0;
for (i = 0; i < src->count; i++) {
- dst->attr[i].data = os_malloc(src->attr[i].len);
+ dst->attr[i].data = os_memdup(src->attr[i].data,
+ src->attr[i].len);
if (dst->attr[i].data == NULL)
break;
dst->count++;
- os_memcpy(dst->attr[i].data, src->attr[i].data,
- src->attr[i].len);
dst->attr[i].len = src->attr[i].len;
}
@@ -1669,3 +1717,14 @@ u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
return 0;
}
+
+
+int radius_gen_session_id(u8 *id, size_t len)
+{
+ /*
+ * Acct-Session-Id and Acct-Multi-Session-Id should be globally and
+ * temporarily unique. A high quality random number is required
+ * therefore. This could be be improved by switching to a GUID.
+ */
+ return os_get_random(id, len);
+}
diff --git a/contrib/wpa/src/radius/radius.h b/contrib/wpa/src/radius/radius.h
index 5977339..630c0f9 100644
--- a/contrib/wpa/src/radius/radius.h
+++ b/contrib/wpa/src/radius/radius.h
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2012, 2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -52,6 +52,8 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_USER_PASSWORD = 2,
RADIUS_ATTR_NAS_IP_ADDRESS = 4,
RADIUS_ATTR_NAS_PORT = 5,
+ RADIUS_ATTR_SERVICE_TYPE = 6,
+ RADIUS_ATTR_FRAMED_IP_ADDRESS = 8,
RADIUS_ATTR_FRAMED_MTU = 12,
RADIUS_ATTR_REPLY_MESSAGE = 18,
RADIUS_ATTR_STATE = 24,
@@ -79,6 +81,7 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52,
RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
RADIUS_ATTR_EVENT_TIMESTAMP = 55,
+ RADIUS_ATTR_EGRESS_VLANID = 56,
RADIUS_ATTR_NAS_PORT_TYPE = 61,
RADIUS_ATTR_TUNNEL_TYPE = 64,
RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
@@ -99,8 +102,13 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES = 130,
RADIUS_ATTR_LOCATION_CAPABLE = 131,
RADIUS_ATTR_REQUESTED_LOCATION_INFO = 132,
+ RADIUS_ATTR_GSS_ACCEPTOR_SERVICE_NAME = 164,
+ RADIUS_ATTR_GSS_ACCEPTOR_HOST_NAME = 165,
+ RADIUS_ATTR_GSS_ACCEPTOR_SERVICE_SPECIFICS = 166,
+ RADIUS_ATTR_GSS_ACCEPTOR_REALM_NAME = 167,
RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177,
RADIUS_ATTR_WLAN_HESSID = 181,
+ RADIUS_ATTR_WLAN_REASON_CODE = 185,
RADIUS_ATTR_WLAN_PAIRWISE_CIPHER = 186,
RADIUS_ATTR_WLAN_GROUP_CIPHER = 187,
RADIUS_ATTR_WLAN_AKM_SUITE = 188,
@@ -108,6 +116,9 @@ enum { RADIUS_ATTR_USER_NAME = 1,
};
+/* Service-Type values (RFC 2865, 5.6) */
+#define RADIUS_SERVICE_TYPE_FRAMED 2
+
/* Termination-Action */
#define RADIUS_TERMINATION_ACTION_DEFAULT 0
#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1
@@ -187,6 +198,11 @@ enum {
RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION = 3,
RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ = 4,
RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL = 5,
+ RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM = 6,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME = 7,
+ RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP = 8,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING = 9,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL = 10,
};
#ifdef _MSC_VER
@@ -236,7 +252,8 @@ void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
- size_t secret_len);
+ size_t secret_len,
+ int require_message_authenticator);
struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
const u8 *data, size_t data_len);
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
@@ -250,8 +267,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
size_t secret_len, const u8 *req_auth);
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
u8 type);
-void radius_msg_make_authenticator(struct radius_msg *msg,
- const u8 *data, size_t len);
+int radius_msg_make_authenticator(struct radius_msg *msg);
struct radius_ms_mppe_keys *
radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
const u8 *secret, size_t secret_len);
@@ -274,7 +290,8 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
const u8 *data, size_t data_len,
const u8 *secret, size_t secret_len);
int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
-int radius_msg_get_vlanid(struct radius_msg *msg);
+int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
+ int *tagged);
char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
const u8 *secret, size_t secret_len,
struct radius_msg *sent_msg, size_t n);
@@ -319,4 +336,6 @@ int radius_copy_class(struct radius_class_data *dst,
u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs);
+int radius_gen_session_id(u8 *id, size_t len);
+
#endif /* RADIUS_H */
diff --git a/contrib/wpa/src/radius/radius_client.c b/contrib/wpa/src/radius/radius_client.c
index 693f61e..a3db404 100644
--- a/contrib/wpa/src/radius/radius_client.c
+++ b/contrib/wpa/src/radius/radius_client.c
@@ -26,12 +26,12 @@
#define RADIUS_CLIENT_MAX_WAIT 120
/**
- * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
+ * RADIUS_CLIENT_MAX_FAILOVER - RADIUS client maximum retries
*
- * Maximum number of retransmit attempts before the entry is removed from
+ * Maximum number of server failovers before the entry is removed from
* retransmit list.
*/
-#define RADIUS_CLIENT_MAX_RETRIES 10
+#define RADIUS_CLIENT_MAX_FAILOVER 3
/**
* RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
@@ -110,11 +110,16 @@ struct radius_msg_list {
os_time_t next_try;
/**
- * attempts - Number of transmission attempts
+ * attempts - Number of transmission attempts for one server
*/
int attempts;
/**
+ * accu_attempts - Number of accumulated attempts
+ */
+ int accu_attempts;
+
+ /**
* next_wait - Next retransmission wait time in seconds
*/
int next_wait;
@@ -226,6 +231,16 @@ struct radius_client_data {
* next_radius_identifier - Next RADIUS message identifier to use
*/
u8 next_radius_identifier;
+
+ /**
+ * interim_error_cb - Interim accounting error callback
+ */
+ void (*interim_error_cb)(const u8 *addr, void *ctx);
+
+ /**
+ * interim_error_cb_ctx - interim_error_cb() context data
+ */
+ void *interim_error_cb_ctx;
};
@@ -297,6 +312,25 @@ int radius_client_register(struct radius_client_data *radius,
}
+/**
+ * radius_client_set_interim_erro_cb - Register an interim acct error callback
+ * @radius: RADIUS client context from radius_client_init()
+ * @addr: Station address from the failed message
+ * @cb: Handler for interim accounting errors
+ * @ctx: Context pointer for handler callbacks
+ *
+ * This function is used to register a handler for processing failed
+ * transmission attempts of interim accounting update messages.
+ */
+void radius_client_set_interim_error_cb(struct radius_client_data *radius,
+ void (*cb)(const u8 *addr, void *ctx),
+ void *ctx)
+{
+ radius->interim_error_cb = cb;
+ radius->interim_error_cb_ctx = ctx;
+}
+
+
/*
* Returns >0 if message queue was flushed (i.e., the message that triggered
* the error is not available anymore)
@@ -308,7 +342,7 @@ static int radius_client_handle_send_error(struct radius_client_data *radius,
int _errno = errno;
wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
- _errno == EBADF || _errno == ENETUNREACH) {
+ _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Send failed - maybe interface status changed -"
@@ -336,9 +370,13 @@ static int radius_client_retransmit(struct radius_client_data *radius,
int s;
struct wpabuf *buf;
size_t prev_num_msgs;
+ u8 *acct_delay_time;
+ size_t acct_delay_time_len;
+ int num_servers;
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM) {
+ num_servers = conf->num_acct_servers;
if (radius->acct_sock < 0)
radius_client_init_acct(radius);
if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
@@ -355,6 +393,7 @@ static int radius_client_retransmit(struct radius_client_data *radius,
conf->acct_server->retransmissions++;
}
} else {
+ num_servers = conf->num_auth_servers;
if (radius->auth_sock < 0)
radius_client_init_auth(radius);
if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
@@ -371,14 +410,62 @@ static int radius_client_retransmit(struct radius_client_data *radius,
conf->auth_server->retransmissions++;
}
}
+
+ if (entry->msg_type == RADIUS_ACCT_INTERIM) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Failed to transmit interim accounting update to "
+ MACSTR " - drop message and request a new update",
+ MAC2STR(entry->addr));
+ if (radius->interim_error_cb)
+ radius->interim_error_cb(entry->addr,
+ radius->interim_error_cb_ctx);
+ return 1;
+ }
+
if (s < 0) {
wpa_printf(MSG_INFO,
"RADIUS: No valid socket for retransmission");
return 1;
}
+ if (entry->msg_type == RADIUS_ACCT &&
+ radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
+ &acct_delay_time, &acct_delay_time_len,
+ NULL) == 0 &&
+ acct_delay_time_len == 4) {
+ struct radius_hdr *hdr;
+ u32 delay_time;
+
+ /*
+ * Need to assign a new identifier since attribute contents
+ * changes.
+ */
+ hdr = radius_msg_get_hdr(entry->msg);
+ hdr->identifier = radius_client_get_id(radius);
+
+ /* Update Acct-Delay-Time to show wait time in queue */
+ delay_time = now - entry->first_try;
+ WPA_PUT_BE32(acct_delay_time, delay_time);
+
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
+ delay_time);
+ radius_msg_finish_acct(entry->msg, entry->shared_secret,
+ entry->shared_secret_len);
+ if (radius->conf->msg_dumps)
+ radius_msg_dump(entry->msg);
+ }
+
/* retransmit; remove entry if too many attempts */
+ if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER *
+ RADIUS_CLIENT_NUM_FAILOVER * num_servers) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
+ return 1;
+ }
+
entry->attempts++;
+ entry->accu_attempts++;
hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
radius_msg_get_hdr(entry->msg)->identifier);
@@ -395,10 +482,6 @@ static int radius_client_retransmit(struct radius_client_data *radius,
entry->next_wait *= 2;
if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
- if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
- wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
- return 1;
- }
return 0;
}
@@ -407,7 +490,6 @@ static int radius_client_retransmit(struct radius_client_data *radius,
static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
{
struct radius_client_data *radius = eloop_ctx;
- struct hostapd_radius_servers *conf = radius->conf;
struct os_reltime now;
os_time_t first;
struct radius_msg_list *entry, *prev, *tmp;
@@ -420,6 +502,30 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
return;
os_get_reltime(&now);
+
+ while (entry) {
+ if (now.sec >= entry->next_try) {
+ s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
+ radius->acct_sock;
+ if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
+ (s < 0 && entry->attempts > 0)) {
+ if (entry->msg_type == RADIUS_ACCT ||
+ entry->msg_type == RADIUS_ACCT_INTERIM)
+ acct_failover++;
+ else
+ auth_failover++;
+ }
+ }
+ entry = entry->next;
+ }
+
+ if (auth_failover)
+ radius_client_auth_failover(radius);
+
+ if (acct_failover)
+ radius_client_acct_failover(radius);
+
+ entry = radius->msgs;
first = 0;
prev = NULL;
@@ -447,17 +553,6 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
continue;
}
- s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
- radius->acct_sock;
- if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
- (s < 0 && entry->attempts > 0)) {
- if (entry->msg_type == RADIUS_ACCT ||
- entry->msg_type == RADIUS_ACCT_INTERIM)
- acct_failover++;
- else
- auth_failover++;
- }
-
if (first == 0 || entry->next_try < first)
first = entry->next_try;
@@ -468,6 +563,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
if (radius->msgs) {
if (first < now.sec)
first = now.sec;
+ eloop_cancel_timeout(radius_client_timer, radius, NULL);
eloop_register_timeout(first - now.sec, 0,
radius_client_timer, radius, NULL);
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
@@ -475,12 +571,6 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
"retransmit in %ld seconds",
(long int) (first - now.sec));
}
-
- if (auth_failover && conf->num_auth_servers > 1)
- radius_client_auth_failover(radius);
-
- if (acct_failover && conf->num_acct_servers > 1)
- radius_client_acct_failover(radius);
}
@@ -604,7 +694,10 @@ static void radius_client_list_add(struct radius_client_data *radius,
entry->first_try = entry->last_attempt.sec;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
entry->attempts = 1;
+ entry->accu_attempts = 1;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+ if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
+ entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
entry->next = radius->msgs;
radius->msgs = entry;
radius_client_update_timeout(radius);
@@ -625,39 +718,6 @@ static void radius_client_list_add(struct radius_client_data *radius,
}
-static void radius_client_list_del(struct radius_client_data *radius,
- RadiusType msg_type, const u8 *addr)
-{
- struct radius_msg_list *entry, *prev, *tmp;
-
- if (addr == NULL)
- return;
-
- entry = radius->msgs;
- prev = NULL;
- while (entry) {
- if (entry->msg_type == msg_type &&
- os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
- if (prev)
- prev->next = entry->next;
- else
- radius->msgs = entry->next;
- tmp = entry;
- entry = entry->next;
- hostapd_logger(radius->ctx, addr,
- HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_DEBUG,
- "Removing matching RADIUS message");
- radius_client_msg_free(tmp);
- radius->num_msgs--;
- continue;
- }
- prev = entry;
- entry = entry->next;
- }
-}
-
-
/**
* radius_client_send - Send a RADIUS request
* @radius: RADIUS client context from radius_client_init()
@@ -669,16 +729,19 @@ static void radius_client_list_del(struct radius_client_data *radius,
* This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
* accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
* between accounting and interim accounting messages is that the interim
- * message will override any pending interim accounting updates while a new
- * accounting message does not remove any pending messages.
+ * message will not be retransmitted. Instead, a callback is used to indicate
+ * that the transmission failed for the specific station @addr so that a new
+ * interim accounting update message can be generated with up-to-date session
+ * data instead of trying to resend old information.
*
* The message is added on the retransmission queue and will be retransmitted
* automatically until a response is received or maximum number of retries
- * (RADIUS_CLIENT_MAX_RETRIES) is reached.
+ * (RADIUS_CLIENT_MAX_FAILOVER * RADIUS_CLIENT_NUM_FAILOVER) is reached. No
+ * such retries are used with RADIUS_ACCT_INTERIM, i.e., such a pending message
+ * is removed from the queue automatically on transmission failure.
*
* The related device MAC address can be used to identify pending messages that
- * can be removed with radius_client_flush_auth() or with interim accounting
- * updates.
+ * can be removed with radius_client_flush_auth().
*/
int radius_client_send(struct radius_client_data *radius,
struct radius_msg *msg, RadiusType msg_type,
@@ -691,11 +754,6 @@ int radius_client_send(struct radius_client_data *radius,
int s, res;
struct wpabuf *buf;
- if (msg_type == RADIUS_ACCT_INTERIM) {
- /* Remove any pending interim acct update for the same STA. */
- radius_client_list_del(radius, msg_type, addr);
- }
-
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
if (conf->acct_server && radius->acct_sock < 0)
radius_client_init_acct(radius);
@@ -869,13 +927,13 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
switch (res) {
case RADIUS_RX_PROCESSED:
radius_msg_free(msg);
- /* continue */
+ /* fall through */
case RADIUS_RX_QUEUED:
radius_client_msg_free(req);
return;
case RADIUS_RX_INVALID_AUTHENTICATOR:
invalid_authenticator++;
- /* continue */
+ /* fall through */
case RADIUS_RX_UNKNOWN:
/* continue with next handler */
break;
@@ -1015,6 +1073,9 @@ radius_change_server(struct radius_client_data *radius,
int sel_sock;
struct radius_msg_list *entry;
struct hostapd_radius_servers *conf = radius->conf;
+ struct sockaddr_in disconnect_addr = {
+ .sin_family = AF_UNSPEC,
+ };
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -1023,6 +1084,12 @@ radius_change_server(struct radius_client_data *radius,
hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
nserv->port);
+ if (oserv && oserv == nserv) {
+ /* Reconnect to same server, flush */
+ if (auth)
+ radius_client_flush(radius, 1);
+ }
+
if (oserv && oserv != nserv &&
(nserv->shared_secret_len != oserv->shared_secret_len ||
os_memcmp(nserv->shared_secret, oserv->shared_secret,
@@ -1043,14 +1110,13 @@ radius_change_server(struct radius_client_data *radius,
}
}
- /* Reset retry counters for the new server */
- for (entry = radius->msgs; oserv && oserv != nserv && entry;
- entry = entry->next) {
+ /* Reset retry counters */
+ for (entry = radius->msgs; oserv && entry; entry = entry->next) {
if ((auth && entry->msg_type != RADIUS_AUTH) ||
(!auth && entry->msg_type != RADIUS_ACCT))
continue;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
- entry->attempts = 0;
+ entry->attempts = 1;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
}
@@ -1125,6 +1191,11 @@ radius_change_server(struct radius_client_data *radius,
}
}
+ /* Force a reconnect by disconnecting the socket first */
+ if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
+ sizeof(disconnect_addr)) < 0)
+ wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
+
if (connect(sel_sock, addr, addrlen) < 0) {
wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
return -1;
@@ -1587,11 +1658,16 @@ static int radius_client_dump_acct_server(char *buf, size_t buflen,
int radius_client_get_mib(struct radius_client_data *radius, char *buf,
size_t buflen)
{
- struct hostapd_radius_servers *conf = radius->conf;
+ struct hostapd_radius_servers *conf;
int i;
struct hostapd_radius_server *serv;
int count = 0;
+ if (!radius)
+ return 0;
+
+ conf = radius->conf;
+
if (conf->auth_servers) {
for (i = 0; i < conf->num_auth_servers; i++) {
serv = &conf->auth_servers[i];
diff --git a/contrib/wpa/src/radius/radius_client.h b/contrib/wpa/src/radius/radius_client.h
index 3db16aa..8ca0874 100644
--- a/contrib/wpa/src/radius/radius_client.h
+++ b/contrib/wpa/src/radius/radius_client.h
@@ -241,6 +241,9 @@ int radius_client_register(struct radius_client_data *radius,
const u8 *shared_secret, size_t shared_secret_len,
void *data),
void *data);
+void radius_client_set_interim_error_cb(struct radius_client_data *radius,
+ void (*cb)(const u8 *addr, void *ctx),
+ void *ctx);
int radius_client_send(struct radius_client_data *radius,
struct radius_msg *msg,
RadiusType msg_type, const u8 *addr);
diff --git a/contrib/wpa/src/radius/radius_das.c b/contrib/wpa/src/radius/radius_das.c
index b7d991b..aaa3fc2 100644
--- a/contrib/wpa/src/radius/radius_das.c
+++ b/contrib/wpa/src/radius/radius_das.c
@@ -23,9 +23,11 @@ struct radius_das_data {
struct hostapd_ip_addr client_addr;
unsigned int time_window;
int require_event_timestamp;
+ int require_message_authenticator;
void *ctx;
enum radius_das_res (*disconnect)(void *ctx,
struct radius_das_attrs *attr);
+ enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
};
@@ -160,6 +162,10 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
abuf, from_port);
error = 508;
break;
+ case RADIUS_DAS_COA_FAILED:
+ /* not used with Disconnect-Request */
+ error = 405;
+ break;
case RADIUS_DAS_SUCCESS:
error = 0;
break;
@@ -183,6 +189,195 @@ fail:
}
+static struct radius_msg * radius_das_coa(struct radius_das_data *das,
+ struct radius_msg *msg,
+ const char *abuf, int from_port)
+{
+ struct radius_hdr *hdr;
+ struct radius_msg *reply;
+ u8 allowed[] = {
+ RADIUS_ATTR_USER_NAME,
+ RADIUS_ATTR_NAS_IP_ADDRESS,
+ RADIUS_ATTR_CALLING_STATION_ID,
+ RADIUS_ATTR_NAS_IDENTIFIER,
+ RADIUS_ATTR_ACCT_SESSION_ID,
+ RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+ RADIUS_ATTR_EVENT_TIMESTAMP,
+ RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+#ifdef CONFIG_HS20
+ RADIUS_ATTR_VENDOR_SPECIFIC,
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_IPV6
+ RADIUS_ATTR_NAS_IPV6_ADDRESS,
+#endif /* CONFIG_IPV6 */
+ 0
+ };
+ int error = 405;
+ u8 attr;
+ enum radius_das_res res;
+ struct radius_das_attrs attrs;
+ u8 *buf;
+ size_t len;
+ char tmp[100];
+ u8 sta_addr[ETH_ALEN];
+
+ hdr = radius_msg_get_hdr(msg);
+
+ if (!das->coa) {
+ wpa_printf(MSG_INFO, "DAS: CoA not supported");
+ goto fail;
+ }
+
+ attr = radius_msg_find_unlisted_attr(msg, allowed);
+ if (attr) {
+ wpa_printf(MSG_INFO,
+ "DAS: Unsupported attribute %u in CoA-Request from %s:%d",
+ attr, abuf, from_port);
+ error = 401;
+ goto fail;
+ }
+
+ os_memset(&attrs, 0, sizeof(attrs));
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+ &buf, &len, NULL) == 0) {
+ if (len != 4) {
+ wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d",
+ abuf, from_port);
+ error = 407;
+ goto fail;
+ }
+ attrs.nas_ip_addr = buf;
+ }
+
+#ifdef CONFIG_IPV6
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
+ &buf, &len, NULL) == 0) {
+ if (len != 16) {
+ wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d",
+ abuf, from_port);
+ error = 407;
+ goto fail;
+ }
+ attrs.nas_ipv6_addr = buf;
+ }
+#endif /* CONFIG_IPV6 */
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+ &buf, &len, NULL) == 0) {
+ attrs.nas_identifier = buf;
+ attrs.nas_identifier_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ &buf, &len, NULL) == 0) {
+ if (len >= sizeof(tmp))
+ len = sizeof(tmp) - 1;
+ os_memcpy(tmp, buf, len);
+ tmp[len] = '\0';
+ if (hwaddr_aton2(tmp, sta_addr) < 0) {
+ wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
+ "'%s' from %s:%d", tmp, abuf, from_port);
+ error = 407;
+ goto fail;
+ }
+ attrs.sta_addr = sta_addr;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+ &buf, &len, NULL) == 0) {
+ attrs.user_name = buf;
+ attrs.user_name_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ &buf, &len, NULL) == 0) {
+ attrs.acct_session_id = buf;
+ attrs.acct_session_id_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+ &buf, &len, NULL) == 0) {
+ attrs.acct_multi_session_id = buf;
+ attrs.acct_multi_session_id_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) == 0) {
+ attrs.cui = buf;
+ attrs.cui_len = len;
+ }
+
+#ifdef CONFIG_HS20
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+ &buf, &len, NULL) == 0) {
+ if (len < 10 || WPA_GET_BE32(buf) != RADIUS_VENDOR_ID_WFA ||
+ buf[4] != RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING ||
+ buf[5] < 6) {
+ wpa_printf(MSG_INFO,
+ "DAS: Unsupported attribute %u in CoA-Request from %s:%d",
+ attr, abuf, from_port);
+ error = 401;
+ goto fail;
+ }
+ attrs.hs20_t_c_filtering = &buf[6];
+ }
+
+ if (!attrs.hs20_t_c_filtering) {
+ wpa_printf(MSG_INFO,
+ "DAS: No supported authorization change attribute in CoA-Request from %s:%d",
+ abuf, from_port);
+ error = 402;
+ goto fail;
+ }
+#endif /* CONFIG_HS20 */
+
+ res = das->coa(das->ctx, &attrs);
+ switch (res) {
+ case RADIUS_DAS_NAS_MISMATCH:
+ wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
+ abuf, from_port);
+ error = 403;
+ break;
+ case RADIUS_DAS_SESSION_NOT_FOUND:
+ wpa_printf(MSG_INFO,
+ "DAS: Session not found for request from %s:%d",
+ abuf, from_port);
+ error = 503;
+ break;
+ case RADIUS_DAS_MULTI_SESSION_MATCH:
+ wpa_printf(MSG_INFO,
+ "DAS: Multiple sessions match for request from %s:%d",
+ abuf, from_port);
+ error = 508;
+ break;
+ case RADIUS_DAS_COA_FAILED:
+ wpa_printf(MSG_INFO, "DAS: CoA failed for request from %s:%d",
+ abuf, from_port);
+ error = 407;
+ break;
+ case RADIUS_DAS_SUCCESS:
+ error = 0;
+ break;
+ }
+
+fail:
+ reply = radius_msg_new(error ? RADIUS_CODE_COA_NAK :
+ RADIUS_CODE_COA_ACK, hdr->identifier);
+ if (!reply)
+ return NULL;
+
+ if (error &&
+ !radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error)) {
+ radius_msg_free(reply);
+ return NULL;
+ }
+
+ return reply;
+}
+
+
static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
struct radius_das_data *das = eloop_ctx;
@@ -218,7 +413,8 @@ static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
len, abuf, from_port);
- if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
+ if (das->client_addr.u.v4.s_addr &&
+ das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
return;
}
@@ -234,9 +430,11 @@ static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
radius_msg_dump(msg);
if (radius_msg_verify_das_req(msg, das->shared_secret,
- das->shared_secret_len)) {
- wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
- "from %s:%d - drop", abuf, from_port);
+ das->shared_secret_len,
+ das->require_message_authenticator)) {
+ wpa_printf(MSG_DEBUG,
+ "DAS: Invalid authenticator or Message-Authenticator in packet from %s:%d - drop",
+ abuf, from_port);
goto fail;
}
@@ -267,19 +465,7 @@ static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
reply = radius_das_disconnect(das, msg, abuf, from_port);
break;
case RADIUS_CODE_COA_REQUEST:
- /* TODO */
- reply = radius_msg_new(RADIUS_CODE_COA_NAK,
- hdr->identifier);
- if (reply == NULL)
- break;
-
- /* Unsupported Service */
- if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
- 405)) {
- radius_msg_free(reply);
- reply = NULL;
- break;
- }
+ reply = radius_das_coa(das, msg, abuf, from_port);
break;
default:
wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
@@ -362,19 +548,21 @@ radius_das_init(struct radius_das_conf *conf)
das->time_window = conf->time_window;
das->require_event_timestamp = conf->require_event_timestamp;
+ das->require_message_authenticator =
+ conf->require_message_authenticator;
das->ctx = conf->ctx;
das->disconnect = conf->disconnect;
+ das->coa = conf->coa;
os_memcpy(&das->client_addr, conf->client_addr,
sizeof(das->client_addr));
- das->shared_secret = os_malloc(conf->shared_secret_len);
+ das->shared_secret = os_memdup(conf->shared_secret,
+ conf->shared_secret_len);
if (das->shared_secret == NULL) {
radius_das_deinit(das);
return NULL;
}
- os_memcpy(das->shared_secret, conf->shared_secret,
- conf->shared_secret_len);
das->shared_secret_len = conf->shared_secret_len;
das->sock = radius_das_open_socket(conf->port);
diff --git a/contrib/wpa/src/radius/radius_das.h b/contrib/wpa/src/radius/radius_das.h
index ce731d4..233d662 100644
--- a/contrib/wpa/src/radius/radius_das.h
+++ b/contrib/wpa/src/radius/radius_das.h
@@ -16,6 +16,7 @@ enum radius_das_res {
RADIUS_DAS_NAS_MISMATCH,
RADIUS_DAS_SESSION_NOT_FOUND,
RADIUS_DAS_MULTI_SESSION_MATCH,
+ RADIUS_DAS_COA_FAILED,
};
struct radius_das_attrs {
@@ -35,6 +36,9 @@ struct radius_das_attrs {
size_t acct_multi_session_id_len;
const u8 *cui;
size_t cui_len;
+
+ /* Authorization changes */
+ const u8 *hs20_t_c_filtering;
};
struct radius_das_conf {
@@ -44,9 +48,11 @@ struct radius_das_conf {
const struct hostapd_ip_addr *client_addr;
unsigned int time_window;
int require_event_timestamp;
+ int require_message_authenticator;
void *ctx;
enum radius_das_res (*disconnect)(void *ctx,
struct radius_das_attrs *attr);
+ enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
};
struct radius_das_data *
diff --git a/contrib/wpa/src/radius/radius_server.c b/contrib/wpa/src/radius/radius_server.c
index 744283c..b621ada 100644
--- a/contrib/wpa/src/radius/radius_server.c
+++ b/contrib/wpa/src/radius/radius_server.c
@@ -1,6 +1,6 @@
/*
* RADIUS authentication server
- * Copyright (c) 2005-2009, 2011-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -26,9 +26,14 @@
#define RADIUS_SESSION_TIMEOUT 60
/**
+ * RADIUS_SESSION_MAINTAIN - Completed session expiration timeout in seconds
+ */
+#define RADIUS_SESSION_MAINTAIN 5
+
+/**
* RADIUS_MAX_SESSION - Maximum number of active sessions
*/
-#define RADIUS_MAX_SESSION 100
+#define RADIUS_MAX_SESSION 1000
/**
* RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
@@ -75,6 +80,7 @@ struct radius_session {
struct eap_eapol_interface *eap_if;
char *username; /* from User-Name attribute */
char *nas_ip;
+ u8 mac_addr[ETH_ALEN]; /* from Calling-Station-Id attribute */
struct radius_msg *last_msg;
char *last_from_addr;
@@ -87,8 +93,11 @@ struct radius_session {
unsigned int remediation:1;
unsigned int macacl:1;
+ unsigned int t_c_filtering:1;
struct hostapd_radius_attr *accept_attr;
+
+ u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
};
/**
@@ -106,6 +115,14 @@ struct radius_client {
int shared_secret_len;
struct radius_session *sessions;
struct radius_server_counters counters;
+
+ u8 next_dac_identifier;
+ struct radius_msg *pending_dac_coa_req;
+ u8 pending_dac_coa_id;
+ u8 pending_dac_coa_addr[ETH_ALEN];
+ struct radius_msg *pending_dac_disconnect_req;
+ u8 pending_dac_disconnect_id;
+ u8 pending_dac_disconnect_addr[ETH_ALEN];
};
/**
@@ -267,6 +284,8 @@ struct radius_server_data {
unsigned int tls_session_lifetime;
+ unsigned int tls_flags;
+
/**
* wps - Wi-Fi Protected Setup context
*
@@ -338,6 +357,9 @@ struct radius_server_data {
char *subscr_remediation_url;
u8 subscr_remediation_method;
+ char *hs20_sim_provisioning_url;
+
+ char *t_c_server_url;
#ifdef CONFIG_SQLITE
sqlite3 *db;
@@ -359,6 +381,44 @@ static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
static void radius_server_session_remove_timeout(void *eloop_ctx,
void *timeout_ctx);
+#ifdef CONFIG_SQLITE
+#ifdef CONFIG_HS20
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_sim_provisioning(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE sim_provisioning("
+ " mobile_identifier_hash TEXT PRIMARY KEY,"
+ " imsi TEXT,"
+ " mac_addr TEXT,"
+ " eap_method TEXT,"
+ " timestamp TEXT"
+ ");";
+
+ RADIUS_DEBUG("Adding database table for SIM provisioning information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ RADIUS_ERROR("SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_HS20 */
+#endif /* CONFIG_SQLITE */
+
+
void srv_log(struct radius_session *sess, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
@@ -616,17 +676,34 @@ static void radius_server_testing_options(struct radius_session *sess,
}
+#ifdef CONFIG_ERP
+static struct eap_server_erp_key *
+radius_server_erp_find_key(struct radius_server_data *data, const char *keyname)
+{
+ struct eap_server_erp_key *erp;
+
+ dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key,
+ list) {
+ if (os_strcmp(erp->keyname_nai, keyname) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_ERP */
+
+
static struct radius_session *
radius_server_get_new_session(struct radius_server_data *data,
struct radius_client *client,
struct radius_msg *msg, const char *from_addr)
{
- u8 *user;
- size_t user_len;
+ u8 *user, *id;
+ size_t user_len, id_len;
int res;
struct radius_session *sess;
struct eap_config eap_conf;
- struct eap_user tmp;
+ struct eap_user *tmp;
RADIUS_DEBUG("Creating a new session");
@@ -637,12 +714,27 @@ radius_server_get_new_session(struct radius_server_data *data,
}
RADIUS_DUMP_ASCII("User-Name", user, user_len);
- os_memset(&tmp, 0, sizeof(tmp));
- res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp);
- bin_clear_free(tmp.password, tmp.password_len);
+ tmp = os_zalloc(sizeof(*tmp));
+ if (!tmp)
+ return NULL;
+ res = data->get_eap_user(data->conf_ctx, user, user_len, 0, tmp);
+#ifdef CONFIG_ERP
+ if (res != 0 && data->erp) {
+ char *username;
+
+ username = os_zalloc(user_len + 1);
+ if (username) {
+ os_memcpy(username, user, user_len);
+ if (radius_server_erp_find_key(data, username))
+ res = 0;
+ os_free(username);
+ }
+ }
+#endif /* CONFIG_ERP */
if (res != 0) {
RADIUS_DEBUG("User-Name not found from user database");
+ eap_user_free(tmp);
return NULL;
}
@@ -650,24 +742,41 @@ radius_server_get_new_session(struct radius_server_data *data,
sess = radius_server_new_session(data, client);
if (sess == NULL) {
RADIUS_DEBUG("Failed to create a new session");
+ eap_user_free(tmp);
return NULL;
}
- sess->accept_attr = tmp.accept_attr;
- sess->macacl = tmp.macacl;
+ sess->accept_attr = tmp->accept_attr;
+ sess->macacl = tmp->macacl;
+ eap_user_free(tmp);
sess->username = os_malloc(user_len * 4 + 1);
if (sess->username == NULL) {
- radius_server_session_free(data, sess);
+ radius_server_session_remove(data, sess);
return NULL;
}
printf_encode(sess->username, user_len * 4 + 1, user, user_len);
sess->nas_ip = os_strdup(from_addr);
if (sess->nas_ip == NULL) {
- radius_server_session_free(data, sess);
+ radius_server_session_remove(data, sess);
return NULL;
}
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, &id,
+ &id_len, NULL) == 0) {
+ char buf[3 * ETH_ALEN];
+
+ os_memset(buf, 0, sizeof(buf));
+ if (id_len >= sizeof(buf))
+ id_len = sizeof(buf) - 1;
+ os_memcpy(buf, id, id_len);
+ if (hwaddr_aton2(buf, sess->mac_addr) < 0)
+ os_memset(sess->mac_addr, 0, ETH_ALEN);
+ else
+ RADIUS_DEBUG("Calling-Station-Id: " MACSTR,
+ MAC2STR(sess->mac_addr));
+ }
+
srv_log(sess, "New session created");
os_memset(&eap_conf, 0, sizeof(eap_conf));
@@ -691,13 +800,14 @@ radius_server_get_new_session(struct radius_server_data *data,
eap_conf.server_id_len = os_strlen(data->server_id);
eap_conf.erp = data->erp;
eap_conf.tls_session_lifetime = data->tls_session_lifetime;
+ eap_conf.tls_flags = data->tls_flags;
radius_server_testing_options(sess, &eap_conf);
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
&eap_conf);
if (sess->eap == NULL) {
RADIUS_DEBUG("Failed to initialize EAP state machine for the "
"new session");
- radius_server_session_free(data, sess);
+ radius_server_session_remove(data, sess);
return NULL;
}
sess->eap_if = eap_get_interface(sess->eap);
@@ -710,6 +820,236 @@ radius_server_get_new_session(struct radius_server_data *data,
}
+#ifdef CONFIG_HS20
+static void radius_srv_hs20_t_c_pending(struct radius_session *sess)
+{
+#ifdef CONFIG_SQLITE
+ char *sql;
+ char addr[3 * ETH_ALEN], *id_str;
+ const u8 *id;
+ size_t id_len;
+
+ if (!sess->server->db || !sess->eap ||
+ is_zero_ether_addr(sess->mac_addr))
+ return;
+
+ os_snprintf(addr, sizeof(addr), MACSTR, MAC2STR(sess->mac_addr));
+
+ id = eap_get_identity(sess->eap, &id_len);
+ if (!id)
+ return;
+ id_str = os_malloc(id_len + 1);
+ if (!id_str)
+ return;
+ os_memcpy(id_str, id, id_len);
+ id_str[id_len] = '\0';
+
+ sql = sqlite3_mprintf("INSERT OR REPLACE INTO pending_tc (mac_addr,identity) VALUES (%Q,%Q)",
+ addr, id_str);
+ os_free(id_str);
+ if (!sql)
+ return;
+
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ RADIUS_ERROR("Failed to add pending_tc entry into sqlite database: %s",
+ sqlite3_errmsg(sess->server->db));
+ }
+ sqlite3_free(sql);
+#endif /* CONFIG_SQLITE */
+}
+#endif /* CONFIG_HS20 */
+
+
+static void radius_server_add_session(struct radius_session *sess)
+{
+#ifdef CONFIG_SQLITE
+ char *sql;
+ char addr_txt[ETH_ALEN * 3];
+ struct os_time now;
+
+ if (!sess->server->db)
+ return;
+
+
+ os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
+ MAC2STR(sess->mac_addr));
+
+ os_get_time(&now);
+ sql = sqlite3_mprintf("INSERT OR REPLACE INTO current_sessions(mac_addr,identity,start_time,nas,hs20_t_c_filtering) VALUES (%Q,%Q,%d,%Q,%u)",
+ addr_txt, sess->username, now.sec,
+ sess->nas_ip, sess->t_c_filtering);
+ if (sql) {
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
+ NULL) != SQLITE_OK) {
+ RADIUS_ERROR("Failed to add current_sessions entry into sqlite database: %s",
+ sqlite3_errmsg(sess->server->db));
+ }
+ sqlite3_free(sql);
+ }
+#endif /* CONFIG_SQLITE */
+}
+
+
+static void db_update_last_msk(struct radius_session *sess, const char *msk)
+{
+#ifdef CONFIG_RADIUS_TEST
+#ifdef CONFIG_SQLITE
+ char *sql = NULL;
+ char *id_str = NULL;
+ const u8 *id;
+ size_t id_len;
+ const char *serial_num;
+
+ if (!sess->server->db)
+ return;
+
+ serial_num = eap_get_serial_num(sess->eap);
+ if (serial_num) {
+ id_len = 5 + os_strlen(serial_num) + 1;
+ id_str = os_malloc(id_len);
+ if (!id_str)
+ return;
+ os_snprintf(id_str, id_len, "cert-%s", serial_num);
+ } else {
+ id = eap_get_identity(sess->eap, &id_len);
+ if (!id)
+ return;
+ id_str = os_malloc(id_len + 1);
+ if (!id_str)
+ return;
+ os_memcpy(id_str, id, id_len);
+ id_str[id_len] = '\0';
+ }
+
+ sql = sqlite3_mprintf("UPDATE users SET last_msk=%Q WHERE identity=%Q",
+ msk, id_str);
+ os_free(id_str);
+ if (!sql)
+ return;
+
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ RADIUS_DEBUG("Failed to update last_msk: %s",
+ sqlite3_errmsg(sess->server->db));
+ }
+ sqlite3_free(sql);
+#endif /* CONFIG_SQLITE */
+#endif /* CONFIG_RADIUS_TEST */
+}
+
+
+#ifdef CONFIG_HS20
+
+static int radius_server_is_sim_method(struct radius_session *sess)
+{
+ const char *name;
+
+ name = eap_get_method(sess->eap);
+ return name &&
+ (os_strcmp(name, "SIM") == 0 ||
+ os_strcmp(name, "AKA") == 0 ||
+ os_strcmp(name, "AKA'") == 0);
+}
+
+
+static int radius_server_hs20_missing_sim_pps(struct radius_msg *request)
+{
+ u8 *buf, *pos, *end, type, sublen;
+ size_t len;
+
+ buf = NULL;
+ for (;;) {
+ if (radius_msg_get_attr_ptr(request,
+ RADIUS_ATTR_VENDOR_SPECIFIC,
+ &buf, &len, buf) < 0)
+ return 0;
+ if (len < 6)
+ continue;
+ pos = buf;
+ end = buf + len;
+ if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
+ continue;
+ pos += 4;
+
+ type = *pos++;
+ sublen = *pos++;
+ if (sublen < 2)
+ continue; /* invalid length */
+ sublen -= 2; /* skip header */
+ if (pos + sublen > end)
+ continue; /* invalid WFA VSA */
+
+ if (type != RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION)
+ continue;
+
+ RADIUS_DUMP("HS2.0 mobile device version", pos, sublen);
+ if (sublen < 1 + 2)
+ continue;
+ if (pos[0] == 0)
+ continue; /* Release 1 STA does not support provisioning
+
+ */
+ /* UpdateIdentifier 0 indicates no PPS MO */
+ return WPA_GET_BE16(pos + 1) == 0;
+ }
+}
+
+
+#define HS20_MOBILE_ID_HASH_LEN 16
+
+static int radius_server_sim_provisioning_session(struct radius_session *sess,
+ const u8 *hash)
+{
+#ifdef CONFIG_SQLITE
+ char *sql;
+ char addr_txt[ETH_ALEN * 3];
+ char hash_txt[2 * HS20_MOBILE_ID_HASH_LEN + 1];
+ struct os_time now;
+ int res;
+ const char *imsi, *eap_method;
+
+ if (!sess->server->db ||
+ (!db_table_exists(sess->server->db, "sim_provisioning") &&
+ db_table_create_sim_provisioning(sess->server->db) < 0))
+ return -1;
+
+ imsi = eap_get_imsi(sess->eap);
+ if (!imsi)
+ return -1;
+
+ eap_method = eap_get_method(sess->eap);
+ if (!eap_method)
+ return -1;
+
+ os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
+ MAC2STR(sess->mac_addr));
+ wpa_snprintf_hex(hash_txt, sizeof(hash_txt), hash,
+ HS20_MOBILE_ID_HASH_LEN);
+
+ os_get_time(&now);
+ sql = sqlite3_mprintf("INSERT INTO sim_provisioning(mobile_identifier_hash,imsi,mac_addr,eap_method,timestamp) VALUES (%Q,%Q,%Q,%Q,%u)",
+ hash_txt, imsi, addr_txt, eap_method, now.sec);
+ if (!sql)
+ return -1;
+
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ RADIUS_ERROR("Failed to add SIM provisioning entry into sqlite database: %s",
+ sqlite3_errmsg(sess->server->db));
+ res = -1;
+ } else {
+ res = 0;
+ }
+ sqlite3_free(sql);
+ return res;
+#endif /* CONFIG_SQLITE */
+ return -1;
+}
+
+#endif /* CONFIG_HS20 */
+
+
static struct radius_msg *
radius_server_encapsulate_eap(struct radius_server_data *data,
struct radius_client *client,
@@ -720,6 +1060,7 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
int code;
unsigned int sess_id;
struct radius_hdr *hdr = radius_msg_get_hdr(request);
+ u16 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
if (sess->eap_if->eapFail) {
sess->eap_if->eapFail = FALSE;
@@ -754,9 +1095,18 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
int len;
#ifdef CONFIG_RADIUS_TEST
+ char buf[2 * 64 + 1];
+
+ len = sess->eap_if->eapKeyDataLen;
+ if (len > 64)
+ len = 64;
+ len = wpa_snprintf_hex(buf, sizeof(buf),
+ sess->eap_if->eapKeyData, len);
+ buf[len] = '\0';
+
if (data->dump_msk_file) {
FILE *f;
- char buf[2 * 64 + 1];
+
f = fopen(data->dump_msk_file, "a");
if (f) {
len = sess->eap_if->eapKeyDataLen;
@@ -770,6 +1120,8 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
fclose(f);
}
}
+
+ db_update_last_msk(sess, buf);
#endif /* CONFIG_RADIUS_TEST */
if (sess->eap_if->eapKeyDataLen > 64) {
len = 32;
@@ -811,6 +1163,103 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
buf, 0)) {
RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
}
+ } else if (code == RADIUS_CODE_ACCESS_ACCEPT &&
+ data->hs20_sim_provisioning_url &&
+ radius_server_is_sim_method(sess) &&
+ radius_server_hs20_missing_sim_pps(request)) {
+ u8 *buf, *pos, hash[HS20_MOBILE_ID_HASH_LEN];
+ size_t prefix_len, url_len;
+
+ RADIUS_DEBUG("Device needs HS 2.0 SIM provisioning");
+
+ if (os_get_random(hash, HS20_MOBILE_ID_HASH_LEN) < 0) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+ RADIUS_DUMP("hotspot2dot0-mobile-identifier-hash",
+ hash, HS20_MOBILE_ID_HASH_LEN);
+
+ if (radius_server_sim_provisioning_session(sess, hash) < 0) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ prefix_len = os_strlen(data->hs20_sim_provisioning_url);
+ url_len = prefix_len + 2 * HS20_MOBILE_ID_HASH_LEN;
+ buf = os_malloc(1 + url_len + 1);
+ if (!buf) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+ pos = buf;
+ *pos++ = data->subscr_remediation_method;
+ os_memcpy(pos, data->hs20_sim_provisioning_url, prefix_len);
+ pos += prefix_len;
+ wpa_snprintf_hex((char *) pos, 2 * HS20_MOBILE_ID_HASH_LEN + 1,
+ hash, HS20_MOBILE_ID_HASH_LEN);
+ RADIUS_DEBUG("HS 2.0 subscription remediation URL: %s",
+ (char *) &buf[1]);
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
+ buf, 1 + url_len)) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
+ }
+ os_free(buf);
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->t_c_filtering) {
+ u8 buf[4] = { 0x01, 0x00, 0x00, 0x00 }; /* E=1 */
+ const char *url = data->t_c_server_url, *pos;
+ char *url2, *end2, *pos2;
+ size_t url_len;
+
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
+ buf, sizeof(buf))) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ if (!url) {
+ RADIUS_DEBUG("No t_c_server_url configured");
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ pos = os_strstr(url, "@1@");
+ if (!pos) {
+ RADIUS_DEBUG("No @1@ macro in t_c_server_url");
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ url_len = os_strlen(url) + ETH_ALEN * 3 - 1 - 3;
+ url2 = os_malloc(url_len + 1);
+ if (!url2) {
+ RADIUS_DEBUG("Failed to allocate room for T&C Server URL");
+ os_free(url2);
+ radius_msg_free(msg);
+ return NULL;
+ }
+ pos2 = url2;
+ end2 = url2 + url_len + 1;
+ os_memcpy(pos2, url, pos - url);
+ pos2 += pos - url;
+ os_snprintf(pos2, end2 - pos2, MACSTR, MAC2STR(sess->mac_addr));
+ pos2 += ETH_ALEN * 3 - 1;
+ os_memcpy(pos2, pos + 3, os_strlen(pos + 3));
+ if (!radius_msg_add_wfa(msg,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL,
+ (const u8 *) url2, url_len)) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-T-C-URL");
+ os_free(url2);
+ radius_msg_free(msg);
+ return NULL;
+ }
+ os_free(url2);
+
+ radius_srv_hs20_t_c_pending(sess);
}
#endif /* CONFIG_HS20 */
@@ -833,12 +1282,24 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
}
}
+ if (code == RADIUS_CODE_ACCESS_REJECT) {
+ if (radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
+ reason) < 0) {
+ RADIUS_DEBUG("Failed to add WLAN-Reason-Code attribute");
+ radius_msg_free(msg);
+ return NULL;
+ }
+ }
+
if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
client->shared_secret_len,
hdr->authenticator) < 0) {
RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
}
+ if (code == RADIUS_CODE_ACCESS_ACCEPT)
+ radius_server_add_session(sess);
+
return msg;
}
@@ -985,6 +1446,51 @@ static int radius_server_reject(struct radius_server_data *data,
}
+static void radius_server_hs20_t_c_check(struct radius_session *sess,
+ struct radius_msg *msg)
+{
+#ifdef CONFIG_HS20
+ u8 *buf, *pos, *end, type, sublen, *timestamp = NULL;
+ size_t len;
+
+ buf = NULL;
+ for (;;) {
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+ &buf, &len, buf) < 0)
+ break;
+ if (len < 6)
+ continue;
+ pos = buf;
+ end = buf + len;
+ if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
+ continue;
+ pos += 4;
+
+ type = *pos++;
+ sublen = *pos++;
+ if (sublen < 2)
+ continue; /* invalid length */
+ sublen -= 2; /* skip header */
+ if (pos + sublen > end)
+ continue; /* invalid WFA VSA */
+
+ if (type == RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP && len >= 4) {
+ timestamp = pos;
+ break;
+ }
+ }
+
+ if (!timestamp)
+ return;
+ RADIUS_DEBUG("HS20-Timestamp: %u", WPA_GET_BE32(timestamp));
+ if (sess->t_c_timestamp != WPA_GET_BE32(timestamp)) {
+ RADIUS_DEBUG("Last read T&C timestamp does not match HS20-Timestamp --> require filtering");
+ sess->t_c_filtering = 1;
+ }
+#endif /* CONFIG_HS20 */
+}
+
+
static int radius_server_request(struct radius_server_data *data,
struct radius_msg *msg,
struct sockaddr *from, socklen_t fromlen,
@@ -1057,7 +1563,7 @@ static int radius_server_request(struct radius_server_data *data,
"message");
return -1;
}
-
+
eap = radius_msg_get_eap(msg);
if (eap == NULL && sess->macacl) {
reply = radius_server_macacl(data, client, sess, msg);
@@ -1115,10 +1621,15 @@ static int radius_server_request(struct radius_server_data *data,
if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
is_complete = 1;
- if (sess->eap_if->eapFail)
+ if (sess->eap_if->eapFail) {
srv_log(sess, "EAP authentication failed");
- else if (sess->eap_if->eapSuccess)
+ db_update_last_msk(sess, "FAIL");
+ } else if (sess->eap_if->eapSuccess) {
srv_log(sess, "EAP authentication succeeded");
+ }
+
+ if (sess->eap_if->eapSuccess)
+ radius_server_hs20_t_c_check(sess, msg);
reply = radius_server_encapsulate_eap(data, client, sess, msg);
@@ -1172,7 +1683,7 @@ send_reply:
sess->sess_id);
eloop_cancel_timeout(radius_server_session_remove_timeout,
data, sess);
- eloop_register_timeout(10, 0,
+ eloop_register_timeout(RADIUS_SESSION_MAINTAIN, 0,
radius_server_session_remove_timeout,
data, sess);
}
@@ -1181,6 +1692,116 @@ send_reply:
}
+static void
+radius_server_receive_disconnect_resp(struct radius_server_data *data,
+ struct radius_client *client,
+ struct radius_msg *msg, int ack)
+{
+ struct radius_hdr *hdr;
+
+ if (!client->pending_dac_disconnect_req) {
+ RADIUS_DEBUG("Ignore unexpected Disconnect response");
+ radius_msg_free(msg);
+ return;
+ }
+
+ hdr = radius_msg_get_hdr(msg);
+ if (hdr->identifier != client->pending_dac_disconnect_id) {
+ RADIUS_DEBUG("Ignore unexpected Disconnect response with unexpected identifier %u (expected %u)",
+ hdr->identifier,
+ client->pending_dac_disconnect_id);
+ radius_msg_free(msg);
+ return;
+ }
+
+ if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
+ client->shared_secret_len,
+ client->pending_dac_disconnect_req, 0)) {
+ RADIUS_DEBUG("Ignore Disconnect response with invalid authenticator");
+ radius_msg_free(msg);
+ return;
+ }
+
+ RADIUS_DEBUG("Disconnect-%s received for " MACSTR,
+ ack ? "ACK" : "NAK",
+ MAC2STR(client->pending_dac_disconnect_addr));
+
+ radius_msg_free(msg);
+ radius_msg_free(client->pending_dac_disconnect_req);
+ client->pending_dac_disconnect_req = NULL;
+}
+
+
+static void radius_server_receive_coa_resp(struct radius_server_data *data,
+ struct radius_client *client,
+ struct radius_msg *msg, int ack)
+{
+ struct radius_hdr *hdr;
+#ifdef CONFIG_SQLITE
+ char addrtxt[3 * ETH_ALEN];
+ char *sql;
+ int res;
+#endif /* CONFIG_SQLITE */
+
+ if (!client->pending_dac_coa_req) {
+ RADIUS_DEBUG("Ignore unexpected CoA response");
+ radius_msg_free(msg);
+ return;
+ }
+
+ hdr = radius_msg_get_hdr(msg);
+ if (hdr->identifier != client->pending_dac_coa_id) {
+ RADIUS_DEBUG("Ignore unexpected CoA response with unexpected identifier %u (expected %u)",
+ hdr->identifier,
+ client->pending_dac_coa_id);
+ radius_msg_free(msg);
+ return;
+ }
+
+ if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
+ client->shared_secret_len,
+ client->pending_dac_coa_req, 0)) {
+ RADIUS_DEBUG("Ignore CoA response with invalid authenticator");
+ radius_msg_free(msg);
+ return;
+ }
+
+ RADIUS_DEBUG("CoA-%s received for " MACSTR,
+ ack ? "ACK" : "NAK",
+ MAC2STR(client->pending_dac_coa_addr));
+
+ radius_msg_free(msg);
+ radius_msg_free(client->pending_dac_coa_req);
+ client->pending_dac_coa_req = NULL;
+
+#ifdef CONFIG_SQLITE
+ if (!data->db)
+ return;
+
+ os_snprintf(addrtxt, sizeof(addrtxt), MACSTR,
+ MAC2STR(client->pending_dac_coa_addr));
+
+ if (ack) {
+ sql = sqlite3_mprintf("UPDATE current_sessions SET hs20_t_c_filtering=0, waiting_coa_ack=0, coa_ack_received=1 WHERE mac_addr=%Q",
+ addrtxt);
+ } else {
+ sql = sqlite3_mprintf("UPDATE current_sessions SET waiting_coa_ack=0 WHERE mac_addr=%Q",
+ addrtxt);
+ }
+ if (!sql)
+ return;
+
+ res = sqlite3_exec(data->db, sql, NULL, NULL, NULL);
+ sqlite3_free(sql);
+ if (res != SQLITE_OK) {
+ RADIUS_ERROR("Failed to update current_sessions entry: %s",
+ sqlite3_errmsg(data->db));
+ return;
+ }
+#endif /* CONFIG_SQLITE */
+}
+
+
static void radius_server_receive_auth(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -1261,6 +1882,26 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx,
radius_msg_dump(msg);
}
+ if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_ACK) {
+ radius_server_receive_disconnect_resp(data, client, msg, 1);
+ return;
+ }
+
+ if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_NAK) {
+ radius_server_receive_disconnect_resp(data, client, msg, 0);
+ return;
+ }
+
+ if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_ACK) {
+ radius_server_receive_coa_resp(data, client, msg, 1);
+ return;
+ }
+
+ if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_NAK) {
+ radius_server_receive_coa_resp(data, client, msg, 0);
+ return;
+ }
+
if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) {
RADIUS_DEBUG("Unexpected RADIUS code %d",
radius_msg_get_hdr(msg)->code);
@@ -1521,6 +2162,8 @@ static void radius_server_free_clients(struct radius_server_data *data,
radius_server_free_sessions(data, prev->sessions);
os_free(prev->shared_secret);
+ radius_msg_free(prev->pending_dac_coa_req);
+ radius_msg_free(prev->pending_dac_disconnect_req);
os_free(prev);
}
}
@@ -1642,7 +2285,7 @@ radius_server_read_clients(const char *client_file, int ipv6)
entry->addr.s_addr = addr.s_addr;
val = 0;
for (i = 0; i < mask; i++)
- val |= 1 << (31 - i);
+ val |= 1U << (31 - i);
entry->mask.s_addr = htonl(val);
}
#ifdef CONFIG_IPV6
@@ -1749,12 +2392,19 @@ radius_server_init(struct radius_server_conf *conf)
data->erp = conf->erp;
data->erp_domain = conf->erp_domain;
data->tls_session_lifetime = conf->tls_session_lifetime;
+ data->tls_flags = conf->tls_flags;
if (conf->subscr_remediation_url) {
data->subscr_remediation_url =
os_strdup(conf->subscr_remediation_url);
}
data->subscr_remediation_method = conf->subscr_remediation_method;
+ if (conf->hs20_sim_provisioning_url)
+ data->hs20_sim_provisioning_url =
+ os_strdup(conf->hs20_sim_provisioning_url);
+
+ if (conf->t_c_server_url)
+ data->t_c_server_url = os_strdup(conf->t_c_server_url);
#ifdef CONFIG_SQLITE
if (conf->sqlite_file) {
@@ -1872,6 +2522,8 @@ void radius_server_deinit(struct radius_server_data *data)
os_free(data->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
os_free(data->subscr_remediation_url);
+ os_free(data->hs20_sim_provisioning_url);
+ os_free(data->t_c_server_url);
#ifdef CONFIG_SQLITE
if (data->db)
@@ -2040,6 +2692,7 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity,
sess->accept_attr = user->accept_attr;
sess->remediation = user->remediation;
sess->macacl = user->macacl;
+ sess->t_c_timestamp = user->t_c_timestamp;
}
if (ret) {
@@ -2083,15 +2736,8 @@ radius_server_erp_get_key(void *ctx, const char *keyname)
{
struct radius_session *sess = ctx;
struct radius_server_data *data = sess->server;
- struct eap_server_erp_key *erp;
- dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key,
- list) {
- if (os_strcmp(erp->keyname_nai, keyname) == 0)
- return erp;
- }
-
- return NULL;
+ return radius_server_erp_find_key(data, keyname);
}
@@ -2166,3 +2812,212 @@ void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
radius_msg_free(msg);
}
+
+
+#ifdef CONFIG_SQLITE
+
+struct db_session_fields {
+ char *identity;
+ char *nas;
+ int hs20_t_c_filtering;
+ int waiting_coa_ack;
+ int coa_ack_received;
+};
+
+
+static int get_db_session_fields(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct db_session_fields *fields = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (!argv[i])
+ continue;
+
+ RADIUS_DEBUG("Session DB: %s=%s", col[i], argv[i]);
+
+ if (os_strcmp(col[i], "identity") == 0) {
+ os_free(fields->identity);
+ fields->identity = os_strdup(argv[i]);
+ } else if (os_strcmp(col[i], "nas") == 0) {
+ os_free(fields->nas);
+ fields->nas = os_strdup(argv[i]);
+ } else if (os_strcmp(col[i], "hs20_t_c_filtering") == 0) {
+ fields->hs20_t_c_filtering = atoi(argv[i]);
+ } else if (os_strcmp(col[i], "waiting_coa_ack") == 0) {
+ fields->waiting_coa_ack = atoi(argv[i]);
+ } else if (os_strcmp(col[i], "coa_ack_received") == 0) {
+ fields->coa_ack_received = atoi(argv[i]);
+ }
+ }
+
+ return 0;
+}
+
+
+static void free_db_session_fields(struct db_session_fields *fields)
+{
+ os_free(fields->identity);
+ fields->identity = NULL;
+ os_free(fields->nas);
+ fields->nas = NULL;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+int radius_server_dac_request(struct radius_server_data *data, const char *req)
+{
+#ifdef CONFIG_SQLITE
+ char *sql;
+ int res;
+ int disconnect;
+ const char *pos = req;
+ u8 addr[ETH_ALEN];
+ char addrtxt[3 * ETH_ALEN];
+ int t_c_clear = 0;
+ struct db_session_fields fields;
+ struct sockaddr_in das;
+ struct radius_client *client;
+ struct radius_msg *msg;
+ struct wpabuf *buf;
+ u8 identifier;
+ struct os_time now;
+
+ if (!data)
+ return -1;
+
+ /* req: <disconnect|coa> <MAC Address> [t_c_clear] */
+
+ if (os_strncmp(pos, "disconnect ", 11) == 0) {
+ disconnect = 1;
+ pos += 11;
+ } else if (os_strncmp(req, "coa ", 4) == 0) {
+ disconnect = 0;
+ pos += 4;
+ } else {
+ return -1;
+ }
+
+ if (hwaddr_aton(pos, addr))
+ return -1;
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ if (os_strstr(pos, "t_c_clear"))
+ t_c_clear = 1;
+ }
+
+ if (!disconnect && !t_c_clear) {
+ RADIUS_ERROR("DAC request for CoA without any authorization change");
+ return -1;
+ }
+
+ if (!data->db) {
+ RADIUS_ERROR("SQLite database not in use");
+ return -1;
+ }
+
+ os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(addr));
+
+ sql = sqlite3_mprintf("SELECT * FROM current_sessions WHERE mac_addr=%Q",
+ addrtxt);
+ if (!sql)
+ return -1;
+
+ os_memset(&fields, 0, sizeof(fields));
+ res = sqlite3_exec(data->db, sql, get_db_session_fields, &fields, NULL);
+ sqlite3_free(sql);
+ if (res != SQLITE_OK) {
+ RADIUS_ERROR("Failed to find matching current_sessions entry from sqlite database: %s",
+ sqlite3_errmsg(data->db));
+ free_db_session_fields(&fields);
+ return -1;
+ }
+
+ if (!fields.nas) {
+ RADIUS_ERROR("No NAS information found from current_sessions");
+ free_db_session_fields(&fields);
+ return -1;
+ }
+
+ os_memset(&das, 0, sizeof(das));
+ das.sin_family = AF_INET;
+ das.sin_addr.s_addr = inet_addr(fields.nas);
+ das.sin_port = htons(3799);
+
+ free_db_session_fields(&fields);
+
+ client = radius_server_get_client(data, &das.sin_addr, 0);
+ if (!client) {
+ RADIUS_ERROR("No NAS information available to protect the packet");
+ return -1;
+ }
+
+ identifier = client->next_dac_identifier++;
+
+ msg = radius_msg_new(disconnect ? RADIUS_CODE_DISCONNECT_REQUEST :
+ RADIUS_CODE_COA_REQUEST, identifier);
+ if (!msg)
+ return -1;
+
+ os_snprintf(addrtxt, sizeof(addrtxt), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(addr));
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ (u8 *) addrtxt, os_strlen(addrtxt))) {
+ RADIUS_ERROR("Could not add Calling-Station-Id");
+ radius_msg_free(msg);
+ return -1;
+ }
+
+ if (!disconnect && t_c_clear) {
+ u8 val[4] = { 0x00, 0x00, 0x00, 0x00 }; /* E=0 */
+
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
+ val, sizeof(val))) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
+ radius_msg_free(msg);
+ return -1;
+ }
+ }
+
+ os_get_time(&now);
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+ now.sec)) {
+ RADIUS_ERROR("Failed to add Event-Timestamp attribute");
+ radius_msg_free(msg);
+ return -1;
+ }
+
+ radius_msg_finish_acct(msg, (u8 *) client->shared_secret,
+ client->shared_secret_len);
+
+ if (wpa_debug_level <= MSG_MSGDUMP)
+ radius_msg_dump(msg);
+
+ buf = radius_msg_get_buf(msg);
+ if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
+ (struct sockaddr *) &das, sizeof(das)) < 0) {
+ RADIUS_ERROR("Failed to send packet - sendto: %s",
+ strerror(errno));
+ radius_msg_free(msg);
+ return -1;
+ }
+
+ if (disconnect) {
+ radius_msg_free(client->pending_dac_disconnect_req);
+ client->pending_dac_disconnect_req = msg;
+ client->pending_dac_disconnect_id = identifier;
+ os_memcpy(client->pending_dac_disconnect_addr, addr, ETH_ALEN);
+ } else {
+ radius_msg_free(client->pending_dac_coa_req);
+ client->pending_dac_coa_req = msg;
+ client->pending_dac_coa_id = identifier;
+ os_memcpy(client->pending_dac_coa_addr, addr, ETH_ALEN);
+ }
+
+ return 0;
+#else /* CONFIG_SQLITE */
+ return -1;
+#endif /* CONFIG_SQLITE */
+}
diff --git a/contrib/wpa/src/radius/radius_server.h b/contrib/wpa/src/radius/radius_server.h
index 7a25802..53728f9 100644
--- a/contrib/wpa/src/radius/radius_server.h
+++ b/contrib/wpa/src/radius/radius_server.h
@@ -172,6 +172,8 @@ struct radius_server_conf {
unsigned int tls_session_lifetime;
+ unsigned int tls_flags;
+
/**
* wps - Wi-Fi Protected Setup context
*
@@ -231,6 +233,9 @@ struct radius_server_conf {
char *subscr_remediation_url;
u8 subscr_remediation_method;
+ char *hs20_sim_provisioning_url;
+
+ char *t_c_server_url;
};
@@ -244,5 +249,6 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
size_t buflen);
void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx);
+int radius_server_dac_request(struct radius_server_data *data, const char *req);
#endif /* RADIUS_SERVER_H */
diff --git a/contrib/wpa/src/rsn_supp/peerkey.c b/contrib/wpa/src/rsn_supp/peerkey.c
deleted file mode 100644
index 79764d9..0000000
--- a/contrib/wpa/src/rsn_supp/peerkey.c
+++ /dev/null
@@ -1,1155 +0,0 @@
-/*
- * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#ifdef CONFIG_PEERKEY
-
-#include "common.h"
-#include "eloop.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "crypto/random.h"
-#include "common/ieee802_11_defs.h"
-#include "wpa.h"
-#include "wpa_i.h"
-#include "wpa_ie.h"
-#include "peerkey.h"
-
-
-static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
-{
- os_memcpy(pos, ie, ie_len);
- return pos + ie_len;
-}
-
-
-static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len)
-{
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = RSN_SELECTOR_LEN + data_len;
- RSN_SELECTOR_PUT(pos, kde);
- pos += RSN_SELECTOR_LEN;
- os_memcpy(pos, data, data_len);
- pos += data_len;
- return pos;
-}
-
-
-static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-#if 0
- struct wpa_sm *sm = eloop_ctx;
- struct wpa_peerkey *peerkey = timeout_ctx;
-#endif
- /* TODO: time out SMK and any STK that was generated using this SMK */
-}
-
-
-static void wpa_supplicant_peerkey_free(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey)
-{
- eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
- os_free(peerkey);
-}
-
-
-static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
- const u8 *peer,
- u16 mui, u16 error_type, int ver)
-{
- size_t rlen;
- struct wpa_eapol_key *err;
- struct wpa_eapol_key_192 *err192;
- struct rsn_error_kde error;
- u8 *rbuf, *pos;
- size_t kde_len;
- u16 key_info;
-
- kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error);
- if (peer)
- kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
-
- rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
- NULL, sizeof(*err) + kde_len, &rlen,
- (void *) &err);
- if (rbuf == NULL)
- return -1;
- err192 = (struct wpa_eapol_key_192 *) err;
-
- err->type = EAPOL_KEY_TYPE_RSN;
- key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
- WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR |
- WPA_KEY_INFO_REQUEST;
- WPA_PUT_BE16(err->key_info, key_info);
- WPA_PUT_BE16(err->key_length, 0);
- os_memcpy(err->replay_counter, sm->request_counter,
- WPA_REPLAY_COUNTER_LEN);
- inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
-
- WPA_PUT_BE16(err->key_data_length, (u16) kde_len);
- pos = (u8 *) (err + 1);
-
- if (peer) {
- /* Peer MAC Address KDE */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
- }
-
- /* Error KDE */
- error.mui = host_to_be16(mui);
- error.error_type = host_to_be16(error_type);
- wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error));
-
- if (peer) {
- wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer "
- MACSTR " mui %d error_type %d)",
- MAC2STR(peer), mui, error_type);
- } else {
- wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error "
- "(mui %d error_type %d)", mui, error_type);
- }
-
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
- ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
-
- return 0;
-}
-
-
-static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
- const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- int ver, struct wpa_peerkey *peerkey)
-{
- size_t rlen;
- struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
- u8 *rbuf, *pos;
- size_t kde_len;
- u16 key_info;
-
- /* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */
- kde_len = peerkey->rsnie_p_len +
- 2 + RSN_SELECTOR_LEN + ETH_ALEN +
- 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN;
-
- rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
- NULL, sizeof(*reply) + kde_len, &rlen,
- (void *) &reply);
- if (rbuf == NULL)
- return -1;
- reply192 = (struct wpa_eapol_key_192 *) reply;
-
- reply->type = EAPOL_KEY_TYPE_RSN;
- key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
- WPA_KEY_INFO_SECURE;
- WPA_PUT_BE16(reply->key_info, key_info);
- WPA_PUT_BE16(reply->key_length, 0);
- os_memcpy(reply->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
-
- os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN);
-
- WPA_PUT_BE16(reply->key_data_length, (u16) kde_len);
- pos = (u8 *) (reply + 1);
-
- /* Peer RSN IE */
- pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
-
- /* Initiator MAC Address KDE */
- pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN);
-
- /* Initiator Nonce */
- wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
-
- wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
- ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
-
- return 0;
-}
-
-
-static int wpa_supplicant_process_smk_m2(
- struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key, size_t extra_len, int ver)
-{
- struct wpa_peerkey *peerkey;
- struct wpa_eapol_ie_parse kde;
- struct wpa_ie_data ie;
- int cipher;
- struct rsn_ie_hdr *hdr;
- u8 *pos;
-
- wpa_printf(MSG_DEBUG, "RSN: Received SMK M2");
-
- if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
- wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for "
- "the current network");
- return -1;
- }
-
- if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
- 0) {
- wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
- return -1;
- }
-
- if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
- kde.mac_addr_len < ETH_ALEN) {
- wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
- "SMK M2");
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR,
- MAC2STR(kde.mac_addr));
-
- if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) {
- wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK "
- "M2");
- return -1;
- }
-
- if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
- wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
- return -1;
- }
-
- cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
- sm->allowed_pairwise_cipher, 0);
- if (cipher < 0) {
- wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
- wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
- STK_MUI_SMK, STK_ERR_CPHR_NS,
- ver);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
- wpa_cipher_txt(cipher));
-
- /* TODO: find existing entry and if found, use that instead of adding
- * a new one; how to handle the case where both ends initiate at the
- * same time? */
- peerkey = os_zalloc(sizeof(*peerkey));
- if (peerkey == NULL)
- return -1;
- os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
- os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
- os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
- peerkey->rsnie_i_len = kde.rsn_ie_len;
- peerkey->cipher = cipher;
- peerkey->akmp = ie.key_mgmt;
-
- if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Failed to get random data for PNonce");
- wpa_supplicant_peerkey_free(sm, peerkey);
- return -1;
- }
-
- hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p;
- hdr->elem_id = WLAN_EID_RSN;
- WPA_PUT_LE16(hdr->version, RSN_VERSION);
- pos = (u8 *) (hdr + 1);
- /* Group Suite can be anything for SMK RSN IE; receiver will just
- * ignore it. */
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- pos += RSN_SELECTOR_LEN;
- /* Include only the selected cipher in pairwise cipher suite */
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
- pos += RSN_SELECTOR_LEN;
-
- hdr->len = (pos - peerkey->rsnie_p) - 2;
- peerkey->rsnie_p_len = pos - peerkey->rsnie_p;
- wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
- peerkey->rsnie_p, peerkey->rsnie_p_len);
-
- wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey);
-
- peerkey->next = sm->peerkey;
- sm->peerkey = peerkey;
-
- return 0;
-}
-
-
-/**
- * rsn_smkid - Derive SMK identifier
- * @smk: Station master key (32 bytes)
- * @pnonce: Peer Nonce
- * @mac_p: Peer MAC address
- * @inonce: Initiator Nonce
- * @mac_i: Initiator MAC address
- * @akmp: Negotiated AKM
- *
- * 8.5.1.4 Station to station (STK) key hierarchy
- * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
- */
-static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
- const u8 *inonce, const u8 *mac_i, u8 *smkid,
- int akmp)
-{
- char *title = "SMK Name";
- const u8 *addr[5];
- const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
- ETH_ALEN };
- unsigned char hash[SHA256_MAC_LEN];
-
- addr[0] = (u8 *) title;
- addr[1] = pnonce;
- addr[2] = mac_p;
- addr[3] = inonce;
- addr[4] = mac_i;
-
-#ifdef CONFIG_IEEE80211W
- if (wpa_key_mgmt_sha256(akmp))
- hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
- else
-#endif /* CONFIG_IEEE80211W */
- hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
- os_memcpy(smkid, hash, PMKID_LEN);
-}
-
-
-static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey)
-{
- size_t mlen;
- struct wpa_eapol_key *msg;
- u8 *mbuf;
- size_t kde_len;
- u16 key_info, ver;
-
- kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
-
- mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*msg) + kde_len, &mlen,
- (void *) &msg);
- if (mbuf == NULL)
- return;
-
- msg->type = EAPOL_KEY_TYPE_RSN;
-
- if (peerkey->cipher != WPA_CIPHER_TKIP)
- ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
- else
- ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
- key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
- WPA_PUT_BE16(msg->key_info, key_info);
-
- if (peerkey->cipher != WPA_CIPHER_TKIP)
- WPA_PUT_BE16(msg->key_length, 16);
- else
- WPA_PUT_BE16(msg->key_length, 32);
-
- os_memcpy(msg->replay_counter, peerkey->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
- inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
-
- WPA_PUT_BE16(msg->key_data_length, kde_len);
- wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
- peerkey->smkid, PMKID_LEN);
-
- if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "RSN: Failed to get random data for INonce (STK)");
- os_free(mbuf);
- return;
- }
- wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake",
- peerkey->inonce, WPA_NONCE_LEN);
- os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
-
- wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
- MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
- mbuf, mlen, NULL);
-}
-
-
-static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey)
-{
- size_t mlen;
- struct wpa_eapol_key *msg;
- u8 *mbuf, *pos;
- size_t kde_len;
- u16 key_info, ver;
- be32 lifetime;
-
- kde_len = peerkey->rsnie_i_len +
- 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
-
- mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*msg) + kde_len, &mlen,
- (void *) &msg);
- if (mbuf == NULL)
- return;
-
- msg->type = EAPOL_KEY_TYPE_RSN;
-
- if (peerkey->cipher != WPA_CIPHER_TKIP)
- ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
- else
- ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
- key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK |
- WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
- WPA_PUT_BE16(msg->key_info, key_info);
-
- if (peerkey->cipher != WPA_CIPHER_TKIP)
- WPA_PUT_BE16(msg->key_length, 16);
- else
- WPA_PUT_BE16(msg->key_length, 32);
-
- os_memcpy(msg->replay_counter, peerkey->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
- inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
-
- WPA_PUT_BE16(msg->key_data_length, kde_len);
- pos = (u8 *) (msg + 1);
- pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
- lifetime = host_to_be32(peerkey->lifetime);
- wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
- (u8 *) &lifetime, sizeof(lifetime));
-
- os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
-
- wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
- MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
- peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
- msg->key_mic);
-}
-
-
-static int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey,
- struct wpa_eapol_ie_parse *kde)
-{
- wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")",
- MAC2STR(kde->mac_addr));
-
- if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0)
- {
- wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not "
- "match with the one used in SMK M3");
- return -1;
- }
-
- if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
- wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not "
- "match with the one received in SMK M2");
- return -1;
- }
-
- return 0;
-}
-
-
-static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
- const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- int ver,
- struct wpa_peerkey *peerkey,
- struct wpa_eapol_ie_parse *kde)
-{
- int cipher;
- struct wpa_ie_data ie;
-
- wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")",
- MAC2STR(kde->mac_addr));
- if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN ||
- wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) {
- wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5");
- /* TODO: abort negotiation */
- return -1;
- }
-
- if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
- wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does "
- "not match with INonce used in SMK M1");
- return -1;
- }
-
- if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0)
- {
- wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not "
- "match with the one used in SMK M1");
- return -1;
- }
-
- os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len);
- peerkey->rsnie_p_len = kde->rsn_ie_len;
- os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
-
- cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
- sm->allowed_pairwise_cipher, 0);
- if (cipher < 0) {
- wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
- "unacceptable cipher", MAC2STR(kde->mac_addr));
- wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
- STK_MUI_SMK, STK_ERR_CPHR_NS,
- ver);
- /* TODO: abort negotiation */
- return -1;
- }
- wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
- wpa_cipher_txt(cipher));
- peerkey->cipher = cipher;
-
- return 0;
-}
-
-
-static int wpa_supplicant_process_smk_m45(
- struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key, size_t extra_len, int ver)
-{
- struct wpa_peerkey *peerkey;
- struct wpa_eapol_ie_parse kde;
- u32 lifetime;
-
- if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
- wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
- "the current network");
- return -1;
- }
-
- if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
- 0) {
- wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
- return -1;
- }
-
- if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
- kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN ||
- kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN ||
- kde.lifetime == NULL || kde.lifetime_len < 4) {
- wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or "
- "Lifetime KDE in SMK M4/M5");
- return -1;
- }
-
- for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
- if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 &&
- os_memcmp(peerkey->initiator ? peerkey->inonce :
- peerkey->pnonce,
- key->key_nonce, WPA_NONCE_LEN) == 0)
- break;
- }
- if (peerkey == NULL) {
- wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found "
- "for SMK M4/M5: peer " MACSTR,
- MAC2STR(kde.mac_addr));
- return -1;
- }
-
- if (peerkey->initiator) {
- if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver,
- peerkey, &kde) < 0)
- return -1;
- } else {
- if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0)
- return -1;
- }
-
- os_memcpy(peerkey->smk, kde.smk, PMK_LEN);
- peerkey->smk_complete = 1;
- wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN);
- lifetime = WPA_GET_BE32(kde.lifetime);
- wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
- if (lifetime > 1000000000)
- lifetime = 1000000000; /* avoid overflowing eloop time */
- peerkey->lifetime = lifetime;
- eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
- sm, peerkey);
-
- if (peerkey->initiator) {
- rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
- peerkey->inonce, sm->own_addr, peerkey->smkid,
- peerkey->akmp);
- wpa_supplicant_send_stk_1_of_4(sm, peerkey);
- } else {
- rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
- peerkey->inonce, peerkey->addr, peerkey->smkid,
- peerkey->akmp);
- }
- wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
-
- return 0;
-}
-
-
-static int wpa_supplicant_process_smk_error(
- struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key, size_t extra_len)
-{
- struct wpa_eapol_ie_parse kde;
- struct rsn_error_kde error;
- u8 peer[ETH_ALEN];
- u16 error_type;
-
- wpa_printf(MSG_DEBUG, "RSN: Received SMK Error");
-
- if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
- wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
- "the current network");
- return -1;
- }
-
- if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
- 0) {
- wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
- return -1;
- }
-
- if (kde.error == NULL || kde.error_len < sizeof(error)) {
- wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error");
- return -1;
- }
-
- if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN)
- os_memcpy(peer, kde.mac_addr, ETH_ALEN);
- else
- os_memset(peer, 0, ETH_ALEN);
- os_memcpy(&error, kde.error, sizeof(error));
- error_type = be_to_host16(error.error_type);
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "RSN: SMK Error KDE received: MUI %d error_type %d peer "
- MACSTR,
- be_to_host16(error.mui), error_type,
- MAC2STR(peer));
-
- if (kde.mac_addr &&
- (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN ||
- error_type == STK_ERR_CPHR_NS)) {
- struct wpa_peerkey *peerkey;
-
- for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
- if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) ==
- 0)
- break;
- }
- if (peerkey == NULL) {
- wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake "
- "found for SMK Error");
- return -1;
- }
- /* TODO: abort SMK/STK handshake and remove all related keys */
- }
-
- return 0;
-}
-
-
-static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey,
- const struct wpa_eapol_key *key,
- u16 ver, const u8 *key_data,
- size_t key_data_len)
-{
- struct wpa_eapol_ie_parse ie;
- size_t kde_buf_len;
- struct wpa_ptk *stk;
- u8 buf[8], *kde_buf, *pos;
- be32 lifetime;
-
- wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from "
- MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
-
- os_memset(&ie, 0, sizeof(ie));
-
- /* RSN: msg 1/4 should contain SMKID for the selected SMK */
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", key_data, key_data_len);
- if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0 ||
- ie.pmkid == NULL) {
- wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
- return;
- }
- if (os_memcmp_const(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
- wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
- ie.pmkid, PMKID_LEN);
- return;
- }
-
- if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "RSN: Failed to get random data for PNonce");
- return;
- }
- wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce",
- peerkey->pnonce, WPA_NONCE_LEN);
-
- /* Calculate STK which will be stored as a temporary STK until it has
- * been verified when processing message 3/4. */
- stk = &peerkey->tstk;
- wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
- sm->own_addr, peerkey->addr,
- peerkey->pnonce, key->key_nonce,
- stk, peerkey->akmp, peerkey->cipher);
- /* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, &stk->tk[16], 8);
- os_memcpy(&stk->tk[16], &stk->tk[24], 8);
- os_memcpy(&stk->tk[24], buf, 8);
- peerkey->tstk_set = 1;
-
- kde_buf_len = peerkey->rsnie_p_len +
- 2 + RSN_SELECTOR_LEN + sizeof(lifetime) +
- 2 + RSN_SELECTOR_LEN + PMKID_LEN;
- kde_buf = os_malloc(kde_buf_len);
- if (kde_buf == NULL)
- return;
- pos = kde_buf;
- pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
- lifetime = host_to_be32(peerkey->lifetime);
- pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
- (u8 *) &lifetime, sizeof(lifetime));
- wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN);
-
- if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
- peerkey->pnonce, kde_buf, kde_buf_len,
- stk)) {
- os_free(kde_buf);
- return;
- }
- os_free(kde_buf);
-
- os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
-}
-
-
-static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey,
- struct wpa_eapol_ie_parse *kde)
-{
- u32 lifetime;
-
- if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
- return;
-
- lifetime = WPA_GET_BE32(kde->lifetime);
-
- if (lifetime >= peerkey->lifetime) {
- wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds "
- "which is larger than or equal to own value %u "
- "seconds - ignored", lifetime, peerkey->lifetime);
- return;
- }
-
- wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds "
- "(own was %u seconds) - updated",
- lifetime, peerkey->lifetime);
- peerkey->lifetime = lifetime;
-
- eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
- eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
- sm, peerkey);
-}
-
-
-static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey,
- const struct wpa_eapol_key *key,
- u16 ver, const u8 *key_data,
- size_t key_data_len)
-{
- struct wpa_eapol_ie_parse kde;
-
- wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
- MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
-
- os_memset(&kde, 0, sizeof(kde));
-
- /* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
- * from the peer. It may also include Lifetime KDE. */
- wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", key_data, key_data_len);
- if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0 ||
- kde.pmkid == NULL || kde.rsn_ie == NULL) {
- wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
- return;
- }
-
- if (os_memcmp_const(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
- wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
- kde.pmkid, PMKID_LEN);
- return;
- }
-
- if (kde.rsn_ie_len != peerkey->rsnie_p_len ||
- os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) {
- wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK "
- "handshakes did not match");
- wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake",
- peerkey->rsnie_p, peerkey->rsnie_p_len);
- wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake",
- kde.rsn_ie, kde.rsn_ie_len);
- return;
- }
-
- wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
-
- wpa_supplicant_send_stk_3_of_4(sm, peerkey);
- os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN);
-}
-
-
-static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey,
- const struct wpa_eapol_key *key,
- u16 ver, const u8 *key_data,
- size_t key_data_len)
-{
- struct wpa_eapol_ie_parse kde;
- size_t key_len;
- const u8 *_key;
- u8 key_buf[32], rsc[6];
-
- wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from "
- MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
-
- os_memset(&kde, 0, sizeof(kde));
-
- /* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
- * Lifetime KDE. */
- wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", key_data, key_data_len);
- if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
- wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
- "STK 3/4");
- return;
- }
-
- if (kde.rsn_ie_len != peerkey->rsnie_i_len ||
- os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) {
- wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK "
- "handshakes did not match");
- wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK "
- "handshake",
- peerkey->rsnie_i, peerkey->rsnie_i_len);
- wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK "
- "handshake",
- kde.rsn_ie, kde.rsn_ie_len);
- return;
- }
-
- if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
- wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK "
- "4-Way Handshake differs from 3 of STK 4-Way "
- "Handshake - drop packet (src=" MACSTR ")",
- MAC2STR(peerkey->addr));
- return;
- }
-
- wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
-
- if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
- WPA_GET_BE16(key->key_info),
- &peerkey->stk))
- return;
-
- _key = peerkey->stk.tk;
- if (peerkey->cipher == WPA_CIPHER_TKIP) {
- /* Swap Tx/Rx keys for Michael MIC */
- os_memcpy(key_buf, _key, 16);
- os_memcpy(key_buf + 16, _key + 24, 8);
- os_memcpy(key_buf + 24, _key + 16, 8);
- _key = key_buf;
- key_len = 32;
- } else
- key_len = 16;
-
- os_memset(rsc, 0, 6);
- if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
- rsc, sizeof(rsc), _key, key_len) < 0) {
- os_memset(key_buf, 0, sizeof(key_buf));
- wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
- "driver.");
- return;
- }
- os_memset(key_buf, 0, sizeof(key_buf));
-}
-
-
-static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey,
- const struct wpa_eapol_key *key,
- u16 ver)
-{
- u8 rsc[6];
-
- wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from "
- MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
-
- os_memset(rsc, 0, 6);
- if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
- rsc, sizeof(rsc), peerkey->stk.tk,
- peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
- wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
- "driver.");
- return;
- }
-}
-
-
-/**
- * peerkey_verify_eapol_key_mic - Verify PeerKey MIC
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @peerkey: Pointer to the PeerKey data for the peer
- * @key: Pointer to the EAPOL-Key frame header
- * @ver: Version bits from EAPOL-Key Key Info
- * @buf: Pointer to the beginning of EAPOL-Key frame
- * @len: Length of the EAPOL-Key frame
- * Returns: 0 on success, -1 on failure
- */
-int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey,
- struct wpa_eapol_key_192 *key, u16 ver,
- const u8 *buf, size_t len)
-{
- u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
- size_t mic_len = 16;
- int ok = 0;
-
- if (peerkey->initiator && !peerkey->stk_set) {
- wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
- sm->own_addr, peerkey->addr,
- peerkey->inonce, key->key_nonce,
- &peerkey->stk, peerkey->akmp, peerkey->cipher);
- peerkey->stk_set = 1;
- }
-
- os_memcpy(mic, key->key_mic, mic_len);
- if (peerkey->tstk_set) {
- os_memset(key->key_mic, 0, mic_len);
- wpa_eapol_key_mic(peerkey->tstk.kck, peerkey->tstk.kck_len,
- sm->key_mgmt, ver, buf, len, key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
- wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
- "when using TSTK - ignoring TSTK");
- } else {
- ok = 1;
- peerkey->tstk_set = 0;
- peerkey->stk_set = 1;
- os_memcpy(&peerkey->stk, &peerkey->tstk,
- sizeof(peerkey->stk));
- os_memset(&peerkey->tstk, 0, sizeof(peerkey->tstk));
- }
- }
-
- if (!ok && peerkey->stk_set) {
- os_memset(key->key_mic, 0, mic_len);
- wpa_eapol_key_mic(peerkey->stk.kck, peerkey->stk.kck_len,
- sm->key_mgmt, ver, buf, len, key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
- wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
- "- dropping packet");
- return -1;
- }
- ok = 1;
- }
-
- if (!ok) {
- wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC "
- "- dropping packet");
- return -1;
- }
-
- os_memcpy(peerkey->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
- peerkey->replay_counter_set = 1;
- return 0;
-}
-
-
-/**
- * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1)
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @peer: MAC address of the peer STA
- * Returns: 0 on success, or -1 on failure
- *
- * Send an EAPOL-Key Request to the current authenticator to start STK
- * handshake with the peer.
- */
-int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
-{
- size_t rlen, kde_len;
- struct wpa_eapol_key *req;
- int key_info, ver;
- u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos;
- u16 count;
- struct rsn_ie_hdr *hdr;
- struct wpa_peerkey *peerkey;
- struct wpa_ie_data ie;
-
- if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled)
- return -1;
-
- if (sm->ap_rsn_ie &&
- wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 &&
- !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) {
- wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK");
- return -1;
- }
-
- if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
- ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
- else
- ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
- if (wpa_sm_get_bssid(sm, bssid) < 0) {
- wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
- "SMK M1");
- return -1;
- }
-
- /* TODO: find existing entry and if found, use that instead of adding
- * a new one */
- peerkey = os_zalloc(sizeof(*peerkey));
- if (peerkey == NULL)
- return -1;
- peerkey->initiator = 1;
- os_memcpy(peerkey->addr, peer, ETH_ALEN);
- peerkey->akmp = sm->key_mgmt;
-
- /* SMK M1:
- * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
- * MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE))
- */
-
- hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i;
- hdr->elem_id = WLAN_EID_RSN;
- WPA_PUT_LE16(hdr->version, RSN_VERSION);
- pos = (u8 *) (hdr + 1);
- /* Group Suite can be anything for SMK RSN IE; receiver will just
- * ignore it. */
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- pos += RSN_SELECTOR_LEN;
- count_pos = pos;
- pos += 2;
-
- count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher);
- pos += count * RSN_SELECTOR_LEN;
- WPA_PUT_LE16(count_pos, count);
-
- hdr->len = (pos - peerkey->rsnie_i) - 2;
- peerkey->rsnie_i_len = pos - peerkey->rsnie_i;
- wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
- peerkey->rsnie_i, peerkey->rsnie_i_len);
-
- kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
-
- rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*req) + kde_len, &rlen,
- (void *) &req);
- if (rbuf == NULL) {
- wpa_supplicant_peerkey_free(sm, peerkey);
- return -1;
- }
-
- req->type = EAPOL_KEY_TYPE_RSN;
- key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
- WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver;
- WPA_PUT_BE16(req->key_info, key_info);
- WPA_PUT_BE16(req->key_length, 0);
- os_memcpy(req->replay_counter, sm->request_counter,
- WPA_REPLAY_COUNTER_LEN);
- inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
-
- if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Failed to get random data for INonce");
- os_free(rbuf);
- wpa_supplicant_peerkey_free(sm, peerkey);
- return -1;
- }
- os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
- wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake",
- req->key_nonce, WPA_NONCE_LEN);
-
- WPA_PUT_BE16(req->key_data_length, (u16) kde_len);
- pos = (u8 *) (req + 1);
-
- /* Initiator RSN IE */
- pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
- /* Peer MAC address KDE */
- wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
-
- wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
- MACSTR ")", MAC2STR(peer));
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
- ETH_P_EAPOL, rbuf, rlen, req->key_mic);
-
- peerkey->next = sm->peerkey;
- sm->peerkey = peerkey;
-
- return 0;
-}
-
-
-/**
- * peerkey_deinit - Free PeerKey values
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-void peerkey_deinit(struct wpa_sm *sm)
-{
- struct wpa_peerkey *prev, *peerkey = sm->peerkey;
- while (peerkey) {
- prev = peerkey;
- peerkey = peerkey->next;
- wpa_supplicant_peerkey_free(sm, prev);
- }
- sm->peerkey = NULL;
-}
-
-
-void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver,
- const u8 *key_data, size_t key_data_len)
-{
- if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
- (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
- /* 3/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver,
- key_data, key_data_len);
- } else if (key_info & WPA_KEY_INFO_ACK) {
- /* 1/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver,
- key_data, key_data_len);
- } else if (key_info & WPA_KEY_INFO_SECURE) {
- /* 4/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
- } else {
- /* 2/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver,
- key_data, key_data_len);
- }
-}
-
-
-void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
- struct wpa_eapol_key *key, size_t extra_len,
- u16 key_info, u16 ver)
-{
- if (key_info & WPA_KEY_INFO_ERROR) {
- /* SMK Error */
- wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len);
- } else if (key_info & WPA_KEY_INFO_ACK) {
- /* SMK M2 */
- wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len,
- ver);
- } else {
- /* SMK M4 or M5 */
- wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len,
- ver);
- }
-}
-
-#endif /* CONFIG_PEERKEY */
diff --git a/contrib/wpa/src/rsn_supp/peerkey.h b/contrib/wpa/src/rsn_supp/peerkey.h
deleted file mode 100644
index 6ccd948..0000000
--- a/contrib/wpa/src/rsn_supp/peerkey.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef PEERKEY_H
-#define PEERKEY_H
-
-#define PEERKEY_MAX_IE_LEN 80
-struct wpa_peerkey {
- struct wpa_peerkey *next;
- int initiator; /* whether this end was initator for SMK handshake */
- u8 addr[ETH_ALEN]; /* other end MAC address */
- u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
- u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */
- u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */
- size_t rsnie_i_len;
- u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */
- size_t rsnie_p_len;
- u8 smk[PMK_LEN];
- int smk_complete;
- u8 smkid[PMKID_LEN];
- u32 lifetime;
- int cipher; /* Selected cipher (WPA_CIPHER_*) */
- u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
- int replay_counter_set;
- int akmp;
-
- struct wpa_ptk stk, tstk;
- int stk_set, tstk_set;
-};
-
-
-#ifdef CONFIG_PEERKEY
-
-int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey,
- struct wpa_eapol_key_192 *key, u16 ver,
- const u8 *buf, size_t len);
-void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver,
- const u8 *key_data, size_t key_data_len);
-void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
- struct wpa_eapol_key *key, size_t extra_len,
- u16 key_info, u16 ver);
-void peerkey_deinit(struct wpa_sm *sm);
-
-#else /* CONFIG_PEERKEY */
-
-static inline int
-peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
- const u8 *buf, size_t len)
-{
- return -1;
-}
-
-static inline void
-peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver,
- const u8 *key_data, size_t key_data_len)
-{
-}
-
-static inline void
-peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
- struct wpa_eapol_key *key, size_t extra_len,
- u16 key_info, u16 ver)
-{
-}
-
-static inline void peerkey_deinit(struct wpa_sm *sm)
-{
-}
-
-#endif /* CONFIG_PEERKEY */
-
-#endif /* PEERKEY_H */
diff --git a/contrib/wpa/src/rsn_supp/pmksa_cache.c b/contrib/wpa/src/rsn_supp/pmksa_cache.c
index ef7b683..d720f7b 100644
--- a/contrib/wpa/src/rsn_supp/pmksa_cache.c
+++ b/contrib/wpa/src/rsn_supp/pmksa_cache.c
@@ -15,7 +15,7 @@
#include "wpa_i.h"
#include "pmksa_cache.h"
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
static const int pmksa_cache_max_entries = 32;
@@ -43,7 +43,10 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry,
enum pmksa_free_reason reason)
{
- wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+ wpa_sm_remove_pmkid(pmksa->sm, entry->network_ctx, entry->aa,
+ entry->pmkid,
+ entry->fils_cache_id_set ? entry->fils_cache_id :
+ NULL);
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx, reason);
_pmksa_cache_free_entry(entry);
@@ -93,7 +96,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
- pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL);
+ pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0);
if (entry) {
sec = pmksa->pmksa->reauth_time - now.sec;
if (sec < 0)
@@ -109,12 +112,14 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @pmkid: Calculated PMKID
* @kck: Key confirmation key or %NULL if not yet derived
* @kck_len: KCK length in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @network_ctx: Network configuration context for this PMK
* @akmp: WPA_KEY_MGMT_* used in key derivation
+ * @cache_id: Pointer to FILS Cache Identifier or %NULL if not advertised
* Returns: Pointer to the added PMKSA cache entry or %NULL on error
*
* This function create a PMKSA entry for a new PMK and adds it to the PMKSA
@@ -124,13 +129,14 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
- const u8 *kck, size_t kck_len,
- const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+ const u8 *pmkid, const u8 *kck, size_t kck_len,
+ const u8 *aa, const u8 *spa, void *network_ctx, int akmp,
+ const u8 *cache_id)
{
- struct rsn_pmksa_cache_entry *entry, *pos, *prev;
+ struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
- if (pmk_len > PMK_LEN)
+ if (pmk_len > PMK_LEN_MAX)
return NULL;
if (wpa_key_mgmt_suite_b(akmp) && !kck)
@@ -141,29 +147,45 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ if (pmkid)
+ os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+ else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
else if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
else
- rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
- wpa_key_mgmt_sha256(akmp));
+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, akmp);
os_get_reltime(&now);
entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
entry->akmp = akmp;
+ if (cache_id) {
+ entry->fils_cache_id_set = 1;
+ os_memcpy(entry->fils_cache_id, cache_id, FILS_CACHE_ID_LEN);
+ }
os_memcpy(entry->aa, aa, ETH_ALEN);
entry->network_ctx = network_ctx;
+ return pmksa_cache_add_entry(pmksa, entry);
+}
+
+
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ struct rsn_pmksa_cache_entry *pos, *prev;
+
/* Replace an old entry for the same Authenticator (if found) with the
* new entry */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
- if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
- if (pos->pmk_len == pmk_len &&
- os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
+ if (os_memcmp(entry->aa, pos->aa, ETH_ALEN) == 0) {
+ if (pos->pmk_len == entry->pmk_len &&
+ os_memcmp_const(pos->pmk, entry->pmk,
+ entry->pmk_len) == 0 &&
os_memcmp_const(pos->pmkid, entry->pmkid,
PMKID_LEN) == 0) {
wpa_printf(MSG_DEBUG, "WPA: reusing previous "
@@ -189,8 +211,8 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
"the current AP and any PMKSA cache entry "
"that was based on the old PMK");
if (!pos->opportunistic)
- pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
- pos->pmk_len);
+ pmksa_cache_flush(pmksa, entry->network_ctx,
+ pos->pmk, pos->pmk_len);
pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
break;
}
@@ -241,8 +263,11 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
}
pmksa->pmksa_count++;
wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
- " network_ctx=%p", MAC2STR(entry->aa), network_ctx);
- wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+ " network_ctx=%p akmp=0x%x", MAC2STR(entry->aa),
+ entry->network_ctx, entry->akmp);
+ wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid,
+ entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
+ entry->pmk, entry->pmk_len);
return entry;
}
@@ -317,17 +342,20 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
* @aa: Authenticator address or %NULL to match any
* @pmkid: PMKID or %NULL to match any
* @network_ctx: Network context or %NULL to match any
+ * @akmp: Specific AKMP to search for or 0 for any
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
*/
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid,
- const void *network_ctx)
+ const void *network_ctx,
+ int akmp)
{
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
while (entry) {
if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
(pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
+ (!akmp || akmp == entry->akmp) &&
(network_ctx == NULL || network_ctx == entry->network_ctx))
return entry;
entry = entry->next;
@@ -342,16 +370,19 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
const u8 *aa)
{
struct rsn_pmksa_cache_entry *new_entry;
+ os_time_t old_expiration = old_entry->expiration;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
- NULL, 0,
+ NULL, NULL, 0,
aa, pmksa->sm->own_addr,
- old_entry->network_ctx, old_entry->akmp);
+ old_entry->network_ctx, old_entry->akmp,
+ old_entry->fils_cache_id_set ?
+ old_entry->fils_cache_id : NULL);
if (new_entry == NULL)
return NULL;
/* TODO: reorder entries based on expiration time? */
- new_entry->expiration = old_entry->expiration;
+ new_entry->expiration = old_expiration;
new_entry->opportunistic = 1;
return new_entry;
@@ -363,6 +394,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context
* @aa: Authenticator address for the new AP
+ * @akmp: Specific AKMP to search for or 0 for any
* Returns: Pointer to a new PMKSA cache entry or %NULL if not available
*
* Try to create a new PMKSA cache entry opportunistically by guessing that the
@@ -371,7 +403,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
- const u8 *aa)
+ const u8 *aa, int akmp)
{
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
@@ -379,7 +411,8 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
if (network_ctx == NULL)
return NULL;
while (entry) {
- if (entry->network_ctx == network_ctx) {
+ if (entry->network_ctx == network_ctx &&
+ (!akmp || entry->akmp == akmp)) {
entry = pmksa_cache_clone_entry(pmksa, entry, aa);
if (entry) {
wpa_printf(MSG_DEBUG, "RSN: added "
@@ -394,6 +427,24 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
}
+static struct rsn_pmksa_cache_entry *
+pmksa_cache_get_fils_cache_id(struct rsn_pmksa_cache *pmksa,
+ const void *network_ctx, const u8 *cache_id)
+{
+ struct rsn_pmksa_cache_entry *entry;
+
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
+ if (network_ctx == entry->network_ctx &&
+ entry->fils_cache_id_set &&
+ os_memcmp(cache_id, entry->fils_cache_id,
+ FILS_CACHE_ID_LEN) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+
/**
* pmksa_cache_get_current - Get the current used PMKSA entry
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -426,33 +477,44 @@ void pmksa_cache_clear_current(struct wpa_sm *sm)
* @bssid: BSSID for PMKSA or %NULL if not used
* @network_ctx: Network configuration context
* @try_opportunistic: Whether to allow opportunistic PMKSA caching
+ * @fils_cache_id: Pointer to FILS Cache Identifier or %NULL if not used
* Returns: 0 if PMKSA was found or -1 if no matching entry was found
*/
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid, void *network_ctx,
- int try_opportunistic)
+ int try_opportunistic, const u8 *fils_cache_id,
+ int akmp)
{
struct rsn_pmksa_cache *pmksa = sm->pmksa;
wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
- "try_opportunistic=%d", network_ctx, try_opportunistic);
+ "try_opportunistic=%d akmp=0x%x",
+ network_ctx, try_opportunistic, akmp);
if (pmkid)
wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
pmkid, PMKID_LEN);
if (bssid)
wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR,
MAC2STR(bssid));
+ if (fils_cache_id)
+ wpa_printf(MSG_DEBUG,
+ "RSN: Search for FILS Cache Identifier %02x%02x",
+ fils_cache_id[0], fils_cache_id[1]);
sm->cur_pmksa = NULL;
if (pmkid)
sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
- network_ctx);
+ network_ctx, akmp);
if (sm->cur_pmksa == NULL && bssid)
sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
- network_ctx);
+ network_ctx, akmp);
if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
network_ctx,
- bssid);
+ bssid, akmp);
+ if (sm->cur_pmksa == NULL && fils_cache_id)
+ sm->cur_pmksa = pmksa_cache_get_fils_cache_id(pmksa,
+ network_ctx,
+ fils_cache_id);
if (sm->cur_pmksa) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
sm->cur_pmksa->pmkid, PMKID_LEN);
@@ -479,11 +541,20 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
char *pos = buf;
struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
+ int cache_id_used = 0;
+
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
+ if (entry->fils_cache_id_set) {
+ cache_id_used = 1;
+ break;
+ }
+ }
os_get_reltime(&now);
ret = os_snprintf(pos, buf + len - pos,
"Index / AA / PMKID / expiration (in seconds) / "
- "opportunistic\n");
+ "opportunistic%s\n",
+ cache_id_used ? " / FILS Cache Identifier" : "");
if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
@@ -498,18 +569,36 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
pos += ret;
pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
PMKID_LEN);
- ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+ ret = os_snprintf(pos, buf + len - pos, " %d %d",
(int) (entry->expiration - now.sec),
entry->opportunistic);
if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
+ if (entry->fils_cache_id_set) {
+ ret = os_snprintf(pos, buf + len - pos, " %02x%02x",
+ entry->fils_cache_id[0],
+ entry->fils_cache_id[1]);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ ret = os_snprintf(pos, buf + len - pos, "\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
entry = entry->next;
}
return pos - buf;
}
+struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa->pmksa;
+}
+
+
/**
* pmksa_cache_init - Initialize PMKSA cache
* @free_cb: Callback function to be called when a PMKSA cache entry is freed
diff --git a/contrib/wpa/src/rsn_supp/pmksa_cache.h b/contrib/wpa/src/rsn_supp/pmksa_cache.h
index f8e040e..6c49fa9 100644
--- a/contrib/wpa/src/rsn_supp/pmksa_cache.h
+++ b/contrib/wpa/src/rsn_supp/pmksa_cache.h
@@ -15,12 +15,20 @@
struct rsn_pmksa_cache_entry {
struct rsn_pmksa_cache_entry *next;
u8 pmkid[PMKID_LEN];
- u8 pmk[PMK_LEN];
+ u8 pmk[PMK_LEN_MAX];
size_t pmk_len;
os_time_t expiration;
int akmp; /* WPA_KEY_MGMT_* */
u8 aa[ETH_ALEN];
+ /*
+ * If FILS Cache Identifier is included (fils_cache_id_set), this PMKSA
+ * cache entry is applicable to all BSSs (any BSSID/aa[]) that
+ * advertise the same FILS Cache Identifier within the same ESS.
+ */
+ u8 fils_cache_id[2];
+ unsigned int fils_cache_id_set:1;
+
os_time_t reauth_time;
/**
@@ -44,7 +52,7 @@ enum pmksa_free_reason {
PMKSA_EXPIRE,
};
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -53,20 +61,27 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid,
- const void *network_ctx);
+ const void *network_ctx,
+ int akmp);
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
- const u8 *kck, size_t kck_len,
- const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
+ const u8 *pmkid, const u8 *kck, size_t kck_len,
+ const u8 *aa, const u8 *spa, void *network_ctx, int akmp,
+ const u8 *cache_id);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry);
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
void pmksa_cache_clear_current(struct wpa_sm *sm);
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid, void *network_ctx,
- int try_opportunistic);
+ int try_opportunistic, const u8 *fils_cache_id,
+ int akmp);
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
- void *network_ctx, const u8 *aa);
+ void *network_ctx, const u8 *aa, int akmp);
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
const u8 *pmk, size_t pmk_len);
@@ -86,7 +101,7 @@ static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
- const void *network_ctx)
+ const void *network_ctx, int akmp)
{
return NULL;
}
@@ -104,9 +119,23 @@ static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
}
static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_head(struct rsn_pmksa_cache *pmksa)
+{
+ return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
- const u8 *kck, size_t kck_len,
- const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+ const u8 *pmkid, const u8 *kck, size_t kck_len,
+ const u8 *aa, const u8 *spa, void *network_ctx, int akmp,
+ const u8 *cache_id)
{
return NULL;
}
@@ -118,7 +147,9 @@ static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid,
void *network_ctx,
- int try_opportunistic)
+ int try_opportunistic,
+ const u8 *fils_cache_id,
+ int akmp)
{
return -1;
}
diff --git a/contrib/wpa/src/rsn_supp/preauth.c b/contrib/wpa/src/rsn_supp/preauth.c
index c6534af..d0c43f4 100644
--- a/contrib/wpa/src/rsn_supp/preauth.c
+++ b/contrib/wpa/src/rsn_supp/preauth.c
@@ -18,7 +18,7 @@
#include "wpa_i.h"
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
#define PMKID_CANDIDATE_PRIO_SCAN 1000
@@ -93,11 +93,11 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol,
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
pmk, pmk_len);
sm->pmk_len = pmk_len;
- pmksa_cache_add(sm->pmksa, pmk, pmk_len,
+ pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL,
NULL, 0,
sm->preauth_bssid, sm->own_addr,
sm->network_ctx,
- WPA_KEY_MGMT_IEEE8021X);
+ WPA_KEY_MGMT_IEEE8021X, NULL);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: failed to get master session key from "
@@ -323,7 +323,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
struct rsn_pmksa_candidate, list) {
struct rsn_pmksa_cache_entry *p = NULL;
- p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL);
+ p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL, 0);
if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
(p == NULL || p->opportunistic)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
@@ -342,7 +342,8 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
/* Some drivers (e.g., NDIS) expect to get notified about the
* PMKIDs again, so report the existing data now. */
if (p) {
- wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
+ wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid,
+ NULL, p->pmk, p->pmk_len);
}
dl_list_del(&candidate->list);
@@ -371,7 +372,7 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
if (sm->network_ctx && sm->proactive_key_caching)
pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
- bssid);
+ bssid, 0);
if (!preauth) {
wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
@@ -482,7 +483,7 @@ void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
return;
- pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL);
+ pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL, 0);
if (pmksa && (!pmksa->opportunistic ||
!(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
return;
@@ -538,4 +539,4 @@ int rsn_preauth_in_progress(struct wpa_sm *sm)
return sm->preauth_eapol != NULL;
}
-#endif /* IEEE8021X_EAPOL */
+#endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
diff --git a/contrib/wpa/src/rsn_supp/preauth.h b/contrib/wpa/src/rsn_supp/preauth.h
index 277f066..8caf3ee 100644
--- a/contrib/wpa/src/rsn_supp/preauth.h
+++ b/contrib/wpa/src/rsn_supp/preauth.h
@@ -11,7 +11,7 @@
struct wpa_scan_results;
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
void pmksa_candidate_free(struct wpa_sm *sm);
int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
@@ -27,7 +27,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int rsn_preauth_in_progress(struct wpa_sm *sm);
-#else /* IEEE8021X_EAPOL */
+#else /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
static inline void pmksa_candidate_free(struct wpa_sm *sm)
{
@@ -74,6 +74,6 @@ static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
return 0;
}
-#endif /* IEEE8021X_EAPOL */
+#endif /* IEEE8021X_EAPOL && !CONFIG_NO_WPA */
#endif /* PREAUTH_H */
diff --git a/contrib/wpa/src/rsn_supp/tdls.c b/contrib/wpa/src/rsn_supp/tdls.c
index cce59d7..704c95e 100644
--- a/contrib/wpa/src/rsn_supp/tdls.c
+++ b/contrib/wpa/src/rsn_supp/tdls.c
@@ -35,6 +35,7 @@
#define TDLS_TESTING_DECLINE_RESP BIT(9)
#define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10)
#define TDLS_TESTING_WRONG_MIC BIT(11)
+#define TDLS_TESTING_DOUBLE_TPK_M2 BIT(12)
unsigned int tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
@@ -303,10 +304,9 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
peer->sm_tmr.peer_capab = peer_capab;
peer->sm_tmr.buf_len = msg_len;
os_free(peer->sm_tmr.buf);
- peer->sm_tmr.buf = os_malloc(msg_len);
+ peer->sm_tmr.buf = os_memdup(msg, msg_len);
if (peer->sm_tmr.buf == NULL)
return -1;
- os_memcpy(peer->sm_tmr.buf, msg, msg_len);
wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
"(action_code=%u)", action_code);
@@ -413,8 +413,9 @@ static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer,
size_t len[2];
u8 data[3 * ETH_ALEN];
- /* IEEE Std 802.11z-2010 8.5.9.1:
- * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce))
+ /* IEEE Std 802.11-2016 12.7.9.2:
+ * TPK-Key-Input = Hash(min(SNonce, ANonce) || max(SNonce, ANonce))
+ * Hash = SHA-256 for TDLS
*/
len[0] = WPA_NONCE_LEN;
len[1] = WPA_NONCE_LEN;
@@ -432,11 +433,8 @@ static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer,
key_input, SHA256_MAC_LEN);
/*
- * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK",
- * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY)
- * TODO: is N_KEY really included in KDF Context and if so, in which
- * presentation format (little endian 16-bit?) is it used? It gets
- * added by the KDF anyway..
+ * TPK = KDF-Hash-Length(TPK-Key-Input, "TDLS PMK",
+ * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID)
*/
if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) {
@@ -645,9 +643,15 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
*/
if (peer->initiator) {
+ u8 addr[ETH_ALEN];
+
wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
" - try to renew", MAC2STR(peer->addr));
- wpa_tdls_start(sm, peer->addr);
+ /* cache the peer address before do_teardown */
+ os_memcpy(addr, peer->addr, ETH_ALEN);
+ wpa_tdls_do_teardown(sm, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ wpa_tdls_start(sm, addr);
} else {
wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
" - tear down", MAC2STR(peer->addr));
@@ -1214,9 +1218,10 @@ skip_ies:
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_DIFF_BSSID) {
+ struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos;
+
wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in "
"Link Identifier");
- struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos;
wpa_tdls_linkid(sm, peer, l);
l->bssid[5] ^= 0x01;
pos += sizeof(*l);
@@ -1589,7 +1594,7 @@ static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
peer->supp_rates, sizeof(peer->supp_rates),
kde->supp_rates + 2, kde->supp_rates_len - 2,
kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
- kde->ext_supp_rates_len - 2);
+ kde->ext_supp_rates ? kde->ext_supp_rates_len - 2 : 0);
return 0;
}
@@ -2120,6 +2125,13 @@ skip_add_peer:
goto error;
}
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_DOUBLE_TPK_M2) {
+ wpa_printf(MSG_INFO, "TDLS: Testing - Send another TPK M2");
+ wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
+ }
+#endif /* CONFIG_TDLS_TESTING */
+
return 0;
error:
@@ -2147,11 +2159,11 @@ static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout,
sm, peer);
#ifdef CONFIG_TDLS_TESTING
- if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) {
- wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK "
- "expiration");
- eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
- }
+ if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Testing - disable TPK expiration");
+ eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+ }
#endif /* CONFIG_TDLS_TESTING */
}
@@ -2367,7 +2379,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
kde.ftie, sizeof(*ftie));
ftie = (struct wpa_tdls_ftie *) kde.ftie;
- if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
+ if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does "
"not match with FTIE SNonce used in TPK M1");
/* Silently discard the frame */
@@ -2428,7 +2440,7 @@ skip_rsn:
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
"TPK Handshake Message 3");
if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0)
- goto error;
+ goto error_no_msg;
if (!peer->tpk_success) {
/*
@@ -2449,6 +2461,7 @@ skip_rsn:
error:
wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1,
status);
+error_no_msg:
wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -2545,13 +2558,13 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
goto error;
}
- if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
+ if (os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does "
"not match with FTIE ANonce used in TPK M2");
goto error;
}
- if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
+ if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not "
"match with FTIE SNonce used in TPK M1");
goto error;
@@ -2905,14 +2918,14 @@ void wpa_tdls_disassoc(struct wpa_sm *sm)
static int wpa_tdls_prohibited(struct ieee802_11_elems *elems)
{
/* bit 38 - TDLS Prohibited */
- return !!(elems->ext_capab[2 + 4] & 0x40);
+ return !!(elems->ext_capab[4] & 0x40);
}
static int wpa_tdls_chan_switch_prohibited(struct ieee802_11_elems *elems)
{
/* bit 39 - TDLS Channel Switch Prohibited */
- return !!(elems->ext_capab[2 + 4] & 0x80);
+ return !!(elems->ext_capab[4] & 0x80);
}
@@ -2925,7 +2938,7 @@ void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
if (ies == NULL ||
ieee802_11_parse_elems(ies, len, &elems, 0) == ParseFailed ||
- elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ elems.ext_capab == NULL || elems.ext_capab_len < 5)
return;
sm->tdls_prohibited = wpa_tdls_prohibited(&elems);
@@ -2944,7 +2957,7 @@ void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
if (ies == NULL ||
ieee802_11_parse_elems(ies, len, &elems, 0) == ParseFailed ||
- elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ elems.ext_capab == NULL || elems.ext_capab_len < 5)
return;
if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) {
diff --git a/contrib/wpa/src/rsn_supp/wpa.c b/contrib/wpa/src/rsn_supp/wpa.c
index 206cda9..9163f61 100644
--- a/contrib/wpa/src/rsn_supp/wpa.c
+++ b/contrib/wpa/src/rsn_supp/wpa.c
@@ -1,6 +1,7 @@
/*
* WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ * Copyright(c) 2015 Intel Deutschland GmbH
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,38 +10,53 @@
#include "includes.h"
#include "common.h"
+#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
+#include "crypto/aes_siv.h"
+#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
+#include "drivers/driver.h"
#include "wpa.h"
#include "eloop.h"
#include "preauth.h"
#include "pmksa_cache.h"
#include "wpa_i.h"
#include "wpa_ie.h"
-#include "peerkey.h"
+
+
+static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
/**
* wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
* @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @kck: Key Confirmation Key (KCK, part of PTK)
- * @kck_len: KCK length in octets
+ * @ptk: PTK for Key Confirmation/Encryption Key
* @ver: Version field from Key Info
* @dest: Destination address for the frame
* @proto: Ethertype (usually ETH_P_EAPOL)
* @msg: EAPOL-Key message
* @msg_len: Length of message
* @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ * Returns: >= 0 on success, < 0 on failure
*/
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
- int ver, const u8 *dest, u16 proto,
- u8 *msg, size_t msg_len, u8 *key_mic)
+int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
+ int ver, const u8 *dest, u16 proto,
+ u8 *msg, size_t msg_len, u8 *key_mic)
{
- size_t mic_len = wpa_mic_len(sm->key_mgmt);
+ int ret = -1;
+ size_t mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ wpa_printf(MSG_DEBUG, "WPA: Send EAPOL-Key frame to " MACSTR
+ " ver=%d mic_len=%d key_mgmt=0x%x",
+ MAC2STR(dest), ver, (int) mic_len, sm->key_mgmt);
if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
/*
* Association event was not yet received; try to fetch
@@ -58,21 +74,95 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
MAC2STR(dest));
}
}
- if (key_mic &&
- wpa_eapol_key_mic(kck, kck_len, sm->key_mgmt, ver, msg, msg_len,
- key_mic)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
- "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
- ver, sm->key_mgmt);
+
+ if (mic_len) {
+ if (key_mic && (!ptk || !ptk->kck_len))
+ goto out;
+
+ if (key_mic &&
+ wpa_eapol_key_mic(ptk->kck, ptk->kck_len, sm->key_mgmt, ver,
+ msg, msg_len, key_mic)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+ "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
+ ver, sm->key_mgmt);
+ goto out;
+ }
+ if (ptk)
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK",
+ ptk->kck, ptk->kck_len);
+ wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC",
+ key_mic, mic_len);
+ } else {
+#ifdef CONFIG_FILS
+ /* AEAD cipher - Key MIC field not used */
+ struct ieee802_1x_hdr *s_hdr, *hdr;
+ struct wpa_eapol_key *s_key, *key;
+ u8 *buf, *s_key_data, *key_data;
+ size_t buf_len = msg_len + AES_BLOCK_SIZE;
+ size_t key_data_len;
+ u16 eapol_len;
+ const u8 *aad[1];
+ size_t aad_len[1];
+
+ if (!ptk || !ptk->kek_len)
+ goto out;
+
+ key_data_len = msg_len - sizeof(struct ieee802_1x_hdr) -
+ sizeof(struct wpa_eapol_key) - 2;
+
+ buf = os_malloc(buf_len);
+ if (!buf)
+ goto out;
+
+ os_memcpy(buf, msg, msg_len);
+ hdr = (struct ieee802_1x_hdr *) buf;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ key_data = ((u8 *) (key + 1)) + 2;
+
+ /* Update EAPOL header to include AES-SIV overhead */
+ eapol_len = be_to_host16(hdr->length);
+ eapol_len += AES_BLOCK_SIZE;
+ hdr->length = host_to_be16(eapol_len);
+
+ /* Update Key Data Length field to include AES-SIV overhead */
+ WPA_PUT_BE16((u8 *) (key + 1), AES_BLOCK_SIZE + key_data_len);
+
+ s_hdr = (struct ieee802_1x_hdr *) msg;
+ s_key = (struct wpa_eapol_key *) (s_hdr + 1);
+ s_key_data = ((u8 *) (s_key + 1)) + 2;
+
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Plaintext Key Data",
+ s_key_data, key_data_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
+ /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
+ * to Key Data (exclusive). */
+ aad[0] = buf;
+ aad_len[0] = key_data - buf;
+ if (aes_siv_encrypt(ptk->kek, ptk->kek_len,
+ s_key_data, key_data_len,
+ 1, aad, aad_len, key_data) < 0) {
+ os_free(buf);
+ goto out;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPA: Encrypted Key Data from SIV",
+ key_data, AES_BLOCK_SIZE + key_data_len);
+
+ os_free(msg);
+ msg = buf;
+ msg_len = buf_len;
+#else /* CONFIG_FILS */
goto out;
+#endif /* CONFIG_FILS */
}
- wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len);
- wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len);
+
wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
- wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
+ ret = wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
eapol_sm_notify_tx_eapol_key(sm->eapol);
out:
os_free(msg);
+ return ret;
}
@@ -90,12 +180,10 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
{
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
int key_info, ver;
- u8 bssid[ETH_ALEN], *rbuf, *key_mic;
+ u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
- if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->key_mgmt))
+ if (wpa_use_akm_defined(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
wpa_key_mgmt_sha256(sm->key_mgmt))
@@ -111,19 +199,20 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
return;
}
- mic_len = wpa_mic_len(sm->key_mgmt);
- hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
+ mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return;
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = WPA_KEY_INFO_REQUEST | ver;
if (sm->ptk_set)
+ key_info |= WPA_KEY_INFO_SECURE;
+ if (sm->ptk_set && mic_len)
key_info |= WPA_KEY_INFO_MIC;
if (error)
key_info |= WPA_KEY_INFO_ERROR;
@@ -135,21 +224,19 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
WPA_REPLAY_COUNTER_LEN);
inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
- if (mic_len == 24)
- WPA_PUT_BE16(reply192->key_data_length, 0);
- else
- WPA_PUT_BE16(reply->key_data_length, 0);
+ mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(mic + mic_len, 0);
if (!(key_info & WPA_KEY_INFO_MIC))
key_mic = NULL;
else
- key_mic = reply192->key_mic; /* same offset in reply */
+ key_mic = mic;
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Sending EAPOL-Key Request (error=%d "
"pairwise=%d ptk_set=%d len=%lu)",
error, pairwise, sm->ptk_set, (unsigned long) rlen);
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
- ETH_P_EAPOL, rbuf, rlen, key_mic);
+ wpa_eapol_key_send(sm, &sm->ptk, ver, bssid, ETH_P_EAPOL, rbuf, rlen,
+ key_mic);
}
@@ -183,7 +270,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
* event before receiving this 1/4 message, so try to find a
* matching PMKSA cache entry here. */
sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
- NULL);
+ NULL, 0);
if (sm->cur_pmksa) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: found matching PMKID from PMKSA cache");
@@ -203,31 +290,63 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
eapol_sm_notify_cached(sm->eapol);
#ifdef CONFIG_IEEE80211R
sm->xxkey_len = 0;
+#ifdef CONFIG_SAE
+ if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE &&
+ sm->pmk_len == PMK_LEN) {
+ /* Need to allow FT key derivation to proceed with
+ * PMK from SAE being used as the XXKey in cases where
+ * the PMKID in msg 1/4 matches the PMKSA entry that was
+ * just added based on SAE authentication for the
+ * initial mobility domain association. */
+ os_memcpy(sm->xxkey, sm->pmk, sm->pmk_len);
+ sm->xxkey_len = sm->pmk_len;
+ }
+#endif /* CONFIG_SAE */
#endif /* CONFIG_IEEE80211R */
} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
int res, pmk_len;
- pmk_len = PMK_LEN;
- res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
+
+ if (wpa_key_mgmt_sha384(sm->key_mgmt))
+ pmk_len = PMK_LEN_SUITE_B_192;
+ else
+ pmk_len = PMK_LEN;
+ res = eapol_sm_get_key(sm->eapol, sm->pmk, pmk_len);
if (res) {
- /*
- * EAP-LEAP is an exception from other EAP methods: it
- * uses only 16-byte PMK.
- */
- res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
- pmk_len = 16;
+ if (pmk_len == PMK_LEN) {
+ /*
+ * EAP-LEAP is an exception from other EAP
+ * methods: it uses only 16-byte PMK.
+ */
+ res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
+ pmk_len = 16;
+ }
} else {
#ifdef CONFIG_IEEE80211R
u8 buf[2 * PMK_LEN];
if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
{
- os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN);
- sm->xxkey_len = PMK_LEN;
+ if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
+ os_memcpy(sm->xxkey, buf,
+ SHA384_MAC_LEN);
+ sm->xxkey_len = SHA384_MAC_LEN;
+ } else {
+ os_memcpy(sm->xxkey, buf + PMK_LEN,
+ PMK_LEN);
+ sm->xxkey_len = PMK_LEN;
+ }
os_memset(buf, 0, sizeof(buf));
}
#endif /* CONFIG_IEEE80211R */
}
if (res == 0) {
struct rsn_pmksa_cache_entry *sa = NULL;
+ const u8 *fils_cache_id = NULL;
+
+#ifdef CONFIG_FILS
+ if (sm->fils_cache_id_set)
+ fils_cache_id = sm->fils_cache_id;
+#endif /* CONFIG_FILS */
+
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
@@ -236,15 +355,16 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt)) {
sa = pmksa_cache_add(sm->pmksa,
- sm->pmk, pmk_len,
+ sm->pmk, pmk_len, NULL,
NULL, 0,
src_addr, sm->own_addr,
sm->network_ctx,
- sm->key_mgmt);
+ sm->key_mgmt,
+ fils_cache_id);
}
if (!sm->cur_pmksa && pmkid &&
- pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
- {
+ pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL,
+ 0)) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: the new PMK matches with the "
"PMKID");
@@ -257,13 +377,18 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
* much we can do here without knowing what
* exactly caused the server to misbehave.
*/
- wpa_dbg(sm->ctx->msg_ctx, MSG_INFO,
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: PMKID mismatch - authentication server may have derived different MSK?!");
return -1;
}
if (!sm->cur_pmksa)
sm->cur_pmksa = sa;
+#ifdef CONFIG_IEEE80211R
+ } else if (wpa_key_mgmt_ft(sm->key_mgmt) && sm->ft_protocol) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Continue 4-way handshake without PMK/PMKID for association using FT protocol");
+#endif /* CONFIG_IEEE80211R */
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to get master session key from "
@@ -318,7 +443,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
* @wpa_ie: WPA/RSN IE
* @wpa_ie_len: Length of the WPA/RSN IE
* @ptk: PTK to use for keyed hash and encryption
- * Returns: 0 on success, -1 on failure
+ * Returns: >= 0 on success, < 0 on failure
*/
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
const struct wpa_eapol_key *key,
@@ -328,9 +453,9 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
{
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *key_mic;
u8 *rsn_ie_buf = NULL;
+ u16 key_info;
if (wpa_ie == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - "
@@ -351,13 +476,12 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
if (rsn_ie_buf == NULL)
return -1;
os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len);
- res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len,
+ res = wpa_insert_pmkid(rsn_ie_buf, &wpa_ie_len,
sm->pmk_r1_name);
if (res < 0) {
os_free(rsn_ie_buf);
return -1;
}
- wpa_ie_len += res;
if (sm->assoc_resp_ies) {
os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
@@ -371,8 +495,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
- mic_len = wpa_mic_len(sm->key_mgmt);
- hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
+ mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
NULL, hdrlen + wpa_ie_len,
&rlen, (void *) &reply);
@@ -380,13 +504,16 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
os_free(rsn_ie_buf);
return -1;
}
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
- WPA_PUT_BE16(reply->key_info,
- ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
+ key_info = ver | WPA_KEY_INFO_KEY_TYPE;
+ if (mic_len)
+ key_info |= WPA_KEY_INFO_MIC;
+ else
+ key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+ WPA_PUT_BE16(reply->key_info, key_info);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
@@ -396,38 +523,41 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- key_mic = reply192->key_mic; /* same offset for reply and reply192 */
- if (mic_len == 24) {
- WPA_PUT_BE16(reply192->key_data_length, wpa_ie_len);
- os_memcpy(reply192 + 1, wpa_ie, wpa_ie_len);
- } else {
- WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
- os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
- }
+ key_mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len); /* Key Data Length */
+ os_memcpy(key_mic + mic_len + 2, wpa_ie, wpa_ie_len); /* Key Data */
os_free(rsn_ie_buf);
os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, key_mic);
-
- return 0;
+ return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen,
+ key_mic);
}
static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
+ const u8 *z = NULL;
+ size_t z_len = 0;
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_DPP2
+ if (sm->key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+ z = wpabuf_head(sm->dpp_z);
+ z_len = wpabuf_len(sm->dpp_z);
+ }
+#endif /* CONFIG_DPP2 */
+
return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
sm->own_addr, sm->bssid, sm->snonce,
key->key_nonce, ptk, sm->key_mgmt,
- sm->pairwise_cipher);
+ sm->pairwise_cipher, z, z_len);
}
@@ -490,7 +620,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
/* Calculate PTK which will be stored as a temporary PTK until it has
* been verified when processing message 3/4. */
ptk = &sm->tptk;
- wpa_derive_ptk(sm, src_addr, key, ptk);
+ if (wpa_derive_ptk(sm, src_addr, key, ptk) < 0)
+ goto failed;
if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
u8 buf[8];
/* Supplicant: swap tx/rx Mic keys */
@@ -504,6 +635,33 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in EAPOL-Key 2/4");
+ goto failed;
+ }
+
+ kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
+ if (!kde_buf) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
+ goto failed;
+ }
+
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
+ pos = kde + kde_len;
+ if (ocv_insert_oci_kde(&ci, &pos) < 0)
+ goto failed;
+ kde_len = pos - kde;
+ }
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_P2P
if (sm->p2p) {
kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
@@ -525,7 +683,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
#endif /* CONFIG_P2P */
if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
- kde, kde_len, ptk))
+ kde, kde_len, ptk) < 0)
goto failed;
os_free(kde_buf);
@@ -561,7 +719,9 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
eapol_sm_notify_portValid(sm->eapol, TRUE);
- if (wpa_key_mgmt_wpa_psk(sm->key_mgmt))
+ if (wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
+ sm->key_mgmt == WPA_KEY_MGMT_DPP ||
+ sm->key_mgmt == WPA_KEY_MGMT_OWE)
eapol_sm_notify_eap_success(sm->eapol, TRUE);
/*
* Start preauthentication after a short wait to avoid a
@@ -570,7 +730,9 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
* likelihood of the first preauth EAPOL-Start frame getting to
* the target AP.
*/
- eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
+ if (!dl_list_empty(&sm->pmksa_candidates))
+ eloop_register_timeout(1, 0, wpa_sm_start_preauth,
+ sm, NULL);
}
if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
@@ -603,7 +765,6 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
int keylen, rsclen;
enum wpa_alg alg;
const u8 *key_rsc;
- u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
if (sm->ptk.installed) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -629,6 +790,11 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
alg = wpa_cipher_to_alg(sm->pairwise_cipher);
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+ if (keylen <= 0 || (unsigned int) keylen != sm->ptk.tk_len) {
+ wpa_printf(MSG_DEBUG, "WPA: TK length mismatch: %d != %lu",
+ keylen, (long unsigned int) sm->ptk.tk_len);
+ return -1;
+ }
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
@@ -649,6 +815,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
/* TK is not needed anymore in supplicant */
os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+ sm->ptk.tk_len = 0;
sm->ptk.installed = 1;
if (sm->wpa_ptk_rekey) {
@@ -781,12 +948,43 @@ static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
}
+static int wpa_supplicant_rsc_relaxation(const struct wpa_sm *sm,
+ const u8 *rsc)
+{
+ int rsclen;
+
+ if (!sm->wpa_rsc_relaxation)
+ return 0;
+
+ rsclen = wpa_cipher_rsc_len(sm->group_cipher);
+
+ /*
+ * Try to detect RSC (endian) corruption issue where the AP sends
+ * the RSC bytes in EAPOL-Key message in the wrong order, both if
+ * it's actually a 6-byte field (as it should be) and if it treats
+ * it as an 8-byte field.
+ * An AP model known to have this bug is the Sapido RB-1632.
+ */
+ if (rsclen == 6 && ((rsc[5] && !rsc[0]) || rsc[6] || rsc[7])) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "RSC %02x%02x%02x%02x%02x%02x%02x%02x is likely bogus, using 0",
+ rsc[0], rsc[1], rsc[2], rsc[3],
+ rsc[4], rsc[5], rsc[6], rsc[7]);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
const u8 *gtk, size_t gtk_len,
int key_info)
{
struct wpa_gtk_data gd;
+ const u8 *key_rsc;
/*
* IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
@@ -812,11 +1010,15 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
os_memcpy(gd.gtk, gtk, gtk_len);
gd.gtk_len = gtk_len;
+ key_rsc = key->key_rsc;
+ if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
+ key_rsc = null_rsc;
+
if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
(wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
gtk_len, gtk_len,
&gd.key_rsc_len, &gd.alg) ||
- wpa_supplicant_install_gtk(sm, &gd, key->key_rsc, 0))) {
+ wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Failed to install GTK");
os_memset(&gd, 0, sizeof(gd));
@@ -824,8 +1026,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
}
os_memset(&gd, 0, sizeof(gd));
- wpa_supplicant_key_neg_complete(sm, sm->bssid,
- key_info & WPA_KEY_INFO_SECURE);
return 0;
}
@@ -851,7 +1051,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
}
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
+ "WPA: IGTK keyid %d pn " COMPACT_MACSTR,
keyidx, MAC2STR(igtk->pn));
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
if (keyidx > 4095) {
@@ -863,9 +1063,27 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn),
igtk->igtk, len) < 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Failed to configure IGTK to the driver");
- return -1;
+ if (keyidx == 0x0400 || keyidx == 0x0500) {
+ /* Assume the AP has broken PMF implementation since it
+ * seems to have swapped the KeyID bytes. The AP cannot
+ * be trusted to implement BIP correctly or provide a
+ * valid IGTK, so do not try to configure this key with
+ * swapped KeyID bytes. Instead, continue without
+ * configuring the IGTK so that the driver can drop any
+ * received group-addressed robust management frames due
+ * to missing keys.
+ *
+ * Normally, this error behavior would result in us
+ * disconnecting, but there are number of deployed APs
+ * with this broken behavior, so as an interoperability
+ * workaround, allow the connection to proceed. */
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Ignore IGTK configuration error due to invalid IGTK KeyID byte order");
+ } else {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure IGTK to the driver");
+ return -1;
+ }
}
if (wnm_sleep) {
@@ -1053,8 +1271,8 @@ static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm,
if (sm->assoc_resp_ies) {
pos = sm->assoc_resp_ies;
end = pos + sm->assoc_resp_ies_len;
- while (pos + 2 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 2) {
+ if (2 + pos[1] > end - pos)
break;
switch (*pos) {
case WLAN_EID_MOBILITY_DOMAIN:
@@ -1150,7 +1368,7 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
* @ver: Version bits from EAPOL-Key Key Info
* @key_info: Key Info
* @ptk: PTK to use for keyed hash and encryption
- * Returns: 0 on success, -1 on failure
+ * Returns: >= 0 on success, < 0 on failure
*/
int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
const struct wpa_eapol_key *key,
@@ -1159,22 +1377,24 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
{
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *key_mic;
- mic_len = wpa_mic_len(sm->key_mgmt);
- hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
+ mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_SECURE;
- key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
+ key_info |= ver | WPA_KEY_INFO_KEY_TYPE;
+ if (mic_len)
+ key_info |= WPA_KEY_INFO_MIC;
+ else
+ key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
WPA_PUT_BE16(reply->key_info, key_info);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
@@ -1183,17 +1403,12 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- key_mic = reply192->key_mic; /* same offset for reply and reply192 */
- if (mic_len == 24)
- WPA_PUT_BE16(reply192->key_data_length, 0);
- else
- WPA_PUT_BE16(reply->key_data_length, 0);
+ key_mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(key_mic + mic_len, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, key_mic);
-
- return 0;
+ return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen,
+ key_mic);
}
@@ -1265,8 +1480,28 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in EAPOL-Key 3/4");
+ return;
+ }
+
+ if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
- &sm->ptk)) {
+ &sm->ptk) < 0) {
goto failed;
}
@@ -1289,8 +1524,11 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
- wpa_supplicant_key_neg_complete(sm, sm->bssid,
- key_info & WPA_KEY_INFO_SECURE);
+ /* No GTK to be set to the driver */
+ } else if (!ie.gtk && sm->proto == WPA_PROTO_RSN) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: No GTK KDE included in EAPOL-Key msg 3/4");
+ goto failed;
} else if (ie.gtk &&
wpa_supplicant_pairwise_gtk(sm, key,
ie.gtk, ie.gtk_len, key_info) < 0) {
@@ -1305,16 +1543,26 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
+ if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.gtk)
+ wpa_supplicant_key_neg_complete(sm, sm->bssid,
+ key_info & WPA_KEY_INFO_SECURE);
+
if (ie.gtk)
wpa_sm_set_rekey_offload(sm);
- if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ /* Add PMKSA cache entry for Suite B AKMs here since PMKID can be
+ * calculated only after KCK has been derived. Though, do not replace an
+ * existing PMKSA entry after each 4-way handshake (i.e., new KCK/PMKID)
+ * to avoid unnecessary changes of PMKID while continuing to use the
+ * same PMK. */
+ if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !sm->cur_pmksa) {
struct rsn_pmksa_cache_entry *sa;
- sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+ sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL,
sm->ptk.kck, sm->ptk.kck_len,
sm->bssid, sm->own_addr,
- sm->network_ctx, sm->key_mgmt);
+ sm->network_ctx, sm->key_mgmt, NULL);
if (!sm->cur_pmksa)
sm->cur_pmksa = sa;
}
@@ -1336,7 +1584,8 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
int maxkeylen;
struct wpa_eapol_ie_parse ie;
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
+ wpa_hexdump_key(MSG_DEBUG, "RSN: msg 1/2 key data",
+ keydata, keydatalen);
if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
return -1;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
@@ -1351,6 +1600,26 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
}
maxkeylen = gd->gtk_len = ie.gtk_len - 2;
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in EAPOL-Key group msg 1/2");
+ return -1;
+ }
+
+ if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
+ ocv_errorstr);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
gd->gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
@@ -1470,22 +1739,30 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
{
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *key_mic;
+ size_t kde_len = 0;
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm))
+ kde_len = OCV_OCI_KDE_LEN;
+#endif /* CONFIG_OCV */
- mic_len = wpa_mic_len(sm->key_mgmt);
- hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
+ mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- hdrlen, &rlen, (void *) &reply);
+ hdrlen + kde_len, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
- key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+ key_info |= ver | WPA_KEY_INFO_SECURE;
+ if (mic_len)
+ key_info |= WPA_KEY_INFO_MIC;
+ else
+ key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
WPA_PUT_BE16(reply->key_info, key_info);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
@@ -1494,17 +1771,32 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- key_mic = reply192->key_mic; /* same offset for reply and reply192 */
- if (mic_len == 24)
- WPA_PUT_BE16(reply192->key_data_length, 0);
- else
- WPA_PUT_BE16(reply->key_data_length, 0);
+ key_mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data Length */
- wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid,
- ETH_P_EAPOL, rbuf, rlen, key_mic);
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
- return 0;
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in EAPOL-Key 2/2");
+ os_free(rbuf);
+ return -1;
+ }
+
+ pos = key_mic + mic_len + 2; /* Key Data */
+ if (ocv_insert_oci_kde(&ci, &pos) < 0) {
+ os_free(rbuf);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
+ return wpa_eapol_key_send(sm, &sm->ptk, ver, sm->bssid, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
}
@@ -1517,8 +1809,9 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
u16 key_info;
int rekey, ret;
struct wpa_gtk_data gd;
+ const u8 *key_rsc;
- if (!sm->msg_3_of_4_ok) {
+ if (!sm->msg_3_of_4_ok && !wpa_fils_is_completed(sm)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Group Key Handshake started prior to completion of 4-way handshake");
goto failed;
@@ -1547,13 +1840,17 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
if (ret)
goto failed;
- if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc, 0) ||
- wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
+ key_rsc = key->key_rsc;
+ if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
+ key_rsc = null_rsc;
+
+ if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) ||
+ wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0)
goto failed;
os_memset(&gd, 0, sizeof(gd));
if (rekey) {
- wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Group rekeying "
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying "
"completed with " MACSTR " [GTK=%s]",
MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
wpa_sm_cancel_auth_timeout(sm);
@@ -1575,42 +1872,68 @@ failed:
static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_eapol_key_192 *key,
+ struct wpa_eapol_key *key,
u16 ver,
const u8 *buf, size_t len)
{
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
int ok = 0;
- size_t mic_len = wpa_mic_len(sm->key_mgmt);
+ size_t mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
- os_memcpy(mic, key->key_mic, mic_len);
+ os_memcpy(mic, key + 1, mic_len);
if (sm->tptk_set) {
- os_memset(key->key_mic, 0, mic_len);
- wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len, sm->key_mgmt,
- ver, buf, len, key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
+ os_memset(key + 1, 0, mic_len);
+ if (wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len,
+ sm->key_mgmt,
+ ver, buf, len, (u8 *) (key + 1)) < 0 ||
+ os_memcmp_const(mic, key + 1, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
} else {
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
ok = 1;
sm->tptk_set = 0;
sm->ptk_set = 1;
os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+ /*
+ * This assures the same TPTK in sm->tptk can never be
+ * copied twice to sm->ptk as the new PTK. In
+ * combination with the installed flag in the wpa_ptk
+ * struct, this assures the same PTK is only installed
+ * once.
+ */
+ sm->renew_snonce = 1;
}
}
if (!ok && sm->ptk_set) {
- os_memset(key->key_mic, 0, mic_len);
- wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len, sm->key_mgmt,
- ver, buf, len, key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
+ os_memset(key + 1, 0, mic_len);
+ if (wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len,
+ sm->key_mgmt,
+ ver, buf, len, (u8 *) (key + 1)) < 0 ||
+ os_memcmp_const(mic, key + 1, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz2;
+#endif /* TEST_FUZZ */
return -1;
}
+#ifdef TEST_FUZZ
+ continue_fuzz2:
+#endif /* TEST_FUZZ */
ok = 1;
}
@@ -1630,7 +1953,8 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
- struct wpa_eapol_key *key, u16 ver,
+ struct wpa_eapol_key *key,
+ size_t mic_len, u16 ver,
u8 *key_data, size_t *key_data_len)
{
wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
@@ -1651,6 +1975,8 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
return -1;
#else /* CONFIG_NO_RC4 */
u8 ek[32];
+
+ wpa_printf(MSG_DEBUG, "WPA: Decrypt Key Data using RC4");
os_memcpy(ek, key->key_iv, 16);
os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) {
@@ -1663,9 +1989,12 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
#endif /* CONFIG_NO_RC4 */
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
- sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ wpa_use_aes_key_wrap(sm->key_mgmt)) {
u8 *buf;
+
+ wpa_printf(MSG_DEBUG,
+ "WPA: Decrypt Key Data using AES-UNWRAP (KEK length %u)",
+ (unsigned int) sm->ptk.kek_len);
if (*key_data_len < 8 || *key_data_len % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported AES-WRAP len %u",
@@ -1679,17 +2008,28 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
+#ifdef TEST_FUZZ
+ os_memset(buf, 0x11, *key_data_len);
+#endif /* TEST_FUZZ */
if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
key_data, buf)) {
- os_free(buf);
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore AES unwrap failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
+ bin_clear_free(buf, *key_data_len);
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - "
"could not decrypt EAPOL-Key key data");
return -1;
}
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
os_memcpy(key_data, buf, *key_data_len);
- os_free(buf);
- WPA_PUT_BE16(key->key_data_length, *key_data_len);
+ bin_clear_free(buf, *key_data_len);
+ WPA_PUT_BE16(((u8 *) (key + 1)) + mic_len, *key_data_len);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported key_info type %d", ver);
@@ -1752,6 +2092,76 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm,
}
+#ifdef CONFIG_FILS
+static int wpa_supp_aead_decrypt(struct wpa_sm *sm, u8 *buf, size_t buf_len,
+ size_t *key_data_len)
+{
+ struct wpa_ptk *ptk;
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ u8 *pos, *tmp;
+ const u8 *aad[1];
+ size_t aad_len[1];
+
+ if (*key_data_len < AES_BLOCK_SIZE) {
+ wpa_printf(MSG_INFO, "No room for AES-SIV data in the frame");
+ return -1;
+ }
+
+ if (sm->tptk_set)
+ ptk = &sm->tptk;
+ else if (sm->ptk_set)
+ ptk = &sm->ptk;
+ else
+ return -1;
+
+ hdr = (struct ieee802_1x_hdr *) buf;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ pos = (u8 *) (key + 1);
+ pos += 2; /* Pointing at the Encrypted Key Data field */
+
+ tmp = os_malloc(*key_data_len);
+ if (!tmp)
+ return -1;
+
+ /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
+ * to Key Data (exclusive). */
+ aad[0] = buf;
+ aad_len[0] = pos - buf;
+ if (aes_siv_decrypt(ptk->kek, ptk->kek_len, pos, *key_data_len,
+ 1, aad, aad_len, tmp) < 0) {
+ wpa_printf(MSG_INFO, "Invalid AES-SIV data in the frame");
+ bin_clear_free(tmp, *key_data_len);
+ return -1;
+ }
+
+ /* AEAD decryption and validation completed successfully */
+ (*key_data_len) -= AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Decrypted Key Data",
+ tmp, *key_data_len);
+
+ /* Replace Key Data field with the decrypted version */
+ os_memcpy(pos, tmp, *key_data_len);
+ pos -= 2; /* Key Data Length field */
+ WPA_PUT_BE16(pos, *key_data_len);
+ bin_clear_free(tmp, *key_data_len);
+
+ if (sm->tptk_set) {
+ sm->tptk_set = 0;
+ sm->ptk_set = 1;
+ os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+ }
+
+ os_memcpy(sm->rx_replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ sm->rx_replay_counter_set = 1;
+
+ return 0;
+}
+#endif /* CONFIG_FILS */
+
+
/**
* wpa_sm_rx_eapol - Process received WPA EAPOL frames
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -1774,20 +2184,18 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
size_t plen, data_len, key_data_len;
const struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- struct wpa_eapol_key_192 *key192;
u16 key_info, ver;
u8 *tmp = NULL;
int ret = -1;
- struct wpa_peerkey *peerkey = NULL;
- u8 *key_data;
+ u8 *mic, *key_data;
size_t mic_len, keyhdrlen;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- mic_len = wpa_mic_len(sm->key_mgmt);
- keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+ mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ keyhdrlen = sizeof(*key) + mic_len + 2;
if (len < sizeof(*hdr) + keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -1834,17 +2242,12 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
* Make a copy of the frame since we need to modify the buffer during
* MAC validation and Key Data decryption.
*/
- tmp = os_malloc(data_len);
+ tmp = os_memdup(buf, data_len);
if (tmp == NULL)
goto out;
- os_memcpy(tmp, buf, data_len);
key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
- key192 = (struct wpa_eapol_key_192 *)
- (tmp + sizeof(struct ieee802_1x_hdr));
- if (mic_len == 24)
- key_data = (u8 *) (key192 + 1);
- else
- key_data = (u8 *) (key + 1);
+ mic = (u8 *) (key + 1);
+ key_data = mic + mic_len + 2;
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
@@ -1855,11 +2258,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
goto out;
}
- if (mic_len == 24)
- key_data_len = WPA_GET_BE16(key192->key_data_length);
- else
- key_data_len = WPA_GET_BE16(key->key_data_length);
- wpa_eapol_key_dump(sm, key, key_data_len, key192->key_mic, mic_len);
+ key_data_len = WPA_GET_BE16(mic + mic_len);
+ wpa_eapol_key_dump(sm, key, key_data_len, mic, mic_len);
if (key_data_len > plen - keyhdrlen) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
@@ -1877,23 +2277,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
- !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
- sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
+ !wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d",
ver);
goto out;
}
- if (sm->key_mgmt == WPA_KEY_MGMT_OSEN &&
- ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "OSEN: Unsupported EAPOL-Key descriptor version %d",
- ver);
- goto out;
- }
-
- if (wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ if (wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
@@ -1904,7 +2295,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
- if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+ !wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"FT: AP did not use AES-128-CMAC");
goto out;
@@ -1914,8 +2306,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
- sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
- !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ !wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
"negotiated AES-128-CMAC");
@@ -1924,7 +2315,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
} else
#endif /* CONFIG_IEEE80211W */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
- !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
@@ -1944,7 +2335,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
} else
goto out;
} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
- !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: GCMP is used, but EAPOL-Key "
@@ -1952,44 +2343,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
goto out;
}
-#ifdef CONFIG_PEERKEY
- for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
- if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
- break;
- }
-
- if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
- if (!peerkey->initiator && peerkey->replay_counter_set &&
- os_memcmp(key->replay_counter, peerkey->replay_counter,
- WPA_REPLAY_COUNTER_LEN) <= 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "RSN: EAPOL-Key Replay Counter did not "
- "increase (STK) - dropping packet");
- goto out;
- } else if (peerkey->initiator) {
- u8 _tmp[WPA_REPLAY_COUNTER_LEN];
- os_memcpy(_tmp, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
- inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
- if (os_memcmp(_tmp, peerkey->replay_counter,
- WPA_REPLAY_COUNTER_LEN) != 0) {
- wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "RSN: EAPOL-Key Replay "
- "Counter did not match (STK) - "
- "dropping packet");
- goto out;
- }
- }
- }
-
- if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "RSN: Ack bit in key_info from STK peer");
- goto out;
- }
-#endif /* CONFIG_PEERKEY */
-
- if (!peerkey && sm->rx_replay_counter_set &&
+ if (sm->rx_replay_counter_set &&
os_memcmp(key->replay_counter, sm->rx_replay_counter,
WPA_REPLAY_COUNTER_LEN) <= 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1998,11 +2352,13 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
goto out;
}
- if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
-#ifdef CONFIG_PEERKEY
- && (peerkey == NULL || !peerkey->initiator)
-#endif /* CONFIG_PEERKEY */
- ) {
+ if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Unsupported SMK bit in key_info");
+ goto out;
+ }
+
+ if (!(key_info & WPA_KEY_INFO_ACK)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: No Ack bit in key_info");
goto out;
@@ -2014,19 +2370,19 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
goto out;
}
- if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
- wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
+ if ((key_info & WPA_KEY_INFO_MIC) &&
+ wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
goto out;
-#ifdef CONFIG_PEERKEY
- if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
- peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
- data_len))
- goto out;
-#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_FILS
+ if (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ if (wpa_supp_aead_decrypt(sm, tmp, data_len, &key_data_len))
+ goto out;
+ }
+#endif /* CONFIG_FILS */
if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
- (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && mic_len) {
/*
* Only decrypt the Key Data field if the frame's authenticity
* was verified. When using AES-SIV (FILS), the MIC flag is not
@@ -2038,7 +2394,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
"WPA: Ignore EAPOL-Key with encrypted but unauthenticated data");
goto out;
}
- if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data,
+ if (wpa_supplicant_decrypt_key_data(sm, key, mic_len,
+ ver, key_data,
&key_data_len))
goto out;
}
@@ -2050,11 +2407,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
"non-zero key index");
goto out;
}
- if (peerkey) {
- /* PeerKey 4-Way Handshake */
- peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
- key_data, key_data_len);
- } else if (key_info & WPA_KEY_INFO_MIC) {
+ if (key_info & (WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_ENCR_KEY_DATA)) {
/* 3/4 4-Way Handshake */
wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
key_data_len);
@@ -2064,19 +2418,16 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ver, key_data,
key_data_len);
}
- } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
- /* PeerKey SMK Handshake */
- peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
- ver);
} else {
- if (key_info & WPA_KEY_INFO_MIC) {
+ if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
+ (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA))) {
/* 1/2 Group Key Handshake */
wpa_supplicant_process_1_of_2(sm, src_addr, key,
key_data, key_data_len,
ver);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: EAPOL-Key (Group) without Mic bit - "
+ "WPA: EAPOL-Key (Group) without Mic/Encr bit - "
"dropped");
}
}
@@ -2251,6 +2602,7 @@ static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
}
if (deauth) {
+ sm->pmk_len = 0;
os_memset(sm->pmk, 0, sizeof(sm->pmk));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -2308,10 +2660,24 @@ void wpa_sm_deinit(struct wpa_sm *sm)
os_free(sm->ap_rsn_ie);
wpa_sm_drop_sa(sm);
os_free(sm->ctx);
- peerkey_deinit(sm);
#ifdef CONFIG_IEEE80211R
os_free(sm->assoc_resp_ies);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TESTING_OPTIONS
+ wpabuf_free(sm->test_assoc_ie);
+#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_FILS_SK_PFS
+ crypto_ecdh_deinit(sm->fils_ecdh);
+#endif /* CONFIG_FILS_SK_PFS */
+#ifdef CONFIG_FILS
+ wpabuf_free(sm->fils_ft_ies);
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ crypto_ecdh_deinit(sm->owe_ecdh);
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ wpabuf_clear_free(sm->dpp_z);
+#endif /* CONFIG_DPP2 */
os_free(sm);
}
@@ -2353,8 +2719,21 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
wpa_ft_prepare_auth_request(sm, NULL);
clear_keys = 0;
+ sm->ft_protocol = 1;
+ } else {
+ sm->ft_protocol = 0;
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_FILS
+ if (sm->fils_completed) {
+ /*
+ * Clear portValid to kick EAPOL state machine to re-enter
+ * AUTHENTICATED state to get the EAPOL port Authorized.
+ */
+ wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
+ clear_keys = 0;
+ }
+#endif /* CONFIG_FILS */
if (clear_keys) {
/*
@@ -2395,7 +2774,6 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
{
eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
- peerkey_deinit(sm);
rsn_preauth_deinit(sm);
pmksa_cache_clear_current(sm);
if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
@@ -2403,14 +2781,19 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
#ifdef CONFIG_TDLS
wpa_tdls_disassoc(sm);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_FILS
+ sm->fils_completed = 0;
+#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
sm->ft_reassoc_completed = 0;
+ sm->ft_protocol = 0;
#endif /* CONFIG_IEEE80211R */
/* Keys are not needed in the WPA state machine anymore */
wpa_sm_drop_sa(sm);
sm->msg_3_of_4_ok = 0;
+ os_memset(sm->bssid, 0, ETH_ALEN);
}
@@ -2419,16 +2802,19 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @pmk: The new PMK
* @pmk_len: The length of the new PMK in bytes
+ * @pmkid: Calculated PMKID
* @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
*
* Configure the PMK for WPA state machine.
*/
void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
- const u8 *bssid)
+ const u8 *pmkid, const u8 *bssid)
{
if (sm == NULL)
return;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Set PMK based on external data",
+ pmk, pmk_len);
sm->pmk_len = pmk_len;
os_memcpy(sm->pmk, pmk, pmk_len);
@@ -2439,9 +2825,9 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
#endif /* CONFIG_IEEE80211R */
if (bssid) {
- pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+ pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0,
bssid, sm->own_addr,
- sm->network_ctx, sm->key_mgmt);
+ sm->network_ctx, sm->key_mgmt, NULL);
}
}
@@ -2459,11 +2845,15 @@ void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
return;
if (sm->cur_pmksa) {
+ wpa_hexdump_key(MSG_DEBUG,
+ "WPA: Set PMK based on current PMKSA",
+ sm->cur_pmksa->pmk, sm->cur_pmksa->pmk_len);
sm->pmk_len = sm->cur_pmksa->pmk_len;
os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
} else {
- sm->pmk_len = PMK_LEN;
- os_memset(sm->pmk, 0, PMK_LEN);
+ wpa_printf(MSG_DEBUG, "WPA: No current PMKSA - clear PMK");
+ sm->pmk_len = 0;
+ os_memset(sm->pmk, 0, PMK_LEN_MAX);
}
}
@@ -2511,7 +2901,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
if (config) {
sm->network_ctx = config->network_ctx;
- sm->peerkey_enabled = config->peerkey_enabled;
sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher;
sm->proactive_key_caching = config->proactive_key_caching;
sm->eap_workaround = config->eap_workaround;
@@ -2523,9 +2912,18 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->ssid_len = 0;
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
sm->p2p = config->p2p;
+ sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
+#ifdef CONFIG_FILS
+ if (config->fils_cache_id) {
+ sm->fils_cache_id_set = 1;
+ os_memcpy(sm->fils_cache_id, config->fils_cache_id,
+ FILS_CACHE_ID_LEN);
+ } else {
+ sm->fils_cache_id_set = 0;
+ }
+#endif /* CONFIG_FILS */
} else {
sm->network_ctx = NULL;
- sm->peerkey_enabled = 0;
sm->allowed_pairwise_cipher = 0;
sm->proactive_key_caching = 0;
sm->eap_workaround = 0;
@@ -2533,6 +2931,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->ssid_len = 0;
sm->wpa_ptk_rekey = 0;
sm->p2p = 0;
+ sm->wpa_rsc_relaxation = 0;
}
}
@@ -2634,6 +3033,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_MFP:
sm->mfp = value;
break;
+ case WPA_PARAM_OCV:
+ sm->ocv = value;
+ break;
default:
break;
}
@@ -2677,9 +3079,12 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
>= 0 &&
rsn.capabilities & (WPA_CAPABILITY_MFPR |
WPA_CAPABILITY_MFPC)) {
- ret = os_snprintf(pos, end - pos, "pmf=%d\n",
+ ret = os_snprintf(pos, end - pos, "pmf=%d\n"
+ "mgmt_group_cipher=%s\n",
(rsn.capabilities &
- WPA_CAPABILITY_MFPR) ? 2 : 1);
+ WPA_CAPABILITY_MFPR) ? 2 : 1,
+ wpa_cipher_txt(
+ sm->mgmt_group_cipher));
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2705,6 +3110,19 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
}
+int wpa_sm_ocv_enabled(struct wpa_sm *sm)
+{
+ struct wpa_ie_data rsn;
+
+ if (!sm->ocv || !sm->ap_rsn_ie)
+ return 0;
+
+ return wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+ &rsn) >= 0 &&
+ (rsn.capabilities & WPA_CAPABILITY_OCVC);
+}
+
+
/**
* wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -2720,6 +3138,17 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
if (sm == NULL)
return -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->test_assoc_ie) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Replace association WPA/RSN IE");
+ if (*wpa_ie_len < wpabuf_len(sm->test_assoc_ie))
+ return -1;
+ os_memcpy(wpa_ie, wpabuf_head(sm->test_assoc_ie),
+ wpabuf_len(sm->test_assoc_ie));
+ res = wpabuf_len(sm->test_assoc_ie);
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
if (res < 0)
return -1;
@@ -2734,12 +3163,15 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
* the correct version of the IE even if PMKSA caching is
* aborted (which would remove PMKID from IE generation).
*/
- sm->assoc_wpa_ie = os_malloc(*wpa_ie_len);
+ sm->assoc_wpa_ie = os_memdup(wpa_ie, *wpa_ie_len);
if (sm->assoc_wpa_ie == NULL)
return -1;
- os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
sm->assoc_wpa_ie_len = *wpa_ie_len;
+ } else {
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Leave previously set WPA IE default",
+ sm->assoc_wpa_ie, sm->assoc_wpa_ie_len);
}
return 0;
@@ -2770,11 +3202,10 @@ int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
sm->assoc_wpa_ie_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len);
- sm->assoc_wpa_ie = os_malloc(len);
+ sm->assoc_wpa_ie = os_memdup(ie, len);
if (sm->assoc_wpa_ie == NULL)
return -1;
- os_memcpy(sm->assoc_wpa_ie, ie, len);
sm->assoc_wpa_ie_len = len;
}
@@ -2805,11 +3236,10 @@ int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
sm->ap_wpa_ie_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len);
- sm->ap_wpa_ie = os_malloc(len);
+ sm->ap_wpa_ie = os_memdup(ie, len);
if (sm->ap_wpa_ie == NULL)
return -1;
- os_memcpy(sm->ap_wpa_ie, ie, len);
sm->ap_wpa_ie_len = len;
}
@@ -2840,11 +3270,10 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
sm->ap_rsn_ie_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
- sm->ap_rsn_ie = os_malloc(len);
+ sm->ap_rsn_ie = os_memdup(ie, len);
if (sm->ap_rsn_ie == NULL)
return -1;
- os_memcpy(sm->ap_rsn_ie, ie, len);
sm->ap_rsn_ie_len = len;
}
@@ -2883,11 +3312,43 @@ int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
}
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm)
+{
+ return pmksa_cache_head(sm->pmksa);
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_add_entry(struct wpa_sm *sm,
+ struct rsn_pmksa_cache_entry * entry)
+{
+ return pmksa_cache_add_entry(sm->pmksa, entry);
+}
+
+
+void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid, const u8 *bssid,
+ const u8 *fils_cache_id)
+{
+ sm->cur_pmksa = pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0,
+ bssid, sm->own_addr, sm->network_ctx,
+ sm->key_mgmt, fils_cache_id);
+}
+
+
+int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
+ const void *network_ctx)
+{
+ return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx, 0) != NULL;
+}
+
+
void wpa_sm_drop_sa(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
sm->ptk_set = 0;
sm->tptk_set = 0;
+ sm->pmk_len = 0;
os_memset(sm->pmk, 0, sizeof(sm->pmk));
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
@@ -2899,8 +3360,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+ sm->xxkey_len = 0;
os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+ sm->pmk_r0_len = 0;
os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+ sm->pmk_r1_len = 0;
#endif /* CONFIG_IEEE80211R */
}
@@ -2985,27 +3449,6 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
#endif /* CONFIG_WNM */
-#ifdef CONFIG_PEERKEY
-int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
- const u8 *buf, size_t len)
-{
- struct wpa_peerkey *peerkey;
-
- for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
- if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
- break;
- }
-
- if (!peerkey)
- return 0;
-
- wpa_sm_rx_eapol(sm, src_addr, buf, len);
-
- return 1;
-}
-#endif /* CONFIG_PEERKEY */
-
-
#ifdef CONFIG_P2P
int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
@@ -3047,3 +3490,1205 @@ void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
}
sm->ptk_set = 1;
}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+
+void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf)
+{
+ wpabuf_free(sm->test_assoc_ie);
+ sm->test_assoc_ie = buf;
+}
+
+
+const u8 * wpa_sm_get_anonce(struct wpa_sm *sm)
+{
+ return sm->anonce;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm)
+{
+ return sm->key_mgmt;
+}
+
+
+#ifdef CONFIG_FILS
+
+struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md)
+{
+ struct wpabuf *buf = NULL;
+ struct wpabuf *erp_msg;
+ struct wpabuf *pub = NULL;
+
+ erp_msg = eapol_sm_build_erp_reauth_start(sm->eapol);
+ if (!erp_msg && !sm->cur_pmksa) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Neither ERP EAP-Initiate/Re-auth nor PMKSA cache entry is available - skip FILS");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "FILS: Try to use FILS (erp=%d pmksa_cache=%d)",
+ erp_msg != NULL, sm->cur_pmksa != NULL);
+
+ sm->fils_completed = 0;
+
+ if (!sm->assoc_wpa_ie) {
+ wpa_printf(MSG_INFO, "FILS: No own RSN IE set for FILS");
+ goto fail;
+ }
+
+ if (random_get_bytes(sm->fils_nonce, FILS_NONCE_LEN) < 0 ||
+ random_get_bytes(sm->fils_session, FILS_SESSION_LEN) < 0)
+ goto fail;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Generated FILS Nonce",
+ sm->fils_nonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: Generated FILS Session",
+ sm->fils_session, FILS_SESSION_LEN);
+
+#ifdef CONFIG_FILS_SK_PFS
+ sm->fils_dh_group = dh_group;
+ if (dh_group) {
+ crypto_ecdh_deinit(sm->fils_ecdh);
+ sm->fils_ecdh = crypto_ecdh_init(dh_group);
+ if (!sm->fils_ecdh) {
+ wpa_printf(MSG_INFO,
+ "FILS: Could not initialize ECDH with group %d",
+ dh_group);
+ goto fail;
+ }
+ pub = crypto_ecdh_get_pubkey(sm->fils_ecdh, 1);
+ if (!pub)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "FILS: Element (DH public key)",
+ pub);
+ sm->fils_dh_elem_len = wpabuf_len(pub);
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ buf = wpabuf_alloc(1000 + sm->assoc_wpa_ie_len +
+ (pub ? wpabuf_len(pub) : 0));
+ if (!buf)
+ goto fail;
+
+ /* Fields following the Authentication algorithm number field */
+
+ /* Authentication Transaction seq# */
+ wpabuf_put_le16(buf, 1);
+
+ /* Status Code */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* TODO: FILS PK */
+#ifdef CONFIG_FILS_SK_PFS
+ if (dh_group) {
+ /* Finite Cyclic Group */
+ wpabuf_put_le16(buf, dh_group);
+ /* Element */
+ wpabuf_put_buf(buf, pub);
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ /* RSNE */
+ wpa_hexdump(MSG_DEBUG, "FILS: RSNE in FILS Authentication frame",
+ sm->assoc_wpa_ie, sm->assoc_wpa_ie_len);
+ wpabuf_put_data(buf, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len);
+
+ if (md) {
+ /* MDE when using FILS for FT initial association */
+ struct rsn_mdie *mdie;
+
+ wpabuf_put_u8(buf, WLAN_EID_MOBILITY_DOMAIN);
+ wpabuf_put_u8(buf, sizeof(*mdie));
+ mdie = wpabuf_put(buf, sizeof(*mdie));
+ os_memcpy(mdie->mobility_domain, md, MOBILITY_DOMAIN_ID_LEN);
+ mdie->ft_capab = 0;
+ }
+
+ /* FILS Nonce */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(buf, sm->fils_nonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
+
+ /* FILS Wrapped Data */
+ sm->fils_erp_pmkid_set = 0;
+ if (erp_msg) {
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_buf(buf, erp_msg);
+ /* Calculate pending PMKID here so that we do not need to
+ * maintain a copy of the EAP-Initiate/Reauth message. */
+ if (fils_pmkid_erp(sm->key_mgmt, wpabuf_head(erp_msg),
+ wpabuf_len(erp_msg),
+ sm->fils_erp_pmkid) == 0)
+ sm->fils_erp_pmkid_set = 1;
+ }
+
+ wpa_hexdump_buf(MSG_DEBUG, "RSN: FILS fields for Authentication frame",
+ buf);
+
+fail:
+ wpabuf_free(erp_msg);
+ wpabuf_free(pub);
+ return buf;
+}
+
+
+int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
+ size_t len)
+{
+ const u8 *pos, *end;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsn;
+ int pmkid_match = 0;
+ u8 ick[FILS_ICK_MAX_LEN];
+ size_t ick_len;
+ int res;
+ struct wpabuf *dh_ss = NULL;
+ const u8 *g_sta = NULL;
+ size_t g_sta_len = 0;
+ const u8 *g_ap = NULL;
+ size_t g_ap_len = 0;
+ struct wpabuf *pub = NULL;
+
+ os_memcpy(sm->bssid, bssid, ETH_ALEN);
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
+ data, len);
+ pos = data;
+ end = data + len;
+
+ /* TODO: FILS PK */
+#ifdef CONFIG_FILS_SK_PFS
+ if (sm->fils_dh_group) {
+ u16 group;
+
+ /* Using FILS PFS */
+
+ /* Finite Cyclic Group */
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No room for Finite Cyclic Group");
+ goto fail;
+ }
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ if (group != sm->fils_dh_group) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unexpected change in Finite Cyclic Group: %u (expected %u)",
+ group, sm->fils_dh_group);
+ goto fail;
+ }
+
+ /* Element */
+ if ((size_t) (end - pos) < sm->fils_dh_elem_len) {
+ wpa_printf(MSG_DEBUG, "FILS: No room for Element");
+ goto fail;
+ }
+
+ if (!sm->fils_ecdh) {
+ wpa_printf(MSG_DEBUG, "FILS: No ECDH state available");
+ goto fail;
+ }
+ dh_ss = crypto_ecdh_set_peerkey(sm->fils_ecdh, 1, pos,
+ sm->fils_dh_elem_len);
+ if (!dh_ss) {
+ wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
+ goto fail;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", dh_ss);
+ g_ap = pos;
+ g_ap_len = sm->fils_dh_elem_len;
+ pos += sm->fils_dh_elem_len;
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
+ if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
+ goto fail;
+ }
+
+ /* RSNE */
+ wpa_hexdump(MSG_DEBUG, "FILS: RSN element", elems.rsn_ie,
+ elems.rsn_ie_len);
+ if (!elems.rsn_ie ||
+ wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: No RSN element");
+ goto fail;
+ }
+
+ if (!elems.fils_nonce) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
+ goto fail;
+ }
+ os_memcpy(sm->fils_anonce, elems.fils_nonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce", sm->fils_anonce, FILS_NONCE_LEN);
+
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+ struct wpa_ft_ies parse;
+
+ if (!elems.mdie || !elems.ftie) {
+ wpa_printf(MSG_DEBUG, "FILS+FT: No MDE or FTE");
+ goto fail;
+ }
+
+ if (wpa_ft_parse_ies(pos, end - pos, &parse,
+ wpa_key_mgmt_sha384(sm->key_mgmt)) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS+FT: Failed to parse IEs");
+ goto fail;
+ }
+
+ if (!parse.r0kh_id) {
+ wpa_printf(MSG_DEBUG,
+ "FILS+FT: No R0KH-ID subelem in FTE");
+ goto fail;
+ }
+ os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
+ sm->r0kh_id_len = parse.r0kh_id_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "FILS+FT: R0KH-ID",
+ sm->r0kh_id, sm->r0kh_id_len);
+
+ if (!parse.r1kh_id) {
+ wpa_printf(MSG_DEBUG,
+ "FILS+FT: No R1KH-ID subelem in FTE");
+ goto fail;
+ }
+ os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS+FT: R1KH-ID",
+ sm->r1kh_id, FT_R1KH_ID_LEN);
+
+ /* TODO: Check MDE and FTE payload */
+
+ wpabuf_free(sm->fils_ft_ies);
+ sm->fils_ft_ies = wpabuf_alloc(2 + elems.mdie_len +
+ 2 + elems.ftie_len);
+ if (!sm->fils_ft_ies)
+ goto fail;
+ wpabuf_put_data(sm->fils_ft_ies, elems.mdie - 2,
+ 2 + elems.mdie_len);
+ wpabuf_put_data(sm->fils_ft_ies, elems.ftie - 2,
+ 2 + elems.ftie_len);
+ } else {
+ wpabuf_free(sm->fils_ft_ies);
+ sm->fils_ft_ies = NULL;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ /* PMKID List */
+ if (rsn.pmkid && rsn.num_pmkid > 0) {
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
+ rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
+
+ if (rsn.num_pmkid != 1) {
+ wpa_printf(MSG_DEBUG, "FILS: Invalid PMKID selection");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID", rsn.pmkid, PMKID_LEN);
+ if (os_memcmp(sm->cur_pmksa->pmkid, rsn.pmkid, PMKID_LEN) != 0)
+ {
+ wpa_printf(MSG_DEBUG, "FILS: PMKID mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected PMKID",
+ sm->cur_pmksa->pmkid, PMKID_LEN);
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG,
+ "FILS: Matching PMKID - continue using PMKSA caching");
+ pmkid_match = 1;
+ }
+ if (!pmkid_match && sm->cur_pmksa) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No PMKID match - cannot use cached PMKSA entry");
+ sm->cur_pmksa = NULL;
+ }
+
+ /* FILS Session */
+ if (!elems.fils_session) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
+ FILS_SESSION_LEN);
+ if (os_memcmp(sm->fils_session, elems.fils_session, FILS_SESSION_LEN)
+ != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
+ sm->fils_session, FILS_SESSION_LEN);
+ goto fail;
+ }
+
+ /* FILS Wrapped Data */
+ if (!sm->cur_pmksa && elems.fils_wrapped_data) {
+ u8 rmsk[ERP_MAX_KEY_LEN];
+ size_t rmsk_len;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
+ elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len);
+ eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len);
+ if (eapol_sm_failed(sm->eapol))
+ goto fail;
+
+ rmsk_len = ERP_MAX_KEY_LEN;
+ res = eapol_sm_get_key(sm->eapol, rmsk, rmsk_len);
+ if (res == PMK_LEN) {
+ rmsk_len = PMK_LEN;
+ res = eapol_sm_get_key(sm->eapol, rmsk, rmsk_len);
+ }
+ if (res)
+ goto fail;
+
+ res = fils_rmsk_to_pmk(sm->key_mgmt, rmsk, rmsk_len,
+ sm->fils_nonce, sm->fils_anonce,
+ dh_ss ? wpabuf_head(dh_ss) : NULL,
+ dh_ss ? wpabuf_len(dh_ss) : 0,
+ sm->pmk, &sm->pmk_len);
+ os_memset(rmsk, 0, sizeof(rmsk));
+
+ /* Don't use DHss in PTK derivation if PMKSA caching is not
+ * used. */
+ wpabuf_clear_free(dh_ss);
+ dh_ss = NULL;
+
+ if (res)
+ goto fail;
+
+ if (!sm->fils_erp_pmkid_set) {
+ wpa_printf(MSG_DEBUG, "FILS: PMKID not available");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID", sm->fils_erp_pmkid,
+ PMKID_LEN);
+ wpa_printf(MSG_DEBUG, "FILS: ERP processing succeeded - add PMKSA cache entry for the result");
+ sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+ sm->fils_erp_pmkid, NULL, 0,
+ sm->bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt,
+ NULL);
+ }
+
+ if (!sm->cur_pmksa) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No remaining options to continue FILS authentication");
+ goto fail;
+ }
+
+ if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, sm->bssid,
+ sm->fils_nonce, sm->fils_anonce,
+ dh_ss ? wpabuf_head(dh_ss) : NULL,
+ dh_ss ? wpabuf_len(dh_ss) : 0,
+ &sm->ptk, ick, &ick_len,
+ sm->key_mgmt, sm->pairwise_cipher,
+ sm->fils_ft, &sm->fils_ft_len) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive PTK");
+ goto fail;
+ }
+
+ wpabuf_clear_free(dh_ss);
+ dh_ss = NULL;
+
+ sm->ptk_set = 1;
+ sm->tptk_set = 0;
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+
+#ifdef CONFIG_FILS_SK_PFS
+ if (sm->fils_dh_group) {
+ if (!sm->fils_ecdh) {
+ wpa_printf(MSG_INFO, "FILS: ECDH not initialized");
+ goto fail;
+ }
+ pub = crypto_ecdh_get_pubkey(sm->fils_ecdh, 1);
+ if (!pub)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "FILS: gSTA", pub);
+ g_sta = wpabuf_head(pub);
+ g_sta_len = wpabuf_len(pub);
+ if (!g_ap) {
+ wpa_printf(MSG_INFO, "FILS: gAP not available");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: gAP", g_ap, g_ap_len);
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ res = fils_key_auth_sk(ick, ick_len, sm->fils_nonce,
+ sm->fils_anonce, sm->own_addr, sm->bssid,
+ g_sta, g_sta_len, g_ap, g_ap_len,
+ sm->key_mgmt, sm->fils_key_auth_sta,
+ sm->fils_key_auth_ap,
+ &sm->fils_key_auth_len);
+ wpabuf_free(pub);
+ os_memset(ick, 0, sizeof(ick));
+ return res;
+fail:
+ wpabuf_free(pub);
+ wpabuf_clear_free(dh_ss);
+ return -1;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
+{
+ struct rsn_ie_hdr *rsnie;
+ u16 capab;
+ u8 *pos;
+ int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+
+ /* RSNIE[PMKR0Name/PMKR1Name] */
+ rsnie = wpabuf_put(buf, sizeof(*rsnie));
+ rsnie->elem_id = WLAN_EID_RSN;
+ WPA_PUT_LE16(rsnie->version, RSN_VERSION);
+
+ /* Group Suite Selector */
+ if (!wpa_cipher_valid_group(sm->group_cipher)) {
+ wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)",
+ sm->group_cipher);
+ return -1;
+ }
+ pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+ sm->group_cipher));
+
+ /* Pairwise Suite Count */
+ wpabuf_put_le16(buf, 1);
+
+ /* Pairwise Suite List */
+ if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
+ wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)",
+ sm->pairwise_cipher);
+ return -1;
+ }
+ pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+ sm->pairwise_cipher));
+
+ /* Authenticated Key Management Suite Count */
+ wpabuf_put_le16(buf, 1);
+
+ /* Authenticated Key Management Suite List */
+ pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
+ if (sm->key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
+ else {
+ wpa_printf(MSG_WARNING,
+ "FILS+FT: Invalid key management type (%d)",
+ sm->key_mgmt);
+ return -1;
+ }
+
+ /* RSN Capabilities */
+ capab = 0;
+#ifdef CONFIG_IEEE80211W
+ if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ capab |= WPA_CAPABILITY_MFPC;
+#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+ wpabuf_put_le16(buf, capab);
+
+ /* PMKID Count */
+ wpabuf_put_le16(buf, 1);
+
+ /* PMKID List [PMKR1Name] */
+ wpa_hexdump_key(MSG_DEBUG, "FILS+FT: XXKey (FILS-FT)",
+ sm->fils_ft, sm->fils_ft_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "FILS+FT: SSID", sm->ssid, sm->ssid_len);
+ wpa_hexdump(MSG_DEBUG, "FILS+FT: MDID",
+ sm->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
+ wpa_hexdump_ascii(MSG_DEBUG, "FILS+FT: R0KH-ID",
+ sm->r0kh_id, sm->r0kh_id_len);
+ if (wpa_derive_pmk_r0(sm->fils_ft, sm->fils_ft_len, sm->ssid,
+ sm->ssid_len, sm->mobility_domain,
+ sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
+ sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0) {
+ wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMK-R0");
+ return -1;
+ }
+ sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
+ sm->pmk_r0, sm->pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
+ sm->pmk_r0_name, WPA_PMK_NAME_LEN);
+ wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR,
+ MAC2STR(sm->r1kh_id));
+ pos = wpabuf_put(buf, WPA_PMK_NAME_LEN);
+ if (wpa_derive_pmk_r1_name(sm->pmk_r0_name, sm->r1kh_id, sm->own_addr,
+ sm->pmk_r1_name, use_sha384) < 0) {
+ wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+ os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+
+#ifdef CONFIG_IEEE80211W
+ if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+ /* Management Group Cipher Suite */
+ pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ rsnie->len = ((u8 *) wpabuf_put(buf, 0) - (u8 *) rsnie) - 2;
+ return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
+ size_t *kek_len, const u8 **snonce,
+ const u8 **anonce,
+ const struct wpabuf **hlp,
+ unsigned int num_hlp)
+{
+ struct wpabuf *buf;
+ size_t len;
+ unsigned int i;
+
+ len = 1000;
+#ifdef CONFIG_IEEE80211R
+ if (sm->fils_ft_ies)
+ len += wpabuf_len(sm->fils_ft_ies);
+ if (wpa_key_mgmt_ft(sm->key_mgmt))
+ len += 256;
+#endif /* CONFIG_IEEE80211R */
+ for (i = 0; hlp && i < num_hlp; i++)
+ len += 10 + wpabuf_len(hlp[i]);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ return NULL;
+
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(sm->key_mgmt) && sm->fils_ft_ies) {
+ /* MDE and FTE when using FILS+FT */
+ wpabuf_put_buf(buf, sm->fils_ft_ies);
+ /* RSNE with PMKR1Name in PMKID field */
+ if (fils_ft_build_assoc_req_rsne(sm, buf) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
+
+ /* Everything after FILS Session element gets encrypted in the driver
+ * with KEK. The buffer returned from here is the plaintext version. */
+
+ /* TODO: FILS Public Key */
+
+ /* FILS Key Confirm */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + sm->fils_key_auth_len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
+ wpabuf_put_data(buf, sm->fils_key_auth_sta, sm->fils_key_auth_len);
+
+ /* FILS HLP Container */
+ for (i = 0; hlp && i < num_hlp; i++) {
+ const u8 *pos = wpabuf_head(hlp[i]);
+ size_t left = wpabuf_len(hlp[i]);
+
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ if (left <= 254)
+ len = 1 + left;
+ else
+ len = 255;
+ wpabuf_put_u8(buf, len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_HLP_CONTAINER);
+ /* Destination MAC Address, Source MAC Address, HLP Packet.
+ * HLP Packet is in MSDU format (i.e., included the LLC/SNAP
+ * header when LPD is used). */
+ wpabuf_put_data(buf, pos, len - 1);
+ pos += len - 1;
+ left -= len - 1;
+ while (left) {
+ wpabuf_put_u8(buf, WLAN_EID_FRAGMENT);
+ len = left > 255 ? 255 : left;
+ wpabuf_put_u8(buf, len);
+ wpabuf_put_data(buf, pos, len);
+ pos += len;
+ left -= len;
+ }
+ }
+
+ /* TODO: FILS IP Address Assignment */
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "FILS: Failed to get channel info for OCI element");
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ wpa_hexdump_buf(MSG_DEBUG, "FILS: Association Request plaintext", buf);
+
+ *kek = sm->ptk.kek;
+ *kek_len = sm->ptk.kek_len;
+ wpa_hexdump_key(MSG_DEBUG, "FILS: KEK for AEAD", *kek, *kek_len);
+ *snonce = sm->fils_nonce;
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce for AEAD AAD",
+ *snonce, FILS_NONCE_LEN);
+ *anonce = sm->fils_anonce;
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce for AEAD AAD",
+ *anonce, FILS_NONCE_LEN);
+
+ return buf;
+}
+
+
+static void fils_process_hlp_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
+{
+ const u8 *pos, *end;
+
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP response", resp, len);
+ if (len < 2 * ETH_ALEN)
+ return;
+ pos = resp + 2 * ETH_ALEN;
+ end = resp + len;
+ if (end - pos >= 6 &&
+ os_memcmp(pos, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
+ pos += 6; /* Remove SNAP/LLC header */
+ wpa_sm_fils_hlp_rx(sm, resp, resp + ETH_ALEN, pos, end - pos);
+}
+
+
+static void fils_process_hlp_container(struct wpa_sm *sm, const u8 *pos,
+ size_t len)
+{
+ const u8 *end = pos + len;
+ u8 *tmp, *tmp_pos;
+
+ /* Check if there are any FILS HLP Container elements */
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ return;
+ if (pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 + 2 * ETH_ALEN &&
+ pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ pos += 2 + pos[1];
+ }
+ if (end - pos < 2)
+ return; /* No FILS HLP Container elements */
+
+ tmp = os_malloc(end - pos);
+ if (!tmp)
+ return;
+
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos ||
+ pos[0] != WLAN_EID_EXTENSION ||
+ pos[1] < 1 + 2 * ETH_ALEN ||
+ pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ tmp_pos = tmp;
+ os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
+ tmp_pos += pos[1] - 1;
+ pos += 2 + pos[1];
+
+ /* Add possible fragments */
+ while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
+ 2 + pos[1] <= end - pos) {
+ os_memcpy(tmp_pos, pos + 2, pos[1]);
+ tmp_pos += pos[1];
+ pos += 2 + pos[1];
+ }
+
+ fils_process_hlp_resp(sm, tmp, tmp_pos - tmp);
+ }
+
+ os_free(tmp);
+}
+
+
+int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ const u8 *end, *ie_start;
+ struct ieee802_11_elems elems;
+ int keylen, rsclen;
+ enum wpa_alg alg;
+ struct wpa_gtk_data gd;
+ int maxkeylen;
+ struct wpa_eapol_ie_parse kde;
+
+ if (!sm || !sm->ptk_set) {
+ wpa_printf(MSG_DEBUG, "FILS: No KEK available");
+ return -1;
+ }
+
+ if (!wpa_key_mgmt_fils(sm->key_mgmt)) {
+ wpa_printf(MSG_DEBUG, "FILS: Not a FILS AKM");
+ return -1;
+ }
+
+ if (sm->fils_completed) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Association has already been completed for this FILS authentication - ignore unexpected retransmission");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FILS: (Re)Association Response frame",
+ resp, len);
+
+ mgmt = (const struct ieee80211_mgmt *) resp;
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_resp))
+ return -1;
+
+ end = resp + len;
+ /* Same offset for Association Response and Reassociation Response */
+ ie_start = mgmt->u.assoc_resp.variable;
+
+ if (ieee802_11_parse_elems(ie_start, end - ie_start, &elems, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to parse decrypted elements");
+ goto fail;
+ }
+
+ if (!elems.fils_session) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
+ return -1;
+ }
+ if (os_memcmp(elems.fils_session, sm->fils_session,
+ FILS_SESSION_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: FILS Session mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
+ elems.fils_session, FILS_SESSION_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
+ sm->fils_session, FILS_SESSION_LEN);
+ }
+
+ /* TODO: FILS Public Key */
+
+ if (!elems.fils_key_confirm) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
+ goto fail;
+ }
+ if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unexpected Key-Auth length %d (expected %d)",
+ elems.fils_key_confirm_len,
+ (int) sm->fils_key_auth_len);
+ goto fail;
+ }
+ if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_ap,
+ sm->fils_key_auth_len) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
+ elems.fils_key_confirm,
+ elems.fils_key_confirm_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
+ sm->fils_key_auth_ap, sm->fils_key_auth_len);
+ goto fail;
+ }
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in FILS (Re)Association Response frame");
+ goto fail;
+ }
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(sm->key_mgmt) && sm->fils_ft_ies) {
+ struct wpa_ie_data rsn;
+
+ /* Check that PMKR1Name derived by the AP matches */
+ if (!elems.rsn_ie ||
+ wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn) < 0 ||
+ !rsn.pmkid || rsn.num_pmkid != 1 ||
+ os_memcmp(rsn.pmkid, sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS+FT: No RSNE[PMKR1Name] match in AssocResp");
+ goto fail;
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ /* Key Delivery */
+ if (!elems.key_delivery) {
+ wpa_printf(MSG_DEBUG, "FILS: No Key Delivery element");
+ goto fail;
+ }
+
+ /* Parse GTK and set the key to the driver */
+ os_memset(&gd, 0, sizeof(gd));
+ if (wpa_supplicant_parse_ies(elems.key_delivery + WPA_KEY_RSC_LEN,
+ elems.key_delivery_len - WPA_KEY_RSC_LEN,
+ &kde) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to parse KDEs");
+ goto fail;
+ }
+ if (!kde.gtk) {
+ wpa_printf(MSG_DEBUG, "FILS: No GTK KDE");
+ goto fail;
+ }
+ maxkeylen = gd.gtk_len = kde.gtk_len - 2;
+ if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gd.gtk_len, maxkeylen,
+ &gd.key_rsc_len, &gd.alg))
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "FILS: Received GTK", kde.gtk, kde.gtk_len);
+ gd.keyidx = kde.gtk[0] & 0x3;
+ gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
+ !!(kde.gtk[0] & BIT(2)));
+ if (kde.gtk_len - 2 > sizeof(gd.gtk)) {
+ wpa_printf(MSG_DEBUG, "FILS: Too long GTK in GTK KDE (len=%lu)",
+ (unsigned long) kde.gtk_len - 2);
+ goto fail;
+ }
+ os_memcpy(gd.gtk, kde.gtk + 2, kde.gtk_len - 2);
+
+ wpa_printf(MSG_DEBUG, "FILS: Set GTK to driver");
+ if (wpa_supplicant_install_gtk(sm, &gd, elems.key_delivery, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to set GTK");
+ goto fail;
+ }
+
+ if (ieee80211w_set_keys(sm, &kde) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to set IGTK");
+ goto fail;
+ }
+
+ alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+ keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+ if (keylen <= 0 || (unsigned int) keylen != sm->ptk.tk_len) {
+ wpa_printf(MSG_DEBUG, "FILS: TK length mismatch: %u != %lu",
+ keylen, (long unsigned int) sm->ptk.tk_len);
+ goto fail;
+ }
+ rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
+ sm->ptk.tk, keylen);
+ if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
+ sm->ptk.tk, keylen) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
+ MACSTR ")",
+ alg, keylen, MAC2STR(sm->bssid));
+ goto fail;
+ }
+
+ /* TODO: TK could be cleared after auth frame exchange now that driver
+ * takes care of association frame encryption/decryption. */
+ /* TK is not needed anymore in supplicant */
+ os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+ sm->ptk.tk_len = 0;
+ sm->ptk.installed = 1;
+
+ /* FILS HLP Container */
+ fils_process_hlp_container(sm, ie_start, end - ie_start);
+
+ /* TODO: FILS IP Address Assignment */
+
+ wpa_printf(MSG_DEBUG, "FILS: Auth+Assoc completed successfully");
+ sm->fils_completed = 1;
+
+ return 0;
+fail:
+ return -1;
+}
+
+
+void wpa_sm_set_reset_fils_completed(struct wpa_sm *sm, int set)
+{
+ if (sm)
+ sm->fils_completed = !!set;
+}
+
+#endif /* CONFIG_FILS */
+
+
+int wpa_fils_is_completed(struct wpa_sm *sm)
+{
+#ifdef CONFIG_FILS
+ return sm && sm->fils_completed;
+#else /* CONFIG_FILS */
+ return 0;
+#endif /* CONFIG_FILS */
+}
+
+
+#ifdef CONFIG_OWE
+
+struct wpabuf * owe_build_assoc_req(struct wpa_sm *sm, u16 group)
+{
+ struct wpabuf *ie = NULL, *pub = NULL;
+ size_t prime_len;
+
+ if (group == 19)
+ prime_len = 32;
+ else if (group == 20)
+ prime_len = 48;
+ else if (group == 21)
+ prime_len = 66;
+ else
+ return NULL;
+
+ crypto_ecdh_deinit(sm->owe_ecdh);
+ sm->owe_ecdh = crypto_ecdh_init(group);
+ if (!sm->owe_ecdh)
+ goto fail;
+ sm->owe_group = group;
+ pub = crypto_ecdh_get_pubkey(sm->owe_ecdh, 0);
+ pub = wpabuf_zeropad(pub, prime_len);
+ if (!pub)
+ goto fail;
+
+ ie = wpabuf_alloc(5 + wpabuf_len(pub));
+ if (!ie)
+ goto fail;
+ wpabuf_put_u8(ie, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(ie, 1 + 2 + wpabuf_len(pub));
+ wpabuf_put_u8(ie, WLAN_EID_EXT_OWE_DH_PARAM);
+ wpabuf_put_le16(ie, group);
+ wpabuf_put_buf(ie, pub);
+ wpabuf_free(pub);
+ wpa_hexdump_buf(MSG_DEBUG, "OWE: Diffie-Hellman Parameter element",
+ ie);
+
+ return ie;
+fail:
+ wpabuf_free(pub);
+ crypto_ecdh_deinit(sm->owe_ecdh);
+ sm->owe_ecdh = NULL;
+ return NULL;
+}
+
+
+int owe_process_assoc_resp(struct wpa_sm *sm, const u8 *bssid,
+ const u8 *resp_ies, size_t resp_ies_len)
+{
+ struct ieee802_11_elems elems;
+ u16 group;
+ struct wpabuf *secret, *pub, *hkey;
+ int res;
+ u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN];
+ const char *info = "OWE Key Generation";
+ const u8 *addr[2];
+ size_t len[2];
+ size_t hash_len, prime_len;
+ struct wpa_ie_data data;
+
+ if (!resp_ies ||
+ ieee802_11_parse_elems(resp_ies, resp_ies_len, &elems, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_INFO,
+ "OWE: Could not parse Association Response frame elements");
+ return -1;
+ }
+
+ if (sm->cur_pmksa && elems.rsn_ie &&
+ wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, 2 + elems.rsn_ie_len,
+ &data) == 0 &&
+ data.num_pmkid == 1 && data.pmkid &&
+ os_memcmp(sm->cur_pmksa->pmkid, data.pmkid, PMKID_LEN) == 0) {
+ wpa_printf(MSG_DEBUG, "OWE: Use PMKSA caching");
+ wpa_sm_set_pmk_from_pmksa(sm);
+ return 0;
+ }
+
+ if (!elems.owe_dh) {
+ wpa_printf(MSG_INFO,
+ "OWE: No Diffie-Hellman Parameter element found in Association Response frame");
+ return -1;
+ }
+
+ group = WPA_GET_LE16(elems.owe_dh);
+ if (group != sm->owe_group) {
+ wpa_printf(MSG_INFO,
+ "OWE: Unexpected Diffie-Hellman group in response: %u",
+ group);
+ return -1;
+ }
+
+ if (!sm->owe_ecdh) {
+ wpa_printf(MSG_INFO, "OWE: No ECDH state available");
+ return -1;
+ }
+
+ if (group == 19)
+ prime_len = 32;
+ else if (group == 20)
+ prime_len = 48;
+ else if (group == 21)
+ prime_len = 66;
+ else
+ return -1;
+
+ secret = crypto_ecdh_set_peerkey(sm->owe_ecdh, 0,
+ elems.owe_dh + 2,
+ elems.owe_dh_len - 2);
+ secret = wpabuf_zeropad(secret, prime_len);
+ if (!secret) {
+ wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key");
+ return -1;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret);
+
+ /* prk = HKDF-extract(C | A | group, z) */
+
+ pub = crypto_ecdh_get_pubkey(sm->owe_ecdh, 0);
+ if (!pub) {
+ wpabuf_clear_free(secret);
+ return -1;
+ }
+
+ /* PMKID = Truncate-128(Hash(C | A)) */
+ addr[0] = wpabuf_head(pub);
+ len[0] = wpabuf_len(pub);
+ addr[1] = elems.owe_dh + 2;
+ len[1] = elems.owe_dh_len - 2;
+ if (group == 19) {
+ res = sha256_vector(2, addr, len, pmkid);
+ hash_len = SHA256_MAC_LEN;
+ } else if (group == 20) {
+ res = sha384_vector(2, addr, len, pmkid);
+ hash_len = SHA384_MAC_LEN;
+ } else if (group == 21) {
+ res = sha512_vector(2, addr, len, pmkid);
+ hash_len = SHA512_MAC_LEN;
+ } else {
+ res = -1;
+ hash_len = 0;
+ }
+ pub = wpabuf_zeropad(pub, prime_len);
+ if (res < 0 || !pub) {
+ wpabuf_free(pub);
+ wpabuf_clear_free(secret);
+ return -1;
+ }
+
+ hkey = wpabuf_alloc(wpabuf_len(pub) + elems.owe_dh_len - 2 + 2);
+ if (!hkey) {
+ wpabuf_free(pub);
+ wpabuf_clear_free(secret);
+ return -1;
+ }
+
+ wpabuf_put_buf(hkey, pub); /* C */
+ wpabuf_free(pub);
+ wpabuf_put_data(hkey, elems.owe_dh + 2, elems.owe_dh_len - 2); /* A */
+ wpabuf_put_le16(hkey, sm->owe_group); /* group */
+ if (group == 19)
+ res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey),
+ wpabuf_head(secret), wpabuf_len(secret), prk);
+ else if (group == 20)
+ res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey),
+ wpabuf_head(secret), wpabuf_len(secret), prk);
+ else if (group == 21)
+ res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey),
+ wpabuf_head(secret), wpabuf_len(secret), prk);
+ wpabuf_clear_free(hkey);
+ wpabuf_clear_free(secret);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len);
+
+ /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */
+
+ if (group == 19)
+ res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info,
+ os_strlen(info), sm->pmk, hash_len);
+ else if (group == 20)
+ res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info,
+ os_strlen(info), sm->pmk, hash_len);
+ else if (group == 21)
+ res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
+ os_strlen(info), sm->pmk, hash_len);
+ os_memset(prk, 0, SHA512_MAC_LEN);
+ if (res < 0) {
+ sm->pmk_len = 0;
+ return -1;
+ }
+ sm->pmk_len = hash_len;
+
+ wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sm->pmk, sm->pmk_len);
+ wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
+ pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, pmkid, NULL, 0,
+ bssid, sm->own_addr, sm->network_ctx, sm->key_mgmt,
+ NULL);
+
+ return 0;
+}
+
+#endif /* CONFIG_OWE */
+
+
+void wpa_sm_set_fils_cache_id(struct wpa_sm *sm, const u8 *fils_cache_id)
+{
+#ifdef CONFIG_FILS
+ if (sm && fils_cache_id) {
+ sm->fils_cache_id_set = 1;
+ os_memcpy(sm->fils_cache_id, fils_cache_id, FILS_CACHE_ID_LEN);
+ }
+#endif /* CONFIG_FILS */
+}
+
+
+#ifdef CONFIG_DPP2
+void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z)
+{
+ if (sm) {
+ wpabuf_clear_free(sm->dpp_z);
+ sm->dpp_z = z ? wpabuf_dup(z) : NULL;
+ }
+}
+#endif /* CONFIG_DPP2 */
diff --git a/contrib/wpa/src/rsn_supp/wpa.h b/contrib/wpa/src/rsn_supp/wpa.h
index e163b70..8903f8e 100644
--- a/contrib/wpa/src/rsn_supp/wpa.h
+++ b/contrib/wpa/src/rsn_supp/wpa.h
@@ -18,6 +18,7 @@ struct wpa_sm;
struct eapol_sm;
struct wpa_config_blob;
struct hostapd_freq_params;
+struct wpa_channel_info;
struct wpa_sm_ctx {
void *ctx; /* pointer to arbitrary upper level context */
@@ -25,7 +26,7 @@ struct wpa_sm_ctx {
void (*set_state)(void *ctx, enum wpa_states state);
enum wpa_states (*get_state)(void *ctx);
- void (*deauthenticate)(void * ctx, int reason_code);
+ void (*deauthenticate)(void * ctx, int reason_code);
int (*set_key)(void *ctx, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
@@ -38,8 +39,11 @@ struct wpa_sm_ctx {
void (*cancel_auth_timeout)(void *ctx);
u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len,
size_t *msg_len, void **data_pos);
- int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
- int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+ int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
+ const u8 *pmkid, const u8 *fils_cache_id,
+ const u8 *pmk, size_t pmk_len);
+ int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
+ const u8 *pmkid, const u8 *fils_cache_id);
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
const struct wpa_config_blob * (*get_config_blob)(void *ctx,
const char *name);
@@ -77,6 +81,9 @@ struct wpa_sm_ctx {
const u8 *kck, size_t kck_len,
const u8 *replay_ctr);
int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
+ void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
+ const u8 *pkt, size_t pkt_len);
+ int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
};
@@ -90,12 +97,12 @@ enum wpa_sm_conf_params {
WPA_PARAM_KEY_MGMT,
WPA_PARAM_MGMT_GROUP,
WPA_PARAM_RSN_ENABLED,
- WPA_PARAM_MFP
+ WPA_PARAM_MFP,
+ WPA_PARAM_OCV
};
struct rsn_supp_config {
void *network_ctx;
- int peerkey_enabled;
int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
int proactive_key_caching;
int eap_workaround;
@@ -104,6 +111,8 @@ struct rsn_supp_config {
size_t ssid_len;
int wpa_ptk_rekey;
int p2p;
+ int wpa_rsc_relaxation;
+ const u8 *fils_cache_id;
};
#ifndef CONFIG_NO_WPA
@@ -113,7 +122,7 @@ void wpa_sm_deinit(struct wpa_sm *sm);
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
void wpa_sm_notify_disassoc(struct wpa_sm *sm);
void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
- const u8 *bssid);
+ const u8 *pmkid, const u8 *bssid);
void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
@@ -135,6 +144,7 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int wpa_sm_pmf_enabled(struct wpa_sm *sm);
+int wpa_sm_ocv_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -146,6 +156,15 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len);
int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm);
+struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_add_entry(struct wpa_sm *sm,
+ struct rsn_pmksa_cache_entry * entry);
+void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid, const u8 *bssid,
+ const u8 *fils_cache_id);
+int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
+ const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm);
int wpa_sm_has_ptk(struct wpa_sm *sm);
@@ -159,6 +178,7 @@ void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter);
void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
const u8 *ptk_kck, size_t ptk_kck_len,
const u8 *ptk_kek, size_t ptk_kek_len);
+int wpa_fils_is_completed(struct wpa_sm *sm);
#else /* CONFIG_NO_WPA */
@@ -180,7 +200,8 @@ static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm)
}
static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk,
- size_t pmk_len)
+ size_t pmk_len, const u8 *pmkid,
+ const u8 *bssid)
{
}
@@ -262,6 +283,11 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
return 0;
}
+static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
+{
+ return 0;
+}
+
static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
int pairwise)
{
@@ -320,33 +346,25 @@ static inline void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm,
}
static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
- const u8 *ptk_kek)
+ size_t ptk_kck_len,
+ const u8 *ptk_kek, size_t ptk_kek_len)
{
}
-#endif /* CONFIG_NO_WPA */
-
-#ifdef CONFIG_PEERKEY
-int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
-int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
- const u8 *buf, size_t len);
-#else /* CONFIG_PEERKEY */
-static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
-{
- return -1;
-}
-
-static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
- const u8 *buf, size_t len)
+static inline int wpa_fils_is_completed(struct wpa_sm *sm)
{
return 0;
}
-#endif /* CONFIG_PEERKEY */
+
+#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_IEEE80211R
int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie);
+int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len,
+ const u8 *mdie);
+const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm);
int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len);
@@ -371,6 +389,12 @@ static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm,
return 0;
}
+static inline int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len,
+ const u8 *mdie)
+{
+ return 0;
+}
+
static inline int
wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap)
@@ -415,7 +439,32 @@ int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
u8 oper_class,
struct hostapd_freq_params *freq_params);
int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
+#ifdef CONFIG_TDLS_TESTING
+extern unsigned int tdls_testing;
+#endif /* CONFIG_TDLS_TESTING */
+
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
+void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf);
+const u8 * wpa_sm_get_anonce(struct wpa_sm *sm);
+unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm);
+
+struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md);
+int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
+ size_t len);
+struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
+ size_t *kek_len, const u8 **snonce,
+ const u8 **anonce,
+ const struct wpabuf **hlp,
+ unsigned int num_hlp);
+int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len);
+
+struct wpabuf * owe_build_assoc_req(struct wpa_sm *sm, u16 group);
+int owe_process_assoc_resp(struct wpa_sm *sm, const u8 *bssid,
+ const u8 *resp_ies, size_t resp_ies_len);
+
+void wpa_sm_set_reset_fils_completed(struct wpa_sm *sm, int set);
+void wpa_sm_set_fils_cache_id(struct wpa_sm *sm, const u8 *fils_cache_id);
+void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z);
#endif /* WPA_H */
diff --git a/contrib/wpa/src/rsn_supp/wpa_ft.c b/contrib/wpa/src/rsn_supp/wpa_ft.c
index d45bb45..7dcb104 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ft.c
+++ b/contrib/wpa/src/rsn_supp/wpa_ft.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,9 +10,12 @@
#include "common.h"
#include "crypto/aes_wrap.h"
+#include "crypto/sha384.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
@@ -23,6 +26,7 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
{
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *anonce = key->key_nonce;
+ int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
if (sm->xxkey_len == 0) {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
@@ -30,21 +34,26 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
return -1;
}
- wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
- sm->ssid_len, sm->mobility_domain,
- sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
- sm->pmk_r0, sm->pmk_r0_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
+ sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
+ if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
+ sm->ssid_len, sm->mobility_domain,
+ sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
+ sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, sm->pmk_r0_len);
wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
sm->pmk_r0_name, WPA_PMK_NAME_LEN);
- wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
- sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+ sm->pmk_r1_len = sm->pmk_r0_len;
+ if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
+ sm->r1kh_id, sm->own_addr, sm->pmk_r1,
+ sm->pmk_r1_name) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
WPA_PMK_NAME_LEN);
- return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
- sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
- sm->key_mgmt, sm->pairwise_cipher);
+ return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
+ sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
+ ptk_name, sm->key_mgmt, sm->pairwise_cipher);
}
@@ -58,11 +67,13 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
{
struct wpa_ft_ies ft;
+ int use_sha384;
if (sm == NULL)
return 0;
- if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0)
+ use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+ if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0)
return -1;
if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
@@ -146,16 +157,17 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
const u8 *ap_mdie)
{
size_t buf_len;
- u8 *buf, *pos, *ftie_len, *ftie_pos;
+ u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count;
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
struct rsn_ie_hdr *rsnie;
u16 capab;
+ int mdie_len;
sm->ft_completed = 0;
sm->ft_reassoc_completed = 0;
- buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
+ buf_len = 2 + sizeof(struct rsn_mdie) + 2 +
+ sizeof(struct rsn_ftie_sha384) +
2 + sm->r0kh_id_len + ric_ies_len + 100;
buf = os_zalloc(buf_len);
if (buf == NULL)
@@ -201,10 +213,20 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
/* Authenticated Key Management Suite List */
if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+#ifdef CONFIG_SHA384
+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+#endif /* CONFIG_SHA384 */
else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+#ifdef CONFIG_FILS
+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
+#endif /* CONFIG_FILS */
else {
wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)",
sm->key_mgmt);
@@ -216,9 +238,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
/* RSN Capabilities */
capab = 0;
#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ||
+ sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_128 ||
+ sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_256 ||
+ sm->mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256)
capab |= WPA_CAPABILITY_MFPC;
#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -231,34 +258,63 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += WPA_PMK_NAME_LEN;
#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
- /* Management Group Cipher Suite */
+ /* Management Group Cipher Suite */
+ switch (sm->mgmt_group_cipher) {
+ case WPA_CIPHER_AES_128_CMAC:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
+ break;
+ case WPA_CIPHER_BIP_GMAC_128:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
+ pos += RSN_SELECTOR_LEN;
+ break;
+ case WPA_CIPHER_BIP_GMAC_256:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
+ pos += RSN_SELECTOR_LEN;
+ break;
+ case WPA_CIPHER_BIP_CMAC_256:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
+ pos += RSN_SELECTOR_LEN;
+ break;
}
#endif /* CONFIG_IEEE80211W */
rsnie->len = (pos - (u8 *) rsnie) - 2;
/* MDIE */
- *pos++ = WLAN_EID_MOBILITY_DOMAIN;
- *pos++ = sizeof(*mdie);
- mdie = (struct rsn_mdie *) pos;
- pos += sizeof(*mdie);
- os_memcpy(mdie->mobility_domain, sm->mobility_domain,
- MOBILITY_DOMAIN_ID_LEN);
- mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
- sm->mdie_ft_capab;
+ mdie_len = wpa_ft_add_mdie(sm, pos, buf_len - (pos - buf), ap_mdie);
+ if (mdie_len <= 0) {
+ os_free(buf);
+ return NULL;
+ }
+ mdie = (struct rsn_mdie *) (pos + 2);
+ pos += mdie_len;
/* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */
ftie_pos = pos;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ftie_len = pos++;
- ftie = (struct rsn_ftie *) pos;
- pos += sizeof(*ftie);
- os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
- if (anonce)
- os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+ if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
+ struct rsn_ftie_sha384 *ftie;
+
+ ftie = (struct rsn_ftie_sha384 *) pos;
+ fte_mic = ftie->mic;
+ elem_count = &ftie->mic_control[1];
+ pos += sizeof(*ftie);
+ os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
+ if (anonce)
+ os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) pos;
+ fte_mic = ftie->mic;
+ elem_count = &ftie->mic_control[1];
+ pos += sizeof(*ftie);
+ os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
+ if (anonce)
+ os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+ }
if (kck) {
/* R1KH-ID sub-element in third FT message */
*pos++ = FTIE_SUBELEM_R1KH_ID;
@@ -271,6 +327,26 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
*pos++ = sm->r0kh_id_len;
os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
pos += sm->r0kh_id_len;
+#ifdef CONFIG_OCV
+ if (kck && wpa_sm_ocv_enabled(sm)) {
+ /* OCI sub-element in the third FT message */
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in FTE");
+ os_free(buf);
+ return NULL;
+ }
+
+ *pos++ = FTIE_SUBELEM_OCI;
+ *pos++ = OCV_OCI_LEN;
+ if (ocv_insert_oci(&ci, &pos) < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
*ftie_len = pos - ftie_len - 1;
if (ric_ies) {
@@ -292,13 +368,12 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
* RIC-Request (if present)
*/
/* Information element count */
- ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
- ric_ies_len);
+ *elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
- ric_ies_len, ftie->mic) < 0) {
+ ric_ies_len, fte_mic) < 0) {
wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
os_free(buf);
return NULL;
@@ -367,6 +442,37 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
}
+int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *buf, size_t buf_len,
+ const u8 *ap_mdie)
+{
+ u8 *pos = buf;
+ struct rsn_mdie *mdie;
+
+ if (buf_len < 2 + sizeof(*mdie)) {
+ wpa_printf(MSG_INFO,
+ "FT: Failed to add MDIE: short buffer, length=%zu",
+ buf_len);
+ return 0;
+ }
+
+ *pos++ = WLAN_EID_MOBILITY_DOMAIN;
+ *pos++ = sizeof(*mdie);
+ mdie = (struct rsn_mdie *) pos;
+ os_memcpy(mdie->mobility_domain, sm->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN);
+ mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
+ sm->mdie_ft_capab;
+
+ return 2 + sizeof(*mdie);
+}
+
+
+const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm)
+{
+ return sm->mobility_domain;
+}
+
+
int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len)
@@ -375,10 +481,13 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
size_t ft_ies_len;
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
u8 ptk_name[WPA_PMK_NAME_LEN];
int ret;
const u8 *bssid;
+ const u8 *kck;
+ size_t kck_len;
+ int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+ const u8 *anonce, *snonce;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
@@ -404,7 +513,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
return -1;
}
- if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
return -1;
}
@@ -417,16 +526,34 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
return -1;
}
- ftie = (struct rsn_ftie *) parse.ftie;
- if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
- wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
- return -1;
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *ftie;
+
+ ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return -1;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return -1;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
}
- if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
- ftie->snonce, WPA_NONCE_LEN);
+ snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->snonce, WPA_NONCE_LEN);
return -1;
@@ -465,23 +592,34 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
- os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
- wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
- sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
+ os_memcpy(sm->anonce, anonce, WPA_NONCE_LEN);
+ if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
+ sm->r1kh_id, sm->own_addr, sm->pmk_r1,
+ sm->pmk_r1_name) < 0)
+ return -1;
+ sm->pmk_r1_len = sm->pmk_r0_len;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
- if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
- sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
- ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
+ if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
+ anonce, sm->own_addr, bssid,
+ sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt,
+ sm->pairwise_cipher) < 0)
return -1;
- ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kck = sm->ptk.kck2;
+ kck_len = sm->ptk.kck2_len;
+ } else {
+ kck = sm->ptk.kck;
+ kck_len = sm->ptk.kck_len;
+ }
+ ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, anonce,
sm->pmk_r1_name,
- sm->ptk.kck, sm->ptk.kck_len, bssid,
+ kck, kck_len, bssid,
ric_ies, ric_ies_len,
parse.mdie ? parse.mdie - 2 : NULL);
if (ft_ies) {
@@ -544,6 +682,16 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
int keyidx;
enum wpa_alg alg;
size_t gtk_len, keylen, rsc_len;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
if (gtk_elem == NULL) {
wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
@@ -560,8 +708,7 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
return -1;
}
gtk_len = gtk_elem_len - 19;
- if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
- gtk)) {
+ if (aes_unwrap(kek, kek_len, gtk_len / 8, gtk_elem + 11, gtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt GTK");
return -1;
@@ -615,10 +762,24 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
size_t igtk_elem_len)
{
- u8 igtk[WPA_IGTK_LEN];
+ u8 igtk[WPA_IGTK_MAX_LEN];
+ size_t igtk_len;
u16 keyidx;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
- if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+ if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_128 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_CMAC_256)
return 0;
if (igtk_elem == NULL) {
@@ -629,19 +790,19 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
igtk_elem, igtk_elem_len);
- if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
+ igtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (igtk_elem_len != 2 + 6 + 1 + igtk_len + 8) {
wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
"length %lu", (unsigned long) igtk_elem_len);
return -1;
}
- if (igtk_elem[8] != WPA_IGTK_LEN) {
+ if (igtk_elem[8] != igtk_len) {
wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
"%d", igtk_elem[8]);
return -1;
}
- if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
- igtk_elem + 9, igtk)) {
+ if (aes_unwrap(kek, kek_len, igtk_len / 8, igtk_elem + 9, igtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt IGTK");
return -1;
@@ -652,13 +813,16 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
keyidx = WPA_GET_LE16(igtk_elem);
wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
- WPA_IGTK_LEN);
- if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0,
- igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) {
+ igtk_len);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr, keyidx, 0,
+ igtk_elem + 2, 6, igtk, igtk_len) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
"driver.");
+ os_memset(igtk, 0, sizeof(igtk));
return -1;
}
+ os_memset(igtk, 0, sizeof(igtk));
return 0;
}
@@ -670,9 +834,13 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
{
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
unsigned int count;
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ const u8 *kck;
+ size_t kck_len;
+ int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+ const u8 *anonce, *snonce, *fte_mic;
+ u8 fte_elem_count;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@@ -687,7 +855,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return 0;
}
- if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
return -1;
}
@@ -700,25 +868,47 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- ftie = (struct rsn_ftie *) parse.ftie;
- if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
- wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
- return -1;
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *ftie;
+
+ ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return -1;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ fte_elem_count = ftie->mic_control[1];
+ fte_mic = ftie->mic;
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return -1;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ fte_elem_count = ftie->mic_control[1];
+ fte_mic = ftie->mic;
}
- if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
- ftie->snonce, WPA_NONCE_LEN);
+ snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->snonce, WPA_NONCE_LEN);
return -1;
}
- if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
- ftie->anonce, WPA_NONCE_LEN);
+ anonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
sm->anonce, WPA_NONCE_LEN);
return -1;
@@ -763,14 +953,22 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
- if (ftie->mic_control[1] != count) {
+ if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
- ftie->mic_control[1], count);
+ fte_elem_count, count);
return -1;
}
- if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kck = sm->ptk.kck2;
+ kck_len = sm->ptk.kck2_len;
+ } else {
+ kck = sm->ptk.kck;
+ kck_len = sm->ptk.kck_len;
+ }
+
+ if (wpa_ft_mic(kck, kck_len, sm->own_addr, src_addr, 6,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -780,13 +978,32 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, fte_mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
- wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", fte_mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
return -1;
}
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in (Re)Assoc Response");
+ return -1;
+ }
+
+ if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
sm->ft_reassoc_completed = 1;
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
diff --git a/contrib/wpa/src/rsn_supp/wpa_i.h b/contrib/wpa/src/rsn_supp/wpa_i.h
index 85cc862..0c5955c 100644
--- a/contrib/wpa/src/rsn_supp/wpa_i.h
+++ b/contrib/wpa/src/rsn_supp/wpa_i.h
@@ -1,6 +1,6 @@
/*
* Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,7 +11,6 @@
#include "utils/list.h"
-struct wpa_peerkey;
struct wpa_tdls_peer;
struct wpa_eapol_key;
@@ -19,7 +18,7 @@ struct wpa_eapol_key;
* struct wpa_sm - Internal WPA state machine data
*/
struct wpa_sm {
- u8 pmk[PMK_LEN];
+ u8 pmk[PMK_LEN_MAX];
size_t pmk_len;
struct wpa_ptk ptk, tptk;
int ptk_set, tptk_set;
@@ -57,7 +56,6 @@ struct wpa_sm {
int fast_reauth; /* whether EAP fast re-authentication is enabled */
void *network_ctx;
- int peerkey_enabled;
int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
int proactive_key_caching;
int eap_workaround;
@@ -66,6 +64,7 @@ struct wpa_sm {
size_t ssid_len;
int wpa_ptk_rekey;
int p2p;
+ int wpa_rsc_relaxation;
u8 own_addr[ETH_ALEN];
const char *ifname;
@@ -87,15 +86,13 @@ struct wpa_sm {
int rsn_enabled; /* Whether RSN is enabled in configuration */
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
+ int ocv; /* Operating Channel Validation */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
u8 *ap_wpa_ie, *ap_rsn_ie;
size_t ap_wpa_ie_len, ap_rsn_ie_len;
-#ifdef CONFIG_PEERKEY
- struct wpa_peerkey *peerkey;
-#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
int tdls_prohibited;
@@ -116,18 +113,22 @@ struct wpa_sm {
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
- u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+ u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
+ * first 384 bits of MSK */
size_t xxkey_len;
- u8 pmk_r0[PMK_LEN];
+ u8 pmk_r0[PMK_LEN_MAX];
+ size_t pmk_r0_len;
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
- u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
size_t r0kh_id_len;
u8 r1kh_id[FT_R1KH_ID_LEN];
- int ft_completed;
- int ft_reassoc_completed;
+ unsigned int ft_completed:1;
+ unsigned int ft_reassoc_completed:1;
+ unsigned int ft_protocol:1;
int over_the_ds_in_progress;
u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
int set_ptk_after_assoc;
@@ -139,6 +140,39 @@ struct wpa_sm {
#ifdef CONFIG_P2P
u8 p2p_ip_addr[3 * 4];
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ struct wpabuf *test_assoc_ie;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_FILS
+ u8 fils_nonce[FILS_NONCE_LEN];
+ u8 fils_session[FILS_SESSION_LEN];
+ u8 fils_anonce[FILS_NONCE_LEN];
+ u8 fils_key_auth_ap[FILS_MAX_KEY_AUTH_LEN];
+ u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
+ size_t fils_key_auth_len;
+ unsigned int fils_completed:1;
+ unsigned int fils_erp_pmkid_set:1;
+ unsigned int fils_cache_id_set:1;
+ u8 fils_erp_pmkid[PMKID_LEN];
+ u8 fils_cache_id[FILS_CACHE_ID_LEN];
+ struct crypto_ecdh *fils_ecdh;
+ int fils_dh_group;
+ size_t fils_dh_elem_len;
+ struct wpabuf *fils_ft_ies;
+ u8 fils_ft[FILS_FT_MAX_LEN];
+ size_t fils_ft_len;
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+ struct crypto_ecdh *owe_ecdh;
+ u16 owe_group;
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ struct wpabuf *dpp_z;
+#endif /* CONFIG_DPP2 */
};
@@ -210,18 +244,23 @@ static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
msg_len, data_pos);
}
-static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid,
- const u8 *pmkid)
+static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
+ const u8 *bssid, const u8 *pmkid,
+ const u8 *cache_id, const u8 *pmk,
+ size_t pmk_len)
{
WPA_ASSERT(sm->ctx->add_pmkid);
- return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid);
+ return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
+ cache_id, pmk, pmk_len);
}
-static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid,
- const u8 *pmkid)
+static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
+ const u8 *bssid, const u8 *pmkid,
+ const u8 *cache_id)
{
WPA_ASSERT(sm->ctx->remove_pmkid);
- return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid);
+ return sm->ctx->remove_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
+ cache_id);
}
static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,
@@ -349,16 +388,31 @@ wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr)
static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm,
const u8 *pmk, size_t pmk_len)
{
- if (!sm->proactive_key_caching)
- return 0;
if (!sm->ctx->key_mgmt_set_pmk)
return -1;
return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
}
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
- int ver, const u8 *dest, u16 proto,
- u8 *msg, size_t msg_len, u8 *key_mic);
+static inline void wpa_sm_fils_hlp_rx(struct wpa_sm *sm,
+ const u8 *dst, const u8 *src,
+ const u8 *pkt, size_t pkt_len)
+{
+ if (sm->ctx->fils_hlp_rx)
+ sm->ctx->fils_hlp_rx(sm->ctx->ctx, dst, src, pkt, pkt_len);
+}
+
+static inline int wpa_sm_channel_info(struct wpa_sm *sm,
+ struct wpa_channel_info *ci)
+{
+ if (!sm->ctx->channel_info)
+ return -1;
+ return sm->ctx->channel_info(sm->ctx->ctx, ci);
+}
+
+
+int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
+ int ver, const u8 *dest, u16 proto,
+ u8 *msg, size_t msg_len, u8 *key_mic);
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
const struct wpa_eapol_key *key,
int ver, const u8 *nonce,
diff --git a/contrib/wpa/src/rsn_supp/wpa_ie.c b/contrib/wpa/src/rsn_supp/wpa_ie.c
index 0c37b35..ae9f4ca 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ie.c
+++ b/contrib/wpa/src/rsn_supp/wpa_ie.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -161,6 +161,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
#ifdef CONFIG_IEEE80211R
} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+#ifdef CONFIG_SHA384
+ } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+#endif /* CONFIG_SHA384 */
} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
#endif /* CONFIG_IEEE80211R */
@@ -180,6 +184,30 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
+#ifdef CONFIG_FILS
+ } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
+ } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
+#ifdef CONFIG_IEEE80211R
+ } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
+ } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ } else if (key_mgmt & WPA_KEY_MGMT_OWE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ } else if (key_mgmt & WPA_KEY_MGMT_DPP) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ } else if (key_mgmt & WPA_KEY_MGMT_OSEN) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+#endif /* CONFIG_HS20 */
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -195,6 +223,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
if (sm->mfp == 2)
capab |= WPA_CAPABILITY_MFPR;
#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -378,7 +408,7 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
- if (pos + 1 + RSN_SELECTOR_LEN < end &&
+ if (1 + RSN_SELECTOR_LEN < end - pos &&
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
@@ -405,44 +435,6 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
-#ifdef CONFIG_PEERKEY
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
- ie->smk = pos + 2 + RSN_SELECTOR_LEN;
- ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
- ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
- ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
- ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
- ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
- ie->error = pos + 2 + RSN_SELECTOR_LEN;
- ie->error_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-#endif /* CONFIG_PEERKEY */
-
#ifdef CONFIG_IEEE80211W
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
@@ -473,6 +465,17 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
@@ -491,13 +494,13 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
int ret = 0;
os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+ for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
if (pos[0] == 0xdd &&
((pos == buf + len - 1) || pos[1] == 0)) {
/* Ignore padding */
break;
}
- if (pos + 2 + pos[1] > end) {
+ if (2 + pos[1] > end - pos) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
"underflow (ie=%d len=%d pos=%d)",
pos[0], pos[1], (int) (pos - buf));
diff --git a/contrib/wpa/src/rsn_supp/wpa_ie.h b/contrib/wpa/src/rsn_supp/wpa_ie.h
index fe95af0..9d53973 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ie.h
+++ b/contrib/wpa/src/rsn_supp/wpa_ie.h
@@ -21,16 +21,6 @@ struct wpa_eapol_ie_parse {
size_t gtk_len;
const u8 *mac_addr;
size_t mac_addr_len;
-#ifdef CONFIG_PEERKEY
- const u8 *smk;
- size_t smk_len;
- const u8 *nonce;
- size_t nonce_len;
- const u8 *lifetime;
- size_t lifetime_len;
- const u8 *error;
- size_t error_len;
-#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
const u8 *igtk;
size_t igtk_len;
@@ -63,6 +53,10 @@ struct wpa_eapol_ie_parse {
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/contrib/wpa/src/tls/asn1.c b/contrib/wpa/src/tls/asn1.c
index cec1092..822f87c 100644
--- a/contrib/wpa/src/tls/asn1.c
+++ b/contrib/wpa/src/tls/asn1.c
@@ -31,6 +31,10 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
pos = buf;
end = buf + len;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
+ return -1;
+ }
hdr->identifier = *pos++;
hdr->class = hdr->identifier >> 6;
hdr->constructed = !!(hdr->identifier & (1 << 5));
@@ -51,6 +55,10 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
} else
hdr->tag = hdr->identifier & 0x1f;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
+ return -1;
+ }
tmp = *pos++;
if (tmp & 0x80) {
if (tmp == 0xff) {
diff --git a/contrib/wpa/src/tls/asn1.h b/contrib/wpa/src/tls/asn1.h
index 7475007..6bd7df5 100644
--- a/contrib/wpa/src/tls/asn1.h
+++ b/contrib/wpa/src/tls/asn1.h
@@ -20,6 +20,7 @@
#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */
#define ASN1_TAG_REAL 0x09 /* not yet parsed */
#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */
+#define ASN1_TAG_EMBEDDED_PDV 0x0B /* not yet parsed */
#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */
#define ANS1_TAG_RELATIVE_OID 0x0D
#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */
@@ -35,7 +36,8 @@
#define ASN1_TAG_VISIBLESTRING 0x1A
#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */
#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */
-#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */
+#define ASN1_TAG_CHARACTERSTRING 0x1D /* not yet parsed */
+#define ASN1_TAG_BMPSTRING 0x1E /* not yet parsed */
#define ASN1_CLASS_UNIVERSAL 0
#define ASN1_CLASS_APPLICATION 1
diff --git a/contrib/wpa/src/tls/bignum.c b/contrib/wpa/src/tls/bignum.c
index f3baafe..1a87c82 100644
--- a/contrib/wpa/src/tls/bignum.c
+++ b/contrib/wpa/src/tls/bignum.c
@@ -119,10 +119,10 @@ int bignum_cmp(const struct bignum *a, const struct bignum *b)
/**
- * bignum_cmd_d - Compare bignum to standard integer
+ * bignum_cmp_d - Compare bignum to standard integer
* @a: Bignum from bignum_init()
* @b: Small integer
- * Returns: 0 on success, -1 on failure
+ * Returns: -1 if a < b, 0 if a == b, 1 if a > b
*/
int bignum_cmp_d(const struct bignum *a, unsigned long b)
{
diff --git a/contrib/wpa/src/tls/libtommath.c b/contrib/wpa/src/tls/libtommath.c
index 8bc824f..4f7a148 100644
--- a/contrib/wpa/src/tls/libtommath.c
+++ b/contrib/wpa/src/tls/libtommath.c
@@ -116,7 +116,7 @@ typedef int mp_err;
#define MP_PREC 32 /* default digits of precision */
#else
#define MP_PREC 8 /* default digits of precision */
- #endif
+ #endif
#endif
/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
@@ -274,8 +274,8 @@ static int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
*tmpc++ &= MP_MASK;
}
- /* now copy higher words if any, that is in A+B
- * if A or B has more digits add those in
+ /* now copy higher words if any, that is in A+B
+ * if A or B has more digits add those in
*/
if (min != max) {
for (; i < max; i++) {
@@ -499,29 +499,29 @@ static int mp_mul (mp_int * a, mp_int * b, mp_int * c)
#ifdef BN_MP_TOOM_MUL_C
if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
res = mp_toom_mul(a, b, c);
- } else
+ } else
#endif
#ifdef BN_MP_KARATSUBA_MUL_C
/* use Karatsuba? */
if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
res = mp_karatsuba_mul (a, b, c);
- } else
+ } else
#endif
{
/* can we use the fast multiplier?
*
- * The fast multiplier can be used if the output will
- * have less than MP_WARRAY digits and the number of
+ * The fast multiplier can be used if the output will
+ * have less than MP_WARRAY digits and the number of
* digits won't affect carry propagation
*/
#ifdef BN_FAST_S_MP_MUL_DIGS_C
int digs = a->used + b->used + 1;
if ((digs < MP_WARRAY) &&
- MIN(a->used, b->used) <=
+ MIN(a->used, b->used) <=
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
res = fast_s_mp_mul_digs (a, b, c, digs);
- } else
+ } else
#endif
#ifdef BN_S_MP_MUL_DIGS_C
res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
@@ -629,7 +629,7 @@ static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
err = mp_exptmod(&tmpG, &tmpX, P, Y);
mp_clear_multi(&tmpG, &tmpX, NULL);
return err;
-#else
+#else
#error mp_exptmod would always fail
/* no invmod */
return MP_VAL;
@@ -658,7 +658,7 @@ static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
dr = mp_reduce_is_2k(P) << 1;
}
#endif
-
+
/* if the modulus is odd or dr != 0 use the montgomery method */
#ifdef BN_MP_EXPTMOD_FAST_C
if (mp_isodd (P) == 1 || dr != 0) {
@@ -693,7 +693,7 @@ static int mp_cmp (mp_int * a, mp_int * b)
return MP_GT;
}
}
-
+
/* compare digits */
if (a->sign == MP_NEG) {
/* if negative compare opposite direction */
@@ -779,7 +779,7 @@ static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
}
/* init temps */
- if ((res = mp_init_multi(&x, &y, &u, &v,
+ if ((res = mp_init_multi(&x, &y, &u, &v,
&A, &B, &C, &D, NULL)) != MP_OKAY) {
return res;
}
@@ -906,14 +906,14 @@ top:
goto LBL_ERR;
}
}
-
+
/* too big */
while (mp_cmp_mag(&C, b) != MP_LT) {
if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
goto LBL_ERR;
}
}
-
+
/* C is now the inverse */
mp_exch (&C, c);
res = MP_OKAY;
@@ -933,7 +933,7 @@ static int mp_cmp_mag (mp_int * a, mp_int * b)
if (a->used > b->used) {
return MP_GT;
}
-
+
if (a->used < b->used) {
return MP_LT;
}
@@ -1199,8 +1199,8 @@ static void mp_rshd (mp_int * a, int b)
/* top [offset into digits] */
top = a->dp + b;
- /* this is implemented as a sliding window where
- * the window is b-digits long and digits from
+ /* this is implemented as a sliding window where
+ * the window is b-digits long and digits from
* the top of the window are copied to the bottom
*
* e.g.
@@ -1218,13 +1218,13 @@ static void mp_rshd (mp_int * a, int b)
*bottom++ = 0;
}
}
-
+
/* remove excess digits */
a->used -= b;
}
-/* swap the elements of two integers, for cases where you can't simply swap the
+/* swap the elements of two integers, for cases where you can't simply swap the
* mp_int pointers around
*/
static void mp_exch (mp_int * a, mp_int * b)
@@ -1237,7 +1237,7 @@ static void mp_exch (mp_int * a, mp_int * b)
}
-/* trim unused digits
+/* trim unused digits
*
* This is used to ensure that leading zero digits are
* trimed and the leading "used" digit will be non-zero
@@ -1298,7 +1298,7 @@ static int mp_grow (mp_int * a, int size)
#ifdef BN_MP_ABS_C
-/* b = |a|
+/* b = |a|
*
* Simple function copies the input and fixes the sign to positive
*/
@@ -1434,7 +1434,7 @@ static int mp_mul_2d (mp_int * a, int b, mp_int * c)
/* set the carry to the carry bits of the current word */
r = rr;
}
-
+
/* set final carry */
if (r != 0) {
c->dp[(c->used)++] = r;
@@ -1446,7 +1446,7 @@ static int mp_mul_2d (mp_int * a, int b, mp_int * c)
#ifdef BN_MP_INIT_MULTI_C
-static int mp_init_multi(mp_int *mp, ...)
+static int mp_init_multi(mp_int *mp, ...)
{
mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
int n = 0; /* Number of ok inits */
@@ -1460,11 +1460,11 @@ static int mp_init_multi(mp_int *mp, ...)
succeeded in init-ing, then return error.
*/
va_list clean_args;
-
+
/* end the current list */
va_end(args);
-
- /* now start cleaning up */
+
+ /* now start cleaning up */
cur_arg = mp;
va_start(clean_args, mp);
while (n--) {
@@ -1484,7 +1484,7 @@ static int mp_init_multi(mp_int *mp, ...)
#ifdef BN_MP_CLEAR_MULTI_C
-static void mp_clear_multi(mp_int *mp, ...)
+static void mp_clear_multi(mp_int *mp, ...)
{
mp_int* next_mp = mp;
va_list args;
@@ -1558,7 +1558,7 @@ static int mp_count_bits (mp_int * a)
/* get number of digits and add that */
r = (a->used - 1) * DIGIT_BIT;
-
+
/* take the last digit and count the bits in it */
q = a->dp[a->used - 1];
while (q > ((mp_digit) 0)) {
@@ -1628,7 +1628,7 @@ static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
}
return res;
}
-
+
/* init our temps */
if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
return res;
@@ -1638,7 +1638,7 @@ static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
mp_set(&tq, 1);
n = mp_count_bits(a) - mp_count_bits(b);
if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
- ((res = mp_abs(b, &tb)) != MP_OKAY) ||
+ ((res = mp_abs(b, &tb)) != MP_OKAY) ||
((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
goto LBL_ERR;
@@ -1675,17 +1675,17 @@ LBL_ERR:
#else
-/* integer signed division.
+/* integer signed division.
* c*b + d == a [e.g. a/b, c=quotient, d=remainder]
* HAC pp.598 Algorithm 14.20
*
- * Note that the description in HAC is horribly
- * incomplete. For example, it doesn't consider
- * the case where digits are removed from 'x' in
- * the inner loop. It also doesn't consider the
+ * Note that the description in HAC is horribly
+ * incomplete. For example, it doesn't consider
+ * the case where digits are removed from 'x' in
+ * the inner loop. It also doesn't consider the
* case that y has fewer than three digits, etc..
*
- * The overall algorithm is as described as
+ * The overall algorithm is as described as
* 14.20 from HAC but fixed to treat these cases.
*/
static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
@@ -1775,7 +1775,7 @@ static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
continue;
}
- /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
+ /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
* otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
if (x.dp[i] == y.dp[t]) {
q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
@@ -1789,10 +1789,10 @@ static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
}
- /* while (q{i-t-1} * (yt * b + y{t-1})) >
- xi * b**2 + xi-1 * b + xi-2
-
- do q{i-t-1} -= 1;
+ /* while (q{i-t-1} * (yt * b + y{t-1})) >
+ xi * b**2 + xi-1 * b + xi-2
+
+ do q{i-t-1} -= 1;
*/
q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
do {
@@ -1843,10 +1843,10 @@ static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
}
}
- /* now q is the quotient and x is the remainder
- * [which we have to normalize]
+ /* now q is the quotient and x is the remainder
+ * [which we have to normalize]
*/
-
+
/* get sign before writing to c */
x.sign = x.used == 0 ? MP_ZPOS : a->sign;
@@ -1914,7 +1914,7 @@ static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int red
/* init M array */
/* init first cell */
if ((err = mp_init(&M[1])) != MP_OKAY) {
- return err;
+ return err;
}
/* now init the second half of the array */
@@ -1932,7 +1932,7 @@ static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int red
if ((err = mp_init (&mu)) != MP_OKAY) {
goto LBL_M;
}
-
+
if (redmode == 0) {
if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
goto LBL_MU;
@@ -1943,22 +1943,22 @@ static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int red
goto LBL_MU;
}
redux = mp_reduce_2k_l;
- }
+ }
/* create M table
*
- * The M table contains powers of the base,
+ * The M table contains powers of the base,
* e.g. M[x] = G**x mod P
*
- * The first half of the table is not
+ * The first half of the table is not
* computed though accept for M[0] and M[1]
*/
if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
goto LBL_MU;
}
- /* compute the value at M[1<<(winsize-1)] by squaring
- * M[1] (winsize-1) times
+ /* compute the value at M[1<<(winsize-1)] by squaring
+ * M[1] (winsize-1) times
*/
if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
goto LBL_MU;
@@ -1966,7 +1966,7 @@ static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int red
for (x = 0; x < (winsize - 1); x++) {
/* square it */
- if ((err = mp_sqr (&M[1 << (winsize - 1)],
+ if ((err = mp_sqr (&M[1 << (winsize - 1)],
&M[1 << (winsize - 1)])) != MP_OKAY) {
goto LBL_MU;
}
@@ -2117,18 +2117,18 @@ static int mp_sqr (mp_int * a, mp_int * b)
if (a->used >= TOOM_SQR_CUTOFF) {
res = mp_toom_sqr(a, b);
/* Karatsuba? */
- } else
+ } else
#endif
#ifdef BN_MP_KARATSUBA_SQR_C
if (a->used >= KARATSUBA_SQR_CUTOFF) {
res = mp_karatsuba_sqr (a, b);
- } else
+ } else
#endif
{
#ifdef BN_FAST_S_MP_SQR_C
/* can we use the fast comba multiplier? */
- if ((a->used * 2 + 1) < MP_WARRAY &&
- a->used <
+ if ((a->used * 2 + 1) < MP_WARRAY &&
+ a->used <
(1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
res = fast_s_mp_sqr (a, b);
} else
@@ -2145,7 +2145,7 @@ if (a->used >= KARATSUBA_SQR_CUTOFF) {
}
-/* reduces a modulo n where n is of the form 2**p - d
+/* reduces a modulo n where n is of the form 2**p - d
This differs from reduce_2k since "d" can be larger
than a single digit.
*/
@@ -2153,33 +2153,33 @@ static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
{
mp_int q;
int p, res;
-
+
if ((res = mp_init(&q)) != MP_OKAY) {
return res;
}
-
- p = mp_count_bits(n);
+
+ p = mp_count_bits(n);
top:
/* q = a/2**p, a = a mod 2**p */
if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
goto ERR;
}
-
+
/* q = q * d */
- if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
+ if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
goto ERR;
}
-
+
/* a = a + q */
if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
goto ERR;
}
-
+
if (mp_cmp_mag(a, n) != MP_LT) {
s_mp_sub(a, n, a);
goto top;
}
-
+
ERR:
mp_clear(&q);
return res;
@@ -2191,26 +2191,26 @@ static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
{
int res;
mp_int tmp;
-
+
if ((res = mp_init(&tmp)) != MP_OKAY) {
return res;
}
-
+
if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
goto ERR;
}
-
+
if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
goto ERR;
}
-
+
ERR:
mp_clear(&tmp);
return res;
}
-/* computes a = 2**b
+/* computes a = 2**b
*
* Simple algorithm which zeroes the int, grows it then just sets one bit
* as required.
@@ -2243,7 +2243,7 @@ static int mp_2expt (mp_int * a, int b)
static int mp_reduce_setup (mp_int * a, mp_int * b)
{
int res;
-
+
if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
return res;
}
@@ -2251,7 +2251,7 @@ static int mp_reduce_setup (mp_int * a, mp_int * b)
}
-/* reduces x mod m, assumes 0 < x < m**2, mu is
+/* reduces x mod m, assumes 0 < x < m**2, mu is
* precomputed via mp_reduce_setup.
* From HAC pp.604 Algorithm 14.42
*/
@@ -2266,7 +2266,7 @@ static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
}
/* q1 = x / b**(k-1) */
- mp_rshd (&q, um - 1);
+ mp_rshd (&q, um - 1);
/* according to HAC this optimization is ok */
if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
@@ -2282,8 +2282,8 @@ static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
goto CLEANUP;
}
-#else
- {
+#else
+ {
#error mp_reduce would always fail
res = MP_VAL;
goto CLEANUP;
@@ -2292,7 +2292,7 @@ static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
}
/* q3 = q2 / b**(k+1) */
- mp_rshd (&q, um + 1);
+ mp_rshd (&q, um + 1);
/* x = x mod b**(k+1), quick (no division) */
if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
@@ -2326,7 +2326,7 @@ static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
goto CLEANUP;
}
}
-
+
CLEANUP:
mp_clear (&q);
@@ -2335,7 +2335,7 @@ CLEANUP:
/* multiplies |a| * |b| and only computes up to digs digits of result
- * HAC pp. 595, Algorithm 14.12 Modified so you can control how
+ * HAC pp. 595, Algorithm 14.12 Modified so you can control how
* many digits of output are created.
*/
static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
@@ -2349,7 +2349,7 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* can we use the fast multiplier? */
if (((digs) < MP_WARRAY) &&
- MIN (a->used, b->used) <
+ MIN (a->used, b->used) <
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_digs (a, b, c, digs);
}
@@ -2372,10 +2372,10 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
/* setup some aliases */
/* copy of the digit from a used within the nested loop */
tmpx = a->dp[ix];
-
+
/* an alias for the destination shifted ix places */
tmpt = t.dp + ix;
-
+
/* an alias for the digits of b */
tmpy = b->dp;
@@ -2409,15 +2409,15 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* Fast (comba) multiplier
*
- * This is the fast column-array [comba] multiplier. It is
- * designed to compute the columns of the product first
- * then handle the carries afterwards. This has the effect
+ * This is the fast column-array [comba] multiplier. It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards. This has the effect
* of making the nested loops that compute the columns very
* simple and schedulable on super-scalar processors.
*
- * This has been modified to produce a variable number of
- * digits of output so if say only a half-product is required
- * you don't have to compute the upper half (a feature
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
* required for fast Barrett reduction).
*
* Based on Algorithm 14.12 on pp.595 of HAC.
@@ -2441,7 +2441,7 @@ static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
/* clear the carry */
_W = 0;
- for (ix = 0; ix < pa; ix++) {
+ for (ix = 0; ix < pa; ix++) {
int tx, ty;
int iy;
mp_digit *tmpx, *tmpy;
@@ -2454,7 +2454,7 @@ static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
tmpx = a->dp + tx;
tmpy = b->dp + ty;
- /* this is the number of times the loop will iterrate, essentially
+ /* this is the number of times the loop will iterrate, essentially
while (tx++ < a->used && ty-- >= 0) { ... }
*/
iy = MIN(a->used-tx, ty+1);
@@ -2501,8 +2501,8 @@ static int mp_init_size (mp_int * a, int size)
int x;
/* pad size so there are always extra digits */
- size += (MP_PREC * 2) - (size % MP_PREC);
-
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
/* alloc mem */
a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
if (a->dp == NULL) {
@@ -2556,7 +2556,7 @@ static int s_mp_sqr (mp_int * a, mp_int * b)
/* alias for where to store the results */
tmpt = t.dp + (2*ix + 1);
-
+
for (iy = ix + 1; iy < pa; iy++) {
/* first calculate the product */
r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
@@ -2863,24 +2863,24 @@ static int mp_mul_2(mp_int * a, mp_int * b)
/* alias for source */
tmpa = a->dp;
-
+
/* alias for dest */
tmpb = b->dp;
/* carry */
r = 0;
for (x = 0; x < a->used; x++) {
-
- /* get what will be the *next* carry bit from the
- * MSB of the current digit
+
+ /* get what will be the *next* carry bit from the
+ * MSB of the current digit
*/
rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
-
+
/* now shift up this digit, add in the carry [from the previous] */
*tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
-
- /* copy the carry that would be from the source
- * digit into the next iteration
+
+ /* copy the carry that would be from the source
+ * digit into the next iteration
*/
r = rr;
}
@@ -2892,8 +2892,8 @@ static int mp_mul_2(mp_int * a, mp_int * b)
++(b->used);
}
- /* now zero any excess digits on the destination
- * that we didn't write to
+ /* now zero any excess digits on the destination
+ * that we didn't write to
*/
tmpb = b->dp + b->used;
for (x = b->used; x < oldused; x++) {
@@ -3011,7 +3011,7 @@ static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int
/* determine and setup reduction code */
if (redmode == 0) {
-#ifdef BN_MP_MONTGOMERY_SETUP_C
+#ifdef BN_MP_MONTGOMERY_SETUP_C
/* now setup montgomery */
if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
goto LBL_M;
@@ -3026,7 +3026,7 @@ static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int
if (((P->used * 2 + 1) < MP_WARRAY) &&
P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
redux = fast_mp_montgomery_reduce;
- } else
+ } else
#endif
{
#ifdef BN_MP_MONTGOMERY_REDUCE_C
@@ -3077,7 +3077,7 @@ static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int
if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
goto LBL_RES;
}
-#else
+#else
err = MP_VAL;
goto LBL_RES;
#endif
@@ -3245,10 +3245,10 @@ LBL_M:
#ifdef BN_FAST_S_MP_SQR_C
/* the jist of squaring...
- * you do like mult except the offset of the tmpx [one that
- * starts closer to zero] can't equal the offset of tmpy.
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
* So basically you set up iy like before then you min it with
- * (ty-tx) so that it never happens. You double all those
+ * (ty-tx) so that it never happens. You double all those
* you add in the inner loop
After that loop you do the squares and add them in.
@@ -3270,7 +3270,7 @@ static int fast_s_mp_sqr (mp_int * a, mp_int * b)
/* number of output digits to produce */
W1 = 0;
- for (ix = 0; ix < pa; ix++) {
+ for (ix = 0; ix < pa; ix++) {
int tx, ty, iy;
mp_word _W;
mp_digit *tmpy;
@@ -3291,7 +3291,7 @@ static int fast_s_mp_sqr (mp_int * a, mp_int * b)
*/
iy = MIN(a->used-tx, ty+1);
- /* now for squaring tx can never equal ty
+ /* now for squaring tx can never equal ty
* we halve the distance since they approach at a rate of 2x
* and we have to round because odd cases need to be executed
*/
diff --git a/contrib/wpa/src/tls/pkcs5.c b/contrib/wpa/src/tls/pkcs5.c
index 8a93483..a2ad83b 100644
--- a/contrib/wpa/src/tls/pkcs5.c
+++ b/contrib/wpa/src/tls/pkcs5.c
@@ -1,6 +1,6 @@
/*
* PKCS #5 (Password-based Encryption)
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "common.h"
#include "crypto/crypto.h"
#include "crypto/md5.h"
+#include "crypto/sha1.h"
#include "asn1.h"
#include "pkcs5.h"
@@ -18,30 +19,261 @@
struct pkcs5_params {
enum pkcs5_alg {
PKCS5_ALG_UNKNOWN,
- PKCS5_ALG_MD5_DES_CBC
+ PKCS5_ALG_MD5_DES_CBC,
+ PKCS5_ALG_PBES2,
+ PKCS5_ALG_SHA1_3DES_CBC,
} alg;
- u8 salt[8];
+ u8 salt[64];
size_t salt_len;
unsigned int iter_count;
+ enum pbes2_enc_alg {
+ PBES2_ENC_ALG_UNKNOWN,
+ PBES2_ENC_ALG_DES_EDE3_CBC,
+ } enc_alg;
+ u8 iv[8];
+ size_t iv_len;
};
+static int oid_is_rsadsi(struct asn1_oid *oid)
+{
+ return oid->len >= 4 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int pkcs5_is_oid(struct asn1_oid *oid, unsigned long alg)
+{
+ return oid->len == 7 &&
+ oid_is_rsadsi(oid) &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 5 /* pkcs-5 */ &&
+ oid->oid[6] == alg;
+}
+
+
+static int enc_alg_is_oid(struct asn1_oid *oid, unsigned long alg)
+{
+ return oid->len == 6 &&
+ oid_is_rsadsi(oid) &&
+ oid->oid[4] == 3 /* encryptionAlgorithm */ &&
+ oid->oid[5] == alg;
+}
+
+
+static int pkcs12_is_pbe_oid(struct asn1_oid *oid, unsigned long alg)
+{
+ return oid->len == 8 &&
+ oid_is_rsadsi(oid) &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 12 /* pkcs-12 */ &&
+ oid->oid[6] == 1 /* pkcs-12PbeIds */ &&
+ oid->oid[7] == alg;
+}
+
+
static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
{
- if (oid->len == 7 &&
- oid->oid[0] == 1 /* iso */ &&
- oid->oid[1] == 2 /* member-body */ &&
- oid->oid[2] == 840 /* us */ &&
- oid->oid[3] == 113549 /* rsadsi */ &&
- oid->oid[4] == 1 /* pkcs */ &&
- oid->oid[5] == 5 /* pkcs-5 */ &&
- oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
+ if (pkcs5_is_oid(oid, 3)) /* pbeWithMD5AndDES-CBC (PBES1) */
return PKCS5_ALG_MD5_DES_CBC;
-
+ if (pkcs12_is_pbe_oid(oid, 3)) /* pbeWithSHAAnd3-KeyTripleDES-CBC */
+ return PKCS5_ALG_SHA1_3DES_CBC;
+ if (pkcs5_is_oid(oid, 13)) /* id-PBES2 (PBES2) */
+ return PKCS5_ALG_PBES2;
return PKCS5_ALG_UNKNOWN;
}
+static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
+ const u8 *enc_alg_end)
+{
+ struct asn1_hdr hdr;
+ const u8 *end, *kdf_end;
+ struct asn1_oid oid;
+ char obuf[80];
+
+ /*
+ * RFC 2898, Ch. A.4
+ *
+ * PBES2-params ::= SEQUENCE {
+ * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+ * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
+ *
+ * PBES2-KDFs ALGORITHM-IDENTIFIER ::=
+ * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+ */
+
+ if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected SEQUENCE (PBES2-params) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected SEQUENCE (keyDerivationFunc) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ kdf_end = end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Failed to parse OID (keyDerivationFunc algorithm)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 keyDerivationFunc algorithm %s",
+ obuf);
+ if (!pkcs5_is_oid(&oid, 12)) /* id-PBKDF2 */ {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Unsupported PBES2 keyDerivationFunc algorithm %s",
+ obuf);
+ return -1;
+ }
+
+ /*
+ * RFC 2898, C.
+ *
+ * PBKDF2-params ::= SEQUENCE {
+ * salt CHOICE {
+ * specified OCTET STRING,
+ * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ * },
+ * iterationCount INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX) OPTIONAL,
+ * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
+ * algid-hmacWithSHA1
+ * }
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected SEQUENCE (PBKDF2-params) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /* For now, only support the salt CHOICE specified (OCTET STRING) */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING ||
+ hdr.length > sizeof(params->salt)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected OCTET STRING (salt.specified) - found class %d tag 0x%x size %d",
+ hdr.class, hdr.tag, hdr.length);
+ return -1;
+ }
+ pos = hdr.payload + hdr.length;
+ os_memcpy(params->salt, hdr.payload, hdr.length);
+ params->salt_len = hdr.length;
+ wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", params->salt, params->salt_len);
+
+ /* iterationCount INTEGER */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected INTEGER - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length == 1) {
+ params->iter_count = *hdr.payload;
+ } else if (hdr.length == 2) {
+ params->iter_count = WPA_GET_BE16(hdr.payload);
+ } else if (hdr.length == 4) {
+ params->iter_count = WPA_GET_BE32(hdr.payload);
+ } else {
+ wpa_hexdump(MSG_DEBUG,
+ "PKCS #5: Unsupported INTEGER value (iterationCount)",
+ hdr.payload, hdr.length);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
+ params->iter_count);
+ if (params->iter_count == 0 || params->iter_count > 0xffff) {
+ wpa_printf(MSG_INFO, "PKCS #5: Unsupported iterationCount=0x%x",
+ params->iter_count);
+ return -1;
+ }
+
+ /* For now, ignore optional keyLength and prf */
+
+ pos = kdf_end;
+
+ /* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} */
+
+ if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected SEQUENCE (encryptionScheme) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Failed to parse OID (encryptionScheme algorithm)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 encryptionScheme algorithm %s",
+ obuf);
+ if (enc_alg_is_oid(&oid, 7)) {
+ params->enc_alg = PBES2_ENC_ALG_DES_EDE3_CBC;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Unsupported PBES2 encryptionScheme algorithm %s",
+ obuf);
+ return -1;
+ }
+
+ /*
+ * RFC 2898, B.2.2:
+ * The parameters field associated with this OID in an
+ * AlgorithmIdentifier shall have type OCTET STRING (SIZE(8)),
+ * specifying the initialization vector for CBC mode.
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING ||
+ hdr.length != 8) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected OCTET STRING (SIZE(8)) (IV) - found class %d tag 0x%x size %d",
+ hdr.class, hdr.tag, hdr.length);
+ return -1;
+ }
+ os_memcpy(params->iv, hdr.payload, hdr.length);
+ params->iv_len = hdr.length;
+ wpa_hexdump(MSG_DEBUG, "PKCS #5: IV", params->iv, params->iv_len);
+
+ return 0;
+}
+
+
static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
struct pkcs5_params *params)
{
@@ -71,11 +303,23 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
return -1;
}
+ if (params->alg == PKCS5_ALG_PBES2)
+ return pkcs5_get_params_pbes2(params, pos, enc_alg_end);
+
+ /* PBES1 */
+
/*
* PKCS#5, Section 8
* PBEParameter ::= SEQUENCE {
* salt OCTET STRING SIZE(8),
* iterationCount INTEGER }
+ *
+ * Note: The same implementation can be used to parse the PKCS #12
+ * version described in RFC 7292, C:
+ * pkcs-12PbeParams ::= SEQUENCE {
+ * salt OCTET STRING,
+ * iterations INTEGER
+ * }
*/
if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
@@ -89,11 +333,11 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
pos = hdr.payload;
end = hdr.payload + hdr.length;
- /* salt OCTET STRING SIZE(8) */
+ /* salt OCTET STRING SIZE(8) (PKCS #5) or OCTET STRING (PKCS #12) */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING ||
- hdr.length != 8) {
+ hdr.length > sizeof(params->salt)) {
wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
"(salt) - found class %d tag 0x%x size %d",
hdr.class, hdr.tag, hdr.length);
@@ -136,6 +380,174 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
}
+static struct crypto_cipher *
+pkcs5_crypto_init_pbes2(struct pkcs5_params *params, const char *passwd)
+{
+ u8 key[24];
+
+ if (params->enc_alg != PBES2_ENC_ALG_DES_EDE3_CBC ||
+ params->iv_len != 8)
+ return NULL;
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "PKCS #5: PBES2 password for PBKDF2",
+ passwd, os_strlen(passwd));
+ wpa_hexdump(MSG_DEBUG, "PKCS #5: PBES2 salt for PBKDF2",
+ params->salt, params->salt_len);
+ wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 PBKDF2 iterations: %u",
+ params->iter_count);
+ if (pbkdf2_sha1(passwd, params->salt, params->salt_len,
+ params->iter_count, key, sizeof(key)) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES EDE3 key", key, sizeof(key));
+ wpa_hexdump(MSG_DEBUG, "PKCS #5: DES IV", params->iv, params->iv_len);
+
+ return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, params->iv,
+ key, sizeof(key));
+}
+
+
+static void add_byte_array_mod(u8 *a, const u8 *b, size_t len)
+{
+ size_t i;
+ unsigned int carry = 0;
+
+ for (i = len - 1; i < len; i--) {
+ carry = carry + a[i] + b[i];
+ a[i] = carry & 0xff;
+ carry >>= 8;
+ }
+}
+
+
+static int pkcs12_key_gen(const u8 *pw, size_t pw_len, const u8 *salt,
+ size_t salt_len, u8 id, unsigned int iter,
+ size_t out_len, u8 *out)
+{
+ unsigned int u, v, S_len, P_len, i;
+ u8 *D = NULL, *I = NULL, *B = NULL, *pos;
+ int res = -1;
+
+ /* RFC 7292, B.2 */
+ u = SHA1_MAC_LEN;
+ v = 64;
+
+ /* D = copies of ID */
+ D = os_malloc(v);
+ if (!D)
+ goto done;
+ os_memset(D, id, v);
+
+ /* S = copies of salt; P = copies of password, I = S || P */
+ S_len = v * ((salt_len + v - 1) / v);
+ P_len = v * ((pw_len + v - 1) / v);
+ I = os_malloc(S_len + P_len);
+ if (!I)
+ goto done;
+ pos = I;
+ if (salt_len) {
+ for (i = 0; i < S_len; i++)
+ *pos++ = salt[i % salt_len];
+ }
+ if (pw_len) {
+ for (i = 0; i < P_len; i++)
+ *pos++ = pw[i % pw_len];
+ }
+
+ B = os_malloc(v);
+ if (!B)
+ goto done;
+
+ for (;;) {
+ u8 hash[SHA1_MAC_LEN];
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = D;
+ len[0] = v;
+ addr[1] = I;
+ len[1] = S_len + P_len;
+ if (sha1_vector(2, addr, len, hash) < 0)
+ goto done;
+
+ addr[0] = hash;
+ len[0] = SHA1_MAC_LEN;
+ for (i = 1; i < iter; i++) {
+ if (sha1_vector(1, addr, len, hash) < 0)
+ goto done;
+ }
+
+ if (out_len <= u) {
+ os_memcpy(out, hash, out_len);
+ res = 0;
+ goto done;
+ }
+
+ os_memcpy(out, hash, u);
+ out += u;
+ out_len -= u;
+
+ /* I_j = (I_j + B + 1) mod 2^(v*8) */
+ /* B = copies of Ai (final hash value) */
+ for (i = 0; i < v; i++)
+ B[i] = hash[i % u];
+ inc_byte_array(B, v);
+ for (i = 0; i < S_len + P_len; i += v)
+ add_byte_array_mod(&I[i], B, v);
+ }
+
+done:
+ os_free(B);
+ os_free(I);
+ os_free(D);
+ return res;
+}
+
+
+#define PKCS12_ID_ENC 1
+#define PKCS12_ID_IV 2
+#define PKCS12_ID_MAC 3
+
+static struct crypto_cipher *
+pkcs12_crypto_init_sha1(struct pkcs5_params *params, const char *passwd)
+{
+ unsigned int i;
+ u8 *pw;
+ size_t pw_len;
+ u8 key[24];
+ u8 iv[8];
+
+ if (params->alg != PKCS5_ALG_SHA1_3DES_CBC)
+ return NULL;
+
+ pw_len = passwd ? os_strlen(passwd) : 0;
+ pw = os_malloc(2 * (pw_len + 1));
+ if (!pw)
+ return NULL;
+ if (pw_len) {
+ for (i = 0; i <= pw_len; i++)
+ WPA_PUT_BE16(&pw[2 * i], passwd[i]);
+ pw_len = 2 * (pw_len + 1);
+ }
+
+ if (pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
+ PKCS12_ID_ENC, params->iter_count,
+ sizeof(key), key) < 0 ||
+ pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
+ PKCS12_ID_IV, params->iter_count,
+ sizeof(iv), iv) < 0) {
+ os_free(pw);
+ return NULL;
+ }
+
+ os_free(pw);
+
+ wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES key", key, sizeof(key));
+ wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES IV", iv, sizeof(iv));
+
+ return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, iv, key, sizeof(key));
+}
+
+
static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
const char *passwd)
{
@@ -144,6 +556,12 @@ static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
const u8 *addr[2];
size_t len[2];
+ if (params->alg == PKCS5_ALG_PBES2)
+ return pkcs5_crypto_init_pbes2(params, passwd);
+
+ if (params->alg == PKCS5_ALG_SHA1_3DES_CBC)
+ return pkcs12_crypto_init_sha1(params, passwd);
+
if (params->alg != PKCS5_ALG_MD5_DES_CBC)
return NULL;
diff --git a/contrib/wpa/src/tls/rsa.c b/contrib/wpa/src/tls/rsa.c
index 0b7b530..3525eb9 100644
--- a/contrib/wpa/src/tls/rsa.c
+++ b/contrib/wpa/src/tls/rsa.c
@@ -80,7 +80,7 @@ crypto_rsa_import_public_key(const u8 *buf, size_t len)
* PKCS #1, 7.1:
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
- * publicExponent INTEGER -- e
+ * publicExponent INTEGER -- e
* }
*/
diff --git a/contrib/wpa/src/tls/tlsv1_client.c b/contrib/wpa/src/tls/tlsv1_client.c
index a6f0587..a147a54 100644
--- a/contrib/wpa/src/tls/tlsv1_client.c
+++ b/contrib/wpa/src/tls/tlsv1_client.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "common.h"
#include "crypto/sha1.h"
#include "crypto/tls.h"
+#include "x509v3.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
#include "tlsv1_client.h"
@@ -110,7 +111,6 @@ int tls_derive_keys(struct tlsv1_client *conn,
pos += conn->rl.iv_size;
/* server_write_IV */
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
- pos += conn->rl.iv_size;
} else {
/*
* Use IV field to set the mask value for TLS v1.1. A fixed
@@ -264,7 +264,7 @@ failed:
* @in_data: Pointer to plaintext data to be encrypted
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (encrypted TLS data)
- * @out_len: Maximum out_data length
+ * @out_len: Maximum out_data length
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
@@ -494,6 +494,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn)
tlsv1_client_free_dh(conn);
tlsv1_cred_free(conn->cred);
wpabuf_free(conn->partial_input);
+ x509_certificate_chain_free(conn->server_cert);
os_free(conn);
}
@@ -513,6 +514,8 @@ int tlsv1_client_established(struct tlsv1_client *conn)
* tlsv1_client_prf - Use TLS-PRF to derive keying material
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @label: Label (e.g., description of the key) for PRF
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
* @out: Buffer for output data from TLS-PRF
@@ -520,13 +523,26 @@ int tlsv1_client_established(struct tlsv1_client *conn)
* Returns: 0 on success, -1 on failure
*/
int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+ const u8 *context, size_t context_len,
int server_random_first, u8 *out, size_t out_len)
{
- u8 seed[2 * TLS_RANDOM_LEN];
+ u8 *seed, *pos;
+ size_t seed_len = 2 * TLS_RANDOM_LEN;
+ int res;
if (conn->state != ESTABLISHED)
return -1;
+ if (context_len > 65535)
+ return -1;
+
+ if (context)
+ seed_len += 2 + context_len;
+
+ seed = os_malloc(seed_len);
+ if (!seed)
+ return -1;
+
if (server_random_first) {
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
@@ -537,9 +553,18 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
TLS_RANDOM_LEN);
}
- return tls_prf(conn->rl.tls_version,
- conn->master_secret, TLS_MASTER_SECRET_LEN,
- label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+ if (context) {
+ pos = seed + 2 * TLS_RANDOM_LEN;
+ WPA_PUT_BE16(pos, context_len);
+ pos += 2;
+ os_memcpy(pos, context, context_len);
+ }
+
+ res = tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
+ label, seed, seed_len, out, out_len);
+ os_free(seed);
+ return res;
}
@@ -691,18 +716,16 @@ int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
if (data == NULL || data_len == 0)
return 0;
- pos = conn->client_hello_ext = os_malloc(6 + data_len);
+ pos = conn->client_hello_ext = os_malloc(4 + data_len);
if (pos == NULL)
return -1;
- WPA_PUT_BE16(pos, 4 + data_len);
- pos += 2;
WPA_PUT_BE16(pos, ext_type);
pos += 2;
WPA_PUT_BE16(pos, data_len);
pos += 2;
os_memcpy(pos, data, data_len);
- conn->client_hello_ext_len = 6 + data_len;
+ conn->client_hello_ext_len = 4 + data_len;
if (ext_type == TLS_EXT_PAC_OPAQUE) {
conn->session_ticket_included = 1;
@@ -813,9 +836,14 @@ int tlsv1_client_set_cred(struct tlsv1_client *conn,
}
-void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)
+/**
+ * tlsv1_client_set_flags - Set connection flags
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @flags: TLS_CONN_* bitfield
+ */
+void tlsv1_client_set_flags(struct tlsv1_client *conn, unsigned int flags)
{
- conn->disable_time_checks = !enabled;
+ conn->flags = flags;
}
@@ -828,3 +856,38 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
}
+
+
+void tlsv1_client_set_cb(struct tlsv1_client *conn,
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data),
+ void *cb_ctx,
+ int cert_in_cb)
+{
+ conn->event_cb = event_cb;
+ conn->cb_ctx = cb_ctx;
+ conn->cert_in_cb = !!cert_in_cb;
+}
+
+
+int tlsv1_client_get_version(struct tlsv1_client *conn, char *buf,
+ size_t buflen)
+{
+ if (!conn)
+ return -1;
+ switch (conn->rl.tls_version) {
+ case TLS_VERSION_1:
+ os_strlcpy(buf, "TLSv1", buflen);
+ break;
+ case TLS_VERSION_1_1:
+ os_strlcpy(buf, "TLSv1.1", buflen);
+ break;
+ case TLS_VERSION_1_2:
+ os_strlcpy(buf, "TLSv1.2", buflen);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/tls/tlsv1_client.h b/contrib/wpa/src/tls/tlsv1_client.h
index a4e25e9..7fcc256 100644
--- a/contrib/wpa/src/tls/tlsv1_client.h
+++ b/contrib/wpa/src/tls/tlsv1_client.h
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,7 @@ struct tlsv1_client * tlsv1_client_init(void);
void tlsv1_client_deinit(struct tlsv1_client *conn);
int tlsv1_client_established(struct tlsv1_client *conn);
int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+ const u8 *context, size_t context_len,
int server_random_first, u8 *out, size_t out_len);
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
@@ -41,7 +42,7 @@ int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
int tlsv1_client_set_cred(struct tlsv1_client *conn,
struct tlsv1_credentials *cred);
-void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled);
+void tlsv1_client_set_flags(struct tlsv1_client *conn, unsigned int flags);
typedef int (*tlsv1_client_session_ticket_cb)
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
@@ -51,4 +52,12 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
tlsv1_client_session_ticket_cb cb,
void *ctx);
+void tlsv1_client_set_cb(struct tlsv1_client *conn,
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data),
+ void *cb_ctx,
+ int cert_in_cb);
+int tlsv1_client_get_version(struct tlsv1_client *conn, char *buf,
+ size_t buflen);
+
#endif /* TLSV1_CLIENT_H */
diff --git a/contrib/wpa/src/tls/tlsv1_client_i.h b/contrib/wpa/src/tls/tlsv1_client_i.h
index 55fdcf8..12ec8df 100644
--- a/contrib/wpa/src/tls/tlsv1_client_i.h
+++ b/contrib/wpa/src/tls/tlsv1_client_i.h
@@ -29,11 +29,14 @@ struct tlsv1_client {
u8 alert_level;
u8 alert_description;
+ unsigned int flags; /* TLS_CONN_* bitfield */
+
unsigned int certificate_requested:1;
unsigned int session_resumed:1;
unsigned int session_ticket_included:1;
unsigned int use_session_ticket:1;
- unsigned int disable_time_checks:1;
+ unsigned int cert_in_cb:1;
+ unsigned int ocsp_resp_received:1;
struct crypto_public_key *server_rsa_key;
@@ -64,6 +67,12 @@ struct tlsv1_client {
void *session_ticket_cb_ctx;
struct wpabuf *partial_input;
+
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
+
+ struct x509_certificate *server_cert;
};
@@ -81,4 +90,11 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
const u8 *buf, size_t *len,
u8 **out_data, size_t *out_len);
+enum tls_ocsp_result {
+ TLS_OCSP_NO_RESPONSE, TLS_OCSP_INVALID, TLS_OCSP_GOOD, TLS_OCSP_REVOKED
+};
+
+enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
+ const u8 *resp, size_t len);
+
#endif /* TLSV1_CLIENT_I_H */
diff --git a/contrib/wpa/src/tls/tlsv1_client_ocsp.c b/contrib/wpa/src/tls/tlsv1_client_ocsp.c
new file mode 100644
index 0000000..1d7b68c
--- /dev/null
+++ b/contrib/wpa/src/tls/tlsv1_client_ocsp.c
@@ -0,0 +1,803 @@
+/*
+ * TLSv1 client - OCSP
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+#include "crypto/sha1.h"
+#include "asn1.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+
+/* RFC 6960, 4.2.1: OCSPResponseStatus ::= ENUMERATED */
+enum ocsp_response_status {
+ OCSP_RESP_STATUS_SUCCESSFUL = 0,
+ OCSP_RESP_STATUS_MALFORMED_REQ = 1,
+ OCSP_RESP_STATUS_INT_ERROR = 2,
+ OCSP_RESP_STATUS_TRY_LATER = 3,
+ /* 4 not used */
+ OCSP_RESP_STATUS_SIG_REQUIRED = 5,
+ OCSP_RESP_STATUS_UNAUTHORIZED = 6,
+};
+
+
+static int is_oid_basic_ocsp_resp(struct asn1_oid *oid)
+{
+ return oid->len == 10 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 3 /* identified-organization */ &&
+ oid->oid[2] == 6 /* dod */ &&
+ oid->oid[3] == 1 /* internet */ &&
+ oid->oid[4] == 5 /* security */ &&
+ oid->oid[5] == 5 /* mechanisms */ &&
+ oid->oid[6] == 7 /* id-pkix */ &&
+ oid->oid[7] == 48 /* id-ad */ &&
+ oid->oid[8] == 1 /* id-pkix-ocsp */ &&
+ oid->oid[9] == 1 /* id-pkix-ocsp-basic */;
+}
+
+
+static int ocsp_responder_id_match(struct x509_certificate *signer,
+ struct x509_name *name, const u8 *key_hash)
+{
+ if (key_hash) {
+ u8 hash[SHA1_MAC_LEN];
+ const u8 *addr[1] = { signer->public_key };
+ size_t len[1] = { signer->public_key_len };
+
+ if (sha1_vector(1, addr, len, hash) < 0)
+ return 0;
+ return os_memcmp(hash, key_hash, SHA1_MAC_LEN) == 0;
+ }
+
+ return x509_name_compare(&signer->subject, name) == 0;
+}
+
+
+static unsigned int ocsp_hash_data(struct asn1_oid *alg, const u8 *data,
+ size_t data_len, u8 *hash)
+{
+ const u8 *addr[1] = { data };
+ size_t len[1] = { data_len };
+ char buf[100];
+
+ if (x509_sha1_oid(alg)) {
+ if (sha1_vector(1, addr, len, hash) < 0)
+ return 0;
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA1)", hash, 20);
+ return 20;
+ }
+
+ if (x509_sha256_oid(alg)) {
+ if (sha256_vector(1, addr, len, hash) < 0)
+ return 0;
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA256)", hash, 32);
+ return 32;
+ }
+
+ if (x509_sha384_oid(alg)) {
+ if (sha384_vector(1, addr, len, hash) < 0)
+ return 0;
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA384)", hash, 48);
+ return 48;
+ }
+
+ if (x509_sha512_oid(alg)) {
+ if (sha512_vector(1, addr, len, hash) < 0)
+ return 0;
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA512)", hash, 64);
+ return 64;
+ }
+
+
+ asn1_oid_to_str(alg, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "OCSP: Could not calculate hash with alg %s",
+ buf);
+ return 0;
+}
+
+
+static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
+ struct x509_certificate *cert,
+ struct x509_certificate *issuer,
+ const u8 *resp, size_t len,
+ enum tls_ocsp_result *res)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ struct x509_algorithm_identifier alg;
+ const u8 *name_hash, *key_hash;
+ size_t name_hash_len, key_hash_len;
+ const u8 *serial_number;
+ size_t serial_number_len;
+ u8 hash[64];
+ unsigned int hash_len;
+ unsigned int cert_status;
+ os_time_t update;
+ struct os_time now;
+
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: SingleResponse", resp, len);
+
+ /*
+ * SingleResponse ::= SEQUENCE {
+ * certID CertID,
+ * certStatus CertStatus,
+ * thisUpdate GeneralizedTime,
+ * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+
+ /* CertID ::= SEQUENCE */
+ if (asn1_get_next(resp, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (CertID) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING,
+ * issuerKeyHash OCTET STRING,
+ * serialNumber CertificateSerialNumber }
+ */
+
+ /* hashAlgorithm AlgorithmIdentifier */
+ if (x509_parse_algorithm_identifier(pos, end - pos, &alg, &pos))
+ return -1;
+
+ /* issuerNameHash OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected OCTET STRING (issuerNameHash) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ name_hash = hdr.payload;
+ name_hash_len = hdr.length;
+ wpa_hexdump(MSG_DEBUG, "OCSP: issuerNameHash",
+ name_hash, name_hash_len);
+ pos = hdr.payload + hdr.length;
+
+ wpa_hexdump(MSG_DEBUG, "OCSP: Issuer subject DN",
+ issuer->subject_dn, issuer->subject_dn_len);
+ hash_len = ocsp_hash_data(&alg.oid, issuer->subject_dn,
+ issuer->subject_dn_len, hash);
+ if (hash_len == 0 || name_hash_len != hash_len ||
+ os_memcmp(name_hash, hash, hash_len) != 0) {
+ wpa_printf(MSG_DEBUG, "OCSP: issuerNameHash mismatch");
+ wpa_hexdump(MSG_DEBUG, "OCSP: Calculated issuerNameHash",
+ hash, hash_len);
+ return -1;
+ }
+
+ /* issuerKeyHash OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected OCTET STRING (issuerKeyHash) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ key_hash = hdr.payload;
+ key_hash_len = hdr.length;
+ wpa_hexdump(MSG_DEBUG, "OCSP: issuerKeyHash", key_hash, key_hash_len);
+ pos = hdr.payload + hdr.length;
+
+ hash_len = ocsp_hash_data(&alg.oid, issuer->public_key,
+ issuer->public_key_len, hash);
+ if (hash_len == 0 || key_hash_len != hash_len ||
+ os_memcmp(key_hash, hash, hash_len) != 0) {
+ wpa_printf(MSG_DEBUG, "OCSP: issuerKeyHash mismatch");
+ wpa_hexdump(MSG_DEBUG, "OCSP: Calculated issuerKeyHash",
+ hash, hash_len);
+ return -1;
+ }
+
+ /* serialNumber CertificateSerialNumber ::= INTEGER */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_INTEGER ||
+ hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) {
+ wpa_printf(MSG_DEBUG, "OCSP: No INTEGER tag found for serialNumber; class=%d tag=0x%x length=%u",
+ hdr.class, hdr.tag, hdr.length);
+ return -1;
+ }
+ serial_number = hdr.payload;
+ serial_number_len = hdr.length;
+ while (serial_number_len > 0 && serial_number[0] == 0) {
+ serial_number++;
+ serial_number_len--;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: serialNumber", serial_number,
+ serial_number_len);
+
+ if (serial_number_len != cert->serial_number_len ||
+ os_memcmp(serial_number, cert->serial_number,
+ serial_number_len) != 0) {
+ wpa_printf(MSG_DEBUG, "OCSP: serialNumber mismatch");
+ return -1;
+ }
+
+ pos = end;
+ end = resp + len;
+
+ /* certStatus CertStatus ::= CHOICE */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected CHOICE (CertStatus) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ cert_status = hdr.tag;
+ wpa_printf(MSG_DEBUG, "OCSP: certStatus=%u", cert_status);
+ wpa_hexdump(MSG_DEBUG, "OCSP: CertStatus additional data",
+ hdr.payload, hdr.length);
+ pos = hdr.payload + hdr.length;
+
+ os_get_time(&now);
+ /* thisUpdate GeneralizedTime */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_GENERALIZEDTIME ||
+ x509_parse_time(hdr.payload, hdr.length, hdr.tag, &update) < 0) {
+ wpa_printf(MSG_DEBUG, "OCSP: Failed to parse thisUpdate");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "OCSP: thisUpdate %lu", (unsigned long) update);
+ pos = hdr.payload + hdr.length;
+ if ((unsigned long) now.sec < (unsigned long) update) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: thisUpdate time in the future (response not yet valid)");
+ return -1;
+ }
+
+ /* nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL */
+ if (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0)
+ return -1;
+ if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC && hdr.tag == 0) {
+ const u8 *next = hdr.payload + hdr.length;
+
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_GENERALIZEDTIME ||
+ x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+ &update) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Failed to parse nextUpdate");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "OCSP: nextUpdate %lu",
+ (unsigned long) update);
+ pos = next;
+ if ((unsigned long) now.sec > (unsigned long) update) {
+ wpa_printf(MSG_DEBUG, "OCSP: nextUpdate time in the past (response has expired)");
+ return -1;
+ }
+ }
+ }
+
+ /* singleExtensions [1] EXPLICIT Extensions OPTIONAL */
+ if (pos < end) {
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: singleExtensions",
+ pos, end - pos);
+ /* Ignore for now */
+ }
+
+ if (cert_status == 0 /* good */)
+ *res = TLS_OCSP_GOOD;
+ else if (cert_status == 1 /* revoked */)
+ *res = TLS_OCSP_REVOKED;
+ else
+ return -1;
+ return 0;
+}
+
+
+static enum tls_ocsp_result
+tls_process_ocsp_responses(struct tlsv1_client *conn,
+ struct x509_certificate *cert,
+ struct x509_certificate *issuer, const u8 *resp,
+ size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ enum tls_ocsp_result res;
+
+ pos = resp;
+ end = resp + len;
+ while (pos < end) {
+ /* SingleResponse ::= SEQUENCE */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (SingleResponse) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ if (tls_process_ocsp_single_response(conn, cert, issuer,
+ hdr.payload, hdr.length,
+ &res) == 0)
+ return res;
+ pos = hdr.payload + hdr.length;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Did not find a response matching the server certificate");
+ return TLS_OCSP_NO_RESPONSE;
+}
+
+
+static enum tls_ocsp_result
+tls_process_basic_ocsp_response(struct tlsv1_client *conn,
+ struct x509_certificate *srv_cert,
+ const u8 *resp, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ const u8 *resp_data, *sign_value, *key_hash = NULL, *responses;
+ const u8 *resp_data_signed;
+ size_t resp_data_len, sign_value_len, responses_len;
+ size_t resp_data_signed_len;
+ struct x509_algorithm_identifier alg;
+ struct x509_certificate *certs = NULL, *last_cert = NULL;
+ struct x509_certificate *issuer, *signer;
+ struct x509_name name; /* used if key_hash == NULL */
+ char buf[100];
+ os_time_t produced_at;
+ enum tls_ocsp_result res;
+
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
+
+ os_memset(&name, 0, sizeof(name));
+
+ /*
+ * RFC 6960, 4.2.1:
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+
+ if (asn1_get_next(resp, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (BasicOCSPResponse) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /* ResponseData ::= SEQUENCE */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (ResponseData) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ resp_data = hdr.payload;
+ resp_data_len = hdr.length;
+ resp_data_signed = pos;
+ pos = hdr.payload + hdr.length;
+ resp_data_signed_len = pos - resp_data_signed;
+
+ /* signatureAlgorithm AlgorithmIdentifier */
+ if (x509_parse_algorithm_identifier(pos, end - pos, &alg, &pos))
+ return TLS_OCSP_INVALID;
+
+ /* signature BIT STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_BITSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected BITSTRING (signature) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ if (hdr.length < 1)
+ return TLS_OCSP_INVALID;
+ pos = hdr.payload;
+ if (*pos) {
+ wpa_printf(MSG_DEBUG, "OCSP: BITSTRING - %d unused bits", *pos);
+ /* PKCS #1 v1.5 10.2.1:
+ * It is an error if the length in bits of the signature S is
+ * not a multiple of eight.
+ */
+ return TLS_OCSP_INVALID;
+ }
+ sign_value = pos + 1;
+ sign_value_len = hdr.length - 1;
+ pos += hdr.length;
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: signature", sign_value, sign_value_len);
+
+ /* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL */
+ if (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected [0] EXPLICIT (certs) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: certs",
+ hdr.payload, hdr.length);
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+ while (pos < end) {
+ struct x509_certificate *cert;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (Certificate) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+
+ cert = x509_certificate_parse(hdr.payload, hdr.length);
+ if (!cert)
+ goto fail;
+ if (last_cert) {
+ last_cert->next = cert;
+ last_cert = cert;
+ } else {
+ last_cert = certs = cert;
+ }
+ pos = hdr.payload + hdr.length;
+ }
+ }
+
+ /*
+ * ResponseData ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * responderID ResponderID,
+ * producedAt GeneralizedTime,
+ * responses SEQUENCE OF SingleResponse,
+ * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+ pos = resp_data;
+ end = resp_data + resp_data_len;
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: ResponseData", pos, end - pos);
+
+ /*
+ * version [0] EXPLICIT Version DEFAULT v1
+ * Version ::= INTEGER { v1(0) }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 &&
+ hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC &&
+ hdr.tag == 0) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_INTEGER ||
+ hdr.length != 1) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: No INTEGER (len=1) tag found for version field - found class %d tag 0x%x length %d",
+ hdr.class, hdr.tag, hdr.length);
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "OCSP: ResponseData version %u",
+ hdr.payload[0]);
+ if (hdr.payload[0] != 0) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Unsupported ResponseData version %u",
+ hdr.payload[0]);
+ goto no_resp;
+ }
+ pos = hdr.payload + hdr.length;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Default ResponseData version (v1)");
+ }
+
+ /*
+ * ResponderID ::= CHOICE {
+ * byName [1] Name,
+ * byKey [2] KeyHash }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected CHOICE (ResponderID) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+
+ if (hdr.tag == 1) {
+ /* Name */
+ if (x509_parse_name(hdr.payload, hdr.length, &name, &pos) < 0)
+ goto fail;
+ x509_name_string(&name, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "OCSP: ResponderID byName Name: %s", buf);
+ } else if (hdr.tag == 2) {
+ /* KeyHash ::= OCTET STRING */
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected OCTET STRING (KeyHash) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ key_hash = hdr.payload;
+ wpa_hexdump(MSG_DEBUG, "OCSP: ResponderID byKey KeyHash",
+ key_hash, hdr.length);
+ if (hdr.length != SHA1_MAC_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Unexpected byKey KeyHash length %u - expected %u for SHA-1",
+ hdr.length, SHA1_MAC_LEN);
+ goto fail;
+ }
+ pos = hdr.payload + hdr.length;
+ } else {
+ wpa_printf(MSG_DEBUG, "OCSP: Unexpected ResponderID CHOICE %u",
+ hdr.tag);
+ goto fail;
+ }
+
+ /* producedAt GeneralizedTime */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_GENERALIZEDTIME ||
+ x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+ &produced_at) < 0) {
+ wpa_printf(MSG_DEBUG, "OCSP: Failed to parse producedAt");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "OCSP: producedAt %lu",
+ (unsigned long) produced_at);
+ pos = hdr.payload + hdr.length;
+
+ /* responses SEQUENCE OF SingleResponse */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (responses) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ responses = hdr.payload;
+ responses_len = hdr.length;
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: responses", responses, responses_len);
+ pos = hdr.payload + hdr.length;
+
+ if (pos < end) {
+ /* responseExtensions [1] EXPLICIT Extensions OPTIONAL */
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: responseExtensions",
+ pos, end - pos);
+ /* Ignore for now. */
+ }
+
+ if (!srv_cert) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Server certificate not known - cannot check OCSP response");
+ goto no_resp;
+ }
+
+ if (srv_cert->next) {
+ /* Issuer has already been verified in the chain */
+ issuer = srv_cert->next;
+ } else {
+ /* Find issuer from the set of trusted certificates */
+ for (issuer = conn->cred ? conn->cred->trusted_certs : NULL;
+ issuer; issuer = issuer->next) {
+ if (x509_name_compare(&srv_cert->issuer,
+ &issuer->subject) == 0)
+ break;
+ }
+ }
+ if (!issuer) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Server certificate issuer not known - cannot check OCSP response");
+ goto no_resp;
+ }
+
+ if (ocsp_responder_id_match(issuer, &name, key_hash)) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Server certificate issuer certificate matches ResponderID");
+ signer = issuer;
+ } else {
+ for (signer = certs; signer; signer = signer->next) {
+ if (!ocsp_responder_id_match(signer, &name, key_hash) ||
+ x509_name_compare(&srv_cert->issuer,
+ &issuer->subject) != 0 ||
+ !(signer->ext_key_usage &
+ X509_EXT_KEY_USAGE_OCSP) ||
+ x509_certificate_check_signature(issuer, signer) <
+ 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "OCSP: An extra certificate from the response matches ResponderID and is trusted as an OCSP signer");
+ break;
+ }
+ if (!signer) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Could not find OCSP signer certificate");
+ goto no_resp;
+ }
+ }
+
+ x509_free_name(&name);
+ os_memset(&name, 0, sizeof(name));
+ x509_certificate_chain_free(certs);
+ certs = NULL;
+
+ if (x509_check_signature(signer, &alg, sign_value, sign_value_len,
+ resp_data_signed, resp_data_signed_len) < 0) {
+ wpa_printf(MSG_DEBUG, "OCSP: Invalid signature");
+ return TLS_OCSP_INVALID;
+ }
+
+ res = tls_process_ocsp_responses(conn, srv_cert, issuer,
+ responses, responses_len);
+ if (res == TLS_OCSP_REVOKED)
+ srv_cert->ocsp_revoked = 1;
+ else if (res == TLS_OCSP_GOOD)
+ srv_cert->ocsp_good = 1;
+ return res;
+
+no_resp:
+ x509_free_name(&name);
+ x509_certificate_chain_free(certs);
+ return TLS_OCSP_NO_RESPONSE;
+
+fail:
+ x509_free_name(&name);
+ x509_certificate_chain_free(certs);
+ return TLS_OCSP_INVALID;
+}
+
+
+enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
+ const u8 *resp, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ u8 resp_status;
+ struct asn1_oid oid;
+ char obuf[80];
+ struct x509_certificate *cert;
+ enum tls_ocsp_result res = TLS_OCSP_NO_RESPONSE;
+ enum tls_ocsp_result res_first = res;
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len);
+
+ /*
+ * RFC 6960, 4.2.1:
+ * OCSPResponse ::= SEQUENCE {
+ * responseStatus OCSPResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+
+ if (asn1_get_next(resp, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (OCSPResponse) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /* OCSPResponseStatus ::= ENUMERATED */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_ENUMERATED ||
+ hdr.length != 1) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected ENUMERATED (responseStatus) - found class %d tag 0x%x length %u",
+ hdr.class, hdr.tag, hdr.length);
+ return TLS_OCSP_INVALID;
+ }
+ resp_status = hdr.payload[0];
+ wpa_printf(MSG_DEBUG, "OCSP: responseStatus %u", resp_status);
+ pos = hdr.payload + hdr.length;
+ if (resp_status != OCSP_RESP_STATUS_SUCCESSFUL) {
+ wpa_printf(MSG_DEBUG, "OCSP: No stapling result");
+ return TLS_OCSP_NO_RESPONSE;
+ }
+
+ /* responseBytes [0] EXPLICIT ResponseBytes OPTIONAL */
+ if (pos == end)
+ return TLS_OCSP_NO_RESPONSE;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected [0] EXPLICIT (responseBytes) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+
+ /*
+ * ResponseBytes ::= SEQUENCE {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ */
+
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (ResponseBytes) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /* responseType OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Failed to parse OID (responseType)");
+ return TLS_OCSP_INVALID;
+ }
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "OCSP: responseType %s", obuf);
+ if (!is_oid_basic_ocsp_resp(&oid)) {
+ wpa_printf(MSG_DEBUG, "OCSP: Ignore unsupported response type");
+ return TLS_OCSP_NO_RESPONSE;
+ }
+
+ /* response OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected OCTET STRING (response) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+
+ cert = conn->server_cert;
+ while (cert) {
+ if (!cert->ocsp_good && !cert->ocsp_revoked) {
+ char sbuf[128];
+
+ x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Trying to find certificate status for %s",
+ sbuf);
+
+ res = tls_process_basic_ocsp_response(conn, cert,
+ hdr.payload,
+ hdr.length);
+ if (cert == conn->server_cert)
+ res_first = res;
+ }
+ if (res == TLS_OCSP_REVOKED || cert->issuer_trusted)
+ break;
+ cert = cert->next;
+ }
+ return res == TLS_OCSP_REVOKED ? res : res_first;
+}
diff --git a/contrib/wpa/src/tls/tlsv1_client_read.c b/contrib/wpa/src/tls/tlsv1_client_read.c
index 9ce9680..80874e5 100644
--- a/contrib/wpa/src/tls/tlsv1_client_read.c
+++ b/contrib/wpa/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - read handshake message
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,54 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len);
+static int tls_version_disabled(struct tlsv1_client *conn, u16 ver)
+{
+ return (((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
+ ver == TLS_VERSION_1) ||
+ ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
+ ver == TLS_VERSION_1_1) ||
+ ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
+ ver == TLS_VERSION_1_2));
+}
+
+
+static int tls_process_server_hello_extensions(struct tlsv1_client *conn,
+ const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello extensions",
+ pos, len);
+ while (pos < end) {
+ u16 ext, elen;
+
+ if (end - pos < 4) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension header");
+ return -1;
+ }
+
+ ext = WPA_GET_BE16(pos);
+ pos += 2;
+ elen = WPA_GET_BE16(pos);
+ pos += 2;
+
+ if (elen > end - pos) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: ServerHello ExtensionType %u",
+ ext);
+ wpa_hexdump(MSG_DEBUG, "TLSv1: ServerHello extension data",
+ pos, elen);
+
+ pos += elen;
+ }
+
+ return 0;
+}
+
+
static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -76,7 +124,8 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
if (end - pos < 2)
goto decode_error;
tls_version = WPA_GET_BE16(pos);
- if (!tls_version_ok(tls_version)) {
+ if (!tls_version_ok(tls_version) ||
+ tls_version_disabled(conn, tls_version)) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
"ServerHello %u.%u", pos[0], pos[1]);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -165,8 +214,24 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
}
pos++;
+ if (end - pos >= 2) {
+ u16 ext_len;
+
+ ext_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < ext_len) {
+ wpa_printf(MSG_INFO,
+ "TLSv1: Invalid ServerHello extension length: %u (left: %u)",
+ ext_len, (unsigned int) (end - pos));
+ goto decode_error;
+ }
+
+ if (tls_process_server_hello_extensions(conn, pos, ext_len))
+ goto decode_error;
+ pos += ext_len;
+ }
+
if (end != pos) {
- /* TODO: ServerHello extensions */
wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
"end of ServerHello", pos, end - pos);
goto decode_error;
@@ -211,6 +276,73 @@ decode_error:
}
+static void tls_peer_cert_event(struct tlsv1_client *conn, int depth,
+ struct x509_certificate *cert)
+{
+ union tls_event_data ev;
+ struct wpabuf *cert_buf = NULL;
+#ifdef CONFIG_SHA256
+ u8 hash[32];
+#endif /* CONFIG_SHA256 */
+ char subject[128];
+
+ if (!conn->event_cb)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ if ((conn->cred && conn->cred->cert_probe) || conn->cert_in_cb) {
+ cert_buf = wpabuf_alloc_copy(cert->cert_start,
+ cert->cert_len);
+ ev.peer_cert.cert = cert_buf;
+ }
+#ifdef CONFIG_SHA256
+ if (cert_buf) {
+ const u8 *addr[1];
+ size_t len[1];
+ addr[0] = wpabuf_head(cert_buf);
+ len[0] = wpabuf_len(cert_buf);
+ if (sha256_vector(1, addr, len, hash) == 0) {
+ ev.peer_cert.hash = hash;
+ ev.peer_cert.hash_len = sizeof(hash);
+ }
+ }
+#endif /* CONFIG_SHA256 */
+
+ ev.peer_cert.depth = depth;
+ x509_name_string(&cert->subject, subject, sizeof(subject));
+ ev.peer_cert.subject = subject;
+
+ conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+ wpabuf_free(cert_buf);
+}
+
+
+static void tls_cert_chain_failure_event(struct tlsv1_client *conn, int depth,
+ struct x509_certificate *cert,
+ enum tls_fail_reason reason,
+ const char *reason_txt)
+{
+ struct wpabuf *cert_buf = NULL;
+ union tls_event_data ev;
+ char subject[128];
+
+ if (!conn->event_cb || !cert)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.depth = depth;
+ x509_name_string(&cert->subject, subject, sizeof(subject));
+ ev.peer_cert.subject = subject;
+ ev.cert_fail.reason = reason;
+ ev.cert_fail.reason_txt = reason_txt;
+ cert_buf = wpabuf_alloc_copy(cert->cert_start,
+ cert->cert_len);
+ ev.cert_fail.cert = cert_buf;
+ conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ wpabuf_free(cert_buf);
+}
+
+
static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -354,6 +486,8 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
return -1;
}
+ tls_peer_cert_event(conn, idx, cert);
+
if (last == NULL)
chain = cert;
else
@@ -364,31 +498,99 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
pos += cert_len;
}
- if (conn->cred &&
- x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
- &reason, conn->disable_time_checks)
- < 0) {
+ if (conn->cred && conn->cred->server_cert_only && chain) {
+ u8 hash[SHA256_MAC_LEN];
+ char buf[128];
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Validate server certificate hash");
+ x509_name_string(&chain->subject, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "TLSv1: 0: %s", buf);
+ if (sha256_vector(1, &chain->cert_start, &chain->cert_len,
+ hash) < 0 ||
+ os_memcmp(conn->cred->srv_cert_hash, hash,
+ SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Server certificate hash mismatch");
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: SHA256 hash",
+ hash, SHA256_MAC_LEN);
+ if (conn->event_cb) {
+ union tls_event_data ev;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = TLS_FAIL_UNSPECIFIED;
+ ev.cert_fail.reason_txt =
+ "Server certificate mismatch";
+ ev.cert_fail.subject = buf;
+ conn->event_cb(conn->cb_ctx,
+ TLS_CERT_CHAIN_FAILURE, &ev);
+ }
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+ } else if (conn->cred && conn->cred->cert_probe) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Reject server certificate on probe-only rune");
+ if (conn->event_cb) {
+ union tls_event_data ev;
+ char buf[128];
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = TLS_FAIL_SERVER_CHAIN_PROBE;
+ ev.cert_fail.reason_txt =
+ "Server certificate chain probe";
+ if (chain) {
+ x509_name_string(&chain->subject, buf,
+ sizeof(buf));
+ ev.cert_fail.subject = buf;
+ }
+ conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE,
+ &ev);
+ }
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ } else if (conn->cred && conn->cred->ca_cert_verify &&
+ x509_certificate_chain_validate(
+ conn->cred->trusted_certs, chain, &reason,
+ !!(conn->flags & TLS_CONN_DISABLE_TIME_CHECKS))
+ < 0) {
int tls_reason;
wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
"validation failed (reason=%d)", reason);
switch (reason) {
case X509_VALIDATE_BAD_CERTIFICATE:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+ "bad certificate");
break;
case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
break;
case X509_VALIDATE_CERTIFICATE_REVOKED:
tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_REVOKED,
+ "certificate revoked");
break;
case X509_VALIDATE_CERTIFICATE_EXPIRED:
tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_EXPIRED,
+ "certificate has expired or is not yet valid");
break;
case X509_VALIDATE_CERTIFICATE_UNKNOWN:
tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
break;
case X509_VALIDATE_UNKNOWN_CA:
tls_reason = TLS_ALERT_UNKNOWN_CA;
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_UNTRUSTED,
+ "unknown CA");
break;
default:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
@@ -399,7 +601,25 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
return -1;
}
- x509_certificate_chain_free(chain);
+ if (conn->cred && !conn->cred->server_cert_only && chain &&
+ (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
+ !(chain->ext_key_usage &
+ (X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_SERVER_AUTH))) {
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+ "certificate not allowed for server authentication");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+ x509_certificate_chain_free(conn->server_cert);
+ conn->server_cert = chain;
+ } else {
+ x509_certificate_chain_free(chain);
+ }
*in_len = end - in_data;
@@ -465,10 +685,9 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
pos, conn->dh_p_len);
goto fail;
}
- conn->dh_p = os_malloc(conn->dh_p_len);
+ conn->dh_p = os_memdup(pos, conn->dh_p_len);
if (conn->dh_p == NULL)
goto fail;
- os_memcpy(conn->dh_p, pos, conn->dh_p_len);
pos += conn->dh_p_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
conn->dh_p, conn->dh_p_len);
@@ -480,10 +699,9 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (val == 0 || val > (size_t) (end - pos))
goto fail;
conn->dh_g_len = val;
- conn->dh_g = os_malloc(conn->dh_g_len);
+ conn->dh_g = os_memdup(pos, conn->dh_g_len);
if (conn->dh_g == NULL)
goto fail;
- os_memcpy(conn->dh_g, pos, conn->dh_g_len);
pos += conn->dh_g_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
conn->dh_g, conn->dh_g_len);
@@ -497,17 +715,16 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (val == 0 || val > (size_t) (end - pos))
goto fail;
conn->dh_ys_len = val;
- conn->dh_ys = os_malloc(conn->dh_ys_len);
+ conn->dh_ys = os_memdup(pos, conn->dh_ys_len);
if (conn->dh_ys == NULL)
goto fail;
- os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
pos += conn->dh_ys_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
conn->dh_ys, conn->dh_ys_len);
server_params_end = pos;
if (key_exchange == TLS_KEY_X_DHE_RSA) {
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+ u8 hash[64];
int hlen;
if (conn->rl.tls_version == TLS_VERSION_1_2) {
@@ -524,18 +741,21 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
*/
if (end - pos < 2)
goto fail;
- if (pos[0] != TLS_HASH_ALG_SHA256 ||
+ if ((pos[0] != TLS_HASH_ALG_SHA256 &&
+ pos[0] != TLS_HASH_ALG_SHA384 &&
+ pos[0] != TLS_HASH_ALG_SHA512) ||
pos[1] != TLS_SIGN_ALG_RSA) {
wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
pos[0], pos[1]);
goto fail;
}
- pos += 2;
hlen = tlsv12_key_x_server_params_hash(
- conn->rl.tls_version, conn->client_random,
+ conn->rl.tls_version, pos[0],
+ conn->client_random,
conn->server_random, server_params,
server_params_end - server_params, hash);
+ pos += 2;
#else /* CONFIG_TLSV12 */
goto fail;
#endif /* CONFIG_TLSV12 */
@@ -567,6 +787,229 @@ fail:
}
+static enum tls_ocsp_result
+tls_process_certificate_status_ocsp_response(struct tlsv1_client *conn,
+ const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+ u32 ocsp_resp_len;
+
+ /* opaque OCSPResponse<1..2^24-1>; */
+ if (end - pos < 3) {
+ wpa_printf(MSG_INFO, "TLSv1: Too short OCSPResponse");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return TLS_OCSP_INVALID;
+ }
+ ocsp_resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (end - pos < ocsp_resp_len) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated OCSPResponse");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return TLS_OCSP_INVALID;
+ }
+
+ return tls_process_ocsp_response(conn, pos, ocsp_resp_len);
+}
+
+
+static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type, status_type;
+ enum tls_ocsp_result res;
+ struct x509_certificate *cert;
+ int depth;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Expected Handshake; received content type 0x%x",
+ ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Too short CertificateStatus (left=%lu)",
+ (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Mismatch in CertificateStatus length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Received unexpected handshake message %d (expected CertificateStatus)",
+ type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateStatus");
+
+ /*
+ * struct {
+ * CertificateStatusType status_type;
+ * select (status_type) {
+ * case ocsp: OCSPResponse;
+ * case ocsp_multi: OCSPResponseList;
+ * } response;
+ * } CertificateStatus;
+ */
+ if (end - pos < 1) {
+ wpa_printf(MSG_INFO, "TLSv1: Too short CertificateStatus");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ status_type = *pos++;
+ wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatus status_type %u",
+ status_type);
+
+ if (status_type == 1 /* ocsp */) {
+ res = tls_process_certificate_status_ocsp_response(
+ conn, pos, end - pos);
+ } else if (status_type == 2 /* ocsp_multi */) {
+ int good = 0, revoked = 0;
+ u32 resp_len;
+
+ res = TLS_OCSP_NO_RESPONSE;
+
+ /*
+ * opaque OCSPResponse<0..2^24-1>;
+ *
+ * struct {
+ * OCSPResponse ocsp_response_list<1..2^24-1>;
+ * } OCSPResponseList;
+ */
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponseList");
+ res = TLS_OCSP_INVALID;
+ goto done;
+ }
+ resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (end - pos < resp_len) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponseList(len=%u)",
+ resp_len);
+ res = TLS_OCSP_INVALID;
+ goto done;
+ }
+ end = pos + resp_len;
+
+ while (end - pos >= 3) {
+ resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (resp_len > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponse(len=%u; left=%d) in ocsp_multi",
+ resp_len, (int) (end - pos));
+ res = TLS_OCSP_INVALID;
+ break;
+ }
+ if (!resp_len)
+ continue; /* Skip an empty response */
+ res = tls_process_certificate_status_ocsp_response(
+ conn, pos - 3, resp_len + 3);
+ if (res == TLS_OCSP_REVOKED)
+ revoked++;
+ else if (res == TLS_OCSP_GOOD)
+ good++;
+ pos += resp_len;
+ }
+
+ if (revoked)
+ res = TLS_OCSP_REVOKED;
+ else if (good)
+ res = TLS_OCSP_GOOD;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Ignore unsupported CertificateStatus");
+ goto skip;
+ }
+
+done:
+ if (res == TLS_OCSP_REVOKED) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_CERTIFICATE_REVOKED);
+ for (cert = conn->server_cert, depth = 0; cert;
+ cert = cert->next, depth++) {
+ if (cert->ocsp_revoked) {
+ tls_cert_chain_failure_event(
+ conn, depth, cert, TLS_FAIL_REVOKED,
+ "certificate revoked");
+ }
+ }
+ return -1;
+ }
+
+ if (conn->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ /*
+ * Verify that each certificate on the chain that is not part
+ * of the trusted certificates has a good status. If not,
+ * terminate handshake.
+ */
+ for (cert = conn->server_cert, depth = 0; cert;
+ cert = cert->next, depth++) {
+ if (!cert->ocsp_good) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ tls_cert_chain_failure_event(
+ conn, depth, cert,
+ TLS_FAIL_UNSPECIFIED,
+ "bad certificate status response");
+ return -1;
+ }
+ if (cert->issuer_trusted)
+ break;
+ }
+ }
+
+ if ((conn->flags & TLS_CONN_REQUIRE_OCSP) && res != TLS_OCSP_GOOD) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ res == TLS_OCSP_INVALID ? TLS_ALERT_DECODE_ERROR :
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ if (conn->server_cert)
+ tls_cert_chain_failure_event(
+ conn, 0, conn->server_cert,
+ TLS_FAIL_UNSPECIFIED,
+ "bad certificate status response");
+ return -1;
+ }
+
+ conn->ocsp_resp_received = 1;
+
+skip:
+ *in_len = end - in_data;
+
+ conn->state = SERVER_KEY_EXCHANGE;
+
+ return 0;
+}
+
+
static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -608,6 +1051,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
end = pos + len;
+ if ((conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ type == TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS)
+ return tls_process_certificate_status(conn, ct, in_data,
+ in_len);
if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
return tls_process_certificate_request(conn, ct, in_data,
in_len);
@@ -617,7 +1064,9 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected ServerKeyExchange/"
- "CertificateRequest/ServerHelloDone)", type);
+ "CertificateRequest/ServerHelloDone%s)", type,
+ (conn->flags & TLS_CONN_REQUEST_OCSP) ?
+ "/CertificateStatus" : "");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -771,6 +1220,15 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
+ if ((conn->flags & TLS_CONN_REQUIRE_OCSP) &&
+ !conn->ocsp_resp_received) {
+ wpa_printf(MSG_INFO,
+ "TLSv1: No OCSP response received - reject handshake");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ return -1;
+ }
+
*in_len = end - in_data;
conn->state = CLIENT_KEY_EXCHANGE;
diff --git a/contrib/wpa/src/tls/tlsv1_client_write.c b/contrib/wpa/src/tls/tlsv1_client_write.c
index d192f44..4a1147b 100644
--- a/contrib/wpa/src/tls/tlsv1_client_write.c
+++ b/contrib/wpa/src/tls/tlsv1_client_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - write handshake message
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -47,11 +47,34 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
struct os_time now;
size_t len, i;
+ u8 *ext_start;
+ u16 tls_version = TLS_VERSION;
- wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
+ /* Pick the highest locally enabled TLS version */
+#ifdef CONFIG_TLSV12
+ if ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
+ tls_version == TLS_VERSION_1_2)
+ tls_version = TLS_VERSION_1_1;
+#endif /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+ if ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
+ tls_version == TLS_VERSION_1_1)
+ tls_version = TLS_VERSION_1;
+#endif /* CONFIG_TLSV11 */
+ if ((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
+ tls_version == TLS_VERSION_1) {
+ wpa_printf(MSG_INFO, "TLSv1: No TLS version allowed");
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello (ver %s)",
+ tls_version_str(tls_version));
*out_len = 0;
os_get_time(&now);
+#ifdef TEST_FUZZ
+ now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
WPA_PUT_BE32(conn->client_random, now.sec);
if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
@@ -61,7 +84,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
conn->client_random, TLS_RANDOM_LEN);
- len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
+ len = 150 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
hello = os_malloc(len);
if (hello == NULL)
return NULL;
@@ -81,7 +104,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
pos += 3;
/* body - ClientHello */
/* ProtocolVersion client_version */
- WPA_PUT_BE16(pos, TLS_VERSION);
+ WPA_PUT_BE16(pos, tls_version);
pos += 2;
/* Random random: uint32 gmt_unix_time, opaque random_bytes */
os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
@@ -101,12 +124,124 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
*pos++ = 1;
*pos++ = TLS_COMPRESSION_NULL;
+ /* Extension */
+ ext_start = pos;
+ pos += 2;
+
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+ /*
+ * Add signature_algorithms extension since we support only
+ * SHA256 (and not the default SHA1) with TLSv1.2.
+ */
+ /* ExtensionsType extension_type = signature_algorithms(13) */
+ WPA_PUT_BE16(pos, TLS_EXT_SIGNATURE_ALGORITHMS);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 8);
+ pos += 2;
+ /* supported_signature_algorithms<2..2^16-2> length */
+ WPA_PUT_BE16(pos, 6);
+ pos += 2;
+ /* supported_signature_algorithms */
+ *pos++ = TLS_HASH_ALG_SHA512;
+ *pos++ = TLS_SIGN_ALG_RSA;
+ *pos++ = TLS_HASH_ALG_SHA384;
+ *pos++ = TLS_SIGN_ALG_RSA;
+ *pos++ = TLS_HASH_ALG_SHA256;
+ *pos++ = TLS_SIGN_ALG_RSA;
+ }
+#endif /* CONFIG_TLSV12 */
+
if (conn->client_hello_ext) {
os_memcpy(pos, conn->client_hello_ext,
conn->client_hello_ext_len);
pos += conn->client_hello_ext_len;
}
+ if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Add status_request extension for OCSP stapling");
+ /* ExtensionsType extension_type = status_request(5) */
+ WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 5);
+ pos += 2;
+
+ /*
+ * RFC 6066, 8:
+ * struct {
+ * CertificateStatusType status_type;
+ * select (status_type) {
+ * case ocsp: OCSPStatusRequest;
+ * } request;
+ * } CertificateStatusRequest;
+ *
+ * enum { ocsp(1), (255) } CertificateStatusType;
+ */
+ *pos++ = 1; /* status_type = ocsp(1) */
+
+ /*
+ * struct {
+ * ResponderID responder_id_list<0..2^16-1>;
+ * Extensions request_extensions;
+ * } OCSPStatusRequest;
+ *
+ * opaque ResponderID<1..2^16-1>;
+ * opaque Extensions<0..2^16-1>;
+ */
+ WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+ pos += 2;
+ WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+ pos += 2;
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Add status_request_v2 extension for OCSP stapling");
+ /* ExtensionsType extension_type = status_request_v2(17) */
+ WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 7);
+ pos += 2;
+
+ /*
+ * RFC 6961, 2.2:
+ * struct {
+ * CertificateStatusType status_type;
+ * uint16 request_length;
+ * select (status_type) {
+ * case ocsp: OCSPStatusRequest;
+ * case ocsp_multi: OCSPStatusRequest;
+ * } request;
+ * } CertificateStatusRequestItemV2;
+ *
+ * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+ *
+ * struct {
+ * CertificateStatusRequestItemV2
+ * certificate_status_req_list<1..2^16-1>;
+ * } CertificateStatusRequestListV2;
+ */
+
+ /* certificate_status_req_list<1..2^16-1> */
+ WPA_PUT_BE16(pos, 5);
+ pos += 2;
+
+ /* CertificateStatusRequestItemV2 */
+ *pos++ = 2; /* status_type = ocsp_multi(2) */
+ /* OCSPStatusRequest as shown above for v1 */
+ WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+ pos += 2;
+ WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+ pos += 2;
+ }
+
+ if (pos == ext_start + 2)
+ pos -= 2; /* no extensions */
+ else
+ WPA_PUT_BE16(ext_start, pos - ext_start - 2);
+
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
@@ -134,6 +269,11 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
struct x509_certificate *cert;
pos = *msgpos;
+ if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
rhdr = pos;
@@ -154,7 +294,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
pos += 3;
cert = conn->cred ? conn->cred->cert : NULL;
while (cert) {
- if (pos + 3 + cert->cert_len > end) {
+ if (3 + cert->cert_len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
"for Certificate (cert_len=%lu left=%lu)",
(unsigned long) cert->cert_len,
@@ -265,9 +405,16 @@ static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
dh_yc, dh_yc_len);
+ if (end - *pos < 2) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ os_free(dh_yc);
+ return -1;
+ }
WPA_PUT_BE16(*pos, dh_yc_len);
*pos += 2;
- if (*pos + dh_yc_len > end) {
+ if (dh_yc_len > (size_t) (end - *pos)) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
"message buffer for Yc");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -789,6 +936,8 @@ static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
"successfully");
+ if (!conn->session_resumed && conn->use_session_ticket)
+ conn->session_resumed = 1;
conn->state = ESTABLISHED;
return msg;
diff --git a/contrib/wpa/src/tls/tlsv1_common.c b/contrib/wpa/src/tls/tlsv1_common.c
index dabc12a..e178915 100644
--- a/contrib/wpa/src/tls/tlsv1_common.c
+++ b/contrib/wpa/src/tls/tlsv1_common.c
@@ -21,7 +21,7 @@
* RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
* Add support for commonly used cipher suites; don't bother with exportable
* suites.
- */
+ */
static const struct tls_cipher_suite tls_cipher_suites[] = {
{ TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL,
@@ -335,7 +335,7 @@ int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
#ifdef CONFIG_TLSV12
-int tlsv12_key_x_server_params_hash(u16 tls_version,
+int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_alg,
const u8 *client_random,
const u8 *server_random,
const u8 *server_params,
@@ -343,14 +343,30 @@ int tlsv12_key_x_server_params_hash(u16 tls_version,
{
size_t hlen;
struct crypto_hash *ctx;
-
- ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
+ enum crypto_hash_alg alg;
+
+ switch (hash_alg) {
+ case TLS_HASH_ALG_SHA256:
+ alg = CRYPTO_HASH_ALG_SHA256;
+ hlen = SHA256_MAC_LEN;
+ break;
+ case TLS_HASH_ALG_SHA384:
+ alg = CRYPTO_HASH_ALG_SHA384;
+ hlen = 48;
+ break;
+ case TLS_HASH_ALG_SHA512:
+ alg = CRYPTO_HASH_ALG_SHA512;
+ hlen = 64;
+ break;
+ default:
+ return -1;
+ }
+ ctx = crypto_hash_init(alg, NULL, 0);
if (ctx == NULL)
return -1;
crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
crypto_hash_update(ctx, server_params, server_params_len);
- hlen = SHA256_MAC_LEN;
if (crypto_hash_finish(ctx, hash, &hlen) < 0)
return -1;
@@ -466,9 +482,24 @@ int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
"\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
{
- wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256");
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-256");
+ decrypted = buf + 19;
+ buflen -= 19;
+ } else if (buflen >= 19 + 48 &&
+ os_memcmp(buf, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01"
+ "\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19) == 0)
+ {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-384");
+ decrypted = buf + 19;
+ buflen -= 19;
+ } else if (buflen >= 19 + 64 &&
+ os_memcmp(buf, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01"
+ "\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19) == 0)
+ {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-512");
decrypted = buf + 19;
buflen -= 19;
+
} else {
wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
os_free(buf);
diff --git a/contrib/wpa/src/tls/tlsv1_common.h b/contrib/wpa/src/tls/tlsv1_common.h
index 26e68af..e30b15a 100644
--- a/contrib/wpa/src/tls/tlsv1_common.h
+++ b/contrib/wpa/src/tls/tlsv1_common.h
@@ -169,6 +169,8 @@ enum {
#define TLS_EXT_TRUSTED_CA_KEYS 3 /* RFC 4366 */
#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */
#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */
+#define TLS_EXT_SIGNATURE_ALGORITHMS 13 /* RFC 5246 */
+#define TLS_EXT_STATUS_REQUEST_V2 17 /* RFC 6961 */
#define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */
#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
@@ -257,7 +259,8 @@ int tls_version_ok(u16 ver);
const char * tls_version_str(u16 ver);
int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
-int tlsv12_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_Alg,
+ const u8 *client_random,
const u8 *server_random,
const u8 *server_params,
size_t server_params_len, u8 *hash);
diff --git a/contrib/wpa/src/tls/tlsv1_cred.c b/contrib/wpa/src/tls/tlsv1_cred.c
index 1ea6827..842e5dd 100644
--- a/contrib/wpa/src/tls/tlsv1_cred.c
+++ b/contrib/wpa/src/tls/tlsv1_cred.c
@@ -1,6 +1,6 @@
/*
* TLSv1 credentials
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,9 @@
#include "common.h"
#include "base64.h"
#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "pkcs5.h"
+#include "pkcs8.h"
#include "x509v3.h"
#include "tlsv1_cred.h"
@@ -33,6 +36,8 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred)
crypto_private_key_free(cred->key);
os_free(cred->dh_p);
os_free(cred->dh_g);
+ os_free(cred->ocsp_stapling_response);
+ os_free(cred->ocsp_stapling_response_multi);
os_free(cred);
}
@@ -190,6 +195,43 @@ int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
const u8 *cert_blob, size_t cert_blob_len,
const char *path)
{
+ if (cert && os_strncmp(cert, "hash://", 7) == 0) {
+ const char *pos = cert + 7;
+ if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Unsupported ca_cert hash value '%s'",
+ cert);
+ return -1;
+ }
+ pos += 14;
+ if (os_strlen(pos) != 32 * 2) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Unexpected SHA256 hash length in ca_cert '%s'",
+ cert);
+ return -1;
+ }
+ if (hexstr2bin(pos, cred->srv_cert_hash, 32) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Invalid SHA256 hash value in ca_cert '%s'",
+ cert);
+ return -1;
+ }
+ cred->server_cert_only = 1;
+ cred->ca_cert_verify = 0;
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Checking only server certificate match");
+ return 0;
+ }
+
+ if (cert && os_strncmp(cert, "probe://", 8) == 0) {
+ cred->cert_probe = 1;
+ cred->ca_cert_verify = 0;
+ wpa_printf(MSG_DEBUG, "TLSv1: Only probe server certificate");
+ return 0;
+ }
+
+ cred->ca_cert_verify = cert || cert_blob || path;
+
if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
cert_blob, cert_blob_len) < 0)
return -1;
@@ -288,6 +330,735 @@ static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
}
+#ifdef PKCS12_FUNCS
+
+static int oid_is_rsadsi(struct asn1_oid *oid)
+{
+ return oid->len >= 4 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int pkcs12_is_bagtype_oid(struct asn1_oid *oid, unsigned long type)
+{
+ return oid->len == 9 &&
+ oid_is_rsadsi(oid) &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 12 /* pkcs-12 */ &&
+ oid->oid[6] == 10 &&
+ oid->oid[7] == 1 /* bagtypes */ &&
+ oid->oid[8] == type;
+}
+
+
+static int is_oid_pkcs7(struct asn1_oid *oid)
+{
+ return oid->len == 7 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */ &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 7 /* pkcs-7 */;
+}
+
+
+static int is_oid_pkcs7_data(struct asn1_oid *oid)
+{
+ return is_oid_pkcs7(oid) && oid->oid[6] == 1 /* data */;
+}
+
+
+static int is_oid_pkcs7_enc_data(struct asn1_oid *oid)
+{
+ return is_oid_pkcs7(oid) && oid->oid[6] == 6 /* encryptedData */;
+}
+
+
+static int is_oid_pkcs9(struct asn1_oid *oid)
+{
+ return oid->len >= 6 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */ &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 9 /* pkcs-9 */;
+}
+
+
+static int is_oid_pkcs9_friendly_name(struct asn1_oid *oid)
+{
+ return oid->len == 7 && is_oid_pkcs9(oid) &&
+ oid->oid[6] == 20;
+}
+
+
+static int is_oid_pkcs9_local_key_id(struct asn1_oid *oid)
+{
+ return oid->len == 7 && is_oid_pkcs9(oid) &&
+ oid->oid[6] == 21;
+}
+
+
+static int is_oid_pkcs9_x509_cert(struct asn1_oid *oid)
+{
+ return oid->len == 8 && is_oid_pkcs9(oid) &&
+ oid->oid[6] == 22 /* certTypes */ &&
+ oid->oid[7] == 1 /* x509Certificate */;
+}
+
+
+static int pkcs12_keybag(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len)
+{
+ /* TODO */
+ return 0;
+}
+
+
+static int pkcs12_pkcs8_keybag(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len,
+ const char *passwd)
+{
+ struct crypto_private_key *key;
+
+ /* PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo */
+ key = pkcs8_enc_key_import(buf, len, passwd);
+ if (!key)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Successfully decrypted PKCS8ShroudedKeyBag");
+ crypto_private_key_free(cred->key);
+ cred->key = key;
+
+ return 0;
+}
+
+
+static int pkcs12_certbag(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ char obuf[80];
+ const u8 *pos, *end;
+
+ /*
+ * CertBag ::= SEQUENCE {
+ * certId BAG-TYPE.&id ({CertTypes}),
+ * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
+ * }
+ */
+
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (CertBag) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Failed to parse OID (certId)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: certId %s", obuf);
+
+ if (!is_oid_pkcs9_x509_cert(&oid)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Ignored unsupported certificate type (certId %s)",
+ obuf);
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] EXPLICIT (certValue) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected OCTET STRING (x509Certificate) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PKCS #12: x509Certificate",
+ hdr.payload, hdr.length);
+ if (cred->cert) {
+ struct x509_certificate *cert;
+
+ wpa_printf(MSG_DEBUG, "PKCS #12: Ignore extra certificate");
+ cert = x509_certificate_parse(hdr.payload, hdr.length);
+ if (!cert) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Failed to parse x509Certificate");
+ return 0;
+ }
+ x509_certificate_chain_free(cert);
+
+ return 0;
+ }
+ return tlsv1_set_cert(cred, NULL, hdr.payload, hdr.length);
+}
+
+
+static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
+{
+ struct asn1_hdr hdr;
+
+ /*
+ * RFC 2985, 5.5.1:
+ * friendlyName ATTRIBUTE ::= {
+ * WITH SYNTAX BMPString (SIZE(1..pkcs-9-ub-friendlyName))
+ * EQUALITY MATCHING RULE caseIgnoreMatch
+ * SINGLE VALUE TRUE
+ * ID pkcs-9-at-friendlyName
+ * }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_BMPSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected BMPSTRING (friendlyName) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return 0;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
+ hdr.payload, hdr.length);
+ return 0;
+}
+
+
+static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
+{
+ struct asn1_hdr hdr;
+
+ /*
+ * RFC 2985, 5.5.2:
+ * localKeyId ATTRIBUTE ::= {
+ * WITH SYNTAX OCTET STRING
+ * EQUALITY MATCHING RULE octetStringMatch
+ * SINGLE VALUE TRUE
+ * ID pkcs-9-at-localKeyId
+ * }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected OCTET STRING (localKeyID) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
+ hdr.payload, hdr.length);
+ return 0;
+}
+
+
+static int pkcs12_parse_attr(const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+ struct asn1_hdr hdr;
+ struct asn1_oid a_oid;
+ char obuf[80];
+
+ /*
+ * PKCS12Attribute ::= SEQUENCE {
+ * attrId ATTRIBUTE.&id ({PKCS12AttrSet}),
+ * attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
+ * }
+ */
+
+ if (asn1_get_oid(pos, end - pos, &a_oid, &pos)) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Failed to parse OID (attrId)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&a_oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: attrId %s", obuf);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SET (attrValues) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
+ hdr.payload, hdr.length);
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (is_oid_pkcs9_friendly_name(&a_oid))
+ return pkcs12_parse_attr_friendly_name(pos, end);
+ if (is_oid_pkcs9_local_key_id(&a_oid))
+ return pkcs12_parse_attr_local_key_id(pos, end);
+
+ wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unknown attribute");
+ return 0;
+}
+
+
+static int pkcs12_safebag(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len, const char *passwd)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ char obuf[80];
+ const u8 *pos = buf, *end = buf + len;
+ const u8 *value;
+ size_t value_len;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: SafeBag", buf, len);
+
+ /* BAG-TYPE ::= TYPE-IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Failed to parse OID (BAG-TYPE)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: BAG-TYPE %s", obuf);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] EXPLICIT (bagValue) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return 0;
+ }
+ value = hdr.payload;
+ value_len = hdr.length;
+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagValue", value, value_len);
+ pos = hdr.payload + hdr.length;
+
+ if (pos < end) {
+ /* bagAttributes SET OF PKCS12Attribute OPTIONAL */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SET (bagAttributes) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
+ hdr.payload, hdr.length);
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+ while (pos < end) {
+ /* PKCS12Attribute ::= SEQUENCE */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (PKCS12Attribute) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
+ return -1;
+ pos = hdr.payload + hdr.length;
+ }
+ }
+
+ if (pkcs12_is_bagtype_oid(&oid, 1))
+ return pkcs12_keybag(cred, value, value_len);
+ if (pkcs12_is_bagtype_oid(&oid, 2))
+ return pkcs12_pkcs8_keybag(cred, value, value_len, passwd);
+ if (pkcs12_is_bagtype_oid(&oid, 3))
+ return pkcs12_certbag(cred, value, value_len);
+
+ wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unsupported BAG-TYPE");
+ return 0;
+}
+
+
+static int pkcs12_safecontents(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len,
+ const char *passwd)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+
+ /* SafeContents ::= SEQUENCE OF SafeBag */
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (SafeContents) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * SafeBag ::= SEQUENCE {
+ * bagId BAG-TYPE.&id ({PKCS12BagSet})
+ * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
+ * bagAttributes SET OF PKCS12Attribute OPTIONAL
+ * }
+ */
+
+ while (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (SafeBag) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
+ return -1;
+ pos = hdr.payload + hdr.length;
+ }
+
+ return 0;
+}
+
+
+static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
+ const u8 *pos, const u8 *end,
+ const char *passwd)
+{
+ struct asn1_hdr hdr;
+
+ /* Data ::= OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data", hdr.payload, hdr.length);
+
+ return pkcs12_safecontents(cred, hdr.payload, hdr.length, passwd);
+}
+
+
+static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
+ const u8 *pos, const u8 *end,
+ const char *passwd)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ char buf[80];
+ const u8 *enc_alg;
+ u8 *data;
+ size_t enc_alg_len, data_len;
+ int res = -1;
+
+ /*
+ * EncryptedData ::= SEQUENCE {
+ * version Version,
+ * encryptedContentInfo EncryptedContentInfo }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (EncryptedData) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return 0;
+ }
+ pos = hdr.payload;
+
+ /* Version ::= INTEGER */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length != 1 || hdr.payload[0] != 0) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized PKCS #7 version");
+ return -1;
+ }
+ pos = hdr.payload + hdr.length;
+
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #12: EncryptedContentInfo",
+ pos, end - pos);
+
+ /*
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (EncryptedContentInfo) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
+ return -1;
+ }
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: EncryptedContentInfo::contentType %s",
+ buf);
+
+ if (!is_oid_pkcs7_data(&oid)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Unsupported EncryptedContentInfo::contentType %s",
+ buf);
+ return 0;
+ }
+
+ /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ enc_alg = hdr.payload;
+ enc_alg_len = hdr.length;
+ pos = hdr.payload + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] IMPLICIT (encryptedContent) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ /* EncryptedContent ::= OCTET STRING */
+ data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
+ passwd, &data_len);
+ if (data) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "PKCS #12: Decrypted encryptedContent",
+ data, data_len);
+ res = pkcs12_safecontents(cred, data, data_len, passwd);
+ os_free(data);
+ }
+
+ return res;
+}
+
+
+static int pkcs12_parse_content(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len,
+ const char *passwd)
+{
+ const u8 *pos = buf;
+ const u8 *end = buf + len;
+ struct asn1_oid oid;
+ char txt[80];
+ struct asn1_hdr hdr;
+
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #12: ContentInfo", buf, len);
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
+ return 0;
+ }
+
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", txt);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return 0;
+ }
+ pos = hdr.payload;
+
+ if (is_oid_pkcs7_data(&oid))
+ return pkcs12_parse_content_data(cred, pos, end, passwd);
+ if (is_oid_pkcs7_enc_data(&oid))
+ return pkcs12_parse_content_enc_data(cred, pos, end, passwd);
+
+ wpa_printf(MSG_DEBUG, "PKCS #12: Ignored unsupported contentType %s",
+ txt);
+
+ return 0;
+}
+
+
+static int pkcs12_parse(struct tlsv1_credentials *cred,
+ const u8 *key, size_t len, const char *passwd)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ struct asn1_oid oid;
+ char buf[80];
+
+ /*
+ * PFX ::= SEQUENCE {
+ * version INTEGER {v3(3)}(v3,...),
+ * authSafe ContentInfo,
+ * macData MacData OPTIONAL
+ * }
+ */
+
+ if (asn1_get_next(key, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (PFX) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length != 1 || hdr.payload[0] != 3) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized version");
+ return -1;
+ }
+ pos = hdr.payload + hdr.length;
+
+ /*
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (authSafe) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Could not find OBJECT IDENTIFIER (contentType); assume PKCS #12 not used");
+ return -1;
+ }
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", buf);
+ if (!is_oid_pkcs7_data(&oid)) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Unsupported contentType %s",
+ buf);
+ return -1;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+
+ /* Data ::= OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ /*
+ * AuthenticatedSafe ::= SEQUENCE OF ContentInfo
+ * -- Data if unencrypted
+ * -- EncryptedData if password-encrypted
+ * -- EnvelopedData if public key-encrypted
+ */
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data content",
+ hdr.payload, hdr.length);
+
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE within Data content - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ while (end > pos) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (ContentInfo) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
+ passwd) < 0)
+ return -1;
+
+ pos = hdr.payload + hdr.length;
+ }
+
+ return 0;
+}
+
+#endif /* PKCS12_FUNCS */
+
+
static int tlsv1_set_key(struct tlsv1_credentials *cred,
const u8 *key, size_t len, const char *passwd)
{
@@ -296,6 +1067,10 @@ static int tlsv1_set_key(struct tlsv1_credentials *cred,
cred->key = tlsv1_set_key_pem(key, len);
if (cred->key == NULL)
cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
+#ifdef PKCS12_FUNCS
+ if (!cred->key)
+ pkcs12_parse(cred, key, len, passwd);
+#endif /* PKCS12_FUNCS */
if (cred->key == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
return -1;
@@ -391,10 +1166,9 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
if (hdr.length == 0)
return -1;
os_free(cred->dh_p);
- cred->dh_p = os_malloc(hdr.length);
+ cred->dh_p = os_memdup(hdr.payload, hdr.length);
if (cred->dh_p == NULL)
return -1;
- os_memcpy(cred->dh_p, hdr.payload, hdr.length);
cred->dh_p_len = hdr.length;
pos = hdr.payload + hdr.length;
@@ -413,10 +1187,9 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
if (hdr.length == 0)
return -1;
os_free(cred->dh_g);
- cred->dh_g = os_malloc(hdr.length);
+ cred->dh_g = os_memdup(hdr.payload, hdr.length);
if (cred->dh_g == NULL)
return -1;
- os_memcpy(cred->dh_g, hdr.payload, hdr.length);
cred->dh_g_len = hdr.length;
return 0;
diff --git a/contrib/wpa/src/tls/tlsv1_cred.h b/contrib/wpa/src/tls/tlsv1_cred.h
index 68fbdc9..716e93c 100644
--- a/contrib/wpa/src/tls/tlsv1_cred.h
+++ b/contrib/wpa/src/tls/tlsv1_cred.h
@@ -14,11 +14,19 @@ struct tlsv1_credentials {
struct x509_certificate *cert;
struct crypto_private_key *key;
+ unsigned int cert_probe:1;
+ unsigned int ca_cert_verify:1;
+ unsigned int server_cert_only:1;
+ u8 srv_cert_hash[32];
+
/* Diffie-Hellman parameters */
u8 *dh_p; /* prime */
size_t dh_p_len;
u8 *dh_g; /* generator */
size_t dh_g_len;
+
+ char *ocsp_stapling_response;
+ char *ocsp_stapling_response_multi;
};
diff --git a/contrib/wpa/src/tls/tlsv1_server.c b/contrib/wpa/src/tls/tlsv1_server.c
index ba47337..12dcc85 100644
--- a/contrib/wpa/src/tls/tlsv1_server.c
+++ b/contrib/wpa/src/tls/tlsv1_server.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -164,7 +164,8 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
/* need more data */
wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
"yet supported");
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
goto failed;
}
ct = pos[0];
@@ -204,6 +205,7 @@ failed:
msg = tlsv1_server_send_alert(conn, conn->alert_level,
conn->alert_description,
out_len);
+ conn->write_alerts++;
}
return msg;
@@ -216,7 +218,7 @@ failed:
* @in_data: Pointer to plaintext data to be encrypted
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (encrypted TLS data)
- * @out_len: Maximum out_data length
+ * @out_len: Maximum out_data length
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
@@ -296,6 +298,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
}
tlsv1_server_log(conn, "Received alert %d:%d",
out_pos[0], out_pos[1]);
+ conn->read_alerts++;
if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
/* Continue processing */
pos += used;
@@ -459,6 +462,8 @@ int tlsv1_server_established(struct tlsv1_server *conn)
* tlsv1_server_prf - Use TLS-PRF to derive keying material
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @label: Label (e.g., description of the key) for PRF
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
* @out: Buffer for output data from TLS-PRF
@@ -466,13 +471,26 @@ int tlsv1_server_established(struct tlsv1_server *conn)
* Returns: 0 on success, -1 on failure
*/
int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+ const u8 *context, size_t context_len,
int server_random_first, u8 *out, size_t out_len)
{
- u8 seed[2 * TLS_RANDOM_LEN];
+ u8 *seed, *pos;
+ size_t seed_len = 2 * TLS_RANDOM_LEN;
+ int res;
if (conn->state != ESTABLISHED)
return -1;
+ if (context_len > 65535)
+ return -1;
+
+ if (context)
+ seed_len += 2 + context_len;
+
+ seed = os_malloc(seed_len);
+ if (!seed)
+ return -1;
+
if (server_random_first) {
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
@@ -483,9 +501,18 @@ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
TLS_RANDOM_LEN);
}
- return tls_prf(conn->rl.tls_version,
- conn->master_secret, TLS_MASTER_SECRET_LEN,
- label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+ if (context) {
+ pos = seed + 2 * TLS_RANDOM_LEN;
+ WPA_PUT_BE16(pos, context_len);
+ pos += 2;
+ os_memcpy(pos, context, context_len);
+ }
+
+ res = tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
+ label, seed, seed_len, out, out_len);
+ os_free(seed);
+ return res;
}
@@ -708,6 +735,24 @@ void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
}
+int tlsv1_server_get_failed(struct tlsv1_server *conn)
+{
+ return conn->state == FAILED;
+}
+
+
+int tlsv1_server_get_read_alerts(struct tlsv1_server *conn)
+{
+ return conn->read_alerts;
+}
+
+
+int tlsv1_server_get_write_alerts(struct tlsv1_server *conn)
+{
+ return conn->write_alerts;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
{
diff --git a/contrib/wpa/src/tls/tlsv1_server.h b/contrib/wpa/src/tls/tlsv1_server.h
index 10e7699..c9c0875 100644
--- a/contrib/wpa/src/tls/tlsv1_server.h
+++ b/contrib/wpa/src/tls/tlsv1_server.h
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,7 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred);
void tlsv1_server_deinit(struct tlsv1_server *conn);
int tlsv1_server_established(struct tlsv1_server *conn);
int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+ const u8 *context, size_t context_len,
int server_random_first, u8 *out, size_t out_len);
u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
const u8 *in_data, size_t in_len, size_t *out_len);
@@ -48,6 +49,10 @@ void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
void (*cb)(void *ctx, const char *msg), void *ctx);
+int tlsv1_server_get_failed(struct tlsv1_server *conn);
+int tlsv1_server_get_read_alerts(struct tlsv1_server *conn);
+int tlsv1_server_get_write_alerts(struct tlsv1_server *conn);
+
void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags);
#endif /* TLSV1_SERVER_H */
diff --git a/contrib/wpa/src/tls/tlsv1_server_i.h b/contrib/wpa/src/tls/tlsv1_server_i.h
index 96d79b3..2622585 100644
--- a/contrib/wpa/src/tls/tlsv1_server_i.h
+++ b/contrib/wpa/src/tls/tlsv1_server_i.h
@@ -30,6 +30,8 @@ struct tlsv1_server {
u8 alert_level;
u8 alert_description;
+ int read_alerts, write_alerts;
+
struct crypto_public_key *client_rsa_key;
struct tls_verify_hash verify;
@@ -55,6 +57,9 @@ struct tlsv1_server {
void *log_cb_ctx;
int use_session_ticket;
+ unsigned int status_request:1;
+ unsigned int status_request_v2:1;
+ unsigned int status_request_multi:1;
u8 *dh_secret;
size_t dh_secret_len;
diff --git a/contrib/wpa/src/tls/tlsv1_server_read.c b/contrib/wpa/src/tls/tlsv1_server_read.c
index 0f237ba..e957678 100644
--- a/contrib/wpa/src/tls/tlsv1_server_read.c
+++ b/contrib/wpa/src/tls/tlsv1_server_read.c
@@ -46,6 +46,78 @@ static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
}
+static void tls_process_status_request_item(struct tlsv1_server *conn,
+ const u8 *req, size_t req_len)
+{
+ const u8 *pos, *end;
+ u8 status_type;
+
+ pos = req;
+ end = req + req_len;
+
+ /*
+ * RFC 6961, 2.2:
+ * struct {
+ * CertificateStatusType status_type;
+ * uint16 request_length;
+ * select (status_type) {
+ * case ocsp: OCSPStatusRequest;
+ * case ocsp_multi: OCSPStatusRequest;
+ * } request;
+ * } CertificateStatusRequestItemV2;
+ *
+ * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+ */
+
+ if (end - pos < 1)
+ return; /* Truncated data */
+
+ status_type = *pos++;
+ wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatusType %u", status_type);
+ if (status_type != 1 && status_type != 2)
+ return; /* Unsupported status type */
+ /*
+ * For now, only OCSP stapling is supported, so ignore the specific
+ * request, if any.
+ */
+ wpa_hexdump(MSG_DEBUG, "TLSv1: OCSPStatusRequest", pos, end - pos);
+
+ if (status_type == 2)
+ conn->status_request_multi = 1;
+}
+
+
+static void tls_process_status_request_v2(struct tlsv1_server *conn,
+ const u8 *ext, size_t ext_len)
+{
+ const u8 *pos, *end;
+
+ conn->status_request_v2 = 1;
+
+ pos = ext;
+ end = ext + ext_len;
+
+ /*
+ * RFC 6961, 2.2:
+ * struct {
+ * CertificateStatusRequestItemV2
+ * certificate_status_req_list<1..2^16-1>;
+ * } CertificateStatusRequestListV2;
+ */
+
+ while (end - pos >= 2) {
+ u16 len;
+
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > end - pos)
+ break; /* Truncated data */
+ tls_process_status_request_item(conn, pos, len);
+ pos += len;
+ }
+}
+
+
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -67,8 +139,11 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
pos = in_data;
left = *in_len;
- if (left < 4)
+ if (left < 4) {
+ tlsv1_server_log(conn,
+ "Truncated handshake message (expected ClientHello)");
goto decode_error;
+ }
/* HandshakeType msg_type */
if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
@@ -85,8 +160,12 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
pos += 3;
left -= 4;
- if (len > left)
+ if (len > left) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello (len=%d left=%d)",
+ (int) len, (int) left);
goto decode_error;
+ }
/* body - ClientHello */
@@ -94,8 +173,10 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
end = pos + len;
/* ProtocolVersion client_version */
- if (end - pos < 2)
+ if (end - pos < 2) {
+ tlsv1_server_log(conn, "Truncated ClientHello/client_version");
goto decode_error;
+ }
conn->client_version = WPA_GET_BE16(pos);
tlsv1_server_log(conn, "Client version %d.%d",
conn->client_version >> 8,
@@ -124,8 +205,10 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
tls_version_str(conn->rl.tls_version));
/* Random random */
- if (end - pos < TLS_RANDOM_LEN)
+ if (end - pos < TLS_RANDOM_LEN) {
+ tlsv1_server_log(conn, "Truncated ClientHello/client_random");
goto decode_error;
+ }
os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
pos += TLS_RANDOM_LEN;
@@ -133,25 +216,36 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
conn->client_random, TLS_RANDOM_LEN);
/* SessionID session_id */
- if (end - pos < 1)
+ if (end - pos < 1) {
+ tlsv1_server_log(conn, "Truncated ClientHello/session_id len");
goto decode_error;
- if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+ }
+ if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) {
+ tlsv1_server_log(conn, "Truncated ClientHello/session_id");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
pos += 1 + *pos;
/* TODO: add support for session resumption */
/* CipherSuite cipher_suites<2..2^16-1> */
- if (end - pos < 2)
+ if (end - pos < 2) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/cipher_suites len");
goto decode_error;
+ }
num_suites = WPA_GET_BE16(pos);
pos += 2;
- if (end - pos < num_suites)
+ if (end - pos < num_suites) {
+ tlsv1_server_log(conn, "Truncated ClientHello/cipher_suites");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
pos, num_suites);
- if (num_suites & 1)
+ if (num_suites & 1) {
+ tlsv1_server_log(conn, "Odd len ClientHello/cipher_suites");
goto decode_error;
+ }
num_suites /= 2;
cipher_suite = 0;
@@ -187,11 +281,17 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
conn->cipher_suite = cipher_suite;
/* CompressionMethod compression_methods<1..2^8-1> */
- if (end - pos < 1)
+ if (end - pos < 1) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/compression_methods len");
goto decode_error;
+ }
num_suites = *pos++;
- if (end - pos < num_suites)
+ if (end - pos < num_suites) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/compression_methods");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
pos, num_suites);
compr_null_found = 0;
@@ -267,6 +367,11 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
ext_len);
conn->session_ticket_len = ext_len;
}
+ } else if (ext_type == TLS_EXT_STATUS_REQUEST) {
+ conn->status_request = 1;
+ } else if (ext_type == TLS_EXT_STATUS_REQUEST_V2) {
+ tls_process_status_request_v2(conn, pos,
+ ext_len);
}
pos += ext_len;
@@ -471,6 +576,15 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
return -1;
}
+ if (chain && (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
+ !(chain->ext_key_usage &
+ (X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_CLIENT_AUTH))) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
x509_certificate_chain_free(chain);
*in_len = end - in_data;
@@ -1131,6 +1245,7 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
tlsv1_server_log(conn, "Mismatch in verify_data");
+ conn->state = FAILED;
return -1;
}
diff --git a/contrib/wpa/src/tls/tlsv1_server_write.c b/contrib/wpa/src/tls/tlsv1_server_write.c
index 15e6692..8d36cf1 100644
--- a/contrib/wpa/src/tls/tlsv1_server_write.c
+++ b/contrib/wpa/src/tls/tlsv1_server_write.c
@@ -26,7 +26,7 @@ static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
size_t len = 0;
struct x509_certificate *cert;
- cert = conn->cred->cert;
+ cert = conn->cred ? conn->cred->cert : NULL;
while (cert) {
len += 3 + cert->cert_len;
if (x509_certificate_self_signed(cert))
@@ -42,7 +42,7 @@ static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
static int tls_write_server_hello(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
- u8 *pos, *rhdr, *hs_start, *hs_length;
+ u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start;
struct os_time now;
size_t rlen;
@@ -53,6 +53,9 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
pos += TLS_RECORD_HEADER_LEN;
os_get_time(&now);
+#ifdef TEST_FUZZ
+ now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
WPA_PUT_BE32(conn->server_random, now.sec);
if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
@@ -97,6 +100,32 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
/* CompressionMethod compression_method */
*pos++ = TLS_COMPRESSION_NULL;
+ /* Extension */
+ ext_start = pos;
+ pos += 2;
+
+ if (conn->status_request) {
+ /* Add a status_request extension with empty extension_data */
+ /* ExtensionsType extension_type = status_request(5) */
+ WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 0);
+ pos += 2;
+ }
+
+ if (conn->status_request_v2) {
+ /*
+ Add a status_request_v2 extension with empty extension_data
+ */
+ /* ExtensionsType extension_type = status_request_v2(17) */
+ WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 0);
+ pos += 2;
+ }
+
if (conn->session_ticket && conn->session_ticket_cb) {
int res = conn->session_ticket_cb(
conn->session_ticket_cb_ctx,
@@ -133,6 +162,11 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
*/
}
+ if (pos == ext_start + 2)
+ pos -= 2; /* no extensions */
+ else
+ WPA_PUT_BE16(ext_start, pos - ext_start - 2);
+
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
@@ -168,6 +202,11 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
}
pos = *msgpos;
+ if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
tlsv1_server_log(conn, "Send Certificate");
rhdr = pos;
@@ -188,7 +227,7 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
pos += 3;
cert = conn->cred->cert;
while (cert) {
- if (pos + 3 + cert->cert_len > end) {
+ if (3 + cert->cert_len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
"for Certificate (cert_len=%lu left=%lu)",
(unsigned long) cert->cert_len,
@@ -239,6 +278,93 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
}
+static int tls_write_server_certificate_status(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end,
+ int ocsp_multi,
+ char *ocsp_resp,
+ size_t ocsp_resp_len)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen;
+
+ if (!ocsp_resp) {
+ /*
+ * Client did not request certificate status or there is no
+ * matching response cached.
+ */
+ return 0;
+ }
+
+ pos = *msgpos;
+ if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + ocsp_resp_len >
+ (unsigned int) (end - pos)) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+
+ /* body - CertificateStatus
+ *
+ * struct {
+ * CertificateStatusType status_type;
+ * select (status_type) {
+ * case ocsp: OCSPResponse;
+ * case ocsp_multi: OCSPResponseList;
+ * } response;
+ * } CertificateStatus;
+ *
+ * opaque OCSPResponse<1..2^24-1>;
+ *
+ * struct {
+ * OCSPResponse ocsp_response_list<1..2^24-1>;
+ * } OCSPResponseList;
+ */
+
+ /* CertificateStatusType status_type */
+ if (ocsp_multi)
+ *pos++ = 2; /* ocsp_multi(2) */
+ else
+ *pos++ = 1; /* ocsp(1) */
+ /* uint24 length of OCSPResponse */
+ WPA_PUT_BE24(pos, ocsp_resp_len);
+ pos += 3;
+ os_memcpy(pos, ocsp_resp, ocsp_resp_len);
+ pos += ocsp_resp_len;
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
static int tls_write_server_key_exchange(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
@@ -371,7 +497,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
/* body - ServerDHParams */
server_params = pos;
/* dh_p */
- if (pos + 2 + dh_p_len > end) {
+ if (2 + dh_p_len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
"dh_p");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -385,7 +511,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
pos += dh_p_len;
/* dh_g */
- if (pos + 2 + conn->cred->dh_g_len > end) {
+ if (2 + conn->cred->dh_g_len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
"dh_g");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -399,7 +525,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
pos += conn->cred->dh_g_len;
/* dh_Ys */
- if (pos + 2 + dh_ys_len > end) {
+ if (2 + dh_ys_len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
"dh_Ys");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -443,7 +569,8 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
if (conn->rl.tls_version >= TLS_VERSION_1_2) {
#ifdef CONFIG_TLSV12
hlen = tlsv12_key_x_server_params_hash(
- conn->rl.tls_version, conn->client_random,
+ conn->rl.tls_version, TLS_HASH_ALG_SHA256,
+ conn->client_random,
conn->server_random, server_params,
pos - server_params, hash + 19);
@@ -457,7 +584,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
* SignatureAlgorithm signature;
* } SignatureAndHashAlgorithm;
*/
- if (hlen < 0 || pos + 2 > end) {
+ if (hlen < 0 || end - pos < 2) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
@@ -804,24 +931,46 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
{
u8 *msg, *end, *pos;
size_t msglen;
+ int ocsp_multi = 0;
+ char *ocsp_resp = NULL;
+ size_t ocsp_resp_len = 0;
*out_len = 0;
- msglen = 1000 + tls_server_cert_chain_der_len(conn);
+ if (conn->status_request_multi &&
+ conn->cred->ocsp_stapling_response_multi) {
+ ocsp_resp = os_readfile(
+ conn->cred->ocsp_stapling_response_multi,
+ &ocsp_resp_len);
+ ocsp_multi = 1;
+ } else if ((conn->status_request || conn->status_request_v2) &&
+ conn->cred->ocsp_stapling_response) {
+ ocsp_resp = os_readfile(conn->cred->ocsp_stapling_response,
+ &ocsp_resp_len);
+ }
+ if (!ocsp_resp)
+ ocsp_resp_len = 0;
+
+ msglen = 1000 + tls_server_cert_chain_der_len(conn) + ocsp_resp_len;
msg = os_malloc(msglen);
- if (msg == NULL)
+ if (msg == NULL) {
+ os_free(ocsp_resp);
return NULL;
+ }
pos = msg;
end = msg + msglen;
if (tls_write_server_hello(conn, &pos, end) < 0) {
os_free(msg);
+ os_free(ocsp_resp);
return NULL;
}
if (conn->use_session_ticket) {
+ os_free(ocsp_resp);
+
/* Abbreviated handshake using session ticket; RFC 4507 */
if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
tls_write_server_finished(conn, &pos, end) < 0) {
@@ -838,12 +987,16 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
/* Full handshake */
if (tls_write_server_certificate(conn, &pos, end) < 0 ||
+ tls_write_server_certificate_status(conn, &pos, end, ocsp_multi,
+ ocsp_resp, ocsp_resp_len) < 0 ||
tls_write_server_key_exchange(conn, &pos, end) < 0 ||
tls_write_server_certificate_request(conn, &pos, end) < 0 ||
tls_write_server_hello_done(conn, &pos, end) < 0) {
os_free(msg);
+ os_free(ocsp_resp);
return NULL;
}
+ os_free(ocsp_resp);
*out_len = pos - msg;
diff --git a/contrib/wpa/src/tls/x509v3.c b/contrib/wpa/src/tls/x509v3.c
index b51dfcd..fa4d442 100644
--- a/contrib/wpa/src/tls/x509v3.c
+++ b/contrib/wpa/src/tls/x509v3.c
@@ -1,6 +1,6 @@
/*
* X.509v3 certificate parsing and processing (RFC 3280 profile)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,7 +14,7 @@
#include "x509v3.h"
-static void x509_free_name(struct x509_name *name)
+void x509_free_name(struct x509_name *name)
{
size_t i;
@@ -55,6 +55,7 @@ void x509_certificate_free(struct x509_certificate *cert)
x509_free_name(&cert->subject);
os_free(cert->public_key);
os_free(cert->sign_value);
+ os_free(cert->subject_dn);
os_free(cert);
}
@@ -177,9 +178,9 @@ int x509_name_compare(struct x509_name *a, struct x509_name *b)
}
-static int x509_parse_algorithm_identifier(
- const u8 *buf, size_t len,
- struct x509_algorithm_identifier *id, const u8 **next)
+int x509_parse_algorithm_identifier(const u8 *buf, size_t len,
+ struct x509_algorithm_identifier *id,
+ const u8 **next)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
@@ -199,12 +200,11 @@ static int x509_parse_algorithm_identifier(
hdr.class, hdr.tag);
return -1;
}
+ if (hdr.length > buf + len - hdr.payload)
+ return -1;
pos = hdr.payload;
end = pos + hdr.length;
- if (end > buf + len)
- return -1;
-
*next = end;
if (asn1_get_oid(pos, end - pos, &id->oid, &pos))
@@ -243,7 +243,7 @@ static int x509_parse_public_key(const u8 *buf, size_t len,
}
pos = hdr.payload;
- if (pos + hdr.length > end)
+ if (hdr.length > end - pos)
return -1;
end = pos + hdr.length;
*next = end;
@@ -274,13 +274,12 @@ static int x509_parse_public_key(const u8 *buf, size_t len,
*/
}
os_free(cert->public_key);
- cert->public_key = os_malloc(hdr.length - 1);
+ cert->public_key = os_memdup(pos + 1, hdr.length - 1);
if (cert->public_key == NULL) {
wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
"public key");
return -1;
}
- os_memcpy(cert->public_key, pos + 1, hdr.length - 1);
cert->public_key_len = hdr.length - 1;
wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey",
cert->public_key, cert->public_key_len);
@@ -289,8 +288,8 @@ static int x509_parse_public_key(const u8 *buf, size_t len,
}
-static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
- const u8 **next)
+int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
+ const u8 **next)
{
struct asn1_hdr hdr;
const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end;
@@ -319,7 +318,7 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
}
pos = hdr.payload;
- if (pos + hdr.length > buf + len)
+ if (hdr.length > buf + len - pos)
return -1;
end = *next = pos + hdr.length;
@@ -533,12 +532,13 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len)
}
done:
+ if (pos < end)
+ *pos = '\0';
end[-1] = '\0';
}
-static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag,
- os_time_t *val)
+int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val)
{
const char *pos;
int year, month, day, hour, min, sec;
@@ -677,7 +677,7 @@ static int x509_parse_validity(const u8 *buf, size_t len,
pos = hdr.payload;
plen = hdr.length;
- if (pos + plen > buf + len)
+ if (plen > (size_t) (buf + len - pos))
return -1;
*next = pos + plen;
@@ -721,6 +721,15 @@ static int x509_id_ce_oid(struct asn1_oid *oid)
}
+static int x509_any_ext_key_usage_oid(struct asn1_oid *oid)
+{
+ return oid->len == 6 &&
+ x509_id_ce_oid(oid) &&
+ oid->oid[3] == 37 /* extKeyUsage */ &&
+ oid->oid[4] == 0 /* anyExtendedKeyUsage */;
+}
+
+
static int x509_parse_ext_key_usage(struct x509_certificate *cert,
const u8 *pos, size_t len)
{
@@ -801,7 +810,7 @@ static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
}
cert->ca = hdr.payload[0];
- if (hdr.payload + hdr.length == pos + len) {
+ if (hdr.length == pos + len - hdr.payload) {
wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
cert->ca);
return 0;
@@ -917,10 +926,9 @@ static int x509_parse_alt_name_ip(struct x509_name *name,
/* iPAddress OCTET STRING */
wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
os_free(name->ip);
- name->ip = os_malloc(len);
+ name->ip = os_memdup(pos, len);
if (name->ip == NULL)
return -1;
- os_memcpy(name->ip, pos, len);
name->ip_len = len;
return 0;
}
@@ -1074,6 +1082,112 @@ static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
}
+static int x509_id_pkix_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 7 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 3 /* identified-organization */ &&
+ oid->oid[2] == 6 /* dod */ &&
+ oid->oid[3] == 1 /* internet */ &&
+ oid->oid[4] == 5 /* security */ &&
+ oid->oid[5] == 5 /* mechanisms */ &&
+ oid->oid[6] == 7 /* id-pkix */;
+}
+
+
+static int x509_id_kp_oid(struct asn1_oid *oid)
+{
+ /* id-kp */
+ return oid->len >= 8 &&
+ x509_id_pkix_oid(oid) &&
+ oid->oid[7] == 3 /* id-kp */;
+}
+
+
+static int x509_id_kp_server_auth_oid(struct asn1_oid *oid)
+{
+ /* id-kp */
+ return oid->len == 9 &&
+ x509_id_kp_oid(oid) &&
+ oid->oid[8] == 1 /* id-kp-serverAuth */;
+}
+
+
+static int x509_id_kp_client_auth_oid(struct asn1_oid *oid)
+{
+ /* id-kp */
+ return oid->len == 9 &&
+ x509_id_kp_oid(oid) &&
+ oid->oid[8] == 2 /* id-kp-clientAuth */;
+}
+
+
+static int x509_id_kp_ocsp_oid(struct asn1_oid *oid)
+{
+ /* id-kp */
+ return oid->len == 9 &&
+ x509_id_kp_oid(oid) &&
+ oid->oid[8] == 9 /* id-kp-OCSPSigning */;
+}
+
+
+static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert,
+ const u8 *pos, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *end;
+ struct asn1_oid oid;
+
+ /*
+ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+ *
+ * KeyPurposeId ::= OBJECT IDENTIFIER
+ */
+
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+ "(ExtKeyUsageSyntax) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length > pos + len - hdr.payload)
+ return -1;
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ wpa_hexdump(MSG_MSGDUMP, "X509: ExtKeyUsageSyntax", pos, end - pos);
+
+ while (pos < end) {
+ char buf[80];
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos))
+ return -1;
+ if (x509_any_ext_key_usage_oid(&oid)) {
+ os_strlcpy(buf, "anyExtendedKeyUsage", sizeof(buf));
+ cert->ext_key_usage |= X509_EXT_KEY_USAGE_ANY;
+ } else if (x509_id_kp_server_auth_oid(&oid)) {
+ os_strlcpy(buf, "id-kp-serverAuth", sizeof(buf));
+ cert->ext_key_usage |= X509_EXT_KEY_USAGE_SERVER_AUTH;
+ } else if (x509_id_kp_client_auth_oid(&oid)) {
+ os_strlcpy(buf, "id-kp-clientAuth", sizeof(buf));
+ cert->ext_key_usage |= X509_EXT_KEY_USAGE_CLIENT_AUTH;
+ } else if (x509_id_kp_ocsp_oid(&oid)) {
+ os_strlcpy(buf, "id-kp-OCSPSigning", sizeof(buf));
+ cert->ext_key_usage |= X509_EXT_KEY_USAGE_OCSP;
+ } else {
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ }
+ wpa_printf(MSG_DEBUG, "ExtKeyUsage KeyPurposeId: %s", buf);
+ }
+
+ cert->extensions_present |= X509_EXT_EXT_KEY_USAGE;
+
+ return 0;
+}
+
+
static int x509_parse_extension_data(struct x509_certificate *cert,
struct asn1_oid *oid,
const u8 *pos, size_t len)
@@ -1085,7 +1199,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
* certificate policies (section 4.2.1.5)
* name constraints (section 4.2.1.11)
* policy constraints (section 4.2.1.12)
- * extended key usage (section 4.2.1.13)
* inhibit any-policy (section 4.2.1.15)
*/
switch (oid->oid[3]) {
@@ -1097,6 +1210,8 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
return x509_parse_ext_issuer_alt_name(cert, pos, len);
case 19: /* id-ce-basicConstraints */
return x509_parse_ext_basic_constraints(cert, pos, len);
+ case 37: /* id-ce-extKeyUsage */
+ return x509_parse_ext_ext_key_usage(cert, pos, len);
default:
return 1;
}
@@ -1224,6 +1339,7 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
size_t left;
char sbuf[128];
unsigned long value;
+ const u8 *subject_dn;
/* tbsCertificate TBSCertificate ::= SEQUENCE */
if (asn1_get_next(buf, len, &hdr) < 0 ||
@@ -1287,21 +1403,23 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
/* serialNumber CertificateSerialNumber ::= INTEGER */
if (hdr.class != ASN1_CLASS_UNIVERSAL ||
- hdr.tag != ASN1_TAG_INTEGER) {
+ hdr.tag != ASN1_TAG_INTEGER ||
+ hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) {
wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
- "serialNumber; class=%d tag=0x%x",
- hdr.class, hdr.tag);
+ "serialNumber; class=%d tag=0x%x length=%u",
+ hdr.class, hdr.tag, hdr.length);
return -1;
}
- pos = hdr.payload;
- left = hdr.length;
- while (left) {
- cert->serial_number <<= 8;
- cert->serial_number |= *pos++;
- left--;
+ pos = hdr.payload + hdr.length;
+ while (hdr.length > 0 && hdr.payload[0] == 0) {
+ hdr.payload++;
+ hdr.length--;
}
- wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number);
+ os_memcpy(cert->serial_number, hdr.payload, hdr.length);
+ cert->serial_number_len = hdr.length;
+ wpa_hexdump(MSG_MSGDUMP, "X509: serialNumber", cert->serial_number,
+ cert->serial_number_len);
/* signature AlgorithmIdentifier */
if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
@@ -1319,8 +1437,14 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
return -1;
/* subject Name */
+ subject_dn = pos;
if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
return -1;
+ cert->subject_dn = os_malloc(pos - subject_dn);
+ if (!cert->subject_dn)
+ return -1;
+ cert->subject_dn_len = pos - subject_dn;
+ os_memcpy(cert->subject_dn, subject_dn, cert->subject_dn_len);
x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
@@ -1437,7 +1561,7 @@ static int x509_digest_oid(struct asn1_oid *oid)
}
-static int x509_sha1_oid(struct asn1_oid *oid)
+int x509_sha1_oid(struct asn1_oid *oid)
{
return oid->len == 6 &&
oid->oid[0] == 1 /* iso */ &&
@@ -1449,7 +1573,7 @@ static int x509_sha1_oid(struct asn1_oid *oid)
}
-static int x509_sha256_oid(struct asn1_oid *oid)
+static int x509_sha2_oid(struct asn1_oid *oid)
{
return oid->len == 9 &&
oid->oid[0] == 2 /* joint-iso-itu-t */ &&
@@ -1459,11 +1583,31 @@ static int x509_sha256_oid(struct asn1_oid *oid)
oid->oid[4] == 101 /* gov */ &&
oid->oid[5] == 3 /* csor */ &&
oid->oid[6] == 4 /* nistAlgorithm */ &&
- oid->oid[7] == 2 /* hashAlgs */ &&
+ oid->oid[7] == 2 /* hashAlgs */;
+}
+
+
+int x509_sha256_oid(struct asn1_oid *oid)
+{
+ return x509_sha2_oid(oid) &&
oid->oid[8] == 1 /* sha256 */;
}
+int x509_sha384_oid(struct asn1_oid *oid)
+{
+ return x509_sha2_oid(oid) &&
+ oid->oid[8] == 2 /* sha384 */;
+}
+
+
+int x509_sha512_oid(struct asn1_oid *oid)
+{
+ return x509_sha2_oid(oid) &&
+ oid->oid[8] == 3 /* sha512 */;
+}
+
+
/**
* x509_certificate_parse - Parse a X.509 certificate in DER format
* @buf: Pointer to the X.509 certificate in DER format
@@ -1503,12 +1647,12 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
}
pos = hdr.payload;
- if (pos + hdr.length > end) {
+ if (hdr.length > end - pos) {
x509_certificate_free(cert);
return NULL;
}
- if (pos + hdr.length < end) {
+ if (hdr.length < end - pos) {
wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
"encoded certificate",
pos + hdr.length, end - (pos + hdr.length));
@@ -1556,14 +1700,13 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
return NULL;
}
os_free(cert->sign_value);
- cert->sign_value = os_malloc(hdr.length - 1);
+ cert->sign_value = os_memdup(pos + 1, hdr.length - 1);
if (cert->sign_value == NULL) {
wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
"signatureValue");
x509_certificate_free(cert);
return NULL;
}
- os_memcpy(cert->sign_value, pos + 1, hdr.length - 1);
cert->sign_value_len = hdr.length - 1;
wpa_hexdump(MSG_MSGDUMP, "X509: signature",
cert->sign_value, cert->sign_value_len);
@@ -1582,18 +1725,31 @@ struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
int x509_certificate_check_signature(struct x509_certificate *issuer,
struct x509_certificate *cert)
{
+ return x509_check_signature(issuer, &cert->signature,
+ cert->sign_value, cert->sign_value_len,
+ cert->tbs_cert_start, cert->tbs_cert_len);
+}
+
+
+int x509_check_signature(struct x509_certificate *issuer,
+ struct x509_algorithm_identifier *signature,
+ const u8 *sign_value, size_t sign_value_len,
+ const u8 *signed_data, size_t signed_data_len)
+{
struct crypto_public_key *pk;
u8 *data;
const u8 *pos, *end, *next, *da_end;
size_t data_len;
struct asn1_hdr hdr;
struct asn1_oid oid;
- u8 hash[32];
+ u8 hash[64];
size_t hash_len;
+ const u8 *addr[1] = { signed_data };
+ size_t len[1] = { signed_data_len };
- if (!x509_pkcs_oid(&cert->signature.oid) ||
- cert->signature.oid.len != 7 ||
- cert->signature.oid.oid[5] != 1 /* pkcs-1 */) {
+ if (!x509_pkcs_oid(&signature->oid) ||
+ signature->oid.len != 7 ||
+ signature->oid.oid[5] != 1 /* pkcs-1 */) {
wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
"algorithm");
return -1;
@@ -1604,15 +1760,15 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
if (pk == NULL)
return -1;
- data_len = cert->sign_value_len;
+ data_len = sign_value_len;
data = os_malloc(data_len);
if (data == NULL) {
crypto_public_key_free(pk);
return -1;
}
- if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value,
- cert->sign_value_len, data,
+ if (crypto_public_key_decrypt_pkcs1(pk, sign_value,
+ sign_value_len, data,
&data_len) < 0) {
wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
crypto_public_key_free(pk);
@@ -1675,12 +1831,11 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
}
if (x509_sha1_oid(&oid)) {
- if (cert->signature.oid.oid[6] !=
- 5 /* sha-1WithRSAEncryption */) {
+ if (signature->oid.oid[6] != 5 /* sha-1WithRSAEncryption */) {
wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 "
"does not match with certificate "
"signatureAlgorithm (%lu)",
- cert->signature.oid.oid[6]);
+ signature->oid.oid[6]);
os_free(data);
return -1;
}
@@ -1688,12 +1843,36 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
}
if (x509_sha256_oid(&oid)) {
- if (cert->signature.oid.oid[6] !=
+ if (signature->oid.oid[6] !=
11 /* sha2561WithRSAEncryption */) {
wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 "
"does not match with certificate "
"signatureAlgorithm (%lu)",
- cert->signature.oid.oid[6]);
+ signature->oid.oid[6]);
+ os_free(data);
+ return -1;
+ }
+ goto skip_digest_oid;
+ }
+
+ if (x509_sha384_oid(&oid)) {
+ if (signature->oid.oid[6] != 12 /* sha384WithRSAEncryption */) {
+ wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA384 "
+ "does not match with certificate "
+ "signatureAlgorithm (%lu)",
+ signature->oid.oid[6]);
+ os_free(data);
+ return -1;
+ }
+ goto skip_digest_oid;
+ }
+
+ if (x509_sha512_oid(&oid)) {
+ if (signature->oid.oid[6] != 13 /* sha512WithRSAEncryption */) {
+ wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA512 "
+ "does not match with certificate "
+ "signatureAlgorithm (%lu)",
+ signature->oid.oid[6]);
os_free(data);
return -1;
}
@@ -1707,12 +1886,11 @@ int x509_certificate_check_signature(struct x509_certificate *issuer,
}
switch (oid.oid[5]) {
case 5: /* md5 */
- if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */)
- {
+ if (signature->oid.oid[6] != 4 /* md5WithRSAEncryption */) {
wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does "
"not match with certificate "
"signatureAlgorithm (%lu)",
- cert->signature.oid.oid[6]);
+ signature->oid.oid[6]);
os_free(data);
return -1;
}
@@ -1743,34 +1921,41 @@ skip_digest_oid:
wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
hdr.payload, hdr.length);
- switch (cert->signature.oid.oid[6]) {
+ switch (signature->oid.oid[6]) {
case 4: /* md5WithRSAEncryption */
- md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
- hash);
+ md5_vector(1, addr, len, hash);
hash_len = 16;
wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)",
hash, hash_len);
break;
case 5: /* sha-1WithRSAEncryption */
- sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
- hash);
+ sha1_vector(1, addr, len, hash);
hash_len = 20;
wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)",
hash, hash_len);
break;
case 11: /* sha256WithRSAEncryption */
- sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
- hash);
+ sha256_vector(1, addr, len, hash);
hash_len = 32;
wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
hash, hash_len);
break;
- case 2: /* md2WithRSAEncryption */
case 12: /* sha384WithRSAEncryption */
+ sha384_vector(1, addr, len, hash);
+ hash_len = 48;
+ wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA384)",
+ hash, hash_len);
+ break;
case 13: /* sha512WithRSAEncryption */
+ sha512_vector(1, addr, len, hash);
+ hash_len = 64;
+ wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA512)",
+ hash, hash_len);
+ break;
+ case 2: /* md2WithRSAEncryption */
default:
wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
- "algorithm (%lu)", cert->signature.oid.oid[6]);
+ "algorithm (%lu)", signature->oid.oid[6]);
os_free(data);
return -1;
}
@@ -1852,7 +2037,8 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
os_get_time(&now);
for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
- x509_name_string(&cert->subject, buf, sizeof(buf));
+ cert->issuer_trusted = 0;
+ x509_name_string(&cert->subject, buf, sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
if (chain_trusted)
@@ -1876,11 +2062,11 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
wpa_printf(MSG_DEBUG, "X509: Certificate "
"chain issuer name mismatch");
x509_name_string(&cert->issuer, buf,
- sizeof(buf));
+ sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
buf);
x509_name_string(&cert->next->subject, buf,
- sizeof(buf));
+ sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: next cert "
"subject: %s", buf);
*reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
@@ -1937,6 +2123,7 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
"found to complete the chain");
+ cert->issuer_trusted = 1;
chain_trusted = 1;
}
}
diff --git a/contrib/wpa/src/tls/x509v3.h b/contrib/wpa/src/tls/x509v3.h
index 91a35ba..7df8e2a 100644
--- a/contrib/wpa/src/tls/x509v3.h
+++ b/contrib/wpa/src/tls/x509v3.h
@@ -45,13 +45,18 @@ struct x509_name {
struct asn1_oid rid; /* registeredID */
};
+#define X509_MAX_SERIAL_NUM_LEN 20
+
struct x509_certificate {
struct x509_certificate *next;
enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;
- unsigned long serial_number;
+ u8 serial_number[X509_MAX_SERIAL_NUM_LEN];
+ size_t serial_number_len;
struct x509_algorithm_identifier signature;
struct x509_name issuer;
struct x509_name subject;
+ u8 *subject_dn;
+ size_t subject_dn_len;
os_time_t not_before;
os_time_t not_after;
struct x509_algorithm_identifier public_key_alg;
@@ -68,6 +73,7 @@ struct x509_certificate {
#define X509_EXT_KEY_USAGE (1 << 2)
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
+#define X509_EXT_EXT_KEY_USAGE (1 << 5)
/* BasicConstraints */
int ca; /* cA */
@@ -85,6 +91,13 @@ struct x509_certificate {
#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7)
#define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8)
+ /* ExtKeyUsage */
+ unsigned long ext_key_usage;
+#define X509_EXT_KEY_USAGE_ANY (1 << 0)
+#define X509_EXT_KEY_USAGE_SERVER_AUTH (1 << 1)
+#define X509_EXT_KEY_USAGE_CLIENT_AUTH (1 << 2)
+#define X509_EXT_KEY_USAGE_OCSP (1 << 3)
+
/*
* The DER format certificate follows struct x509_certificate. These
* pointers point to that buffer.
@@ -93,6 +106,11 @@ struct x509_certificate {
size_t cert_len;
const u8 *tbs_cert_start;
size_t tbs_cert_len;
+
+ /* Meta data used for certificate validation */
+ unsigned int ocsp_good:1;
+ unsigned int ocsp_revoked:1;
+ unsigned int issuer_trusted:1;
};
enum {
@@ -106,10 +124,21 @@ enum {
};
void x509_certificate_free(struct x509_certificate *cert);
+int x509_parse_algorithm_identifier(const u8 *buf, size_t len,
+ struct x509_algorithm_identifier *id,
+ const u8 **next);
+int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
+ const u8 **next);
+int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val);
struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len);
+void x509_free_name(struct x509_name *name);
void x509_name_string(struct x509_name *name, char *buf, size_t len);
int x509_name_compare(struct x509_name *a, struct x509_name *b);
void x509_certificate_chain_free(struct x509_certificate *cert);
+int x509_check_signature(struct x509_certificate *issuer,
+ struct x509_algorithm_identifier *signature,
+ const u8 *sign_value, size_t sign_value_len,
+ const u8 *signed_data, size_t signed_data_len);
int x509_certificate_check_signature(struct x509_certificate *issuer,
struct x509_certificate *cert);
int x509_certificate_chain_validate(struct x509_certificate *trusted,
@@ -120,4 +149,9 @@ x509_certificate_get_subject(struct x509_certificate *chain,
struct x509_name *name);
int x509_certificate_self_signed(struct x509_certificate *cert);
+int x509_sha1_oid(struct asn1_oid *oid);
+int x509_sha256_oid(struct asn1_oid *oid);
+int x509_sha384_oid(struct asn1_oid *oid);
+int x509_sha512_oid(struct asn1_oid *oid);
+
#endif /* X509V3_H */
diff --git a/contrib/wpa/src/utils/base64.c b/contrib/wpa/src/utils/base64.c
index d44f290..53a92f4 100644
--- a/contrib/wpa/src/utils/base64.c
+++ b/contrib/wpa/src/utils/base64.c
@@ -1,41 +1,38 @@
/*
* Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
+#include <stdint.h>
#include "os.h"
#include "base64.h"
static const unsigned char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const unsigned char base64_url_table[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-/**
- * base64_encode - Base64 encode
- * @src: Data to be encoded
- * @len: Length of the data to be encoded
- * @out_len: Pointer to output length variable, or %NULL if not used
- * Returns: Allocated buffer of out_len bytes of encoded data,
- * or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer. Returned buffer is
- * nul terminated to make it easier to use as a C string. The nul terminator is
- * not included in out_len.
- */
-unsigned char * base64_encode(const unsigned char *src, size_t len,
- size_t *out_len)
+
+static unsigned char * base64_gen_encode(const unsigned char *src, size_t len,
+ size_t *out_len,
+ const unsigned char *table,
+ int add_pad)
{
unsigned char *out, *pos;
const unsigned char *end, *in;
size_t olen;
int line_len;
+ if (len >= SIZE_MAX / 4)
+ return NULL;
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
- olen += olen / 72; /* line feeds */
+ if (add_pad)
+ olen += olen / 72; /* line feeds */
olen++; /* nul termination */
if (olen < len)
return NULL; /* integer overflow */
@@ -48,35 +45,35 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
pos = out;
line_len = 0;
while (end - in >= 3) {
- *pos++ = base64_table[(in[0] >> 2) & 0x3f];
- *pos++ = base64_table[(((in[0] & 0x03) << 4) |
- (in[1] >> 4)) & 0x3f];
- *pos++ = base64_table[(((in[1] & 0x0f) << 2) |
- (in[2] >> 6)) & 0x3f];
- *pos++ = base64_table[in[2] & 0x3f];
+ *pos++ = table[(in[0] >> 2) & 0x3f];
+ *pos++ = table[(((in[0] & 0x03) << 4) | (in[1] >> 4)) & 0x3f];
+ *pos++ = table[(((in[1] & 0x0f) << 2) | (in[2] >> 6)) & 0x3f];
+ *pos++ = table[in[2] & 0x3f];
in += 3;
line_len += 4;
- if (line_len >= 72) {
+ if (add_pad && line_len >= 72) {
*pos++ = '\n';
line_len = 0;
}
}
if (end - in) {
- *pos++ = base64_table[(in[0] >> 2) & 0x3f];
+ *pos++ = table[(in[0] >> 2) & 0x3f];
if (end - in == 1) {
- *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f];
- *pos++ = '=';
+ *pos++ = table[((in[0] & 0x03) << 4) & 0x3f];
+ if (add_pad)
+ *pos++ = '=';
} else {
- *pos++ = base64_table[(((in[0] & 0x03) << 4) |
- (in[1] >> 4)) & 0x3f];
- *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f];
+ *pos++ = table[(((in[0] & 0x03) << 4) |
+ (in[1] >> 4)) & 0x3f];
+ *pos++ = table[((in[1] & 0x0f) << 2) & 0x3f];
}
- *pos++ = '=';
+ if (add_pad)
+ *pos++ = '=';
line_len += 4;
}
- if (line_len)
+ if (add_pad && line_len)
*pos++ = '\n';
*pos = '\0';
@@ -86,26 +83,18 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
}
-/**
- * base64_decode - Base64 decode
- * @src: Data to be decoded
- * @len: Length of the data to be decoded
- * @out_len: Pointer to output length variable
- * Returns: Allocated buffer of out_len bytes of decoded data,
- * or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer.
- */
-unsigned char * base64_decode(const unsigned char *src, size_t len,
- size_t *out_len)
+static unsigned char * base64_gen_decode(const unsigned char *src, size_t len,
+ size_t *out_len,
+ const unsigned char *table)
{
unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, olen;
int pad = 0;
+ size_t extra_pad;
os_memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table) - 1; i++)
- dtable[base64_table[i]] = (unsigned char) i;
+ dtable[table[i]] = (unsigned char) i;
dtable['='] = 0;
count = 0;
@@ -114,21 +103,28 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
count++;
}
- if (count == 0 || count % 4)
+ if (count == 0)
return NULL;
+ extra_pad = (4 - count % 4) % 4;
- olen = count / 4 * 3;
+ olen = (count + extra_pad) / 4 * 3;
pos = out = os_malloc(olen);
if (out == NULL)
return NULL;
count = 0;
- for (i = 0; i < len; i++) {
- tmp = dtable[src[i]];
+ for (i = 0; i < len + extra_pad; i++) {
+ unsigned char val;
+
+ if (i >= len)
+ val = '=';
+ else
+ val = src[i];
+ tmp = dtable[val];
if (tmp == 0x80)
continue;
- if (src[i] == '=')
+ if (val == '=')
pad++;
block[count] = tmp;
count++;
@@ -155,3 +151,53 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
*out_len = pos - out;
return out;
}
+
+
+/**
+ * base64_encode - Base64 encode
+ * @src: Data to be encoded
+ * @len: Length of the data to be encoded
+ * @out_len: Pointer to output length variable, or %NULL if not used
+ * Returns: Allocated buffer of out_len bytes of encoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer. Returned buffer is
+ * nul terminated to make it easier to use as a C string. The nul terminator is
+ * not included in out_len.
+ */
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+ size_t *out_len)
+{
+ return base64_gen_encode(src, len, out_len, base64_table, 1);
+}
+
+
+unsigned char * base64_url_encode(const unsigned char *src, size_t len,
+ size_t *out_len, int add_pad)
+{
+ return base64_gen_encode(src, len, out_len, base64_url_table, add_pad);
+}
+
+
+/**
+ * base64_decode - Base64 decode
+ * @src: Data to be decoded
+ * @len: Length of the data to be decoded
+ * @out_len: Pointer to output length variable
+ * Returns: Allocated buffer of out_len bytes of decoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+ size_t *out_len)
+{
+ return base64_gen_decode(src, len, out_len, base64_table);
+}
+
+
+unsigned char * base64_url_decode(const unsigned char *src, size_t len,
+ size_t *out_len)
+{
+ return base64_gen_decode(src, len, out_len, base64_url_table);
+}
diff --git a/contrib/wpa/src/utils/base64.h b/contrib/wpa/src/utils/base64.h
index aa21fd0..5a72c3e 100644
--- a/contrib/wpa/src/utils/base64.h
+++ b/contrib/wpa/src/utils/base64.h
@@ -13,5 +13,9 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
size_t *out_len);
unsigned char * base64_decode(const unsigned char *src, size_t len,
size_t *out_len);
+unsigned char * base64_url_encode(const unsigned char *src, size_t len,
+ size_t *out_len, int add_pad);
+unsigned char * base64_url_decode(const unsigned char *src, size_t len,
+ size_t *out_len);
#endif /* BASE64_H */
diff --git a/contrib/wpa/src/utils/browser-android.c b/contrib/wpa/src/utils/browser-android.c
index 9ce1a5c..71a1652 100644
--- a/contrib/wpa/src/utils/browser-android.c
+++ b/contrib/wpa/src/utils/browser-android.c
@@ -95,7 +95,7 @@ int hs20_web_browser(const char *url)
if (pid == 0) {
/* run the external command in the child process */
- char *argv[9];
+ char *argv[7];
argv[0] = "browser-android";
argv[1] = "start";
@@ -103,9 +103,7 @@ int hs20_web_browser(const char *url)
argv[3] = "android.intent.action.VIEW";
argv[4] = "-d";
argv[5] = (void *) url;
- argv[6] = "-n";
- argv[7] = "com.android.browser/.BrowserActivity";
- argv[8] = NULL;
+ argv[6] = NULL;
execv("/system/bin/am", argv);
wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
diff --git a/contrib/wpa/src/utils/browser-wpadebug.c b/contrib/wpa/src/utils/browser-wpadebug.c
index 59ba4d1..dfb4b67 100644
--- a/contrib/wpa/src/utils/browser-wpadebug.c
+++ b/contrib/wpa/src/utils/browser-wpadebug.c
@@ -52,7 +52,7 @@ static void http_req(void *ctx, struct http_request *req)
eloop_terminate();
return;
}
- wpabuf_put_str(resp, "User input completed");
+ wpabuf_put_str(resp, "HTTP/1.1\r\n\r\nUser input completed");
if (done) {
eloop_cancel_timeout(browser_timeout, NULL, NULL);
@@ -97,6 +97,7 @@ int hs20_web_browser(const char *url)
if (pid == 0) {
/* run the external command in the child process */
char *argv[14];
+ char *envp[] = { "PATH=/system/bin:/vendor/bin", NULL };
argv[0] = "browser-wpadebug";
argv[1] = "start";
@@ -113,8 +114,8 @@ int hs20_web_browser(const char *url)
argv[12] = "-3"; /* USER_CURRENT_OR_SELF */
argv[13] = NULL;
- execv("/system/bin/am", argv);
- wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ execve("/system/bin/am", argv, envp);
+ wpa_printf(MSG_ERROR, "execve: %s", strerror(errno));
exit(0);
return -1;
}
diff --git a/contrib/wpa/src/utils/browser.c b/contrib/wpa/src/utils/browser.c
index 9cf6152..ad0b382 100644
--- a/contrib/wpa/src/utils/browser.c
+++ b/contrib/wpa/src/utils/browser.c
@@ -166,8 +166,7 @@ int hs20_web_browser(const char *url)
g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_wmclass(GTK_WINDOW(ctx.win), "Hotspot 2.0 client",
- "Hotspot 2.0 client");
+ gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600);
scroll = gtk_scrolled_window_new(NULL, NULL);
diff --git a/contrib/wpa/src/utils/common.c b/contrib/wpa/src/utils/common.c
index 660e9fc..b9c8bfd 100644
--- a/contrib/wpa/src/utils/common.c
+++ b/contrib/wpa/src/utils/common.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -86,7 +86,7 @@ int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
return -1;
/* check for optional mask */
- if (*r == '\0' || isspace(*r)) {
+ if (*r == '\0' || isspace((unsigned char) *r)) {
/* no mask specified, assume default */
os_memset(mask, 0xff, ETH_ALEN);
} else if (maskable && *r == '/') {
@@ -498,7 +498,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
*txt++ = 't';
break;
default:
- if (data[i] >= 32 && data[i] <= 127) {
+ if (data[i] >= 32 && data[i] <= 126) {
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\x%02x",
@@ -697,6 +697,29 @@ int is_hex(const u8 *data, size_t len)
}
+int has_ctrl_char(const u8 *data, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (data[i] < 32 || data[i] == 127)
+ return 1;
+ }
+ return 0;
+}
+
+
+int has_newline(const char *str)
+{
+ while (*str) {
+ if (*str == '\n' || *str == '\r')
+ return 1;
+ str++;
+ }
+ return 0;
+}
+
+
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len)
@@ -978,7 +1001,7 @@ int random_mac_addr_keep_oui(u8 *addr)
* @delim: a string of delimiters
* @last: a pointer to a character following the returned token
* It has to be set to NULL for the first call and passed for any
- * futher call.
+ * further call.
* Returns: a pointer to token position in str or NULL
*
* This function is similar to str_token, but it can be used with both
@@ -1050,7 +1073,8 @@ size_t utf8_unescape(const char *inp, size_t in_size,
in_size--;
}
- while (in_size--) {
+ while (in_size) {
+ in_size--;
if (res_size >= out_size)
return 0;
@@ -1061,8 +1085,9 @@ size_t utf8_unescape(const char *inp, size_t in_size,
return res_size;
case '\\':
- if (!in_size--)
+ if (!in_size)
return 0;
+ in_size--;
inp++;
/* fall through */
@@ -1093,7 +1118,8 @@ size_t utf8_escape(const char *inp, size_t in_size,
if (!in_size)
in_size = os_strlen(inp);
- while (in_size--) {
+ while (in_size) {
+ in_size--;
if (res_size++ >= out_size)
return 0;
@@ -1123,3 +1149,103 @@ int is_ctrl_char(char c)
{
return c > 0 && c < 32;
}
+
+
+/**
+ * ssid_parse - Parse a string that contains SSID in hex or text format
+ * @buf: Input NULL terminated string that contains the SSID
+ * @ssid: Output SSID
+ * Returns: 0 on success, -1 otherwise
+ *
+ * The SSID has to be enclosed in double quotes for the text format or space
+ * or NULL terminated string of hex digits for the hex format. buf can include
+ * additional arguments after the SSID.
+ */
+int ssid_parse(const char *buf, struct wpa_ssid_value *ssid)
+{
+ char *tmp, *res, *end;
+ size_t len;
+
+ ssid->ssid_len = 0;
+
+ tmp = os_strdup(buf);
+ if (!tmp)
+ return -1;
+
+ if (*tmp != '"') {
+ end = os_strchr(tmp, ' ');
+ if (end)
+ *end = '\0';
+ } else {
+ end = os_strchr(tmp + 1, '"');
+ if (!end) {
+ os_free(tmp);
+ return -1;
+ }
+
+ end[1] = '\0';
+ }
+
+ res = wpa_config_parse_string(tmp, &len);
+ if (res && len <= SSID_MAX_LEN) {
+ ssid->ssid_len = len;
+ os_memcpy(ssid->ssid, res, len);
+ }
+
+ os_free(tmp);
+ os_free(res);
+
+ return ssid->ssid_len ? 0 : -1;
+}
+
+
+int str_starts(const char *str, const char *start)
+{
+ return os_strncmp(str, start, os_strlen(start)) == 0;
+}
+
+
+/**
+ * rssi_to_rcpi - Convert RSSI to RCPI
+ * @rssi: RSSI to convert
+ * Returns: RCPI corresponding to the given RSSI value, or 255 if not available.
+ *
+ * It's possible to estimate RCPI based on RSSI in dBm. This calculation will
+ * not reflect the correct value for high rates, but it's good enough for Action
+ * frames which are transmitted with up to 24 Mbps rates.
+ */
+u8 rssi_to_rcpi(int rssi)
+{
+ if (!rssi)
+ return 255; /* not available */
+ if (rssi < -110)
+ return 0;
+ if (rssi > 0)
+ return 220;
+ return (rssi + 110) * 2;
+}
+
+
+char * get_param(const char *cmd, const char *param)
+{
+ const char *pos, *end;
+ char *val;
+ size_t len;
+
+ pos = os_strstr(cmd, param);
+ if (!pos)
+ return NULL;
+
+ pos += os_strlen(param);
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ val = os_malloc(len + 1);
+ if (!val)
+ return NULL;
+ os_memcpy(val, pos, len);
+ val[len] = '\0';
+ return val;
+}
diff --git a/contrib/wpa/src/utils/common.h b/contrib/wpa/src/utils/common.h
index 0b9cc3d..792a30a 100644
--- a/contrib/wpa/src/utils/common.h
+++ b/contrib/wpa/src/utils/common.h
@@ -53,6 +53,15 @@ static inline unsigned int bswap_32(unsigned int v)
}
#endif /* __APPLE__ */
+#ifdef __rtems__
+#include <rtems/endian.h>
+#define __BYTE_ORDER BYTE_ORDER
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+#define bswap_16 CPU_swap_u16
+#define bswap_32 CPU_swap_u32
+#endif /* __rtems__ */
+
#ifdef CONFIG_NATIVE_WINDOWS
#include <winsock.h>
@@ -141,6 +150,7 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define host_to_le32(n) (n)
#define be_to_host32(n) wpa_swap_32(n)
#define host_to_be32(n) wpa_swap_32(n)
+#define host_to_le64(n) (n)
#define WPA_BYTE_SWAP_DEFINED
@@ -313,6 +323,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val)
#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endif
+#ifndef ETH_P_IP
+#define ETH_P_IP 0x0800
+#endif
#ifndef ETH_P_80211_ENCAP
#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
#endif
@@ -328,6 +341,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val)
#ifndef ETH_P_RRB
#define ETH_P_RRB 0x890D
#endif /* ETH_P_RRB */
+#ifndef ETH_P_OUI
+#define ETH_P_OUI 0x88B7
+#endif /* ETH_P_OUI */
#ifdef __GNUC__
@@ -416,9 +432,11 @@ void perror(const char *s);
*/
#ifdef __CHECKER__
#define __force __attribute__((force))
+#undef __bitwise
#define __bitwise __attribute__((bitwise))
#else
#define __force
+#undef __bitwise
#define __bitwise
#endif
@@ -445,6 +463,13 @@ typedef u64 __bitwise le64;
#endif /* __GNUC__ */
#endif /* __must_check */
+#define SSID_MAX_LEN 32
+
+struct wpa_ssid_value {
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len;
+};
+
int hwaddr_aton(const char *txt, u8 *addr);
int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
int hwaddr_compact_aton(const char *txt, u8 *addr);
@@ -461,6 +486,7 @@ int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
size_t len);
int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
+int ssid_parse(const char *buf, struct wpa_ssid_value *ssid);
#ifdef CONFIG_NATIVE_WINDOWS
void wpa_unicode2ascii_inplace(TCHAR *str);
@@ -477,6 +503,8 @@ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
char * wpa_config_parse_string(const char *value, size_t *len);
int is_hex(const u8 *data, size_t len);
+int has_ctrl_char(const u8 *data, size_t len);
+int has_newline(const char *str);
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len);
@@ -536,6 +564,10 @@ size_t utf8_unescape(const char *inp, size_t in_size,
char *outp, size_t out_size);
int is_ctrl_char(char c);
+int str_starts(const char *str, const char *start);
+
+u8 rssi_to_rcpi(int rssi);
+char * get_param(const char *cmd, const char *param);
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/contrib/wpa/src/utils/const_time.h b/contrib/wpa/src/utils/const_time.h
new file mode 100644
index 0000000..ab8f611
--- /dev/null
+++ b/contrib/wpa/src/utils/const_time.h
@@ -0,0 +1,191 @@
+/*
+ * Helper functions for constant time operations
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * These helper functions can be used to implement logic that needs to minimize
+ * externally visible differences in execution path by avoiding use of branches,
+ * avoiding early termination or other time differences, and forcing same memory
+ * access pattern regardless of values.
+ */
+
+#ifndef CONST_TIME_H
+#define CONST_TIME_H
+
+
+#if defined(__clang__)
+#define NO_UBSAN_UINT_OVERFLOW \
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
+#else
+#define NO_UBSAN_UINT_OVERFLOW
+#endif
+
+
+/**
+ * const_time_fill_msb - Fill all bits with MSB value
+ * @val: Input value
+ * Returns: Value with all the bits set to the MSB of the input val
+ */
+static inline unsigned int const_time_fill_msb(unsigned int val)
+{
+ /* Move the MSB to LSB and multiple by -1 to fill in all bits. */
+ return (val >> (sizeof(val) * 8 - 1)) * ~0U;
+}
+
+
+/* Returns: -1 if val is zero; 0 if val is not zero */
+static inline unsigned int const_time_is_zero(unsigned int val)
+ NO_UBSAN_UINT_OVERFLOW
+{
+ /* Set MSB to 1 for 0 and fill rest of bits with the MSB value */
+ return const_time_fill_msb(~val & (val - 1));
+}
+
+
+/* Returns: -1 if a == b; 0 if a != b */
+static inline unsigned int const_time_eq(unsigned int a, unsigned int b)
+{
+ return const_time_is_zero(a ^ b);
+}
+
+
+/* Returns: -1 if a == b; 0 if a != b */
+static inline u8 const_time_eq_u8(unsigned int a, unsigned int b)
+{
+ return (u8) const_time_eq(a, b);
+}
+
+
+/**
+ * const_time_eq_bin - Constant time memory comparison
+ * @a: First buffer to compare
+ * @b: Second buffer to compare
+ * @len: Number of octets to compare
+ * Returns: -1 if buffers are equal, 0 if not
+ *
+ * This function is meant for comparing passwords or hash values where
+ * difference in execution time or memory access pattern could provide external
+ * observer information about the location of the difference in the memory
+ * buffers. The return value does not behave like memcmp(), i.e.,
+ * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike
+ * memcmp(), the execution time of const_time_eq_bin() does not depend on the
+ * contents of the compared memory buffers, but only on the total compared
+ * length.
+ */
+static inline unsigned int const_time_eq_bin(const void *a, const void *b,
+ size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res = 0;
+
+ for (i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return const_time_is_zero(res);
+}
+
+
+/**
+ * const_time_select - Constant time unsigned int selection
+ * @mask: 0 (false) or -1 (true) to identify which value to select
+ * @true_val: Value to select for the true case
+ * @false_val: Value to select for the false case
+ * Returns: true_val if mask == -1, false_val if mask == 0
+ */
+static inline unsigned int const_time_select(unsigned int mask,
+ unsigned int true_val,
+ unsigned int false_val)
+{
+ return (mask & true_val) | (~mask & false_val);
+}
+
+
+/**
+ * const_time_select_int - Constant time int selection
+ * @mask: 0 (false) or -1 (true) to identify which value to select
+ * @true_val: Value to select for the true case
+ * @false_val: Value to select for the false case
+ * Returns: true_val if mask == -1, false_val if mask == 0
+ */
+static inline int const_time_select_int(unsigned int mask, int true_val,
+ int false_val)
+{
+ return (int) const_time_select(mask, (unsigned int) true_val,
+ (unsigned int) false_val);
+}
+
+
+/**
+ * const_time_select_u8 - Constant time u8 selection
+ * @mask: 0 (false) or -1 (true) to identify which value to select
+ * @true_val: Value to select for the true case
+ * @false_val: Value to select for the false case
+ * Returns: true_val if mask == -1, false_val if mask == 0
+ */
+static inline u8 const_time_select_u8(u8 mask, u8 true_val, u8 false_val)
+{
+ return (u8) const_time_select(mask, true_val, false_val);
+}
+
+
+/**
+ * const_time_select_s8 - Constant time s8 selection
+ * @mask: 0 (false) or -1 (true) to identify which value to select
+ * @true_val: Value to select for the true case
+ * @false_val: Value to select for the false case
+ * Returns: true_val if mask == -1, false_val if mask == 0
+ */
+static inline s8 const_time_select_s8(u8 mask, s8 true_val, s8 false_val)
+{
+ return (s8) const_time_select(mask, (unsigned int) true_val,
+ (unsigned int) false_val);
+}
+
+
+/**
+ * const_time_select_bin - Constant time binary buffer selection copy
+ * @mask: 0 (false) or -1 (true) to identify which value to copy
+ * @true_val: Buffer to copy for the true case
+ * @false_val: Buffer to copy for the false case
+ * @len: Number of octets to copy
+ * @dst: Destination buffer for the copy
+ *
+ * This function copies the specified buffer into the destination buffer using
+ * operations with identical memory access pattern regardless of which buffer
+ * is being copied.
+ */
+static inline void const_time_select_bin(u8 mask, const u8 *true_val,
+ const u8 *false_val, size_t len,
+ u8 *dst)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]);
+}
+
+
+static inline int const_time_memcmp(const void *a, const void *b, size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ int diff, res = 0;
+ unsigned int mask;
+
+ if (len == 0)
+ return 0;
+ do {
+ len--;
+ diff = (int) aa[len] - (int) bb[len];
+ mask = const_time_is_zero((unsigned int) diff);
+ res = const_time_select_int(mask, res, diff);
+ } while (len);
+
+ return res;
+}
+
+#endif /* CONST_TIME_H */
diff --git a/contrib/wpa/src/utils/crc32.c b/contrib/wpa/src/utils/crc32.c
new file mode 100644
index 0000000..12d9e2a
--- /dev/null
+++ b/contrib/wpa/src/utils/crc32.c
@@ -0,0 +1,85 @@
+/*
+ * 32-bit CRC for FCS calculation
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/crc32.h"
+
+/*
+ * IEEE 802.11 FCS CRC32
+ * G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 +
+ * x^5 + x^4 + x^2 + x + 1
+ */
+static const u32 crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+};
+
+
+u32 crc32(const u8 *frame, size_t frame_len)
+{
+ size_t i;
+ u32 crc;
+
+ crc = 0xFFFFFFFF;
+ for (i = 0; i < frame_len; i++)
+ crc = crc32_table[(crc ^ frame[i]) & 0xff] ^ (crc >> 8);
+
+ return ~crc;
+}
diff --git a/contrib/wpa/src/utils/crc32.h b/contrib/wpa/src/utils/crc32.h
new file mode 100644
index 0000000..dc31399
--- /dev/null
+++ b/contrib/wpa/src/utils/crc32.h
@@ -0,0 +1,14 @@
+/*
+ * 32-bit CRC for FCS calculation
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CRC32_H
+#define CRC32_H
+
+u32 crc32(const u8 *frame, size_t frame_len);
+
+#endif /* CRC32_H */
diff --git a/contrib/wpa/src/utils/edit_simple.c b/contrib/wpa/src/utils/edit_simple.c
index 13173cb..2ffd1a2 100644
--- a/contrib/wpa/src/utils/edit_simple.c
+++ b/contrib/wpa/src/utils/edit_simple.c
@@ -47,6 +47,12 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
return;
}
+ if (c == '\b') {
+ if (cmdbuf_pos > 0)
+ cmdbuf_pos--;
+ return;
+ }
+
if (c >= 32 && c <= 255) {
if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) {
cmdbuf[cmdbuf_pos++] = c;
diff --git a/contrib/wpa/src/utils/eloop.c b/contrib/wpa/src/utils/eloop.c
index 8647229..bb375be 100644
--- a/contrib/wpa/src/utils/eloop.c
+++ b/contrib/wpa/src/utils/eloop.c
@@ -18,7 +18,12 @@
#error Do not define both of poll and epoll
#endif
-#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL)
+#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE)
+#error Do not define both of poll and kqueue
+#endif
+
+#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \
+ !defined(CONFIG_ELOOP_KQUEUE)
#define CONFIG_ELOOP_SELECT
#endif
@@ -30,6 +35,10 @@
#include <sys/epoll.h>
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+#include <sys/event.h>
+#endif /* CONFIG_ELOOP_KQUEUE */
+
struct eloop_sock {
int sock;
void *eloop_data;
@@ -75,13 +84,20 @@ struct eloop_data {
struct pollfd *pollfds;
struct pollfd **pollfds_map;
#endif /* CONFIG_ELOOP_POLL */
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+ int max_fd;
+ struct eloop_sock *fd_table;
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
#ifdef CONFIG_ELOOP_EPOLL
int epollfd;
int epoll_max_event_num;
- int epoll_max_fd;
- struct eloop_sock *epoll_table;
struct epoll_event *epoll_events;
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ int kqueuefd;
+ int kqueue_nevents;
+ struct kevent *kqueue_events;
+#endif /* CONFIG_ELOOP_KQUEUE */
struct eloop_sock_table readers;
struct eloop_sock_table writers;
struct eloop_sock_table exceptions;
@@ -149,14 +165,24 @@ int eloop_init(void)
#ifdef CONFIG_ELOOP_EPOLL
eloop.epollfd = epoll_create1(0);
if (eloop.epollfd < 0) {
- wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n",
+ wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s",
__func__, strerror(errno));
return -1;
}
+#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ eloop.kqueuefd = kqueue();
+ if (eloop.kqueuefd < 0) {
+ wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+#endif /* CONFIG_ELOOP_KQUEUE */
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
eloop.readers.type = EVENT_TYPE_READ;
eloop.writers.type = EVENT_TYPE_WRITE;
eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
-#endif /* CONFIG_ELOOP_EPOLL */
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
#ifdef WPA_TRACE
signal(SIGSEGV, eloop_sigsegv_handler);
#endif /* WPA_TRACE */
@@ -164,15 +190,84 @@ int eloop_init(void)
}
+#ifdef CONFIG_ELOOP_EPOLL
+static int eloop_sock_queue(int sock, eloop_event_type type)
+{
+ struct epoll_event ev;
+
+ os_memset(&ev, 0, sizeof(ev));
+ switch (type) {
+ case EVENT_TYPE_READ:
+ ev.events = EPOLLIN;
+ break;
+ case EVENT_TYPE_WRITE:
+ ev.events = EPOLLOUT;
+ break;
+ /*
+ * Exceptions are always checked when using epoll, but I suppose it's
+ * possible that someone registered a socket *only* for exception
+ * handling.
+ */
+ case EVENT_TYPE_EXCEPTION:
+ ev.events = EPOLLERR | EPOLLHUP;
+ break;
+ }
+ ev.data.fd = sock;
+ if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
+ wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s",
+ __func__, sock, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+#endif /* CONFIG_ELOOP_EPOLL */
+
+
+#ifdef CONFIG_ELOOP_KQUEUE
+
+static short event_type_kevent_filter(eloop_event_type type)
+{
+ switch (type) {
+ case EVENT_TYPE_READ:
+ return EVFILT_READ;
+ case EVENT_TYPE_WRITE:
+ return EVFILT_WRITE;
+ default:
+ return 0;
+ }
+}
+
+
+static int eloop_sock_queue(int sock, eloop_event_type type)
+{
+ struct kevent ke;
+
+ EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0);
+ if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
+ wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
+ __func__, sock, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_ELOOP_KQUEUE */
+
+
static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
int sock, eloop_sock_handler handler,
void *eloop_data, void *user_data)
{
#ifdef CONFIG_ELOOP_EPOLL
+ struct epoll_event *temp_events;
+#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ struct kevent *temp_events;
+#endif /* CONFIG_ELOOP_EPOLL */
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
struct eloop_sock *temp_table;
- struct epoll_event ev, *temp_events;
int next;
-#endif /* CONFIG_ELOOP_EPOLL */
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
struct eloop_sock *tmp;
int new_max_sock;
@@ -208,26 +303,28 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
eloop.pollfds = n;
}
#endif /* CONFIG_ELOOP_POLL */
-#ifdef CONFIG_ELOOP_EPOLL
- if (new_max_sock >= eloop.epoll_max_fd) {
- next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2;
- temp_table = os_realloc_array(eloop.epoll_table, next,
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+ if (new_max_sock >= eloop.max_fd) {
+ next = new_max_sock + 16;
+ temp_table = os_realloc_array(eloop.fd_table, next,
sizeof(struct eloop_sock));
if (temp_table == NULL)
return -1;
- eloop.epoll_max_fd = next;
- eloop.epoll_table = temp_table;
+ eloop.max_fd = next;
+ eloop.fd_table = temp_table;
}
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
+#ifdef CONFIG_ELOOP_EPOLL
if (eloop.count + 1 > eloop.epoll_max_event_num) {
next = eloop.epoll_max_event_num == 0 ? 8 :
eloop.epoll_max_event_num * 2;
temp_events = os_realloc_array(eloop.epoll_events, next,
sizeof(struct epoll_event));
if (temp_events == NULL) {
- wpa_printf(MSG_ERROR, "%s: malloc for epoll failed. "
- "%s\n", __func__, strerror(errno));
+ wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s",
+ __func__, strerror(errno));
return -1;
}
@@ -235,6 +332,22 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
eloop.epoll_events = temp_events;
}
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ if (eloop.count + 1 > eloop.kqueue_nevents) {
+ next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2;
+ temp_events = os_malloc(next * sizeof(*temp_events));
+ if (!temp_events) {
+ wpa_printf(MSG_ERROR,
+ "%s: malloc for kqueue failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ os_free(eloop.kqueue_events);
+ eloop.kqueue_events = temp_events;
+ eloop.kqueue_nevents = next;
+ }
+#endif /* CONFIG_ELOOP_KQUEUE */
eloop_trace_sock_remove_ref(table);
tmp = os_realloc_array(table->table, table->count + 1,
@@ -256,33 +369,12 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
table->changed = 1;
eloop_trace_sock_add_ref(table);
-#ifdef CONFIG_ELOOP_EPOLL
- os_memset(&ev, 0, sizeof(ev));
- switch (table->type) {
- case EVENT_TYPE_READ:
- ev.events = EPOLLIN;
- break;
- case EVENT_TYPE_WRITE:
- ev.events = EPOLLOUT;
- break;
- /*
- * Exceptions are always checked when using epoll, but I suppose it's
- * possible that someone registered a socket *only* for exception
- * handling.
- */
- case EVENT_TYPE_EXCEPTION:
- ev.events = EPOLLERR | EPOLLHUP;
- break;
- }
- ev.data.fd = sock;
- if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
- wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d "
- "failed. %s\n", __func__, sock, strerror(errno));
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+ if (eloop_sock_queue(sock, table->type) < 0)
return -1;
- }
- os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1],
+ os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1],
sizeof(struct eloop_sock));
-#endif /* CONFIG_ELOOP_EPOLL */
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
return 0;
}
@@ -290,6 +382,9 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
int sock)
{
+#ifdef CONFIG_ELOOP_KQUEUE
+ struct kevent ke;
+#endif /* CONFIG_ELOOP_KQUEUE */
int i;
if (table == NULL || table->table == NULL || table->count == 0)
@@ -313,12 +408,22 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
eloop_trace_sock_add_ref(table);
#ifdef CONFIG_ELOOP_EPOLL
if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
- wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d "
- "failed. %s\n", __func__, sock, strerror(errno));
+ wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s",
+ __func__, sock, strerror(errno));
return;
}
- os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock));
+ os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0,
+ 0, 0);
+ if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
+ wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
+ __func__, sock, strerror(errno));
+ return;
+ }
+ os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
+#endif /* CONFIG_ELOOP_KQUEUE */
}
@@ -511,7 +616,7 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
int i;
for (i = 0; i < nfds; i++) {
- table = &eloop.epoll_table[events[i].data.fd];
+ table = &eloop.fd_table[events[i].data.fd];
if (table->handler == NULL)
continue;
table->handler(table->sock, table->eloop_data,
@@ -525,6 +630,67 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+
+static void eloop_sock_table_dispatch(struct kevent *events, int nfds)
+{
+ struct eloop_sock *table;
+ int i;
+
+ for (i = 0; i < nfds; i++) {
+ table = &eloop.fd_table[events[i].ident];
+ if (table->handler == NULL)
+ continue;
+ table->handler(table->sock, table->eloop_data,
+ table->user_data);
+ if (eloop.readers.changed ||
+ eloop.writers.changed ||
+ eloop.exceptions.changed)
+ break;
+ }
+}
+
+
+static int eloop_sock_table_requeue(struct eloop_sock_table *table)
+{
+ int i, r;
+
+ r = 0;
+ for (i = 0; i < table->count && table->table; i++) {
+ if (eloop_sock_queue(table->table[i].sock, table->type) == -1)
+ r = -1;
+ }
+ return r;
+}
+
+#endif /* CONFIG_ELOOP_KQUEUE */
+
+
+int eloop_sock_requeue(void)
+{
+ int r = 0;
+
+#ifdef CONFIG_ELOOP_KQUEUE
+ close(eloop.kqueuefd);
+ eloop.kqueuefd = kqueue();
+ if (eloop.kqueuefd < 0) {
+ wpa_printf(MSG_ERROR, "%s: kqueue failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ if (eloop_sock_table_requeue(&eloop.readers) < 0)
+ r = -1;
+ if (eloop_sock_table_requeue(&eloop.writers) < 0)
+ r = -1;
+ if (eloop_sock_table_requeue(&eloop.exceptions) < 0)
+ r = -1;
+#endif /* CONFIG_ELOOP_KQUEUE */
+
+ return r;
+}
+
+
static void eloop_sock_table_destroy(struct eloop_sock_table *table)
{
if (table) {
@@ -905,6 +1071,9 @@ void eloop_run(void)
#ifdef CONFIG_ELOOP_EPOLL
int timeout_ms = -1;
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ struct timespec ts;
+#endif /* CONFIG_ELOOP_KQUEUE */
int res;
struct os_reltime tv, now;
@@ -949,6 +1118,10 @@ void eloop_run(void)
_tv.tv_sec = tv.sec;
_tv.tv_usec = tv.usec;
#endif /* CONFIG_ELOOP_SELECT */
+#ifdef CONFIG_ELOOP_KQUEUE
+ ts.tv_sec = tv.sec;
+ ts.tv_nsec = tv.usec * 1000L;
+#endif /* CONFIG_ELOOP_KQUEUE */
}
#ifdef CONFIG_ELOOP_POLL
@@ -974,6 +1147,15 @@ void eloop_run(void)
eloop.count, timeout_ms);
}
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ if (eloop.count == 0) {
+ res = 0;
+ } else {
+ res = kevent(eloop.kqueuefd, NULL, 0,
+ eloop.kqueue_events, eloop.kqueue_nevents,
+ timeout ? &ts : NULL);
+ }
+#endif /* CONFIG_ELOOP_KQUEUE */
if (res < 0 && errno != EINTR && errno != 0) {
wpa_printf(MSG_ERROR, "eloop: %s: %s",
#ifdef CONFIG_ELOOP_POLL
@@ -985,6 +1167,10 @@ void eloop_run(void)
#ifdef CONFIG_ELOOP_EPOLL
"epoll"
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ "kqueue"
+#endif /* CONFIG_ELOOP_EKQUEUE */
+
, strerror(errno));
goto out;
}
@@ -995,6 +1181,7 @@ void eloop_run(void)
eloop_process_pending_signals();
+
/* check if some registered timeouts have occurred */
timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
list);
@@ -1040,6 +1227,9 @@ void eloop_run(void)
#ifdef CONFIG_ELOOP_EPOLL
eloop_sock_table_dispatch(eloop.epoll_events, res);
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ eloop_sock_table_dispatch(eloop.kqueue_events, res);
+#endif /* CONFIG_ELOOP_KQUEUE */
}
eloop.terminate = 0;
@@ -1092,11 +1282,17 @@ void eloop_destroy(void)
os_free(eloop.pollfds);
os_free(eloop.pollfds_map);
#endif /* CONFIG_ELOOP_POLL */
+#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
+ os_free(eloop.fd_table);
+#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
#ifdef CONFIG_ELOOP_EPOLL
- os_free(eloop.epoll_table);
os_free(eloop.epoll_events);
close(eloop.epollfd);
#endif /* CONFIG_ELOOP_EPOLL */
+#ifdef CONFIG_ELOOP_KQUEUE
+ os_free(eloop.kqueue_events);
+ close(eloop.kqueuefd);
+#endif /* CONFIG_ELOOP_KQUEUE */
}
@@ -1135,6 +1331,17 @@ void eloop_wait_for_read_sock(int sock)
FD_SET(sock, &rfds);
select(sock + 1, &rfds, NULL, NULL, NULL);
#endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
+#ifdef CONFIG_ELOOP_KQUEUE
+ int kfd;
+ struct kevent ke1, ke2;
+
+ kfd = kqueue();
+ if (kfd == -1)
+ return;
+ EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
+ kevent(kfd, &ke1, 1, &ke2, 1, NULL);
+ close(kfd);
+#endif /* CONFIG_ELOOP_KQUEUE */
}
#ifdef CONFIG_ELOOP_SELECT
diff --git a/contrib/wpa/src/utils/eloop.h b/contrib/wpa/src/utils/eloop.h
index 07b8c0d..04ee6d1 100644
--- a/contrib/wpa/src/utils/eloop.h
+++ b/contrib/wpa/src/utils/eloop.h
@@ -45,16 +45,16 @@ typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
/**
* eloop_event_handler - eloop generic event callback type
* @eloop_ctx: Registered callback context data (eloop_data)
- * @sock_ctx: Registered callback context data (user_data)
+ * @user_ctx: Registered callback context data (user_data)
*/
-typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+typedef void (*eloop_event_handler)(void *eloop_ctx, void *user_ctx);
/**
* eloop_timeout_handler - eloop timeout event callback type
* @eloop_ctx: Registered callback context data (eloop_data)
- * @sock_ctx: Registered callback context data (user_data)
+ * @user_ctx: Registered callback context data (user_data)
*/
-typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+typedef void (*eloop_timeout_handler)(void *eloop_ctx, void *user_ctx);
/**
* eloop_signal_handler - eloop signal event callback type
@@ -313,6 +313,14 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
void *user_data);
/**
+ * eloop_sock_requeue - Requeue sockets
+ *
+ * Requeue sockets after forking because some implementations require this,
+ * such as epoll and kqueue.
+ */
+int eloop_sock_requeue(void);
+
+/**
* eloop_run - Start the event loop
*
* Start the event loop and continue running as long as there are any
diff --git a/contrib/wpa/src/utils/eloop_win.c b/contrib/wpa/src/utils/eloop_win.c
index de47fb2..9c8b12b 100644
--- a/contrib/wpa/src/utils/eloop_win.c
+++ b/contrib/wpa/src/utils/eloop_win.c
@@ -692,3 +692,9 @@ void eloop_wait_for_read_sock(int sock)
WSAEventSelect(sock, event, 0);
WSACloseEvent(event);
}
+
+
+int eloop_sock_requeue(void)
+{
+ return 0;
+}
diff --git a/contrib/wpa/src/utils/ext_password.c b/contrib/wpa/src/utils/ext_password.c
index 0613119..5615bd7 100644
--- a/contrib/wpa/src/utils/ext_password.c
+++ b/contrib/wpa/src/utils/ext_password.c
@@ -16,10 +16,6 @@
#include "ext_password_i.h"
-#ifdef CONFIG_EXT_PASSWORD_TEST
-extern struct ext_password_backend ext_password_test;
-#endif /* CONFIG_EXT_PASSWORD_TEST */
-
static const struct ext_password_backend *backends[] = {
#ifdef CONFIG_EXT_PASSWORD_TEST
&ext_password_test,
diff --git a/contrib/wpa/src/utils/ext_password_i.h b/contrib/wpa/src/utils/ext_password_i.h
index 043e731..948eaf5 100644
--- a/contrib/wpa/src/utils/ext_password_i.h
+++ b/contrib/wpa/src/utils/ext_password_i.h
@@ -20,4 +20,10 @@ struct ext_password_backend {
struct wpabuf * ext_password_alloc(size_t len);
+/* Available ext_password backends */
+
+#ifdef CONFIG_EXT_PASSWORD_TEST
+extern const struct ext_password_backend ext_password_test;
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+
#endif /* EXT_PASSWORD_I_H */
diff --git a/contrib/wpa/src/utils/http_curl.c b/contrib/wpa/src/utils/http_curl.c
index 653eb54..e62fbf9 100644
--- a/contrib/wpa/src/utils/http_curl.c
+++ b/contrib/wpa/src/utils/http_curl.c
@@ -26,6 +26,17 @@
#include "common.h"
#include "xml-utils.h"
#include "http-utils.h"
+#ifdef EAP_TLS_OPENSSL
+#include "crypto/tls_openssl.h"
+#endif /* EAP_TLS_OPENSSL */
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+ return ASN1_STRING_data((ASN1_STRING *) x);
+}
+#endif /* OpenSSL < 1.1.0 */
struct http_ctx {
@@ -421,6 +432,29 @@ ASN1_SEQUENCE(LogotypeExtn) = {
IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn);
+#ifdef OPENSSL_IS_BORINGSSL
+#define sk_LogotypeInfo_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeInfo) *, (st)))
+#define sk_LogotypeInfo_value(st, i) (LogotypeInfo *) \
+sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeInfo) *, (st)), (i))
+#define sk_LogotypeImage_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeImage) *, (st)))
+#define sk_LogotypeImage_value(st, i) (LogotypeImage *) \
+sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeImage) *, (st)), (i))
+#define sk_LogotypeAudio_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeAudio) *, (st)))
+#define sk_LogotypeAudio_value(st, i) (LogotypeAudio *) \
+sk_value(CHECK_CAST(_STACK *, const STACK_OF(LogotypeAudio) *, (st)), (i))
+#define sk_HashAlgAndValue_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(HashAlgAndValue) *, (st)))
+#define sk_HashAlgAndValue_value(st, i) (HashAlgAndValue *) \
+sk_value(CHECKED_CAST(_STACK *, const STACK_OF(HashAlgAndValue) *, (st)), (i))
+#define sk_ASN1_IA5STRING_num(st) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_IA5STRING) *, (st)))
+#define sk_ASN1_IA5STRING_value(st, i) (ASN1_IA5STRING *) \
+sk_value(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_IA5STRING) *, (st)), (i))
+#else /* OPENSSL_IS_BORINGSSL */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st))
#define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i))
#define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st))
@@ -431,6 +465,14 @@ IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn);
#define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i))
#define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st))
#define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i))
+#else
+DEFINE_STACK_OF(LogotypeInfo)
+DEFINE_STACK_OF(LogotypeImage)
+DEFINE_STACK_OF(LogotypeAudio)
+DEFINE_STACK_OF(HashAlgAndValue)
+DEFINE_STACK_OF(ASN1_IA5STRING)
+#endif
+#endif /* OPENSSL_IS_BORINGSSL */
static void add_logo(struct http_ctx *ctx, struct http_cert *hcert,
@@ -460,12 +502,12 @@ static void add_logo(struct http_ctx *ctx, struct http_cert *hcert,
return;
n->hash_len = ASN1_STRING_length(hash->hashValue);
- n->hash = os_malloc(n->hash_len);
+ n->hash = os_memdup(ASN1_STRING_get0_data(hash->hashValue),
+ n->hash_len);
if (n->hash == NULL) {
os_free(n->alg_oid);
return;
}
- os_memcpy(n->hash, ASN1_STRING_data(hash->hashValue), n->hash_len);
len = ASN1_STRING_length(uri);
n->uri = os_malloc(len + 1);
@@ -474,7 +516,7 @@ static void add_logo(struct http_ctx *ctx, struct http_cert *hcert,
os_free(n->hash);
return;
}
- os_memcpy(n->uri, ASN1_STRING_data(uri), len);
+ os_memcpy(n->uri, ASN1_STRING_get0_data(uri), len);
n->uri[len] = '\0';
hcert->num_logo++;
@@ -618,13 +660,25 @@ static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent)
} else {
BIO_printf(out, "%*stype: default (1)\n", indent, "");
}
+ val = ASN1_INTEGER_get(info->fileSize);
+ BIO_printf(out, "%*sfileSize: %ld\n", indent, "", val);
val = ASN1_INTEGER_get(info->xSize);
BIO_printf(out, "%*sxSize: %ld\n", indent, "", val);
val = ASN1_INTEGER_get(info->ySize);
BIO_printf(out, "%*sySize: %ld\n", indent, "", val);
if (info->resolution) {
- BIO_printf(out, "%*sresolution\n", indent, "");
- /* TODO */
+ BIO_printf(out, "%*sresolution [%d]\n", indent, "",
+ info->resolution->type);
+ switch (info->resolution->type) {
+ case 0:
+ val = ASN1_INTEGER_get(info->resolution->d.numBits);
+ BIO_printf(out, "%*snumBits: %ld\n", indent, "", val);
+ break;
+ case 1:
+ val = ASN1_INTEGER_get(info->resolution->d.tableSize);
+ BIO_printf(out, "%*stableSize: %ld\n", indent, "", val);
+ break;
+ }
}
if (info->language) {
BIO_printf(out, "%*slanguage: ", indent, "");
@@ -777,9 +831,9 @@ static void add_logotype_ext(struct http_ctx *ctx, struct http_cert *hcert,
}
wpa_hexdump(MSG_DEBUG, "logotypeExtn",
- ASN1_STRING_data(os), ASN1_STRING_length(os));
+ ASN1_STRING_get0_data(os), ASN1_STRING_length(os));
- data = ASN1_STRING_data(os);
+ data = ASN1_STRING_get0_data(os);
logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os));
if (logo == NULL) {
wpa_printf(MSG_INFO, "Failed to parse logotypeExtn");
@@ -949,7 +1003,7 @@ static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
- ssl_ctx = ssl->ctx;
+ ssl_ctx = SSL_get_SSL_CTX(ssl);
ctx = SSL_CTX_get_app_data(ssl_ctx);
wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d",
@@ -981,6 +1035,26 @@ static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0)
return 0;
+#ifdef OPENSSL_IS_BORINGSSL
+ if (depth == 0 && ctx->ocsp != NO_OCSP && preverify_ok) {
+ enum ocsp_result res;
+
+ res = check_ocsp_resp(ssl_ctx, ssl, cert, ctx->peer_issuer,
+ ctx->peer_issuer_issuer);
+ if (res == OCSP_REVOKED) {
+ preverify_ok = 0;
+ wpa_printf(MSG_INFO, "OCSP: certificate revoked");
+ if (err == X509_V_OK)
+ X509_STORE_CTX_set_error(
+ x509_ctx, X509_V_ERR_CERT_REVOKED);
+ } else if (res != OCSP_GOOD && (ctx->ocsp == MANDATORY_OCSP)) {
+ preverify_ok = 0;
+ wpa_printf(MSG_INFO,
+ "OCSP: bad certificate status response");
+ }
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
if (!preverify_ok)
ctx->last_err = "TLS validation failed";
@@ -1037,7 +1111,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
{
struct http_ctx *ctx = arg;
const unsigned char *p;
- int len, status, reason;
+ int len, status, reason, res;
OCSP_RESPONSE *rsp;
OCSP_BASICRESP *basic;
OCSP_CERTID *id;
@@ -1079,7 +1153,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
return 0;
}
- store = SSL_CTX_get_cert_store(s->ctx);
+ store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s));
if (ctx->peer_issuer) {
wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer");
debug_dump_cert("OpenSSL: Issuer certificate",
@@ -1142,20 +1216,40 @@ static int ocsp_resp_cb(SSL *s, void *arg)
return 0;
}
- id = OCSP_cert_to_id(NULL, ctx->peer_cert, ctx->peer_issuer);
+ id = OCSP_cert_to_id(EVP_sha256(), ctx->peer_cert, ctx->peer_issuer);
if (!id) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not create OCSP certificate identifier (SHA256)");
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(rsp);
ctx->last_err = "Could not create OCSP certificate identifier";
return 0;
}
- if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
- &this_update, &next_update)) {
+ res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
+ &this_update, &next_update);
+ if (!res) {
+ id = OCSP_cert_to_id(NULL, ctx->peer_cert, ctx->peer_issuer);
+ if (!id) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not create OCSP certificate identifier (SHA1)");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ ctx->last_err =
+ "Could not create OCSP certificate identifier";
+ return 0;
+ }
+
+ res = OCSP_resp_find_status(basic, id, &status, &reason,
+ &produced_at, &this_update,
+ &next_update);
+ }
+
+ if (!res) {
wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
(ctx->ocsp == MANDATORY_OCSP) ? "" :
" (OCSP not required)");
+ OCSP_CERTID_free(id);
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(rsp);
if (ctx->ocsp == MANDATORY_OCSP)
@@ -1163,6 +1257,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
ctx->last_err = "Could not find current server certificate from OCSP response";
return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1;
}
+ OCSP_CERTID_free(id);
if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
tls_show_errors(__func__, "OpenSSL: OCSP status times invalid");
@@ -1194,12 +1289,13 @@ static int ocsp_resp_cb(SSL *s, void *arg)
}
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
static SSL_METHOD patch_ssl_method;
static const SSL_METHOD *real_ssl_method;
static int curl_patch_ssl_new(SSL *s)
{
- SSL_CTX *ssl = s->ctx;
+ SSL_CTX *ssl = SSL_get_SSL_CTX(s);
int ret;
ssl->method = real_ssl_method;
@@ -1210,6 +1306,7 @@ static int curl_patch_ssl_new(SSL *s)
return ret;
}
+#endif /* OpenSSL < 1.1.0 */
#endif /* HAVE_OCSP */
@@ -1228,6 +1325,7 @@ static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm)
SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb);
SSL_CTX_set_tlsext_status_arg(ssl, ctx);
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
/*
* Use a temporary SSL_METHOD to get a callback on SSL_new()
* from libcurl since there is no proper callback registration
@@ -1237,6 +1335,7 @@ static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm)
patch_ssl_method.ssl_new = curl_patch_ssl_new;
real_ssl_method = ssl->method;
ssl->method = &patch_ssl_method;
+#endif /* OpenSSL < 1.1.0 */
}
#endif /* HAVE_OCSP */
@@ -1273,6 +1372,16 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address,
#ifdef EAP_TLS_OPENSSL
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl);
curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx);
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ /* For now, using the CURLOPT_SSL_VERIFYSTATUS option only
+ * with BoringSSL since the OpenSSL specific callback hack to
+ * enable OCSP is not available with BoringSSL. The OCSP
+ * implementation within libcurl is not sufficient for the
+ * Hotspot 2.0 OSU needs, so cannot use this with OpenSSL.
+ */
+ if (ctx->ocsp != NO_OCSP)
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
+#endif /* OPENSSL_IS_BORINGSSL */
#endif /* EAP_TLS_OPENSSL */
} else {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
diff --git a/contrib/wpa/src/utils/json.c b/contrib/wpa/src/utils/json.c
new file mode 100644
index 0000000..b644339
--- /dev/null
+++ b/contrib/wpa/src/utils/json.c
@@ -0,0 +1,576 @@
+/*
+ * JavaScript Object Notation (JSON) parser (RFC7159)
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "base64.h"
+#include "json.h"
+
+#define JSON_MAX_DEPTH 10
+#define JSON_MAX_TOKENS 500
+
+
+void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
+{
+ char *end = txt + maxlen;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (txt + 4 >= end)
+ break;
+
+ switch (data[i]) {
+ case '\"':
+ *txt++ = '\\';
+ *txt++ = '\"';
+ break;
+ case '\\':
+ *txt++ = '\\';
+ *txt++ = '\\';
+ break;
+ case '\n':
+ *txt++ = '\\';
+ *txt++ = 'n';
+ break;
+ case '\r':
+ *txt++ = '\\';
+ *txt++ = 'r';
+ break;
+ case '\t':
+ *txt++ = '\\';
+ *txt++ = 't';
+ break;
+ default:
+ if (data[i] >= 32 && data[i] <= 126) {
+ *txt++ = data[i];
+ } else {
+ txt += os_snprintf(txt, end - txt, "\\u%04x",
+ data[i]);
+ }
+ break;
+ }
+ }
+
+ *txt = '\0';
+}
+
+
+static char * json_parse_string(const char **json_pos, const char *end)
+{
+ const char *pos = *json_pos;
+ char *str, *spos, *s_end;
+ size_t max_len, buf_len;
+ u8 bin[2];
+
+ pos++; /* skip starting quote */
+
+ max_len = end - pos + 1;
+ buf_len = max_len > 10 ? 10 : max_len;
+ str = os_malloc(buf_len);
+ if (!str)
+ return NULL;
+ spos = str;
+ s_end = str + buf_len;
+
+ for (; pos < end; pos++) {
+ if (buf_len < max_len && s_end - spos < 3) {
+ char *tmp;
+ int idx;
+
+ idx = spos - str;
+ buf_len *= 2;
+ if (buf_len > max_len)
+ buf_len = max_len;
+ tmp = os_realloc(str, buf_len);
+ if (!tmp)
+ goto fail;
+ str = tmp;
+ spos = str + idx;
+ s_end = str + buf_len;
+ }
+
+ switch (*pos) {
+ case '\"': /* end string */
+ *spos = '\0';
+ /* caller will move to the next position */
+ *json_pos = pos;
+ return str;
+ case '\\':
+ pos++;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Truncated \\ escape");
+ goto fail;
+ }
+ switch (*pos) {
+ case '"':
+ case '\\':
+ case '/':
+ *spos++ = *pos;
+ break;
+ case 'n':
+ *spos++ = '\n';
+ break;
+ case 'r':
+ *spos++ = '\r';
+ break;
+ case 't':
+ *spos++ = '\t';
+ break;
+ case 'u':
+ if (end - pos < 5 ||
+ hexstr2bin(pos + 1, bin, 2) < 0 ||
+ bin[1] == 0x00) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Invalid \\u escape");
+ goto fail;
+ }
+ if (bin[0] == 0x00) {
+ *spos++ = bin[1];
+ } else {
+ *spos++ = bin[0];
+ *spos++ = bin[1];
+ }
+ pos += 4;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "JSON: Unknown escape '%c'", *pos);
+ goto fail;
+ }
+ break;
+ default:
+ *spos++ = *pos;
+ break;
+ }
+ }
+
+fail:
+ os_free(str);
+ return NULL;
+}
+
+
+static int json_parse_number(const char **json_pos, const char *end,
+ int *ret_val)
+{
+ const char *pos = *json_pos;
+ size_t len;
+ char *str;
+
+ for (; pos < end; pos++) {
+ if (*pos != '-' && (*pos < '0' || *pos > '9')) {
+ pos--;
+ break;
+ }
+ }
+ if (pos == end)
+ pos--;
+ if (pos < *json_pos)
+ return -1;
+ len = pos - *json_pos + 1;
+ str = os_malloc(len + 1);
+ if (!str)
+ return -1;
+ os_memcpy(str, *json_pos, len);
+ str[len] = '\0';
+
+ *ret_val = atoi(str);
+ os_free(str);
+ *json_pos = pos;
+ return 0;
+}
+
+
+static int json_check_tree_state(struct json_token *token)
+{
+ if (!token)
+ return 0;
+ if (json_check_tree_state(token->child) < 0 ||
+ json_check_tree_state(token->sibling) < 0)
+ return -1;
+ if (token->state != JSON_COMPLETED) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Unexpected token state %d (name=%s type=%d)",
+ token->state, token->name ? token->name : "N/A",
+ token->type);
+ return -1;
+ }
+ return 0;
+}
+
+
+static struct json_token * json_alloc_token(unsigned int *tokens)
+{
+ (*tokens)++;
+ if (*tokens > JSON_MAX_TOKENS) {
+ wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded");
+ return NULL;
+ }
+ return os_zalloc(sizeof(struct json_token));
+}
+
+
+struct json_token * json_parse(const char *data, size_t data_len)
+{
+ struct json_token *root = NULL, *curr_token = NULL, *token = NULL;
+ const char *pos, *end;
+ char *str;
+ int num;
+ unsigned int depth = 0;
+ unsigned int tokens = 0;
+
+ pos = data;
+ end = data + data_len;
+
+ for (; pos < end; pos++) {
+ switch (*pos) {
+ case '[': /* start array */
+ case '{': /* start object */
+ if (!curr_token) {
+ token = json_alloc_token(&tokens);
+ if (!token)
+ goto fail;
+ if (!root)
+ root = token;
+ } else if (curr_token->state == JSON_WAITING_VALUE) {
+ token = curr_token;
+ } else if (curr_token->parent &&
+ curr_token->parent->type == JSON_ARRAY &&
+ curr_token->parent->state == JSON_STARTED &&
+ curr_token->state == JSON_EMPTY) {
+ token = curr_token;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Invalid state for start array/object");
+ goto fail;
+ }
+ depth++;
+ if (depth > JSON_MAX_DEPTH) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Max depth exceeded");
+ goto fail;
+ }
+ token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT;
+ token->state = JSON_STARTED;
+ token->child = json_alloc_token(&tokens);
+ if (!token->child)
+ goto fail;
+ curr_token = token->child;
+ curr_token->parent = token;
+ curr_token->state = JSON_EMPTY;
+ break;
+ case ']': /* end array */
+ case '}': /* end object */
+ if (!curr_token || !curr_token->parent ||
+ curr_token->parent->state != JSON_STARTED) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Invalid state for end array/object");
+ goto fail;
+ }
+ depth--;
+ curr_token = curr_token->parent;
+ if ((*pos == ']' &&
+ curr_token->type != JSON_ARRAY) ||
+ (*pos == '}' &&
+ curr_token->type != JSON_OBJECT)) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Array/Object mismatch");
+ goto fail;
+ }
+ if (curr_token->child->state == JSON_EMPTY &&
+ !curr_token->child->child &&
+ !curr_token->child->sibling) {
+ /* Remove pending child token since the
+ * array/object was empty. */
+ json_free(curr_token->child);
+ curr_token->child = NULL;
+ }
+ curr_token->state = JSON_COMPLETED;
+ break;
+ case '\"': /* string */
+ str = json_parse_string(&pos, end);
+ if (!str)
+ goto fail;
+ if (!curr_token) {
+ token = json_alloc_token(&tokens);
+ if (!token)
+ goto fail;
+ token->type = JSON_STRING;
+ token->string = str;
+ token->state = JSON_COMPLETED;
+ } else if (curr_token->parent &&
+ curr_token->parent->type == JSON_ARRAY &&
+ curr_token->parent->state == JSON_STARTED &&
+ curr_token->state == JSON_EMPTY) {
+ curr_token->string = str;
+ curr_token->state = JSON_COMPLETED;
+ curr_token->type = JSON_STRING;
+ wpa_printf(MSG_MSGDUMP,
+ "JSON: String value: '%s'",
+ curr_token->string);
+ } else if (curr_token->state == JSON_EMPTY) {
+ curr_token->type = JSON_VALUE;
+ curr_token->name = str;
+ curr_token->state = JSON_STARTED;
+ } else if (curr_token->state == JSON_WAITING_VALUE) {
+ curr_token->string = str;
+ curr_token->state = JSON_COMPLETED;
+ curr_token->type = JSON_STRING;
+ wpa_printf(MSG_MSGDUMP,
+ "JSON: String value: '%s' = '%s'",
+ curr_token->name,
+ curr_token->string);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Invalid state for a string");
+ os_free(str);
+ goto fail;
+ }
+ break;
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ /* ignore whitespace */
+ break;
+ case ':': /* name/value separator */
+ if (!curr_token || curr_token->state != JSON_STARTED)
+ goto fail;
+ curr_token->state = JSON_WAITING_VALUE;
+ break;
+ case ',': /* member separator */
+ if (!curr_token)
+ goto fail;
+ curr_token->sibling = json_alloc_token(&tokens);
+ if (!curr_token->sibling)
+ goto fail;
+ curr_token->sibling->parent = curr_token->parent;
+ curr_token = curr_token->sibling;
+ curr_token->state = JSON_EMPTY;
+ break;
+ case 't': /* true */
+ case 'f': /* false */
+ case 'n': /* null */
+ if (!((end - pos >= 4 &&
+ os_strncmp(pos, "true", 4) == 0) ||
+ (end - pos >= 5 &&
+ os_strncmp(pos, "false", 5) == 0) ||
+ (end - pos >= 4 &&
+ os_strncmp(pos, "null", 4) == 0))) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Invalid literal name");
+ goto fail;
+ }
+ if (!curr_token) {
+ token = json_alloc_token(&tokens);
+ if (!token)
+ goto fail;
+ curr_token = token;
+ } else if (curr_token->state == JSON_WAITING_VALUE) {
+ wpa_printf(MSG_MSGDUMP,
+ "JSON: Literal name: '%s' = %c",
+ curr_token->name, *pos);
+ } else if (curr_token->parent &&
+ curr_token->parent->type == JSON_ARRAY &&
+ curr_token->parent->state == JSON_STARTED &&
+ curr_token->state == JSON_EMPTY) {
+ wpa_printf(MSG_MSGDUMP,
+ "JSON: Literal name: %c", *pos);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Invalid state for a literal name");
+ goto fail;
+ }
+ switch (*pos) {
+ case 't':
+ curr_token->type = JSON_BOOLEAN;
+ curr_token->number = 1;
+ pos += 3;
+ break;
+ case 'f':
+ curr_token->type = JSON_BOOLEAN;
+ curr_token->number = 0;
+ pos += 4;
+ break;
+ case 'n':
+ curr_token->type = JSON_NULL;
+ pos += 3;
+ break;
+ }
+ curr_token->state = JSON_COMPLETED;
+ break;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* number */
+ if (json_parse_number(&pos, end, &num) < 0)
+ goto fail;
+ if (!curr_token) {
+ token = json_alloc_token(&tokens);
+ if (!token)
+ goto fail;
+ token->type = JSON_NUMBER;
+ token->number = num;
+ token->state = JSON_COMPLETED;
+ } else if (curr_token->state == JSON_WAITING_VALUE) {
+ curr_token->number = num;
+ curr_token->state = JSON_COMPLETED;
+ curr_token->type = JSON_NUMBER;
+ wpa_printf(MSG_MSGDUMP,
+ "JSON: Number value: '%s' = '%d'",
+ curr_token->name,
+ curr_token->number);
+ } else if (curr_token->parent &&
+ curr_token->parent->type == JSON_ARRAY &&
+ curr_token->parent->state == JSON_STARTED &&
+ curr_token->state == JSON_EMPTY) {
+ curr_token->number = num;
+ curr_token->state = JSON_COMPLETED;
+ curr_token->type = JSON_NUMBER;
+ wpa_printf(MSG_MSGDUMP,
+ "JSON: Number value: %d",
+ curr_token->number);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Invalid state for a number");
+ goto fail;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "JSON: Unexpected JSON character: %c", *pos);
+ goto fail;
+ }
+
+ if (!root)
+ root = token;
+ if (!curr_token)
+ curr_token = token;
+ }
+
+ if (json_check_tree_state(root) < 0) {
+ wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree");
+ goto fail;
+ }
+
+ return root;
+fail:
+ wpa_printf(MSG_DEBUG, "JSON: Parsing failed");
+ json_free(root);
+ return NULL;
+}
+
+
+void json_free(struct json_token *json)
+{
+ if (!json)
+ return;
+ json_free(json->child);
+ json_free(json->sibling);
+ os_free(json->name);
+ os_free(json->string);
+ os_free(json);
+}
+
+
+struct json_token * json_get_member(struct json_token *json, const char *name)
+{
+ struct json_token *token, *ret = NULL;
+
+ if (!json || json->type != JSON_OBJECT)
+ return NULL;
+ /* Return last matching entry */
+ for (token = json->child; token; token = token->sibling) {
+ if (token->name && os_strcmp(token->name, name) == 0)
+ ret = token;
+ }
+ return ret;
+}
+
+
+struct wpabuf * json_get_member_base64url(struct json_token *json,
+ const char *name)
+{
+ struct json_token *token;
+ unsigned char *buf;
+ size_t buflen;
+ struct wpabuf *ret;
+
+ token = json_get_member(json, name);
+ if (!token || token->type != JSON_STRING)
+ return NULL;
+ buf = base64_url_decode((const unsigned char *) token->string,
+ os_strlen(token->string), &buflen);
+ if (!buf)
+ return NULL;
+ ret = wpabuf_alloc_ext_data(buf, buflen);
+ if (!ret)
+ os_free(buf);
+
+ return ret;
+}
+
+
+static const char * json_type_str(enum json_type type)
+{
+ switch (type) {
+ case JSON_VALUE:
+ return "VALUE";
+ case JSON_OBJECT:
+ return "OBJECT";
+ case JSON_ARRAY:
+ return "ARRAY";
+ case JSON_STRING:
+ return "STRING";
+ case JSON_NUMBER:
+ return "NUMBER";
+ case JSON_BOOLEAN:
+ return "BOOLEAN";
+ case JSON_NULL:
+ return "NULL";
+ }
+ return "??";
+}
+
+
+static void json_print_token(struct json_token *token, int depth,
+ char *buf, size_t buflen)
+{
+ size_t len;
+ int ret;
+
+ if (!token)
+ return;
+ len = os_strlen(buf);
+ ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]",
+ depth, json_type_str(token->type),
+ token->name ? token->name : "");
+ if (os_snprintf_error(buflen - len, ret)) {
+ buf[len] = '\0';
+ return;
+ }
+ json_print_token(token->child, depth + 1, buf, buflen);
+ json_print_token(token->sibling, depth, buf, buflen);
+}
+
+
+void json_print_tree(struct json_token *root, char *buf, size_t buflen)
+{
+ buf[0] = '\0';
+ json_print_token(root, 1, buf, buflen);
+}
diff --git a/contrib/wpa/src/utils/json.h b/contrib/wpa/src/utils/json.h
new file mode 100644
index 0000000..8faa95d
--- /dev/null
+++ b/contrib/wpa/src/utils/json.h
@@ -0,0 +1,42 @@
+/*
+ * JavaScript Object Notation (JSON) parser (RFC7159)
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef JSON_H
+#define JSON_H
+
+struct json_token {
+ enum json_type {
+ JSON_VALUE,
+ JSON_OBJECT,
+ JSON_ARRAY,
+ JSON_STRING,
+ JSON_NUMBER,
+ JSON_BOOLEAN,
+ JSON_NULL,
+ } type;
+ enum json_parsing_state {
+ JSON_EMPTY,
+ JSON_STARTED,
+ JSON_WAITING_VALUE,
+ JSON_COMPLETED,
+ } state;
+ char *name;
+ char *string;
+ int number;
+ struct json_token *parent, *child, *sibling;
+};
+
+void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len);
+struct json_token * json_parse(const char *data, size_t data_len);
+void json_free(struct json_token *json);
+struct json_token * json_get_member(struct json_token *json, const char *name);
+struct wpabuf * json_get_member_base64url(struct json_token *json,
+ const char *name);
+void json_print_tree(struct json_token *root, char *buf, size_t buflen);
+
+#endif /* JSON_H */
diff --git a/contrib/wpa/src/utils/list.h b/contrib/wpa/src/utils/list.h
index ee2f485..85aa5e3 100644
--- a/contrib/wpa/src/utils/list.h
+++ b/contrib/wpa/src/utils/list.h
@@ -1,6 +1,6 @@
/*
* Doubly-linked list
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -76,8 +76,8 @@ static inline unsigned int dl_list_len(struct dl_list *list)
dl_list_entry((list)->prev, type, member))
#define dl_list_for_each(item, list, type, member) \
- for (item = dl_list_entry((list)->next, type, member); \
- &item->member != (list); \
+ for (item = dl_list_first((list), type, member); \
+ item && item != dl_list_entry((list), type, member); \
item = dl_list_entry(item->member.next, type, member))
#define dl_list_for_each_safe(item, n, list, type, member) \
diff --git a/contrib/wpa/src/utils/module_tests.h b/contrib/wpa/src/utils/module_tests.h
new file mode 100644
index 0000000..3bfe4ad
--- /dev/null
+++ b/contrib/wpa/src/utils/module_tests.h
@@ -0,0 +1,20 @@
+/*
+ * Module tests
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MODULE_TESTS_H
+#define MODULE_TESTS_H
+
+int wpas_module_tests(void);
+int hapd_module_tests(void);
+
+int utils_module_tests(void);
+int wps_module_tests(void);
+int common_module_tests(void);
+int crypto_module_tests(void);
+
+#endif /* MODULE_TESTS_H */
diff --git a/contrib/wpa/src/utils/os.h b/contrib/wpa/src/utils/os.h
index 9e496fb..21ba5c3 100644
--- a/contrib/wpa/src/utils/os.h
+++ b/contrib/wpa/src/utils/os.h
@@ -614,6 +614,18 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz);
*/
int os_memcmp_const(const void *a, const void *b, size_t len);
+
+/**
+ * os_memdup - Allocate duplicate of passed memory chunk
+ * @src: Source buffer to duplicate
+ * @len: Length of source buffer
+ * Returns: %NULL if allocation failed, copy of src buffer otherwise
+ *
+ * This function allocates a memory block like os_malloc() would, and
+ * copies the given source buffer into it.
+ */
+void * os_memdup(const void *src, size_t len);
+
/**
* os_exec - Execute an external program
* @program: Path to the program
@@ -657,6 +669,10 @@ int os_exec(const char *program, const char *arg, int wait_completion);
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
#define TEST_FAIL() testing_test_fail()
int testing_test_fail(void);
+extern char wpa_trace_fail_func[256];
+extern unsigned int wpa_trace_fail_after;
+extern char wpa_trace_test_fail_func[256];
+extern unsigned int wpa_trace_test_fail_after;
#else
#define TEST_FAIL() 0
#endif
diff --git a/contrib/wpa/src/utils/os_internal.c b/contrib/wpa/src/utils/os_internal.c
index ed6eb3c..474c8a3 100644
--- a/contrib/wpa/src/utils/os_internal.c
+++ b/contrib/wpa/src/utils/os_internal.c
@@ -430,22 +430,6 @@ int os_strncmp(const char *s1, const char *s2, size_t n)
}
-char * os_strncpy(char *dest, const char *src, size_t n)
-{
- char *d = dest;
-
- while (n--) {
- *d = *src;
- if (*src == '\0')
- break;
- d++;
- src++;
- }
-
- return dest;
-}
-
-
size_t os_strlcpy(char *dest, const char *src, size_t siz)
{
const char *s = src;
diff --git a/contrib/wpa/src/utils/os_none.c b/contrib/wpa/src/utils/os_none.c
index 0c3214d..5e0a3ad 100644
--- a/contrib/wpa/src/utils/os_none.c
+++ b/contrib/wpa/src/utils/os_none.c
@@ -114,6 +114,12 @@ void * os_zalloc(size_t size)
}
+void * os_memdup(const void *src, size_t n)
+{
+ return NULL;
+}
+
+
#ifdef OS_NO_C_LIB_DEFINES
void * os_malloc(size_t size)
{
@@ -212,12 +218,6 @@ int os_strncmp(const char *s1, const char *s2, size_t n)
}
-char * os_strncpy(char *dest, const char *src, size_t n)
-{
- return dest;
-}
-
-
size_t os_strlcpy(char *dest, const char *src, size_t size)
{
return 0;
diff --git a/contrib/wpa/src/utils/os_unix.c b/contrib/wpa/src/utils/os_unix.c
index 488995c..ce1cf12 100644
--- a/contrib/wpa/src/utils/os_unix.c
+++ b/contrib/wpa/src/utils/os_unix.c
@@ -1,6 +1,6 @@
/*
* OS specific functions for UNIX/POSIX systems
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -80,6 +80,9 @@ int os_get_reltime(struct os_reltime *t)
struct timespec ts;
int res;
+ if (TEST_FAIL())
+ return -1;
+
while (1) {
res = clock_gettime(clock_id, &ts);
if (res == 0) {
@@ -274,6 +277,13 @@ void os_daemonize_terminate(const char *pid_file)
int os_get_random(unsigned char *buf, size_t len)
{
+#ifdef TEST_FUZZ
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = i & 0xff;
+ return 0;
+#else /* TEST_FUZZ */
FILE *f;
size_t rc;
@@ -290,6 +300,7 @@ int os_get_random(unsigned char *buf, size_t len)
fclose(f);
return rc != len ? -1 : 0;
+#endif /* TEST_FUZZ */
}
@@ -399,6 +410,7 @@ void os_program_deinit(void)
if (total)
wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
(unsigned long) total);
+ wpa_trace_deinit();
#endif /* WPA_TRACE */
}
@@ -461,11 +473,7 @@ char * os_readfile(const char *name, size_t *len)
int os_file_exists(const char *fname)
{
- FILE *f = fopen(fname, "rb");
- if (f == NULL)
- return 0;
- fclose(f);
- return 1;
+ return access(fname, F_OK) == 0;
}
@@ -535,6 +543,16 @@ int os_memcmp_const(const void *a, const void *b, size_t len)
}
+void * os_memdup(const void *src, size_t len)
+{
+ void *r = os_malloc(len);
+
+ if (r && src)
+ os_memcpy(r, src, len);
+ return r;
+}
+
+
#ifdef WPA_TRACE
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
@@ -567,6 +585,8 @@ static int testing_fail_alloc(void)
i++;
if (i < res && os_strcmp(func[i], "os_strdup") == 0)
i++;
+ if (i < res && os_strcmp(func[i], "os_memdup") == 0)
+ i++;
pos = wpa_trace_fail_func;
diff --git a/contrib/wpa/src/utils/os_win32.c b/contrib/wpa/src/utils/os_win32.c
index dea27b9..f9e4b30 100644
--- a/contrib/wpa/src/utils/os_win32.c
+++ b/contrib/wpa/src/utils/os_win32.c
@@ -283,3 +283,13 @@ int os_exec(const char *program, const char *arg, int wait_completion)
{
return -1;
}
+
+
+void * os_memdup(const void *src, size_t len)
+{
+ void *r = os_malloc(len);
+
+ if (r)
+ os_memcpy(r, src, len);
+ return r;
+}
diff --git a/contrib/wpa/src/utils/pcsc_funcs.c b/contrib/wpa/src/utils/pcsc_funcs.c
index 6f5ea93..383ed3d 100644
--- a/contrib/wpa/src/utils/pcsc_funcs.c
+++ b/contrib/wpa/src/utils/pcsc_funcs.c
@@ -11,7 +11,11 @@
*/
#include "includes.h"
+#ifdef __APPLE__
+#include <PCSC/winscard.h>
+#else
#include <winscard.h>
+#endif
#include "common.h"
#include "pcsc_funcs.h"
@@ -110,7 +114,11 @@ typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
struct scard_data {
SCARDCONTEXT ctx;
SCARDHANDLE card;
+#ifdef __APPLE__
+ uint32_t protocol;
+#else
DWORD protocol;
+#endif
sim_types sim_type;
int pin1_required;
};
@@ -275,7 +283,7 @@ static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
pos++;
if (pos >= end)
return -1;
- if ((pos + pos[0]) < end)
+ if (pos[0] < end - pos)
end = pos + 1 + pos[0];
pos++;
wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
@@ -504,7 +512,12 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
struct scard_data * scard_init(const char *reader)
{
long ret;
- unsigned long len, pos;
+#ifdef __APPLE__
+ uint32_t len;
+#else
+ unsigned long len;
+#endif
+ unsigned long pos;
struct scard_data *scard;
#ifdef CONFIG_NATIVE_WINDOWS
TCHAR *readers = NULL;
@@ -605,7 +618,7 @@ struct scard_data * scard_init(const char *reader)
readers = NULL;
wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
- (unsigned int) scard->card, scard->protocol,
+ (unsigned int) scard->card, (unsigned long) scard->protocol,
scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
ret = SCardBeginTransaction(scard->card);
@@ -764,7 +777,11 @@ static long scard_transmit(struct scard_data *scard,
unsigned char *_recv, size_t *recv_len)
{
long ret;
+#ifdef __APPLE__
+ uint32_t rlen;
+#else
unsigned long rlen;
+#endif
wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
_send, send_len);
@@ -1385,7 +1402,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
end = buf + len;
/* RES */
- if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
+ if (pos[0] > RES_MAX_LEN || pos[0] > end - pos) {
wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
return -1;
}
@@ -1395,7 +1412,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
/* CK */
- if (pos[0] != CK_LEN || pos + CK_LEN > end) {
+ if (pos[0] != CK_LEN || CK_LEN > end - pos) {
wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
return -1;
}
@@ -1405,7 +1422,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
/* IK */
- if (pos[0] != IK_LEN || pos + IK_LEN > end) {
+ if (pos[0] != IK_LEN || IK_LEN > end - pos) {
wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
return -1;
}
diff --git a/contrib/wpa/src/utils/platform.h b/contrib/wpa/src/utils/platform.h
index 46cfe78..813987e 100644
--- a/contrib/wpa/src/utils/platform.h
+++ b/contrib/wpa/src/utils/platform.h
@@ -15,7 +15,7 @@
\
__ptr->__val; \
})
-#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((uint16_t *)(p)))
-#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((uint32_t *)(p)))
+#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((le16 *)(p)))
+#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((le32 *)(p)))
#endif /* PLATFORM_H */
diff --git a/contrib/wpa/src/utils/radiotap.c b/contrib/wpa/src/utils/radiotap.c
index c9a5023..71996eb 100644
--- a/contrib/wpa/src/utils/radiotap.c
+++ b/contrib/wpa/src/utils/radiotap.c
@@ -13,8 +13,8 @@
*
* See COPYING for more details.
*/
-#include "radiotap_iter.h"
#include "platform.h"
+#include "radiotap_iter.h"
/* function prototypes and related defs are in radiotap_iter.h */
diff --git a/contrib/wpa/src/utils/radiotap.h b/contrib/wpa/src/utils/radiotap.h
index 0572e7c..460af23 100644
--- a/contrib/wpa/src/utils/radiotap.h
+++ b/contrib/wpa/src/utils/radiotap.h
@@ -65,12 +65,12 @@ struct ieee80211_radiotap_header {
* new fields does not count.
*/
uint8_t it_pad;
- uint16_t it_len; /* length of the whole
+ le16 it_len; /* length of the whole
* header in bytes, including
* it_version, it_pad,
* it_len, and data fields.
*/
- uint32_t it_present; /* A bitmap telling which
+ le32 it_present; /* A bitmap telling which
* fields are present. Set bit 31
* (0x80000000) to extend the
* bitmap by another 32 bits.
diff --git a/contrib/wpa/src/utils/radiotap_iter.h b/contrib/wpa/src/utils/radiotap_iter.h
index b768c85..6ea07e3 100644
--- a/contrib/wpa/src/utils/radiotap_iter.h
+++ b/contrib/wpa/src/utils/radiotap_iter.h
@@ -67,7 +67,7 @@ struct ieee80211_radiotap_iterator {
const struct ieee80211_radiotap_namespace *current_namespace;
unsigned char *_arg, *_next_ns_data;
- uint32_t *_next_bitmap;
+ le32 *_next_bitmap;
unsigned char *this_arg;
#ifdef RADIOTAP_SUPPORT_OVERRIDES
diff --git a/contrib/wpa/src/utils/trace.c b/contrib/wpa/src/utils/trace.c
index 8484d27..e0b5b0b 100644
--- a/contrib/wpa/src/utils/trace.c
+++ b/contrib/wpa/src/utils/trace.c
@@ -6,6 +6,10 @@
* See README for more details.
*/
+#ifdef WPA_TRACE_BFD
+#define _GNU_SOURCE
+#include <link.h>
+#endif /* WPA_TRACE_BCD */
#include "includes.h"
#include "common.h"
@@ -25,6 +29,28 @@ static struct dl_list active_references =
static char *prg_fname = NULL;
static bfd *cached_abfd = NULL;
static asymbol **syms = NULL;
+static unsigned long start_offset;
+static int start_offset_looked_up;
+
+
+static int callback(struct dl_phdr_info *info, size_t size, void *data)
+{
+ /*
+ * dl_iterate_phdr(3):
+ * "The first object visited by callback is the main program."
+ */
+ start_offset = info->dlpi_addr;
+
+ /*
+ * dl_iterate_phdr(3):
+ * "The dl_iterate_phdr() function walks through the list of an
+ * application's shared objects and calls the function callback
+ * once for each object, until either all shared objects have
+ * been processed or callback returns a nonzero value."
+ */
+ return 1;
+}
+
static void get_prg_fname(void)
{
@@ -160,7 +186,7 @@ static void wpa_trace_bfd_addr(void *pc)
if (abfd == NULL)
return;
- data.pc = (bfd_hostptr_t) pc;
+ data.pc = (bfd_hostptr_t) (pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -201,7 +227,7 @@ static const char * wpa_trace_bfd_addr2func(void *pc)
if (abfd == NULL)
return NULL;
- data.pc = (bfd_hostptr_t) pc;
+ data.pc = (bfd_hostptr_t) (pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -233,6 +259,11 @@ static void wpa_trace_bfd_init(void)
wpa_printf(MSG_INFO, "Failed to read symbols");
return;
}
+
+ if (!start_offset_looked_up) {
+ dl_iterate_phdr(callback, NULL);
+ start_offset_looked_up = 1;
+ }
}
@@ -268,7 +299,7 @@ size_t wpa_trace_calling_func(const char *buf[], size_t len)
for (i = 0; i < btrace_num; i++) {
struct bfd_data data;
- data.pc = (bfd_hostptr_t) btrace_res[i];
+ data.pc = (bfd_hostptr_t) (btrace_res[i] - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -366,4 +397,13 @@ void wpa_trace_check_ref(const void *addr)
}
}
+
+void wpa_trace_deinit(void)
+{
+#ifdef WPA_TRACE_BFD
+ free(syms);
+ syms = NULL;
+#endif /* WPA_TRACE_BFD */
+}
+
#endif /* WPA_TRACE */
diff --git a/contrib/wpa/src/utils/trace.h b/contrib/wpa/src/utils/trace.h
index 43ed86c..d1636de 100644
--- a/contrib/wpa/src/utils/trace.h
+++ b/contrib/wpa/src/utils/trace.h
@@ -66,4 +66,6 @@ void wpa_trace_dump_funcname(const char *title, void *pc);
#endif /* WPA_TRACE_BFD */
+void wpa_trace_deinit(void);
+
#endif /* TRACE_H */
diff --git a/contrib/wpa/src/utils/utils_module_tests.c b/contrib/wpa/src/utils/utils_module_tests.c
index 41511b9..3af4fcd 100644
--- a/contrib/wpa/src/utils/utils_module_tests.c
+++ b/contrib/wpa/src/utils/utils_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/const_time.h"
#include "common/ieee802_11_defs.h"
#include "utils/bitfield.h"
#include "utils/ext_password.h"
@@ -16,6 +17,8 @@
#include "utils/base64.h"
#include "utils/ip_addr.h"
#include "utils/eloop.h"
+#include "utils/json.h"
+#include "utils/module_tests.h"
struct printf_test_data {
@@ -838,6 +841,373 @@ static int eloop_tests(void)
}
+#ifdef CONFIG_JSON
+struct json_test_data {
+ const char *json;
+ const char *tree;
+};
+
+static const struct json_test_data json_test_cases[] = {
+ { "{}", "[1:OBJECT:]" },
+ { "[]", "[1:ARRAY:]" },
+ { "{", NULL },
+ { "[", NULL },
+ { "}", NULL },
+ { "]", NULL },
+ { "[[]]", "[1:ARRAY:][2:ARRAY:]" },
+ { "{\"t\":\"test\"}", "[1:OBJECT:][2:STRING:t]" },
+ { "{\"t\":123}", "[1:OBJECT:][2:NUMBER:t]" },
+ { "{\"t\":true}", "[1:OBJECT:][2:BOOLEAN:t]" },
+ { "{\"t\":false}", "[1:OBJECT:][2:BOOLEAN:t]" },
+ { "{\"t\":null}", "[1:OBJECT:][2:NULL:t]" },
+ { "{\"t\":truetrue}", NULL },
+ { "\"test\"", "[1:STRING:]" },
+ { "123", "[1:NUMBER:]" },
+ { "true", "[1:BOOLEAN:]" },
+ { "false", "[1:BOOLEAN:]" },
+ { "null", "[1:NULL:]" },
+ { "truetrue", NULL },
+ { " {\t\n\r\"a\"\n:\r1\n,\n\"b\":3\n}\n",
+ "[1:OBJECT:][2:NUMBER:a][2:NUMBER:b]" },
+ { ",", NULL },
+ { "{,}", NULL },
+ { "[,]", NULL },
+ { ":", NULL },
+ { "{:}", NULL },
+ { "[:]", NULL },
+ { "{ \"\\u005c\" : \"\\u005c\" }", "[1:OBJECT:][2:STRING:\\]" },
+ { "[{},{}]", "[1:ARRAY:][2:OBJECT:][2:OBJECT:]" },
+ { "[1,2]", "[1:ARRAY:][2:NUMBER:][2:NUMBER:]" },
+ { "[\"1\",\"2\"]", "[1:ARRAY:][2:STRING:][2:STRING:]" },
+ { "[true,false]", "[1:ARRAY:][2:BOOLEAN:][2:BOOLEAN:]" },
+};
+#endif /* CONFIG_JSON */
+
+
+static int json_tests(void)
+{
+#ifdef CONFIG_JSON
+ unsigned int i;
+ struct json_token *root;
+ char buf[1000];
+
+ wpa_printf(MSG_INFO, "JSON tests");
+
+ for (i = 0; i < ARRAY_SIZE(json_test_cases); i++) {
+ const struct json_test_data *test = &json_test_cases[i];
+ int res = 0;
+
+ root = json_parse(test->json, os_strlen(test->json));
+ if ((root && !test->tree) || (!root && test->tree)) {
+ wpa_printf(MSG_INFO, "JSON test %u failed", i);
+ res = -1;
+ } else if (root) {
+ json_print_tree(root, buf, sizeof(buf));
+ if (os_strcmp(buf, test->tree) != 0) {
+ wpa_printf(MSG_INFO,
+ "JSON test %u tree mismatch: %s %s",
+ i, buf, test->tree);
+ res = -1;
+ }
+ }
+ json_free(root);
+ if (res < 0)
+ return -1;
+
+ }
+#endif /* CONFIG_JSON */
+ return 0;
+}
+
+
+static int const_time_tests(void)
+{
+ struct const_time_fill_msb_test {
+ unsigned int val;
+ unsigned int expected;
+ } const_time_fill_msb_tests[] = {
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 0 },
+ { 1 << (sizeof(unsigned int) * 8 - 1), ~0 },
+ { ~0 - 1, ~0 },
+ { ~0, ~0 }
+ };
+ struct const_time_is_zero_test {
+ unsigned int val;
+ unsigned int expected;
+ } const_time_is_zero_tests[] = {
+ { 0, ~0 },
+ { 1, 0 },
+ { 2, 0 },
+ { 1 << (sizeof(unsigned int) * 8 - 1), 0 },
+ { ~0 - 1, 0 },
+ { ~0, 0 }
+ };
+ struct const_time_eq_test {
+ unsigned int a;
+ unsigned int b;
+ unsigned int expected;
+ unsigned int expected_u8;
+ } const_time_eq_tests[] = {
+ { 0, 1, 0, 0 },
+ { 1, 2, 0, 0 },
+ { 1, 1, ~0, 0xff },
+ { ~0, ~0, ~0, 0xff },
+ { ~0, ~0 - 1, 0, 0 },
+ { 0, 0, ~0, 0xff }
+ };
+ struct const_time_eq_bin_test {
+ u8 *a;
+ u8 *b;
+ size_t len;
+ unsigned int expected;
+ } const_time_eq_bin_tests[] = {
+ { (u8 *) "", (u8 *) "", 0, ~0 },
+ { (u8 *) "abcde", (u8 *) "abcde", 5, ~0 },
+ { (u8 *) "abcde", (u8 *) "Abcde", 5, 0 },
+ { (u8 *) "abcde", (u8 *) "aBcde", 5, 0 },
+ { (u8 *) "abcde", (u8 *) "abCde", 5, 0 },
+ { (u8 *) "abcde", (u8 *) "abcDe", 5, 0 },
+ { (u8 *) "abcde", (u8 *) "abcdE", 5, 0 },
+ { (u8 *) "\x00", (u8 *) "\x01", 1, 0 },
+ { (u8 *) "\x00", (u8 *) "\x80", 1, 0 },
+ { (u8 *) "\x00", (u8 *) "\x00", 1, ~0 }
+ };
+ struct const_time_select_test {
+ unsigned int mask;
+ unsigned int true_val;
+ unsigned int false_val;
+ unsigned int expected;
+ } const_time_select_tests[] = {
+ { ~0, ~0, ~0, ~0 },
+ { 0, ~0, ~0, ~0 },
+ { ~0, ~0, 0, ~0 },
+ { 0, ~0, 0, 0 },
+ { ~0, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa },
+ { 0, 0xaaaaaaaa, 0x55555555, 0x55555555 },
+ { ~0, 3, 3, 3 },
+ { 0, 3, 3, 3 },
+ { ~0, 1, 2, 1 },
+ { 0, 1, 2, 2 }
+ };
+ struct const_time_select_int_test {
+ unsigned int mask;
+ int true_val;
+ int false_val;
+ int expected;
+ } const_time_select_int_tests[] = {
+ { ~0, -128, 127, -128 },
+ { 0, -128, 127, 127 },
+ { ~0, -2147483648, 2147483647, -2147483648 },
+ { 0, -2147483648, 2147483647, 2147483647 },
+ { ~0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ { ~0, -1, 1, -1 },
+ { 0, -1, 1, 1 }
+ };
+ struct const_time_select_u8_test {
+ u8 mask;
+ u8 true_val;
+ u8 false_val;
+ u8 expected;
+ } const_time_select_u8_tests[] = {
+ { ~0, ~0, ~0, ~0 },
+ { 0, ~0, ~0, ~0 },
+ { ~0, ~0, 0, ~0 },
+ { 0, ~0, 0, 0 },
+ { ~0, 0xaa, 0x55, 0xaa },
+ { 0, 0xaa, 0x55, 0x55 },
+ { ~0, 1, 2, 1 },
+ { 0, 1, 2, 2 }
+ };
+ struct const_time_select_s8_test {
+ u8 mask;
+ s8 true_val;
+ s8 false_val;
+ s8 expected;
+ } const_time_select_s8_tests[] = {
+ { ~0, -128, 127, -128 },
+ { 0, -128, 127, 127 },
+ { ~0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ { ~0, -1, 1, -1 },
+ { 0, -1, 1, 1 }
+ };
+ struct const_time_select_bin_test {
+ u8 mask;
+ u8 *true_val;
+ u8 *false_val;
+ size_t len;
+ u8 *expected;
+ } const_time_select_bin_tests[] = {
+ { ~0, (u8 *) "abcde", (u8 *) "ABCDE", 5, (u8 *) "abcde" },
+ { 0, (u8 *) "abcde", (u8 *) "ABCDE", 5, (u8 *) "ABCDE" },
+ { ~0, (u8 *) "", (u8 *) "", 0, (u8 *) "" },
+ { 0, (u8 *) "", (u8 *) "", 0, (u8 *) "" }
+ };
+ struct const_time_memcmp_test {
+ char *a;
+ char *b;
+ size_t len;
+ int expected;
+ } const_time_memcmp_tests[] = {
+ { "abcde", "abcde", 5, 0 },
+ { "abcde", "bbcde", 5, -1 },
+ { "bbcde", "abcde", 5, 1 },
+ { "accde", "abcde", 5, 1 },
+ { "abcee", "abcde", 5, 1 },
+ { "abcdf", "abcde", 5, 1 },
+ { "cbcde", "aXXXX", 5, 2 },
+ { "a", "d", 1, -3 },
+ { "", "", 0, 0 }
+ };
+ unsigned int i;
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "constant time tests");
+
+ for (i = 0; i < ARRAY_SIZE(const_time_fill_msb_tests); i++) {
+ struct const_time_fill_msb_test *test;
+
+ test = &const_time_fill_msb_tests[i];
+ if (const_time_fill_msb(test->val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_fill_msb(0x%x) test failed",
+ test->val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_is_zero_tests); i++) {
+ struct const_time_is_zero_test *test;
+
+ test = &const_time_is_zero_tests[i];
+ if (const_time_is_zero(test->val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_is_zero(0x%x) test failed",
+ test->val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_eq_tests); i++) {
+ struct const_time_eq_test *test;
+
+ test = &const_time_eq_tests[i];
+ if (const_time_eq(test->a, test->b) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_eq(0x%x,0x%x) test failed",
+ test->a, test->b);
+ ret = -1;
+ }
+ if (const_time_eq_u8(test->a, test->b) != test->expected_u8) {
+ wpa_printf(MSG_ERROR,
+ "const_time_eq_u8(0x%x,0x%x) test failed",
+ test->a, test->b);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_eq_bin_tests); i++) {
+ struct const_time_eq_bin_test *test;
+
+ test = &const_time_eq_bin_tests[i];
+ if (const_time_eq_bin(test->a, test->b, test->len) !=
+ test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_eq_bin(len=%u) test failed",
+ (unsigned int) test->len);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_tests); i++) {
+ struct const_time_select_test *test;
+
+ test = &const_time_select_tests[i];
+ if (const_time_select(test->mask, test->true_val,
+ test->false_val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select(0x%x,0x%x,0x%x) test failed",
+ test->mask, test->true_val, test->false_val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_int_tests); i++) {
+ struct const_time_select_int_test *test;
+
+ test = &const_time_select_int_tests[i];
+ if (const_time_select_int(test->mask, test->true_val,
+ test->false_val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select_int(0x%x,%d,%d) test failed",
+ test->mask, test->true_val, test->false_val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_u8_tests); i++) {
+ struct const_time_select_u8_test *test;
+
+ test = &const_time_select_u8_tests[i];
+ if (const_time_select_u8(test->mask, test->true_val,
+ test->false_val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select_u8(0x%x,0x%x,0x%x) test failed",
+ test->mask, test->true_val, test->false_val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_s8_tests); i++) {
+ struct const_time_select_s8_test *test;
+
+ test = &const_time_select_s8_tests[i];
+ if (const_time_select_s8(test->mask, test->true_val,
+ test->false_val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select_s8(0x%x,0x%x,0x%x) test failed",
+ test->mask, test->true_val, test->false_val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_bin_tests); i++) {
+ struct const_time_select_bin_test *test;
+ u8 dst[100];
+
+ test = &const_time_select_bin_tests[i];
+ const_time_select_bin(test->mask, test->true_val,
+ test->false_val, test->len, dst);
+ if (os_memcmp(dst, test->expected, test->len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select_bin(0x%x,%u) test failed",
+ test->mask, (unsigned int) test->len);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_memcmp_tests); i++) {
+ struct const_time_memcmp_test *test;
+ int res;
+
+ test = &const_time_memcmp_tests[i];
+ res = const_time_memcmp(test->a, test->b, test->len);
+ if (res != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_memcmp(%s,%s,%d) test failed (%d != %d)",
+ test->a, test->b, (int) test->len,
+ res, test->expected);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
int utils_module_tests(void)
{
int ret = 0;
@@ -854,6 +1224,8 @@ int utils_module_tests(void)
wpabuf_tests() < 0 ||
ip_addr_tests() < 0 ||
eloop_tests() < 0 ||
+ json_tests() < 0 ||
+ const_time_tests() < 0 ||
int_array_tests() < 0)
ret = -1;
diff --git a/contrib/wpa/src/utils/uuid.c b/contrib/wpa/src/utils/uuid.c
index 0f224f9..98e43d0 100644
--- a/contrib/wpa/src/utils/uuid.c
+++ b/contrib/wpa/src/utils/uuid.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha256.h"
#include "uuid.h"
int uuid_str2bin(const char *str, u8 *bin)
@@ -69,3 +70,27 @@ int is_nil_uuid(const u8 *uuid)
return 0;
return 1;
}
+
+
+int uuid_random(u8 *uuid)
+{
+ struct os_time t;
+ u8 hash[SHA256_MAC_LEN];
+
+ /* Use HMAC-SHA256 and timestamp as context to avoid exposing direct
+ * os_get_random() output in the UUID field. */
+ os_get_time(&t);
+ if (os_get_random(uuid, UUID_LEN) < 0 ||
+ hmac_sha256(uuid, UUID_LEN, (const u8 *) &t, sizeof(t), hash) < 0)
+ return -1;
+
+ os_memcpy(uuid, hash, UUID_LEN);
+
+ /* Version: 4 = random */
+ uuid[6] = (4 << 4) | (uuid[6] & 0x0f);
+
+ /* Variant specified in RFC 4122 */
+ uuid[8] = 0x80 | (uuid[8] & 0x3f);
+
+ return 0;
+}
diff --git a/contrib/wpa/src/utils/uuid.h b/contrib/wpa/src/utils/uuid.h
index 5e860cb..6e20210 100644
--- a/contrib/wpa/src/utils/uuid.h
+++ b/contrib/wpa/src/utils/uuid.h
@@ -14,5 +14,6 @@
int uuid_str2bin(const char *str, u8 *bin);
int uuid_bin2str(const u8 *bin, char *str, size_t max_len);
int is_nil_uuid(const u8 *uuid);
+int uuid_random(u8 *uuid);
#endif /* UUID_H */
diff --git a/contrib/wpa/src/utils/wpa_debug.c b/contrib/wpa/src/utils/wpa_debug.c
index 61c0d5c..c437000 100644
--- a/contrib/wpa/src/utils/wpa_debug.c
+++ b/contrib/wpa/src/utils/wpa_debug.c
@@ -13,7 +13,7 @@
#ifdef CONFIG_DEBUG_SYSLOG
#include <syslog.h>
-static int wpa_debug_syslog = 0;
+int wpa_debug_syslog = 0;
#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
@@ -58,6 +58,10 @@ static int wpa_to_android_level(int level)
#ifndef CONFIG_NO_STDOUT_DEBUG
#ifdef CONFIG_DEBUG_FILE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
static FILE *out_file = NULL;
#endif /* CONFIG_DEBUG_FILE */
@@ -148,7 +152,7 @@ int wpa_debug_open_linux_tracing(void)
strtok_r(line, " ", &tmp2);
tmp_path = strtok_r(NULL, " ", &tmp2);
fstype = strtok_r(NULL, " ", &tmp2);
- if (strcmp(fstype, "debugfs") == 0) {
+ if (fstype && strcmp(fstype, "debugfs") == 0) {
path = tmp_path;
break;
}
@@ -418,6 +422,12 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
#ifdef CONFIG_ANDROID_LOG
_wpa_hexdump(level, title, buf, len, show);
#else /* CONFIG_ANDROID_LOG */
+#ifdef CONFIG_DEBUG_SYSLOG
+ if (wpa_debug_syslog) {
+ _wpa_hexdump(level, title, buf, len, show);
+ return;
+ }
+#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
if (out_file) {
@@ -517,16 +527,18 @@ int wpa_debug_reopen_file(void)
{
#ifdef CONFIG_DEBUG_FILE
int rv;
- if (last_path) {
- char *tmp = os_strdup(last_path);
- wpa_debug_close_file();
- rv = wpa_debug_open_file(tmp);
- os_free(tmp);
- } else {
- wpa_printf(MSG_ERROR, "Last-path was not set, cannot "
- "re-open log file.");
- rv = -1;
- }
+ char *tmp;
+
+ if (!last_path)
+ return 0; /* logfile not used */
+
+ tmp = os_strdup(last_path);
+ if (!tmp)
+ return -1;
+
+ wpa_debug_close_file();
+ rv = wpa_debug_open_file(tmp);
+ os_free(tmp);
return rv;
#else /* CONFIG_DEBUG_FILE */
return 0;
@@ -537,6 +549,8 @@ int wpa_debug_reopen_file(void)
int wpa_debug_open_file(const char *path)
{
#ifdef CONFIG_DEBUG_FILE
+ int out_fd;
+
if (!path)
return 0;
@@ -546,10 +560,28 @@ int wpa_debug_open_file(const char *path)
last_path = os_strdup(path);
}
- out_file = fopen(path, "a");
+ out_fd = open(path, O_CREAT | O_APPEND | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP);
+ if (out_fd < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: Failed to open output file descriptor, using standard output",
+ __func__);
+ return -1;
+ }
+
+#ifdef __linux__
+ if (fcntl(out_fd, F_SETFD, FD_CLOEXEC) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Failed to set FD_CLOEXEC - continue without: %s",
+ __func__, strerror(errno));
+ }
+#endif /* __linux__ */
+
+ out_file = fdopen(out_fd, "a");
if (out_file == NULL) {
wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
"output file, using standard output");
+ close(out_fd);
return -1;
}
#ifndef _WIN32
diff --git a/contrib/wpa/src/utils/wpa_debug.h b/contrib/wpa/src/utils/wpa_debug.h
index 17d8f96..1fe0b7d 100644
--- a/contrib/wpa/src/utils/wpa_debug.h
+++ b/contrib/wpa/src/utils/wpa_debug.h
@@ -14,6 +14,9 @@
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
+#ifdef CONFIG_DEBUG_SYSLOG
+extern int wpa_debug_syslog;
+#endif /* CONFIG_DEBUG_SYSLOG */
/* Debugging function - conditional printf and hex dump. Driver wrappers can
* use these for debugging purposes. */
diff --git a/contrib/wpa/src/utils/wpabuf.c b/contrib/wpa/src/utils/wpabuf.c
index 11e7323..77ee472 100644
--- a/contrib/wpa/src/utils/wpabuf.c
+++ b/contrib/wpa/src/utils/wpabuf.c
@@ -244,15 +244,13 @@ struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
if (a)
len += wpabuf_len(a);
- if (b)
- len += wpabuf_len(b);
+ len += wpabuf_len(b);
n = wpabuf_alloc(len);
if (n) {
if (a)
wpabuf_put_buf(n, a);
- if (b)
- wpabuf_put_buf(n, b);
+ wpabuf_put_buf(n, b);
}
wpabuf_free(a);
@@ -310,3 +308,33 @@ void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
wpabuf_overflow(buf, res);
buf->used += res;
}
+
+
+/**
+ * wpabuf_parse_bin - Parse a null terminated string of binary data to a wpabuf
+ * @buf: Buffer with null terminated string (hexdump) of binary data
+ * Returns: wpabuf or %NULL on failure
+ *
+ * The string len must be a multiple of two and contain only hexadecimal digits.
+ */
+struct wpabuf * wpabuf_parse_bin(const char *buf)
+{
+ size_t len;
+ struct wpabuf *ret;
+
+ len = os_strlen(buf);
+ if (len & 0x01)
+ return NULL;
+ len /= 2;
+
+ ret = wpabuf_alloc(len);
+ if (ret == NULL)
+ return NULL;
+
+ if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
+ wpabuf_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
diff --git a/contrib/wpa/src/utils/wpabuf.h b/contrib/wpa/src/utils/wpabuf.h
index c3ef1ba..01da41b 100644
--- a/contrib/wpa/src/utils/wpabuf.h
+++ b/contrib/wpa/src/utils/wpabuf.h
@@ -37,6 +37,7 @@ void * wpabuf_put(struct wpabuf *buf, size_t len);
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
+struct wpabuf * wpabuf_parse_bin(const char *buf);
/**
@@ -81,7 +82,7 @@ static inline const void * wpabuf_head(const struct wpabuf *buf)
static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
{
- return wpabuf_head(buf);
+ return (const u8 *) wpabuf_head(buf);
}
/**
@@ -96,42 +97,42 @@ static inline void * wpabuf_mhead(struct wpabuf *buf)
static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
{
- return wpabuf_mhead(buf);
+ return (u8 *) wpabuf_mhead(buf);
}
static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
{
- u8 *pos = wpabuf_put(buf, 1);
+ u8 *pos = (u8 *) wpabuf_put(buf, 1);
*pos = data;
}
static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
{
- u8 *pos = wpabuf_put(buf, 2);
+ u8 *pos = (u8 *) wpabuf_put(buf, 2);
WPA_PUT_LE16(pos, data);
}
static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
{
- u8 *pos = wpabuf_put(buf, 4);
+ u8 *pos = (u8 *) wpabuf_put(buf, 4);
WPA_PUT_LE32(pos, data);
}
static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
{
- u8 *pos = wpabuf_put(buf, 2);
+ u8 *pos = (u8 *) wpabuf_put(buf, 2);
WPA_PUT_BE16(pos, data);
}
static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
{
- u8 *pos = wpabuf_put(buf, 3);
+ u8 *pos = (u8 *) wpabuf_put(buf, 3);
WPA_PUT_BE24(pos, data);
}
static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
{
- u8 *pos = wpabuf_put(buf, 4);
+ u8 *pos = (u8 *) wpabuf_put(buf, 4);
WPA_PUT_BE32(pos, data);
}
diff --git a/contrib/wpa/src/utils/xml-utils.c b/contrib/wpa/src/utils/xml-utils.c
index 4916d29..dae91fe 100644
--- a/contrib/wpa/src/utils/xml-utils.c
+++ b/contrib/wpa/src/utils/xml-utils.c
@@ -246,10 +246,10 @@ static void node_to_tnds(struct xml_node_ctx *ctx, xml_node_t *out,
xml_node_create_text(ctx, tnds, NULL, "Path", uri);
val = get_val(ctx, node);
- if (val) {
- xml_node_create_text(ctx, tnds, NULL, "Value", val);
- xml_node_get_text_free(ctx, val);
- }
+ if (val || !xml_node_first_child(ctx, node))
+ xml_node_create_text(ctx, tnds, NULL, "Value",
+ val ? val : "");
+ xml_node_get_text_free(ctx, val);
new_uri = add_path(uri, name);
node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri);
diff --git a/contrib/wpa/src/utils/xml_libxml2.c b/contrib/wpa/src/utils/xml_libxml2.c
index c928394..7b6d276 100644
--- a/contrib/wpa/src/utils/xml_libxml2.c
+++ b/contrib/wpa/src/utils/xml_libxml2.c
@@ -212,6 +212,8 @@ char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node)
xmlDocSetRootElement(doc, n);
xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0);
xmlFreeDoc(doc);
+ if (!buf)
+ return NULL;
pos = (char *) buf;
if (strncmp(pos, "<?xml", 5) == 0) {
pos = strchr(pos, '>');
diff --git a/contrib/wpa/src/wps/wps.c b/contrib/wpa/src/wps/wps.c
index fbaf85a..484df26 100644
--- a/contrib/wpa/src/wps/wps.c
+++ b/contrib/wpa/src/wps/wps.c
@@ -19,6 +19,10 @@
int wps_version_number = 0x20;
int wps_testing_dummy_cred = 0;
int wps_corrupt_pkhash = 0;
+int wps_force_auth_types_in_use = 0;
+u16 wps_force_auth_types = 0;
+int wps_force_encr_types_in_use = 0;
+u16 wps_force_encr_types = 0;
#endif /* CONFIG_WPS_TESTING */
@@ -47,12 +51,11 @@ struct wps_data * wps_init(const struct wps_config *cfg)
}
if (cfg->pin) {
data->dev_pw_id = cfg->dev_pw_id;
- data->dev_password = os_malloc(cfg->pin_len);
+ data->dev_password = os_memdup(cfg->pin, cfg->pin_len);
if (data->dev_password == NULL) {
os_free(data);
return NULL;
}
- os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
data->dev_password_len = cfg->pin_len;
wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password",
data->dev_password, data->dev_password_len);
@@ -71,14 +74,12 @@ struct wps_data * wps_init(const struct wps_config *cfg)
data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
data->dev_password =
- os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+ os_memdup(wpabuf_head(cfg->wps->ap_nfc_dev_pw),
+ wpabuf_len(cfg->wps->ap_nfc_dev_pw));
if (data->dev_password == NULL) {
os_free(data);
return NULL;
}
- os_memcpy(data->dev_password,
- wpabuf_head(cfg->wps->ap_nfc_dev_pw),
- wpabuf_len(cfg->wps->ap_nfc_dev_pw));
data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password",
data->dev_password, data->dev_password_len);
@@ -120,15 +121,14 @@ struct wps_data * wps_init(const struct wps_config *cfg)
if (cfg->new_ap_settings) {
data->new_ap_settings =
- os_malloc(sizeof(*data->new_ap_settings));
+ os_memdup(cfg->new_ap_settings,
+ sizeof(*data->new_ap_settings));
if (data->new_ap_settings == NULL) {
bin_clear_free(data->dev_password,
data->dev_password_len);
os_free(data);
return NULL;
}
- os_memcpy(data->new_ap_settings, cfg->new_ap_settings,
- sizeof(*data->new_ap_settings));
}
if (cfg->peer_addr)
@@ -145,6 +145,8 @@ struct wps_data * wps_init(const struct wps_config *cfg)
data->peer_pubkey_hash_set = 1;
}
+ data->multi_ap_backhaul_sta = cfg->multi_ap_backhaul_sta;
+
return data;
}
@@ -170,7 +172,7 @@ void wps_deinit(struct wps_data *data)
} else if (data->registrar)
wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
- wpabuf_free(data->dh_privkey);
+ wpabuf_clear_free(data->dh_privkey);
wpabuf_free(data->dh_pubkey_e);
wpabuf_free(data->dh_pubkey_r);
wpabuf_free(data->last_msg);
@@ -430,7 +432,7 @@ struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
if (wps_build_version(ie) ||
wps_build_req_type(ie, req_type) ||
- wps_build_wfa_ext(ie, 0, NULL, 0)) {
+ wps_build_wfa_ext(ie, 0, NULL, 0, 0)) {
wpabuf_free(ie);
return NULL;
}
@@ -464,7 +466,7 @@ struct wpabuf * wps_build_assoc_resp_ie(void)
if (wps_build_version(ie) ||
wps_build_resp_type(ie, WPS_RESP_AP) ||
- wps_build_wfa_ext(ie, 0, NULL, 0)) {
+ wps_build_wfa_ext(ie, 0, NULL, 0, 0)) {
wpabuf_free(ie);
return NULL;
}
@@ -516,7 +518,7 @@ struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
wps_build_model_name(dev, ie) ||
wps_build_model_number(dev, ie) ||
wps_build_dev_name(dev, ie) ||
- wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
+ wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0, 0) ||
wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
||
wps_build_secondary_dev_type(dev, ie)
diff --git a/contrib/wpa/src/wps/wps.h b/contrib/wpa/src/wps/wps.h
index 2c91d16..14ce863 100644
--- a/contrib/wpa/src/wps/wps.h
+++ b/contrib/wpa/src/wps/wps.h
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup
- * Copyright (c) 2007-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -100,6 +100,7 @@ struct wps_device_data {
struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
int p2p;
+ u8 multi_ap_ext;
};
/**
@@ -187,6 +188,12 @@ struct wps_config {
* peer_pubkey_hash - Peer public key hash or %NULL if not known
*/
const u8 *peer_pubkey_hash;
+
+ /**
+ * multi_ap_backhaul_sta - Whether this is a Multi-AP backhaul STA
+ * enrollee
+ */
+ int multi_ap_backhaul_sta;
};
struct wps_data * wps_init(const struct wps_config *cfg);
@@ -395,6 +402,37 @@ struct wps_registrar_config {
* PSK is set for a network.
*/
int force_per_enrollee_psk;
+
+ /**
+ * multi_ap_backhaul_ssid - SSID to supply to a Multi-AP backhaul
+ * enrollee
+ *
+ * This SSID is used by the Registrar to fill in information for
+ * Credentials when the enrollee advertises it is a Multi-AP backhaul
+ * STA.
+ */
+ const u8 *multi_ap_backhaul_ssid;
+
+ /**
+ * multi_ap_backhaul_ssid_len - Length of multi_ap_backhaul_ssid in
+ * octets
+ */
+ size_t multi_ap_backhaul_ssid_len;
+
+ /**
+ * multi_ap_backhaul_network_key - The Network Key (PSK) for the
+ * Multi-AP backhaul enrollee.
+ *
+ * This key can be either the ASCII passphrase (8..63 characters) or the
+ * 32-octet PSK (64 hex characters).
+ */
+ const u8 *multi_ap_backhaul_network_key;
+
+ /**
+ * multi_ap_backhaul_network_key_len - Length of
+ * multi_ap_backhaul_network_key in octets
+ */
+ size_t multi_ap_backhaul_network_key_len;
};
@@ -664,6 +702,16 @@ struct wps_context {
u16 encr_types;
/**
+ * encr_types_rsn - Enabled encryption types for RSN (WPS_ENCR_*)
+ */
+ u16 encr_types_rsn;
+
+ /**
+ * encr_types_wpa - Enabled encryption types for WPA (WPS_ENCR_*)
+ */
+ u16 encr_types_wpa;
+
+ /**
* auth_types - Authentication types (bit field of WPS_AUTH_*)
*/
u16 auth_types;
@@ -827,7 +875,7 @@ int wps_build_credential_wrap(struct wpabuf *msg,
unsigned int wps_pin_checksum(unsigned int pin);
unsigned int wps_pin_valid(unsigned int pin);
-unsigned int wps_generate_pin(void);
+int wps_generate_pin(unsigned int *pin);
int wps_pin_str_valid(const char *pin);
void wps_free_pending_msgs(struct upnp_pending_message *msgs);
diff --git a/contrib/wpa/src/wps/wps_attr_build.c b/contrib/wpa/src/wps/wps_attr_build.c
index b689357..4e872f3 100644
--- a/contrib/wpa/src/wps/wps_attr_build.c
+++ b/contrib/wpa/src/wps/wps_attr_build.c
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup - attribute building
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,10 +20,10 @@
int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
{
- struct wpabuf *pubkey;
+ struct wpabuf *pubkey = NULL;
wpa_printf(MSG_DEBUG, "WPS: * Public Key");
- wpabuf_free(wps->dh_privkey);
+ wpabuf_clear_free(wps->dh_privkey);
wps->dh_privkey = NULL;
if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
wps->wps->dh_ctx) {
@@ -60,7 +60,8 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
}
wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
- wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
+ if (wps->dh_privkey && pubkey)
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
#endif /* CONFIG_WPS_NFC */
} else {
wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
@@ -203,7 +204,8 @@ int wps_build_version(struct wpabuf *msg)
int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
- const u8 *auth_macs, size_t auth_macs_count)
+ const u8 *auth_macs, size_t auth_macs_count,
+ u8 multi_ap_subelem)
{
u8 *len;
@@ -244,6 +246,14 @@ int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
MAC2STR(&auth_macs[i * ETH_ALEN]));
}
+ if (multi_ap_subelem) {
+ wpa_printf(MSG_DEBUG, "WPS: * Multi-AP (0x%x)",
+ multi_ap_subelem);
+ wpabuf_put_u8(msg, WFA_ELEM_MULTI_AP);
+ wpabuf_put_u8(msg, 1); /* length */
+ wpabuf_put_u8(msg, multi_ap_subelem);
+ }
+
WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
#ifdef CONFIG_WPS_TESTING
@@ -298,7 +308,16 @@ int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
auth_types &= ~WPS_AUTH_WPA;
auth_types &= ~WPS_AUTH_WPA2;
auth_types &= ~WPS_AUTH_SHARED;
- wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags");
+#ifdef CONFIG_WPS_TESTING
+ if (wps_force_auth_types_in_use) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Testing - replace auth type 0x%x with 0x%x",
+ auth_types, wps_force_auth_types);
+ auth_types = wps_force_auth_types;
+ }
+#endif /* CONFIG_WPS_TESTING */
+ wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags (0x%x)",
+ auth_types);
wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
wpabuf_put_be16(msg, 2);
wpabuf_put_be16(msg, auth_types);
@@ -310,7 +329,16 @@ int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
{
u16 encr_types = WPS_ENCR_TYPES;
encr_types &= ~WPS_ENCR_WEP;
- wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags");
+#ifdef CONFIG_WPS_TESTING
+ if (wps_force_encr_types_in_use) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Testing - replace encr type 0x%x with 0x%x",
+ encr_types, wps_force_encr_types);
+ encr_types = wps_force_encr_types;
+ }
+#endif /* CONFIG_WPS_TESTING */
+ wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags (0x%x)",
+ encr_types);
wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
wpabuf_put_be16(msg, 2);
wpabuf_put_be16(msg, encr_types);
@@ -395,7 +423,8 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
dev_pw_id);
addr[0] = wpabuf_head(pubkey);
hash_len = wpabuf_len(pubkey);
- sha256_vector(1, addr, &hash_len, pubkey_hash);
+ if (sha256_vector(1, addr, &hash_len, pubkey_hash) < 0)
+ return -1;
#ifdef CONFIG_WPS_TESTING
if (wps_corrupt_pkhash) {
wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash",
diff --git a/contrib/wpa/src/wps/wps_attr_parse.c b/contrib/wpa/src/wps/wps_attr_parse.c
index 11a967b..fd51635 100644
--- a/contrib/wpa/src/wps/wps_attr_parse.c
+++ b/contrib/wpa/src/wps/wps_attr_parse.c
@@ -67,6 +67,17 @@ static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
}
attr->registrar_configuration_methods = pos;
break;
+ case WFA_ELEM_MULTI_AP:
+ if (len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Invalid Multi-AP Extension length %u",
+ len);
+ return -1;
+ }
+ attr->multi_ap_ext = *pos;
+ wpa_printf(MSG_DEBUG, "WPS: Multi-AP Extension 0x%02x",
+ attr->multi_ap_ext);
+ break;
default:
wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
"Extension subelement %u", id);
@@ -83,10 +94,10 @@ static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
const u8 *end = pos + len;
u8 id, elen;
- while (pos + 2 <= end) {
+ while (end - pos >= 2) {
id = *pos++;
elen = *pos++;
- if (pos + elen > end)
+ if (elen > end - pos)
break;
if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
return -1;
diff --git a/contrib/wpa/src/wps/wps_attr_parse.h b/contrib/wpa/src/wps/wps_attr_parse.h
index 8188fe9..4de27b2 100644
--- a/contrib/wpa/src/wps/wps_attr_parse.h
+++ b/contrib/wpa/src/wps/wps_attr_parse.h
@@ -97,6 +97,7 @@ struct wps_parse_attr {
const u8 *cred[MAX_CRED_COUNT];
const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
+ u8 multi_ap_ext;
};
int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
diff --git a/contrib/wpa/src/wps/wps_attr_process.c b/contrib/wpa/src/wps/wps_attr_process.c
index eadb22f..e8c4579 100644
--- a/contrib/wpa/src/wps/wps_attr_process.c
+++ b/contrib/wpa/src/wps/wps_attr_process.c
@@ -229,6 +229,16 @@ static int wps_workaround_cred_key(struct wps_credential *cred)
cred->key_len--;
#endif /* CONFIG_WPS_STRICT */
}
+
+
+ if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
+ (cred->key_len < 8 || has_ctrl_char(cred->key, cred->key_len))) {
+ wpa_printf(MSG_INFO, "WPS: Reject credential with invalid WPA/WPA2-Personal passphrase");
+ wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key",
+ cred->key, cred->key_len);
+ return -1;
+ }
+
return 0;
}
diff --git a/contrib/wpa/src/wps/wps_common.c b/contrib/wpa/src/wps/wps_common.c
index 88f85fe..747dc47 100644
--- a/contrib/wpa/src/wps/wps_common.c
+++ b/contrib/wpa/src/wps/wps_common.c
@@ -90,7 +90,7 @@ int wps_derive_keys(struct wps_data *wps)
}
/* Own DH private key is not needed anymore */
- wpabuf_free(wps->dh_privkey);
+ wpabuf_clear_free(wps->dh_privkey);
wps->dh_privkey = NULL;
wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
@@ -100,7 +100,7 @@ int wps_derive_keys(struct wps_data *wps)
len[0] = wpabuf_len(dh_shared);
sha256_vector(1, addr, len, dhkey);
wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
- wpabuf_free(dh_shared);
+ wpabuf_clear_free(dh_shared);
/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
addr[0] = wps->nonce_e;
@@ -129,23 +129,26 @@ int wps_derive_keys(struct wps_data *wps)
}
-void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
- size_t dev_passwd_len)
+int wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
+ size_t dev_passwd_len)
{
u8 hash[SHA256_MAC_LEN];
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
- (dev_passwd_len + 1) / 2, hash);
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
+ (dev_passwd_len + 1) / 2, hash) < 0)
+ return -1;
os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
- dev_passwd + (dev_passwd_len + 1) / 2,
- dev_passwd_len / 2, hash);
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
+ dev_passwd + (dev_passwd_len + 1) / 2,
+ dev_passwd_len / 2, hash) < 0)
+ return -1;
os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
dev_passwd, dev_passwd_len);
wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
+ return 0;
}
@@ -173,7 +176,7 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
wpabuf_len(decrypted))) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
return NULL;
}
@@ -184,14 +187,14 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
pad = *pos;
if (pad > wpabuf_len(decrypted)) {
wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
return NULL;
}
for (i = 0; i < pad; i++) {
if (*pos-- != pad) {
wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
"string");
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
return NULL;
}
}
@@ -235,20 +238,18 @@ unsigned int wps_pin_valid(unsigned int pin)
* wps_generate_pin - Generate a random PIN
* Returns: Eight digit PIN (i.e., including the checksum digit)
*/
-unsigned int wps_generate_pin(void)
+int wps_generate_pin(unsigned int *pin)
{
unsigned int val;
/* Generate seven random digits for the PIN */
- if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) {
- struct os_time now;
- os_get_time(&now);
- val = os_random() ^ now.sec ^ now.usec;
- }
+ if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0)
+ return -1;
val %= 10000000;
/* Append checksum digit */
- return val * 10 + wps_pin_checksum(val);
+ *pin = val * 10 + wps_pin_checksum(val);
+ return 0;
}
@@ -373,9 +374,9 @@ struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band,
(rf_band && wps_build_rf_bands_attr(plain, rf_band)) ||
(channel && wps_build_ap_channel(plain, channel)) ||
wps_build_mac_addr(plain, wps->dev.mac_addr) ||
- wps_build_wfa_ext(plain, 0, NULL, 0)) {
+ wps_build_wfa_ext(plain, 0, NULL, 0, 0)) {
os_free(data.new_psk);
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
@@ -420,10 +421,10 @@ struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
- wps_build_wfa_ext(data, 0, NULL, 0)) {
+ wps_build_wfa_ext(data, 0, NULL, 0, 0)) {
wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
"token");
- wpabuf_free(data);
+ wpabuf_clear_free(data);
return NULL;
}
@@ -585,7 +586,7 @@ struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
wps_build_msg_type(msg, WPS_WSC_ACK) ||
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -609,7 +610,7 @@ struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_config_error(msg, wps->config_error) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -653,6 +654,7 @@ int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey)
pub = wpabuf_zeropad(pub, 192);
if (pub == NULL) {
wpabuf_free(priv);
+ dh5_free(dh_ctx);
return -1;
}
wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub);
@@ -660,7 +662,7 @@ int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey)
wpabuf_free(*pubkey);
*pubkey = pub;
- wpabuf_free(*privkey);
+ wpabuf_clear_free(*privkey);
*privkey = priv;
return 0;
@@ -691,7 +693,7 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
}
*id = 0x10 + val % 0xfff0;
- wpabuf_free(*dev_pw);
+ wpabuf_clear_free(*dev_pw);
*dev_pw = pw;
return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
@@ -724,7 +726,7 @@ struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
nfc_dh_pubkey, NULL, 0) ||
wps_build_uuid_e(msg, ctx->uuid) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -807,7 +809,7 @@ struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
wps_build_ssid(msg, ctx) ||
wps_build_ap_freq(msg, freq) ||
(bssid && wps_build_mac_addr(msg, bssid)) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -846,7 +848,7 @@ struct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx,
wps_build_rf_bands(&ctx->dev, msg, 0) ||
wps_build_serial_number(&ctx->dev, msg) ||
wps_build_uuid_e(msg, ctx->uuid) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -898,7 +900,7 @@ struct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx,
wps_build_rf_bands(&ctx->dev, msg, 0) ||
wps_build_serial_number(&ctx->dev, msg) ||
wps_build_uuid_e(msg, ctx->uuid) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
diff --git a/contrib/wpa/src/wps/wps_defs.h b/contrib/wpa/src/wps/wps_defs.h
index a23b979..9fccb4e 100644
--- a/contrib/wpa/src/wps/wps_defs.h
+++ b/contrib/wpa/src/wps/wps_defs.h
@@ -14,6 +14,10 @@
extern int wps_version_number;
extern int wps_testing_dummy_cred;
extern int wps_corrupt_pkhash;
+extern int wps_force_auth_types_in_use;
+extern u16 wps_force_auth_types;
+extern int wps_force_encr_types_in_use;
+extern u16 wps_force_encr_types;
#define WPS_VERSION wps_version_number
#else /* CONFIG_WPS_TESTING */
@@ -148,7 +152,8 @@ enum {
WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
WFA_ELEM_SETTINGS_DELAY_TIME = 0x04,
- WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05
+ WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05,
+ WFA_ELEM_MULTI_AP = 0x06
};
/* Device Password ID */
diff --git a/contrib/wpa/src/wps/wps_dev_attr.c b/contrib/wpa/src/wps/wps_dev_attr.c
index 0d01211..b209fea 100644
--- a/contrib/wpa/src/wps/wps_dev_attr.c
+++ b/contrib/wpa/src/wps/wps_dev_attr.c
@@ -390,6 +390,14 @@ int wps_process_os_version(struct wps_device_data *dev, const u8 *ver)
}
+void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext)
+{
+ dev->multi_ap_ext = ext;
+ wpa_printf(MSG_DEBUG, "WPS: Multi-AP extension value %02x",
+ dev->multi_ap_ext);
+}
+
+
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)
{
if (bands == NULL) {
diff --git a/contrib/wpa/src/wps/wps_dev_attr.h b/contrib/wpa/src/wps/wps_dev_attr.h
index c9034ad..a4b4173 100644
--- a/contrib/wpa/src/wps/wps_dev_attr.h
+++ b/contrib/wpa/src/wps/wps_dev_attr.h
@@ -29,6 +29,7 @@ int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
int wps_process_device_attrs(struct wps_device_data *dev,
struct wps_parse_attr *attr);
int wps_process_os_version(struct wps_device_data *dev, const u8 *ver);
+void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext);
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
void wps_device_data_free(struct wps_device_data *dev);
int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
diff --git a/contrib/wpa/src/wps/wps_enrollee.c b/contrib/wpa/src/wps/wps_enrollee.c
index 9321b72..80ed603 100644
--- a/contrib/wpa/src/wps/wps_enrollee.c
+++ b/contrib/wpa/src/wps/wps_enrollee.c
@@ -105,6 +105,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
{
struct wpabuf *msg;
u16 config_methods;
+ u8 multi_ap_backhaul_sta = 0;
if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0)
return NULL;
@@ -134,6 +135,9 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
WPS_CONFIG_PHY_PUSHBUTTON);
}
+ if (wps->multi_ap_backhaul_sta)
+ multi_ap_backhaul_sta = MULTI_AP_BACKHAUL_STA;
+
if (wps_build_version(msg) ||
wps_build_msg_type(msg, WPS_M1) ||
wps_build_uuid_e(msg, wps->uuid_e) ||
@@ -152,7 +156,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, multi_ap_backhaul_sta) ||
wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
wpabuf_free(msg);
return NULL;
@@ -173,7 +177,8 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps)
wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
return NULL;
}
- wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+ if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0)
+ return NULL;
if (wps->wps->ap && random_pool_ready() != 1) {
wpa_printf(MSG_INFO,
@@ -189,7 +194,7 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps)
wps_build_msg_type(msg, WPS_M3) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_e_hash(wps, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(msg);
return NULL;
@@ -222,13 +227,13 @@ static struct wpabuf * wps_build_m5(struct wps_data *wps)
wps_build_e_snonce1(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wps->state = RECV_M6;
return msg;
@@ -392,13 +397,13 @@ static struct wpabuf * wps_build_m7(struct wps_data *wps)
(wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
if (wps->wps->ap && wps->wps->registrar) {
/*
@@ -429,7 +434,7 @@ static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
wps_build_msg_type(msg, WPS_WSC_DONE) ||
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -1007,11 +1012,11 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps,
eattr.key_wrap_auth) ||
wps_process_creds(wps, eattr.cred, eattr.cred_len,
eattr.num_cred, attr->version2 != NULL)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = WPS_MSG_DONE;
return WPS_CONTINUE;
@@ -1112,7 +1117,7 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps,
}
if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -1122,11 +1127,11 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps,
if (wps_parse_msg(decrypted, &eattr) < 0 ||
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_r_snonce1(wps, eattr.r_snonce1)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_M5;
return WPS_CONTINUE;
@@ -1165,7 +1170,7 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
}
if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -1175,11 +1180,11 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
if (wps_parse_msg(decrypted, &eattr) < 0 ||
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_r_snonce2(wps, eattr.r_snonce2)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
if (wps->wps->ap)
wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS,
@@ -1236,7 +1241,7 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
if (wps_validate_m8_encr(decrypted, wps->wps->ap,
attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -1249,11 +1254,11 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
eattr.num_cred, attr->version2 != NULL) ||
wps_process_ap_settings_e(wps, &eattr, decrypted,
attr->version2 != NULL)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = WPS_MSG_DONE;
return WPS_CONTINUE;
diff --git a/contrib/wpa/src/wps/wps_er.c b/contrib/wpa/src/wps/wps_er.c
index b840acd..06a8fda 100644
--- a/contrib/wpa/src/wps/wps_er.c
+++ b/contrib/wpa/src/wps/wps_er.c
@@ -322,11 +322,10 @@ static int wps_er_ap_use_cached_settings(struct wps_er *er,
if (!s)
return -1;
- ap->ap_settings = os_malloc(sizeof(*ap->ap_settings));
+ ap->ap_settings = os_memdup(&s->ap_settings, sizeof(*ap->ap_settings));
if (ap->ap_settings == NULL)
return -1;
- os_memcpy(ap->ap_settings, &s->ap_settings, sizeof(*ap->ap_settings));
wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings");
return 0;
}
@@ -1531,7 +1530,7 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
wps_er_build_selected_registrar(msg, sel_reg) ||
wps_er_build_dev_password_id(msg, dev_passwd_id) ||
wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
- wps_build_wfa_ext(msg, 0, auth_macs, count) ||
+ wps_build_wfa_ext(msg, 0, auth_macs, count, 0) ||
wps_er_build_uuid_r(msg, er->wps->uuid)) {
wpabuf_free(msg);
return;
@@ -1958,10 +1957,9 @@ int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
}
os_free(ap->ap_settings);
- ap->ap_settings = os_malloc(sizeof(*cred));
+ ap->ap_settings = os_memdup(cred, sizeof(*cred));
if (ap->ap_settings == NULL)
return -1;
- os_memcpy(ap->ap_settings, cred, sizeof(*cred));
ap->ap_settings->cred_attr = NULL;
wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set "
"config request");
@@ -2018,10 +2016,9 @@ int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
}
os_free(ap->ap_settings);
- ap->ap_settings = os_malloc(sizeof(*cred));
+ ap->ap_settings = os_memdup(cred, sizeof(*cred));
if (ap->ap_settings == NULL)
return -1;
- os_memcpy(ap->ap_settings, cred, sizeof(*cred));
ap->ap_settings->cred_attr = NULL;
if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0)
@@ -2051,7 +2048,7 @@ struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
data.wps = wps;
data.use_cred = cred;
if (wps_build_cred(&data, ret) ||
- wps_build_wfa_ext(ret, 0, NULL, 0)) {
+ wps_build_wfa_ext(ret, 0, NULL, 0, 0)) {
wpabuf_free(ret);
return NULL;
}
diff --git a/contrib/wpa/src/wps/wps_i.h b/contrib/wpa/src/wps/wps_i.h
index f7154f8..2cf22d4 100644
--- a/contrib/wpa/src/wps/wps_i.h
+++ b/contrib/wpa/src/wps/wps_i.h
@@ -125,6 +125,8 @@ struct wps_data {
int pbc_in_m1;
struct wps_nfc_pw_token *nfc_pw_token;
+
+ int multi_ap_backhaul_sta;
};
@@ -132,8 +134,8 @@ struct wps_data {
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
const char *label, u8 *res, size_t res_len);
int wps_derive_keys(struct wps_data *wps);
-void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
- size_t dev_passwd_len);
+int wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
+ size_t dev_passwd_len);
struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
size_t encr_len);
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
@@ -163,7 +165,8 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
struct wpabuf *plain);
int wps_build_version(struct wpabuf *msg);
int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
- const u8 *auth_macs, size_t auth_macs_count);
+ const u8 *auth_macs, size_t auth_macs_count,
+ u8 multi_ap_subelem);
int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
diff --git a/contrib/wpa/src/wps/wps_module_tests.c b/contrib/wpa/src/wps/wps_module_tests.c
index 3506307..23bed4b 100644
--- a/contrib/wpa/src/wps/wps_module_tests.c
+++ b/contrib/wpa/src/wps/wps_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "wps_attr_parse.h"
struct wps_attr_parse_test {
@@ -17,7 +18,7 @@ struct wps_attr_parse_test {
int extra;
};
-const struct wps_attr_parse_test wps_attr_parse_test_cases[] = {
+static const struct wps_attr_parse_test wps_attr_parse_test_cases[] = {
/* Empty message */
{ "", 0, 0 },
/* Truncated attribute header */
diff --git a/contrib/wpa/src/wps/wps_registrar.c b/contrib/wpa/src/wps/wps_registrar.c
index 4ca3a42..0ac5b28 100644
--- a/contrib/wpa/src/wps/wps_registrar.c
+++ b/contrib/wpa/src/wps/wps_registrar.c
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup - Registrar
- * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -188,6 +188,37 @@ struct wps_registrar {
#ifdef WPS_WORKAROUNDS
struct os_reltime pbc_ignore_start;
#endif /* WPS_WORKAROUNDS */
+
+ /**
+ * multi_ap_backhaul_ssid - SSID to supply to a Multi-AP backhaul
+ * enrollee
+ *
+ * This SSID is used by the Registrar to fill in information for
+ * Credentials when the enrollee advertises it is a Multi-AP backhaul
+ * STA.
+ */
+ u8 multi_ap_backhaul_ssid[SSID_MAX_LEN];
+
+ /**
+ * multi_ap_backhaul_ssid_len - Length of multi_ap_backhaul_ssid in
+ * octets
+ */
+ size_t multi_ap_backhaul_ssid_len;
+
+ /**
+ * multi_ap_backhaul_network_key - The Network Key (PSK) for the
+ * Multi-AP backhaul enrollee.
+ *
+ * This key can be either the ASCII passphrase (8..63 characters) or the
+ * 32-octet PSK (64 hex characters).
+ */
+ u8 *multi_ap_backhaul_network_key;
+
+ /**
+ * multi_ap_backhaul_network_key_len - Length of
+ * multi_ap_backhaul_network_key in octets
+ */
+ size_t multi_ap_backhaul_network_key_len;
};
@@ -667,6 +698,22 @@ wps_registrar_init(struct wps_context *wps,
reg->dualband = cfg->dualband;
reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk;
+ if (cfg->multi_ap_backhaul_ssid) {
+ os_memcpy(reg->multi_ap_backhaul_ssid,
+ cfg->multi_ap_backhaul_ssid,
+ cfg->multi_ap_backhaul_ssid_len);
+ reg->multi_ap_backhaul_ssid_len =
+ cfg->multi_ap_backhaul_ssid_len;
+ }
+ if (cfg->multi_ap_backhaul_network_key) {
+ reg->multi_ap_backhaul_network_key =
+ os_memdup(cfg->multi_ap_backhaul_network_key,
+ cfg->multi_ap_backhaul_network_key_len);
+ if (reg->multi_ap_backhaul_network_key)
+ reg->multi_ap_backhaul_network_key_len =
+ cfg->multi_ap_backhaul_network_key_len;
+ }
+
if (wps_set_ie(reg)) {
wps_registrar_deinit(reg);
return NULL;
@@ -703,7 +750,9 @@ void wps_registrar_deinit(struct wps_registrar *reg)
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
wps_registrar_flush(reg);
- wpabuf_free(reg->extra_cred);
+ wpabuf_clear_free(reg->extra_cred);
+ bin_clear_free(reg->multi_ap_backhaul_network_key,
+ reg->multi_ap_backhaul_network_key_len);
os_free(reg);
}
@@ -748,12 +797,11 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
p->wildcard_uuid = 1;
else
os_memcpy(p->uuid, uuid, WPS_UUID_LEN);
- p->pin = os_malloc(pin_len);
+ p->pin = os_memdup(pin, pin_len);
if (p->pin == NULL) {
os_free(p);
return -1;
}
- os_memcpy(p->pin, pin, pin_len);
p->pin_len = pin_len;
if (timeout) {
@@ -881,6 +929,7 @@ static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
const u8 *uuid, size_t *pin_len)
{
struct wps_uuid_pin *pin, *found = NULL;
+ int wildcard = 0;
wps_registrar_expire_pins(reg);
@@ -900,7 +949,7 @@ static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
pin->wildcard_uuid == 2) {
wpa_printf(MSG_DEBUG, "WPS: Found a wildcard "
"PIN. Assigned it for this UUID-E");
- pin->wildcard_uuid++;
+ wildcard = 1;
os_memcpy(pin->uuid, uuid, WPS_UUID_LEN);
found = pin;
break;
@@ -922,6 +971,8 @@ static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
}
*pin_len = found->pin_len;
found->flags |= PIN_LOCKED;
+ if (wildcard)
+ found->wildcard_uuid++;
return found->pin;
}
@@ -1279,7 +1330,7 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_sel_reg_config_methods(reg, beacon) ||
wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
(reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon, 0)) ||
- wps_build_wfa_ext(beacon, 0, auth_macs, count) ||
+ wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) ||
wps_build_vendor_ext(&reg->wps->dev, beacon)) {
wpabuf_free(beacon);
wpabuf_free(probe);
@@ -1309,7 +1360,7 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_device_attrs(&reg->wps->dev, probe) ||
wps_build_probe_config_methods(reg, probe) ||
(reg->dualband && wps_build_rf_bands(&reg->wps->dev, probe, 0)) ||
- wps_build_wfa_ext(probe, 0, auth_macs, count) ||
+ wps_build_wfa_ext(probe, 0, auth_macs, count, 0) ||
wps_build_vendor_ext(&reg->wps->dev, probe)) {
wpabuf_free(beacon);
wpabuf_free(probe);
@@ -1404,10 +1455,9 @@ static int wps_get_dev_password(struct wps_data *wps)
return -1;
}
- wps->dev_password = os_malloc(pin_len);
+ wps->dev_password = os_memdup(pin, pin_len);
if (wps->dev_password == NULL)
return -1;
- os_memcpy(wps->dev_password, pin, pin_len);
wps->dev_password_len = pin_len;
return 0;
@@ -1577,13 +1627,13 @@ int wps_build_credential_wrap(struct wpabuf *msg,
if (wbuf == NULL)
return -1;
if (wps_build_credential(wbuf, cred)) {
- wpabuf_free(wbuf);
+ wpabuf_clear_free(wbuf);
return -1;
}
wpabuf_put_be16(msg, ATTR_CRED);
wpabuf_put_be16(msg, wpabuf_len(wbuf));
wpabuf_put_buf(msg, wbuf);
- wpabuf_free(wbuf);
+ wpabuf_clear_free(wbuf);
return 0;
}
@@ -1591,6 +1641,7 @@ int wps_build_credential_wrap(struct wpabuf *msg,
int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
{
struct wpabuf *cred;
+ struct wps_registrar *reg = wps->wps->registrar;
if (wps->wps->registrar->skip_cred_build)
goto skip_cred_build;
@@ -1602,10 +1653,36 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
}
os_memset(&wps->cred, 0, sizeof(wps->cred));
+ if (wps->peer_dev.multi_ap_ext == MULTI_AP_BACKHAUL_STA &&
+ reg->multi_ap_backhaul_ssid_len) {
+ wpa_printf(MSG_DEBUG, "WPS: Use backhaul STA credentials");
+ os_memcpy(wps->cred.ssid, reg->multi_ap_backhaul_ssid,
+ reg->multi_ap_backhaul_ssid_len);
+ wps->cred.ssid_len = reg->multi_ap_backhaul_ssid_len;
+ /* Backhaul is always WPA2PSK */
+ wps->cred.auth_type = WPS_AUTH_WPA2PSK;
+ wps->cred.encr_type = WPS_ENCR_AES;
+ /* Set MAC address in the Credential to be the Enrollee's MAC
+ * address
+ */
+ os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
+ if (reg->multi_ap_backhaul_network_key) {
+ os_memcpy(wps->cred.key,
+ reg->multi_ap_backhaul_network_key,
+ reg->multi_ap_backhaul_network_key_len);
+ wps->cred.key_len =
+ reg->multi_ap_backhaul_network_key_len;
+ }
+ goto use_provided;
+ }
+
os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
wps->cred.ssid_len = wps->wps->ssid_len;
/* Select the best authentication and encryption type */
+ wpa_printf(MSG_DEBUG,
+ "WPS: Own auth types 0x%x - masked Enrollee auth types 0x%x",
+ wps->wps->auth_types, wps->auth_type);
if (wps->auth_type & WPS_AUTH_WPA2PSK)
wps->auth_type = WPS_AUTH_WPA2PSK;
else if (wps->auth_type & WPS_AUTH_WPAPSK)
@@ -1619,6 +1696,14 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
}
wps->cred.auth_type = wps->auth_type;
+ wpa_printf(MSG_DEBUG,
+ "WPS: Own encr types 0x%x (rsn: 0x%x, wpa: 0x%x) - masked Enrollee encr types 0x%x",
+ wps->wps->encr_types, wps->wps->encr_types_rsn,
+ wps->wps->encr_types_wpa, wps->encr_type);
+ if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPA2PSK)
+ wps->encr_type &= wps->wps->encr_types_rsn;
+ else if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPAPSK)
+ wps->encr_type &= wps->wps->encr_types_wpa;
if (wps->auth_type == WPS_AUTH_WPA2PSK ||
wps->auth_type == WPS_AUTH_WPAPSK) {
if (wps->encr_type & WPS_ENCR_AES)
@@ -1740,14 +1825,14 @@ use_provided:
return -1;
if (wps_build_credential(cred, &wps->cred)) {
- wpabuf_free(cred);
+ wpabuf_clear_free(cred);
return -1;
}
wpabuf_put_be16(msg, ATTR_CRED);
wpabuf_put_be16(msg, wpabuf_len(cred));
wpabuf_put_buf(msg, cred);
- wpabuf_free(cred);
+ wpabuf_clear_free(cred);
skip_cred_build:
if (wps->wps->registrar->extra_cred) {
@@ -1785,7 +1870,7 @@ static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
}
if (wps_build_ap_settings(wps, plain)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
@@ -1793,7 +1878,7 @@ static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
wpabuf_put_be16(msg, ATTR_CRED);
wpabuf_put_be16(msg, wpabuf_len(plain));
wpabuf_put_buf(msg, plain);
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return msg;
}
@@ -1833,7 +1918,7 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps)
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -1853,10 +1938,10 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps)
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain)) {
wpabuf_free(msg);
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
config_in_m2 = 1;
}
#endif /* CONFIG_WPS_NFC */
@@ -1901,7 +1986,7 @@ static struct wpabuf * wps_build_m2d(struct wps_data *wps)
wps_build_assoc_state(wps, msg) ||
wps_build_config_error(msg, err) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -1917,7 +2002,8 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps)
wpa_printf(MSG_DEBUG, "WPS: Building Message M4");
- wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+ if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0)
+ return NULL;
plain = wpabuf_alloc(200);
if (plain == NULL)
@@ -1936,13 +2022,13 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps)
wps_build_r_snonce1(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wps->state = RECV_M5;
return msg;
@@ -1971,13 +2057,13 @@ static struct wpabuf * wps_build_m6(struct wps_data *wps)
wps_build_r_snonce2(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wps->wps_pin_revealed = 1;
wps->state = RECV_M7;
@@ -2008,13 +2094,13 @@ static struct wpabuf * wps_build_m8(struct wps_data *wps)
(!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
- wpabuf_free(msg);
+ wpabuf_clear_free(plain);
+ wpabuf_clear_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wps->state = RECV_DONE;
return msg;
@@ -2343,6 +2429,23 @@ static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)
wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x",
auth_types);
+#ifdef WPS_WORKAROUNDS
+ /*
+ * Some deployed implementations seem to advertise incorrect information
+ * in this attribute. A value of 0x1b (WPA2 + WPA + WPAPSK + OPEN, but
+ * no WPA2PSK) has been reported to be used. Add WPA2PSK to the list to
+ * avoid issues with building Credentials that do not use the strongest
+ * actually supported authentication option (that device does support
+ * WPA2PSK even when it does not claim it here).
+ */
+ if ((auth_types &
+ (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) ==
+ (WPS_AUTH_WPA2 | WPS_AUTH_WPAPSK)) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Workaround - assume Enrollee supports WPA2PSK based on claimed WPA2 support");
+ auth_types |= WPS_AUTH_WPA2PSK;
+ }
+#endif /* WPS_WORKAROUNDS */
wps->auth_type = wps->wps->auth_types & auth_types;
if (wps->auth_type == 0) {
wpa_printf(MSG_DEBUG, "WPS: No match in supported "
@@ -2675,6 +2778,7 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
wps->use_psk_key = 1;
}
#endif /* WPS_WORKAROUNDS */
+ wps_process_vendor_ext_m1(&wps->peer_dev, attr->multi_ap_ext);
wps->state = SEND_M2;
return WPS_CONTINUE;
@@ -2757,7 +2861,7 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
}
if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -2767,11 +2871,11 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
if (wps_parse_msg(decrypted, &eattr) < 0 ||
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_e_snonce1(wps, eattr.e_snonce1)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_M6;
return WPS_CONTINUE;
@@ -2909,7 +3013,7 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps,
if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er,
attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -2920,12 +3024,12 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps,
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_e_snonce2(wps, eattr.e_snonce2) ||
wps_process_ap_settings_r(wps, &eattr)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_M8;
return WPS_CONTINUE;
diff --git a/contrib/wpa/src/wps/wps_upnp.c b/contrib/wpa/src/wps/wps_upnp.c
index 44318e0..ca893a4 100644
--- a/contrib/wpa/src/wps/wps_upnp.c
+++ b/contrib/wpa/src/wps/wps_upnp.c
@@ -599,7 +599,7 @@ static struct wpabuf * build_fake_wsc_ack(void)
wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
wpabuf_put_be16(msg, WPS_NONCE_LEN);
wpabuf_put(msg, WPS_NONCE_LEN);
- if (wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ if (wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -1082,6 +1082,7 @@ upnp_wps_get_iface(struct upnp_wps_device_sm *sm, void *priv)
void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv)
{
struct upnp_wps_device_interface *iface;
+ struct upnp_wps_peer *peer;
if (!sm)
return;
@@ -1102,8 +1103,13 @@ void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv)
iface->wps->registrar);
dl_list_del(&iface->list);
- if (iface->peer.wps)
- wps_deinit(iface->peer.wps);
+ while ((peer = dl_list_first(&iface->peers, struct upnp_wps_peer,
+ list))) {
+ if (peer->wps)
+ wps_deinit(peer->wps);
+ dl_list_del(&peer->list);
+ os_free(peer);
+ }
os_free(iface->ctx->ap_pin);
os_free(iface->ctx);
os_free(iface);
@@ -1141,6 +1147,7 @@ upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
}
wpa_printf(MSG_DEBUG, "WPS UPnP: Init interface instance %p", iface);
+ dl_list_init(&iface->peers);
iface->ctx = ctx;
iface->wps = wps;
iface->priv = priv;
diff --git a/contrib/wpa/src/wps/wps_upnp.h b/contrib/wpa/src/wps/wps_upnp.h
index 87b7ab1..b6f6df5 100644
--- a/contrib/wpa/src/wps/wps_upnp.h
+++ b/contrib/wpa/src/wps/wps_upnp.h
@@ -11,11 +11,14 @@
#ifndef WPS_UPNP_H
#define WPS_UPNP_H
+#include "utils/list.h"
+
struct upnp_wps_device_sm;
struct wps_context;
struct wps_data;
struct upnp_wps_peer {
+ struct dl_list list;
struct wps_data *wps;
};
diff --git a/contrib/wpa/src/wps/wps_upnp_i.h b/contrib/wpa/src/wps/wps_upnp_i.h
index f289fe6..6a7c627 100644
--- a/contrib/wpa/src/wps/wps_upnp_i.h
+++ b/contrib/wpa/src/wps/wps_upnp_i.h
@@ -109,8 +109,7 @@ struct upnp_wps_device_interface {
struct wps_context *wps;
void *priv;
- /* FIX: maintain separate structures for each UPnP peer */
- struct upnp_wps_peer peer;
+ struct dl_list peers; /* active UPnP peer sessions */
};
/*
diff --git a/contrib/wpa/src/wps/wps_upnp_ssdp.c b/contrib/wpa/src/wps/wps_upnp_ssdp.c
index 968fc03..a685ce4 100644
--- a/contrib/wpa/src/wps/wps_upnp_ssdp.c
+++ b/contrib/wpa/src/wps/wps_upnp_ssdp.c
@@ -100,12 +100,6 @@ static int line_length(const char *l)
}
-static int str_starts(const char *str, const char *start)
-{
- return os_strncmp(str, start, os_strlen(start)) == 0;
-}
-
-
/***************************************************************************
* Advertisements.
* These are multicast to the world to tell them we are here.
diff --git a/contrib/wpa/src/wps/wps_upnp_web.c b/contrib/wpa/src/wps/wps_upnp_web.c
index d5b0b5b..7548e84 100644
--- a/contrib/wpa/src/wps/wps_upnp_web.c
+++ b/contrib/wpa/src/wps/wps_upnp_web.c
@@ -300,7 +300,8 @@ static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
* would appear to be required (given that we will be closing it!).
*/
static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
- struct http_request *hreq, char *filename)
+ struct http_request *hreq,
+ const char *filename)
{
struct wpabuf *buf; /* output buffer, allocated */
char *put_length_here;
@@ -409,6 +410,15 @@ send_buf:
}
+static void wps_upnp_peer_del(struct upnp_wps_peer *peer)
+{
+ dl_list_del(&peer->list);
+ if (peer->wps)
+ wps_deinit(peer->wps);
+ os_free(peer);
+}
+
+
static enum http_reply_code
web_process_get_device_info(struct upnp_wps_device_sm *sm,
struct wpabuf **reply, const char **replyname)
@@ -426,7 +436,9 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
if (!iface || iface->ctx->ap_pin == NULL)
return HTTP_INTERNAL_SERVER_ERROR;
- peer = &iface->peer;
+ peer = os_zalloc(sizeof(*peer));
+ if (!peer)
+ return HTTP_INTERNAL_SERVER_ERROR;
/*
* Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
@@ -436,9 +448,6 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
* registration.
*/
- if (peer->wps)
- wps_deinit(peer->wps);
-
os_memset(&cfg, 0, sizeof(cfg));
cfg.wps = iface->wps;
cfg.pin = (u8 *) iface->ctx->ap_pin;
@@ -455,8 +464,22 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
*reply = NULL;
if (*reply == NULL) {
wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
+ os_free(peer);
return HTTP_INTERNAL_SERVER_ERROR;
}
+
+ if (dl_list_len(&iface->peers) > 3) {
+ struct upnp_wps_peer *old;
+
+ old = dl_list_first(&iface->peers, struct upnp_wps_peer, list);
+ if (old) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Drop oldest active session");
+ wps_upnp_peer_del(old);
+ }
+ }
+ dl_list_add_tail(&iface->peers, &peer->list);
+ /* TODO: Could schedule a timeout to free the entry */
+
*replyname = name;
return HTTP_OK;
}
@@ -472,6 +495,8 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
enum wps_process_res res;
enum wsc_op_code op_code;
struct upnp_wps_device_interface *iface;
+ struct wps_parse_attr attr;
+ struct upnp_wps_peer *tmp, *peer;
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
@@ -487,11 +512,56 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
msg = xml_get_base64_item(data, "NewInMessage", &ret);
if (msg == NULL)
return ret;
- res = wps_process_msg(iface->peer.wps, WSC_UPnP, msg);
- if (res == WPS_FAILURE)
+
+ if (wps_parse_msg(msg, &attr)) {
+ wpa_printf(MSG_DEBUG,
+ "WPS UPnP: Could not parse PutMessage - NewInMessage");
+ wpabuf_free(msg);
+ return HTTP_BAD_REQUEST;
+ }
+
+ /* Find a matching active peer session */
+ peer = NULL;
+ dl_list_for_each(tmp, &iface->peers, struct upnp_wps_peer, list) {
+ if (!tmp->wps)
+ continue;
+ if (attr.enrollee_nonce &&
+ os_memcmp(tmp->wps->nonce_e, attr.enrollee_nonce,
+ WPS_NONCE_LEN) != 0)
+ continue; /* Enrollee nonce mismatch */
+ if (attr.msg_type &&
+ *attr.msg_type != WPS_M2 &&
+ *attr.msg_type != WPS_M2D &&
+ attr.registrar_nonce &&
+ os_memcmp(tmp->wps->nonce_r, attr.registrar_nonce,
+ WPS_NONCE_LEN) != 0)
+ continue; /* Registrar nonce mismatch */
+ peer = tmp;
+ break;
+ }
+ if (!peer) {
+ /*
+ Try to use the first entry in case message could work with
+ * it. The actual handler function will reject this, if needed.
+ * This maintains older behavior where only a single peer entry
+ * was supported.
+ */
+ peer = dl_list_first(&iface->peers, struct upnp_wps_peer, list);
+ }
+ if (!peer || !peer->wps) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: No active peer entry found");
+ wpabuf_free(msg);
+ return HTTP_BAD_REQUEST;
+ }
+
+ res = wps_process_msg(peer->wps, WSC_UPnP, msg);
+ if (res == WPS_FAILURE) {
*reply = NULL;
- else
- *reply = wps_get_msg(iface->peer.wps, &op_code);
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Drop active peer session");
+ wps_upnp_peer_del(peer);
+ } else {
+ *reply = wps_get_msg(peer->wps, &op_code);
+ }
wpabuf_free(msg);
if (*reply == NULL)
return HTTP_INTERNAL_SERVER_ERROR;
diff --git a/contrib/wpa/src/wps/wps_validate.c b/contrib/wpa/src/wps/wps_validate.c
index 267b565..5c12bce 100644
--- a/contrib/wpa/src/wps/wps_validate.c
+++ b/contrib/wpa/src/wps/wps_validate.c
@@ -1057,7 +1057,7 @@ static int wps_validate_cred(const u8 *cred, size_t len)
}
-static int wps_validate_credential(const u8 *cred[], size_t len[], size_t num,
+static int wps_validate_credential(const u8 *cred[], u16 len[], size_t num,
int mandatory)
{
size_t i;
diff --git a/contrib/wpa/wpa_supplicant/Android.mk b/contrib/wpa/wpa_supplicant/Android.mk
new file mode 100644
index 0000000..5296931
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/Android.mk
@@ -0,0 +1,1778 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+LOCAL_PATH := $(call my-dir)
+PKG_CONFIG ?= pkg-config
+
+ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),)
+ CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
+endif
+
+include $(LOCAL_PATH)/android.config
+
+# To ignore possible wrong network configurations
+L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
+
+L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
+
+# Set Android log name
+L_CFLAGS += -DANDROID_LOG_NAME=\"wpa_supplicant\"
+
+# Disable unused parameter warnings
+L_CFLAGS += -Wno-unused-parameter
+
+# Set Android extended P2P functionality
+L_CFLAGS += -DANDROID_P2P
+
+ifeq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
+L_CFLAGS += -DANDROID_LIB_STUB
+endif
+
+# Disable roaming in wpa_supplicant
+ifdef CONFIG_NO_ROAMING
+L_CFLAGS += -DCONFIG_NO_ROAMING
+endif
+
+# Use Android specific directory for control interface sockets
+L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/misc/wifi/sockets\"
+
+# Use Android specific directory for wpa_cli command completion history
+L_CFLAGS += -DCONFIG_WPA_CLI_HISTORY_DIR=\"/data/misc/wifi\"
+
+# To force sizeof(enum) = 4
+ifeq ($(TARGET_ARCH),arm)
+L_CFLAGS += -mabi=aapcs-linux
+endif
+
+# C++ flags for binder interface
+L_CPPFLAGS := -std=c++11 -Wall -Werror
+# TODO: Remove these allowed warnings later.
+L_CPPFLAGS += -Wno-unused-variable -Wno-unused-parameter
+L_CPPFLAGS += -Wno-unused-private-field
+
+INCLUDES = $(LOCAL_PATH)
+INCLUDES += $(LOCAL_PATH)/src
+INCLUDES += $(LOCAL_PATH)/src/common
+# INCLUDES += $(LOCAL_PATH)/src/crypto # To force proper includes
+INCLUDES += $(LOCAL_PATH)/src/drivers
+INCLUDES += $(LOCAL_PATH)/src/eap_common
+INCLUDES += $(LOCAL_PATH)/src/eapol_supp
+INCLUDES += $(LOCAL_PATH)/src/eap_peer
+INCLUDES += $(LOCAL_PATH)/src/eap_server
+INCLUDES += $(LOCAL_PATH)/src/hlr_auc_gw
+INCLUDES += $(LOCAL_PATH)/src/l2_packet
+INCLUDES += $(LOCAL_PATH)/src/radius
+INCLUDES += $(LOCAL_PATH)/src/rsn_supp
+INCLUDES += $(LOCAL_PATH)/src/tls
+INCLUDES += $(LOCAL_PATH)/src/utils
+INCLUDES += $(LOCAL_PATH)/src/wps
+INCLUDES += system/security/keystore/include
+ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
+INCLUDES += external/libnl/include
+else
+INCLUDES += external/libnl-headers
+endif
+endif
+
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
+OBJS = config.c
+OBJS += notify.c
+OBJS += bss.c
+OBJS += eap_register.c
+OBJS += src/utils/common.c
+OBJS += src/utils/wpa_debug.c
+OBJS += src/utils/wpabuf.c
+OBJS += src/utils/bitfield.c
+OBJS += wmm_ac.c
+OBJS += op_classes.c
+OBJS += rrm.c
+OBJS_p = wpa_passphrase.c
+OBJS_p += src/utils/common.c
+OBJS_p += src/utils/wpa_debug.c
+OBJS_p += src/utils/wpabuf.c
+OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
+OBJS_c += src/utils/wpa_debug.c
+OBJS_c += src/utils/common.c
+OBJS_c += src/common/cli.c
+OBJS_d =
+OBJS_priv =
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+L_CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+OBJS += src/utils/os_$(CONFIG_OS).c
+OBJS_p += src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/utils/os_$(CONFIG_OS).c
+
+ifdef CONFIG_WPA_TRACE
+L_CFLAGS += -DWPA_TRACE
+OBJS += src/utils/trace.c
+OBJS_p += src/utils/trace.c
+OBJS_c += src/utils/trace.c
+LDFLAGS += -rdynamic
+L_CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+L_CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_p += -lbfd
+LIBS_c += -lbfd
+endif
+endif
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += src/utils/$(CONFIG_ELOOP).c
+OBJS_c += src/utils/$(CONFIG_ELOOP).c
+
+ifdef CONFIG_ELOOP_POLL
+L_CFLAGS += -DCONFIG_ELOOP_POLL
+endif
+
+ifdef CONFIG_ELOOP_EPOLL
+L_CFLAGS += -DCONFIG_ELOOP_EPOLL
+endif
+
+ifdef CONFIG_EAPOL_TEST
+L_CFLAGS += -Werror -DEAPOL_TEST
+endif
+
+ifdef CONFIG_HT_OVERRIDES
+L_CFLAGS += -DCONFIG_HT_OVERRIDES
+endif
+
+ifdef CONFIG_VHT_OVERRIDES
+L_CFLAGS += -DCONFIG_VHT_OVERRIDES
+endif
+
+ifndef CONFIG_BACKEND
+CONFIG_BACKEND=file
+endif
+
+ifeq ($(CONFIG_BACKEND), file)
+OBJS += config_file.c
+ifndef CONFIG_NO_CONFIG_BLOBS
+NEED_BASE64=y
+endif
+L_CFLAGS += -DCONFIG_BACKEND_FILE
+endif
+
+ifeq ($(CONFIG_BACKEND), winreg)
+OBJS += config_winreg.c
+endif
+
+ifeq ($(CONFIG_BACKEND), none)
+OBJS += config_none.c
+endif
+
+ifdef CONFIG_NO_CONFIG_WRITE
+L_CFLAGS += -DCONFIG_NO_CONFIG_WRITE
+endif
+
+ifdef CONFIG_NO_CONFIG_BLOBS
+L_CFLAGS += -DCONFIG_NO_CONFIG_BLOBS
+endif
+
+ifdef CONFIG_NO_SCAN_PROCESSING
+L_CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
+endif
+
+ifdef CONFIG_SUITEB
+L_CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_SUITEB192
+L_CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
+ifdef CONFIG_OCV
+L_CFLAGS += -DCONFIG_OCV
+OBJS += src/common/ocv.c
+CONFIG_IEEE80211W=y
+endif
+
+ifdef CONFIG_IEEE80211W
+L_CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+L_CFLAGS += -DCONFIG_IEEE80211R
+OBJS += src/rsn_supp/wpa_ft.c
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+NEED_SHA256=y
+NEED_AES_SIV=y
+CONFIG_SAE=y
+CONFIG_AP=y
+L_CFLAGS += -DCONFIG_MESH
+OBJS += mesh.c
+OBJS += mesh_mpm.c
+OBJS += mesh_rsn.c
+endif
+
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_DPP
+L_CFLAGS += -DCONFIG_DPP
+OBJS += src/common/dpp.c
+OBJS += dpp_supplicant.c
+NEED_AES_SIV=y
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+NEED_SHA512=y
+NEED_JSON=y
+NEED_GAS_SERVER=y
+NEED_BASE64=y
+ifdef CONFIG_DPP2
+L_CFLAGS += -DCONFIG_DPP2
+endif
+endif
+
+ifdef CONFIG_OWE
+L_CFLAGS += -DCONFIG_OWE
+NEED_ECC=y
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_HMAC_SHA512_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+NEED_SHA512=y
+endif
+
+ifdef CONFIG_FILS
+L_CFLAGS += -DCONFIG_FILS
+NEED_SHA384=y
+NEED_AES_SIV=y
+ifdef CONFIG_FILS_SK_PFS
+L_CFLAGS += -DCONFIG_FILS_SK_PFS
+NEED_ECC=y
+endif
+endif
+
+ifdef CONFIG_MBO
+CONFIG_WNM=y
+endif
+
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+OBJS += wnm_sta.c
+endif
+
+ifdef CONFIG_TDLS
+L_CFLAGS += -DCONFIG_TDLS
+OBJS += src/rsn_supp/tdls.c
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_TDLS_TESTING
+L_CFLAGS += -DCONFIG_TDLS_TESTING
+endif
+
+ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+L_CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL
+endif
+
+ifndef CONFIG_NO_WPA
+OBJS += src/rsn_supp/wpa.c
+OBJS += src/rsn_supp/preauth.c
+OBJS += src/rsn_supp/pmksa_cache.c
+OBJS += src/rsn_supp/wpa_ie.c
+OBJS += src/common/wpa_common.c
+NEED_AES=y
+NEED_SHA1=y
+NEED_MD5=y
+NEED_RC4=y
+else
+L_CFLAGS += -DCONFIG_NO_WPA
+endif
+
+ifdef CONFIG_IBSS_RSN
+NEED_RSN_AUTHENTICATOR=y
+L_CFLAGS += -DCONFIG_IBSS_RSN
+L_CFLAGS += -DCONFIG_NO_VLAN
+OBJS += ibss_rsn.c
+endif
+
+ifdef CONFIG_P2P
+OBJS += p2p_supplicant.c
+OBJS += p2p_supplicant_sd.c
+OBJS += src/p2p/p2p.c
+OBJS += src/p2p/p2p_utils.c
+OBJS += src/p2p/p2p_parse.c
+OBJS += src/p2p/p2p_build.c
+OBJS += src/p2p/p2p_go_neg.c
+OBJS += src/p2p/p2p_sd.c
+OBJS += src/p2p/p2p_pd.c
+OBJS += src/p2p/p2p_invitation.c
+OBJS += src/p2p/p2p_dev_disc.c
+OBJS += src/p2p/p2p_group.c
+OBJS += src/ap/p2p_hostapd.c
+L_CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
+NEED_OFFCHANNEL=y
+CONFIG_WPS=y
+CONFIG_AP=y
+ifdef CONFIG_P2P_STRICT
+L_CFLAGS += -DCONFIG_P2P_STRICT
+endif
+endif
+
+ifdef CONFIG_WIFI_DISPLAY
+L_CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.c
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.c
+L_CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_INTERWORKING
+OBJS += interworking.c
+L_CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
+ifdef CONFIG_FST
+L_CFLAGS += -DCONFIG_FST
+OBJS += src/fst/fst.c
+OBJS += src/fst/fst_session.c
+OBJS += src/fst/fst_iface.c
+OBJS += src/fst/fst_group.c
+OBJS += src/fst/fst_ctrl_aux.c
+ifdef CONFIG_FST_TEST
+L_CFLAGS += -DCONFIG_FST_TEST
+endif
+ifdef CONFIG_CTRL_IFACE
+OBJS += src/fst/fst_ctrl_iface.c
+endif
+endif
+
+
+include $(LOCAL_PATH)/src/drivers/drivers.mk
+
+ifdef CONFIG_AP
+OBJS_d += $(DRV_BOTH_OBJS)
+L_CFLAGS += $(DRV_BOTH_CFLAGS)
+LDFLAGS += $(DRV_BOTH_LDFLAGS)
+LIBS += $(DRV_BOTH_LIBS)
+else
+NEED_AP_MLME=
+OBJS_d += $(DRV_WPA_OBJS)
+L_CFLAGS += $(DRV_WPA_CFLAGS)
+LDFLAGS += $(DRV_WPA_LDFLAGS)
+LIBS += $(DRV_WPA_LIBS)
+endif
+
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=linux
+endif
+
+OBJS_l2 += src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).c
+
+ifeq ($(CONFIG_L2_PACKET), pcap)
+ifdef CONFIG_WINPCAP
+L_CFLAGS += -DCONFIG_WINPCAP
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+else
+LIBS += -ldnet -lpcap
+endif
+endif
+
+ifeq ($(CONFIG_L2_PACKET), winpcap)
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+endif
+
+ifeq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -lpcap
+endif
+
+ifdef CONFIG_ERP
+L_CFLAGS += -DCONFIG_ERP
+NEED_SHA256=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
+ifdef CONFIG_EAP_TLS
+# EAP-TLS
+ifeq ($(CONFIG_EAP_TLS), dyn)
+L_CFLAGS += -DEAP_TLS_DYNAMIC
+EAPDYN += src/eap_peer/eap_tls.so
+else
+L_CFLAGS += -DEAP_TLS
+OBJS += src/eap_peer/eap_tls.c
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+L_CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += src/eap_peer/eap_tls.c
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+# EAP-PEAP
+ifeq ($(CONFIG_EAP_PEAP), dyn)
+L_CFLAGS += -DEAP_PEAP_DYNAMIC
+EAPDYN += src/eap_peer/eap_peap.so
+else
+L_CFLAGS += -DEAP_PEAP
+OBJS += src/eap_peer/eap_peap.c
+OBJS += src/eap_common/eap_peap_common.c
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+# EAP-TTLS
+ifeq ($(CONFIG_EAP_TTLS), dyn)
+L_CFLAGS += -DEAP_TTLS_DYNAMIC
+EAPDYN += src/eap_peer/eap_ttls.so
+else
+L_CFLAGS += -DEAP_TTLS
+OBJS += src/eap_peer/eap_ttls.c
+endif
+TLS_FUNCS=y
+ifndef CONFIG_FIPS
+MS_FUNCS=y
+CHAP=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_MD5
+# EAP-MD5
+ifeq ($(CONFIG_EAP_MD5), dyn)
+L_CFLAGS += -DEAP_MD5_DYNAMIC
+EAPDYN += src/eap_peer/eap_md5.so
+else
+L_CFLAGS += -DEAP_MD5
+OBJS += src/eap_peer/eap_md5.c
+endif
+CHAP=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+# backwards compatibility for old spelling
+ifdef CONFIG_MSCHAPV2
+ifndef CONFIG_EAP_MSCHAPV2
+CONFIG_EAP_MSCHAPV2=y
+endif
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+# EAP-MSCHAPv2
+ifeq ($(CONFIG_EAP_MSCHAPV2), dyn)
+L_CFLAGS += -DEAP_MSCHAPv2_DYNAMIC
+EAPDYN += src/eap_peer/eap_mschapv2.so
+EAPDYN += src/eap_peer/mschapv2.so
+else
+L_CFLAGS += -DEAP_MSCHAPv2
+OBJS += src/eap_peer/eap_mschapv2.c
+OBJS += src/eap_peer/mschapv2.c
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GTC
+# EAP-GTC
+ifeq ($(CONFIG_EAP_GTC), dyn)
+L_CFLAGS += -DEAP_GTC_DYNAMIC
+EAPDYN += src/eap_peer/eap_gtc.so
+else
+L_CFLAGS += -DEAP_GTC
+OBJS += src/eap_peer/eap_gtc.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_OTP
+# EAP-OTP
+ifeq ($(CONFIG_EAP_OTP), dyn)
+L_CFLAGS += -DEAP_OTP_DYNAMIC
+EAPDYN += src/eap_peer/eap_otp.so
+else
+L_CFLAGS += -DEAP_OTP
+OBJS += src/eap_peer/eap_otp.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SIM
+# EAP-SIM
+ifeq ($(CONFIG_EAP_SIM), dyn)
+L_CFLAGS += -DEAP_SIM_DYNAMIC
+EAPDYN += src/eap_peer/eap_sim.so
+else
+L_CFLAGS += -DEAP_SIM
+OBJS += src/eap_peer/eap_sim.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_LEAP
+# EAP-LEAP
+ifeq ($(CONFIG_EAP_LEAP), dyn)
+L_CFLAGS += -DEAP_LEAP_DYNAMIC
+EAPDYN += src/eap_peer/eap_leap.so
+else
+L_CFLAGS += -DEAP_LEAP
+OBJS += src/eap_peer/eap_leap.c
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PSK
+# EAP-PSK
+ifeq ($(CONFIG_EAP_PSK), dyn)
+L_CFLAGS += -DEAP_PSK_DYNAMIC
+EAPDYN += src/eap_peer/eap_psk.so
+else
+L_CFLAGS += -DEAP_PSK
+OBJS += src/eap_peer/eap_psk.c src/eap_common/eap_psk_common.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_AES=y
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_AKA
+# EAP-AKA
+ifeq ($(CONFIG_EAP_AKA), dyn)
+L_CFLAGS += -DEAP_AKA_DYNAMIC
+EAPDYN += src/eap_peer/eap_aka.so
+else
+L_CFLAGS += -DEAP_AKA
+OBJS += src/eap_peer/eap_aka.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_PROXY
+L_CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c
+include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+# EAP-AKA'
+ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
+L_CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
+else
+L_CFLAGS += -DEAP_AKA_PRIME
+endif
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += src/eap_common/eap_sim_common.c
+NEED_AES=y
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_FAST
+# EAP-FAST
+ifeq ($(CONFIG_EAP_FAST), dyn)
+L_CFLAGS += -DEAP_FAST_DYNAMIC
+EAPDYN += src/eap_peer/eap_fast.so
+EAPDYN += src/eap_common/eap_fast_common.c
+else
+L_CFLAGS += -DEAP_FAST
+OBJS += src/eap_peer/eap_fast.c src/eap_peer/eap_fast_pac.c
+OBJS += src/eap_common/eap_fast_common.c
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+NEED_T_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+# EAP-PAX
+ifeq ($(CONFIG_EAP_PAX), dyn)
+L_CFLAGS += -DEAP_PAX_DYNAMIC
+EAPDYN += src/eap_peer/eap_pax.so
+else
+L_CFLAGS += -DEAP_PAX
+OBJS += src/eap_peer/eap_pax.c src/eap_common/eap_pax_common.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+# EAP-SAKE
+ifeq ($(CONFIG_EAP_SAKE), dyn)
+L_CFLAGS += -DEAP_SAKE_DYNAMIC
+EAPDYN += src/eap_peer/eap_sake.so
+else
+L_CFLAGS += -DEAP_SAKE
+OBJS += src/eap_peer/eap_sake.c src/eap_common/eap_sake_common.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GPSK
+# EAP-GPSK
+ifeq ($(CONFIG_EAP_GPSK), dyn)
+L_CFLAGS += -DEAP_GPSK_DYNAMIC
+EAPDYN += src/eap_peer/eap_gpsk.so
+else
+L_CFLAGS += -DEAP_GPSK
+OBJS += src/eap_peer/eap_gpsk.c src/eap_common/eap_gpsk_common.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_GPSK_SHA256
+L_CFLAGS += -DEAP_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+L_CFLAGS += -DEAP_PWD
+OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
+CONFIG_IEEE8021X_EAPOL=y
+NEED_SHA256=y
+NEED_ECC=y
+endif
+
+ifdef CONFIG_EAP_EKE
+# EAP-EKE
+ifeq ($(CONFIG_EAP_EKE), dyn)
+L_CFLAGS += -DEAP_EKE_DYNAMIC
+EAPDYN += src/eap_peer/eap_eke.so
+else
+L_CFLAGS += -DEAP_EKE
+OBJS += src/eap_peer/eap_eke.c src/eap_common/eap_eke_common.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_SHA256=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_WPS
+# EAP-WSC
+L_CFLAGS += -DCONFIG_WPS -DEAP_WSC
+OBJS += wps_supplicant.c
+OBJS += src/utils/uuid.c
+OBJS += src/eap_peer/eap_wsc.c src/eap_common/eap_wsc_common.c
+OBJS += src/wps/wps.c
+OBJS += src/wps/wps_common.c
+OBJS += src/wps/wps_attr_parse.c
+OBJS += src/wps/wps_attr_build.c
+OBJS += src/wps/wps_attr_process.c
+OBJS += src/wps/wps_dev_attr.c
+OBJS += src/wps/wps_enrollee.c
+OBJS += src/wps/wps_registrar.c
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+
+ifdef CONFIG_WPS_NFC
+L_CFLAGS += -DCONFIG_WPS_NFC
+OBJS += src/wps/ndef.c
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+L_CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_ER
+CONFIG_WPS_UPNP=y
+L_CFLAGS += -DCONFIG_WPS_ER
+OBJS += src/wps/wps_er.c
+OBJS += src/wps/wps_er_ssdp.c
+endif
+
+ifdef CONFIG_WPS_UPNP
+L_CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += src/wps/wps_upnp.c
+OBJS += src/wps/wps_upnp_ssdp.c
+OBJS += src/wps/wps_upnp_web.c
+OBJS += src/wps/wps_upnp_event.c
+OBJS += src/wps/wps_upnp_ap.c
+OBJS += src/wps/upnp_xml.c
+OBJS += src/wps/httpread.c
+OBJS += src/wps/http_client.c
+OBJS += src/wps/http_server.c
+endif
+
+ifdef CONFIG_WPS_STRICT
+L_CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += src/wps/wps_validate.c
+endif
+
+ifdef CONFIG_WPS_TESTING
+L_CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+ifdef CONFIG_WPS_REG_DISABLE_OPEN
+L_CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+# EAP-IKEv2
+ifeq ($(CONFIG_EAP_IKEV2), dyn)
+L_CFLAGS += -DEAP_IKEV2_DYNAMIC
+EAPDYN += src/eap_peer/eap_ikev2.so src/eap_peer/ikev2.c
+EAPDYN += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
+else
+L_CFLAGS += -DEAP_IKEV2
+OBJS += src/eap_peer/eap_ikev2.c src/eap_peer/ikev2.c
+OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn)
+L_CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC
+EAPDYN += src/eap_peer/eap_vendor_test.so
+else
+L_CFLAGS += -DEAP_VENDOR_TEST
+OBJS += src/eap_peer/eap_vendor_test.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TNC
+# EAP-TNC
+L_CFLAGS += -DEAP_TNC
+OBJS += src/eap_peer/eap_tnc.c
+OBJS += src/eap_peer/tncc.c
+NEED_BASE64=y
+ifndef CONFIG_NATIVE_WINDOWS
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+endif
+
+ifdef CONFIG_IEEE8021X_EAPOL
+# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
+L_CFLAGS += -DIEEE8021X_EAPOL
+OBJS += src/eapol_supp/eapol_supp_sm.c
+OBJS += src/eap_peer/eap.c src/eap_peer/eap_methods.c
+NEED_EAP_COMMON=y
+ifdef CONFIG_DYNAMIC_EAP_METHODS
+L_CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
+LIBS += -ldl -rdynamic
+endif
+endif
+
+ifdef CONFIG_AP
+NEED_EAP_COMMON=y
+NEED_RSN_AUTHENTICATOR=y
+L_CFLAGS += -DCONFIG_AP
+OBJS += ap.c
+L_CFLAGS += -DCONFIG_NO_RADIUS
+L_CFLAGS += -DCONFIG_NO_ACCOUNTING
+L_CFLAGS += -DCONFIG_NO_VLAN
+OBJS += src/ap/hostapd.c
+OBJS += src/ap/wpa_auth_glue.c
+OBJS += src/ap/utils.c
+OBJS += src/ap/authsrv.c
+OBJS += src/ap/ap_config.c
+OBJS += src/utils/ip_addr.c
+OBJS += src/ap/sta_info.c
+OBJS += src/ap/tkip_countermeasures.c
+OBJS += src/ap/ap_mlme.c
+OBJS += src/ap/ieee802_1x.c
+OBJS += src/eapol_auth/eapol_auth_sm.c
+OBJS += src/ap/ieee802_11_auth.c
+OBJS += src/ap/ieee802_11_shared.c
+OBJS += src/ap/drv_callbacks.c
+OBJS += src/ap/ap_drv_ops.c
+OBJS += src/ap/beacon.c
+OBJS += src/ap/bss_load.c
+OBJS += src/ap/eap_user_db.c
+OBJS += src/ap/neighbor_db.c
+OBJS += src/ap/rrm.c
+ifdef CONFIG_IEEE80211N
+OBJS += src/ap/ieee802_11_ht.c
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
+ifdef CONFIG_IEEE80211AX
+OBJS += src/ap/ieee802_11_he.c
+endif
+endif
+ifdef CONFIG_WNM_AP
+L_CFLAGS += -DCONFIG_WNM_AP
+OBJS += src/ap/wnm_ap.c
+endif
+ifdef CONFIG_MBO
+OBJS += src/ap/mbo_ap.c
+endif
+ifdef CONFIG_FILS
+OBJS += src/ap/fils_hlp.c
+endif
+ifdef CONFIG_CTRL_IFACE
+OBJS += src/ap/ctrl_iface_ap.c
+endif
+
+L_CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
+OBJS += src/eap_server/eap_server.c
+OBJS += src/eap_server/eap_server_identity.c
+OBJS += src/eap_server/eap_server_methods.c
+
+ifdef CONFIG_IEEE80211N
+L_CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
+ifdef CONFIG_IEEE80211AX
+L_CFLAGS += -DCONFIG_IEEE80211AX
+endif
+endif
+
+ifdef NEED_AP_MLME
+OBJS += src/ap/wmm.c
+OBJS += src/ap/ap_list.c
+OBJS += src/ap/ieee802_11.c
+OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
+L_CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_WPS
+L_CFLAGS += -DEAP_SERVER_WSC
+OBJS += src/ap/wps_hostapd.c
+OBJS += src/eap_server/eap_server_wsc.c
+endif
+ifdef CONFIG_DPP
+OBJS += src/ap/dpp_hostapd.c
+OBJS += src/ap/gas_query_ap.c
+endif
+ifdef CONFIG_INTERWORKING
+OBJS += src/ap/gas_serv.c
+endif
+ifdef CONFIG_HS20
+OBJS += src/ap/hs20.c
+endif
+endif
+
+ifdef CONFIG_MBO
+OBJS += mbo.c
+L_CFLAGS += -DCONFIG_MBO
+endif
+
+ifdef CONFIG_TESTING_OPTIONS
+L_CFLAGS += -DCONFIG_TESTING_OPTIONS
+endif
+
+ifdef NEED_RSN_AUTHENTICATOR
+L_CFLAGS += -DCONFIG_NO_RADIUS
+NEED_AES_WRAP=y
+OBJS += src/ap/wpa_auth.c
+OBJS += src/ap/wpa_auth_ie.c
+OBJS += src/ap/pmksa_cache_auth.c
+endif
+
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
+endif
+
+ifdef CONFIG_PCSC
+# PC/SC interface for smartcards (USIM, GSM SIM)
+L_CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
+OBJS += src/utils/pcsc_funcs.c
+# -lpthread may not be needed depending on how pcsc-lite was configured
+ifdef CONFIG_NATIVE_WINDOWS
+#Once MinGW gets support for WinScard, -lwinscard could be used instead of the
+#dynamic symbol loading that is now used in pcsc_funcs.c
+#LIBS += -lwinscard
+else
+LIBS += -lpcsclite -lpthread
+endif
+endif
+
+ifdef CONFIG_SIM_SIMULATOR
+L_CFLAGS += -DCONFIG_SIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef CONFIG_USIM_SIMULATOR
+L_CFLAGS += -DCONFIG_USIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef NEED_MILENAGE
+OBJS += src/crypto/milenage.c
+NEED_AES_ENCBLOCK=y
+endif
+
+ifdef CONFIG_PKCS12
+L_CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef CONFIG_SMARTCARD
+L_CFLAGS += -DCONFIG_SMARTCARD
+endif
+
+ifdef MS_FUNCS
+OBJS += src/crypto/ms_funcs.c
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += src/eap_common/chap.c
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
+OBJS += src/eap_peer/eap_tls_common.c
+ifndef CONFIG_FIPS
+NEED_TLS_PRF=y
+NEED_SHA1=y
+NEED_MD5=y
+endif
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+L_CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+L_CFLAGS += -DEAP_TLS_OPENSSL
+OBJS += src/crypto/tls_openssl.c
+OBJS += src/crypto/tls_openssl_ocsp.c
+LIBS += -lssl
+endif
+OBJS += src/crypto/crypto_openssl.c
+OBJS_p += src/crypto/crypto_openssl.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_openssl.c
+endif
+NEED_SHA256=y
+NEED_TLS_PRF_SHA256=y
+LIBS += -lcrypto
+LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
+ifndef CONFIG_TLS_DEFAULT_CIPHERS
+CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
+endif
+L_CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\"
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_gnutls.c
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
+OBJS_p += src/crypto/crypto_$(CONFIG_CRYPTO).c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_internal.c
+OBJS += src/crypto/sha1-internal.c
+endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
+LIBS += -lgcrypt
+LIBS_p += -lgcrypt
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += src/crypto/crypto_internal-rsa.c
+OBJS += src/crypto/tls_internal.c
+OBJS += src/tls/tlsv1_common.c
+OBJS += src/tls/tlsv1_record.c
+OBJS += src/tls/tlsv1_cred.c
+OBJS += src/tls/tlsv1_client.c
+OBJS += src/tls/tlsv1_client_write.c
+OBJS += src/tls/tlsv1_client_read.c
+OBJS += src/tls/tlsv1_client_ocsp.c
+OBJS += src/tls/asn1.c
+OBJS += src/tls/rsa.c
+OBJS += src/tls/x509v3.c
+OBJS += src/tls/pkcs1.c
+OBJS += src/tls/pkcs5.c
+OBJS += src/tls/pkcs8.c
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += src/crypto/crypto_internal-cipher.c
+endif
+ifdef NEED_MODEXP
+OBJS += src/crypto/crypto_internal-modexp.c
+OBJS += src/tls/bignum.c
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += src/crypto/crypto_libtomcrypt.c
+OBJS_p += src/crypto/crypto_libtomcrypt.c
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += src/crypto/crypto_internal.c
+OBJS_p += src/crypto/crypto_internal.c
+NEED_AES_ENC=y
+L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+L_CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_SHA384=y
+CONFIG_INTERNAL_SHA512=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+L_CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += src/crypto/crypto_none.c
+OBJS_p += src/crypto/crypto_none.c
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifdef TLS_FUNCS
+ifdef CONFIG_SMARTCARD
+ifndef CONFIG_NATIVE_WINDOWS
+ifneq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -ldl
+endif
+endif
+endif
+endif
+
+ifndef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far (see below)
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-dec.c
+endif
+
+ifneq ($(CONFIG_TLS), openssl)
+NEED_INTERNAL_AES_WRAP=y
+endif
+ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP
+# Seems to be needed at least with BoringSSL
+NEED_INTERNAL_AES_WRAP=y
+L_CFLAGS += -DCONFIG_OPENSSL_INTERNAL_AES_WRAP
+endif
+ifdef CONFIG_FIPS
+# Have to use internal AES key wrap routines to use OpenSSL EVP since the
+# OpenSSL AES_wrap_key()/AES_unwrap_key() API is not available in FIPS mode.
+NEED_INTERNAL_AES_WRAP=y
+endif
+
+ifdef NEED_INTERNAL_AES_WRAP
+AESOBJS += src/crypto/aes-unwrap.c
+endif
+ifdef NEED_AES_EAX
+AESOBJS += src/crypto/aes-eax.c
+NEED_AES_CTR=y
+NEED_AES_OMAC1=y
+endif
+ifdef NEED_AES_SIV
+AESOBJS += src/crypto/aes-siv.c
+NEED_AES_CTR=y
+NEED_AES_OMAC1=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += src/crypto/aes-ctr.c
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += src/crypto/aes-encblock.c
+endif
+ifdef NEED_AES_OMAC1
+NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+L_CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
+AESOBJS += src/crypto/aes-omac1.c
+endif
+endif
+ifdef NEED_AES_WRAP
+NEED_AES_ENC=y
+ifdef NEED_INTERNAL_AES_WRAP
+AESOBJS += src/crypto/aes-wrap.c
+endif
+endif
+ifdef NEED_AES_CBC
+NEED_AES_ENC=y
+ifneq ($(CONFIG_TLS), openssl)
+AESOBJS += src/crypto/aes-cbc.c
+endif
+endif
+ifdef NEED_AES_ENC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal-enc.c
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+SHA1OBJS =
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+SHA1OBJS += src/crypto/sha1.c
+endif
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += src/crypto/sha1-internal.c
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += src/crypto/fips_prf_internal.c
+endif
+endif
+ifdef CONFIG_NO_WPA_PASSPHRASE
+L_CFLAGS += -DCONFIG_NO_PBKDF2
+else
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += src/crypto/sha1-tprf.c
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += src/crypto/sha1-tlsprf.c
+endif
+endif
+
+MD5OBJS =
+ifndef CONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+MD5OBJS += src/crypto/md5.c
+endif
+endif
+endif
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+MD5OBJS += src/crypto/md5-internal.c
+endif
+OBJS += $(MD5OBJS)
+OBJS_p += $(MD5OBJS)
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += src/crypto/md4-internal.c
+endif
+endif
+
+DESOBJS = # none needed when not internal
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+DESOBJS += src/crypto/des-internal.c
+endif
+endif
+
+ifdef CONFIG_NO_RC4
+L_CFLAGS += -DCONFIG_NO_RC4
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+ifndef CONFIG_NO_RC4
+OBJS += src/crypto/rc4.c
+endif
+endif
+endif
+
+SHA256OBJS = # none by default
+ifdef NEED_SHA256
+L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+SHA256OBJS += src/crypto/sha256.c
+endif
+endif
+SHA256OBJS += src/crypto/sha256-prf.c
+ifdef CONFIG_INTERNAL_SHA256
+SHA256OBJS += src/crypto/sha256-internal.c
+endif
+ifdef CONFIG_INTERNAL_SHA384
+L_CFLAGS += -DCONFIG_INTERNAL_SHA384
+SHA256OBJS += src/crypto/sha384-internal.c
+endif
+ifdef CONFIG_INTERNAL_SHA512
+L_CFLAGS += -DCONFIG_INTERNAL_SHA512
+SHA256OBJS += src/crypto/sha512-internal.c
+endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += src/crypto/sha256-tlsprf.c
+endif
+ifdef NEED_HMAC_SHA256_KDF
+L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF
+SHA256OBJS += src/crypto/sha256-kdf.c
+endif
+ifdef NEED_HMAC_SHA384_KDF
+L_CFLAGS += -DCONFIG_HMAC_SHA384_KDF
+SHA256OBJS += src/crypto/sha384-kdf.c
+endif
+ifdef NEED_HMAC_SHA512_KDF
+L_CFLAGS += -DCONFIG_HMAC_SHA512_KDF
+SHA256OBJS += src/crypto/sha512-kdf.c
+endif
+OBJS += $(SHA256OBJS)
+endif
+ifdef NEED_SHA384
+L_CFLAGS += -DCONFIG_SHA384
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+OBJS += src/crypto/sha384.c
+endif
+endif
+OBJS += src/crypto/sha384-prf.c
+endif
+ifdef NEED_SHA512
+L_CFLAGS += -DCONFIG_SHA512
+ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
+OBJS += src/crypto/sha512.c
+endif
+endif
+OBJS += src/crypto/sha512-prf.c
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_groups.c
+endif
+ifdef NEED_DH_GROUPS_ALL
+L_CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_group5.c
+endif
+endif
+
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += src/crypto/random.c
+endif
+
+ifdef CONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), y)
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_CTRL_IFACE=named_pipe
+else
+CONFIG_CTRL_IFACE=unix
+endif
+endif
+L_CFLAGS += -DCONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), unix)
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+OBJS += src/common/ctrl_iface_common.c
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+endif
+ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
+L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
+OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c
+endif
+
+ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
+OBJS += dbus/dbus_dict_helpers.c
+OBJS += dbus/dbus_new_helpers.c
+OBJS += dbus/dbus_new.c dbus/dbus_new_handlers.c
+OBJS += dbus/dbus_common.c
+ifdef CONFIG_WPS
+OBJS += dbus/dbus_new_handlers_wps.c
+endif
+ifdef CONFIG_P2P
+OBJS += dbus/dbus_new_handlers_p2p.c
+endif
+ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
+OBJS += dbus/dbus_new_introspect.c
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
+endif
+L_CFLAGS += $(DBUS_INCLUDE)
+endif
+
+ifdef CONFIG_CTRL_IFACE_BINDER
+WPA_SUPPLICANT_USE_BINDER=y
+L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER
+endif
+
+ifdef CONFIG_READLINE
+OBJS_c += src/utils/edit_readline.c
+LIBS_c += -lncurses -lreadline
+else
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += src/utils/edit.c
+else
+OBJS_c += src/utils/edit_simple.c
+endif
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+L_CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32 -lgdi32 -lcrypt32
+LIBS_c += -lws2_32
+LIBS_p += -lws2_32 -lgdi32
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+LIBS_p += -lcrypt32
+endif
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+ifndef CONFIG_CTRL_IFACE
+L_CFLAGS += -DCONFIG_NO_WPA_MSG
+endif
+endif
+
+ifdef CONFIG_ANDROID_LOG
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+endif
+
+ifdef CONFIG_IPV6
+# for eapol_test only
+L_CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef NEED_BASE64
+OBJS += src/utils/base64.c
+endif
+
+ifdef NEED_SME
+OBJS += sme.c
+L_CFLAGS += -DCONFIG_SME
+endif
+
+OBJS += src/common/ieee802_11_common.c
+OBJS += src/common/hw_features_common.c
+
+ifdef NEED_EAP_COMMON
+OBJS += src/eap_common/eap_common.c
+endif
+
+ifndef CONFIG_MAIN
+CONFIG_MAIN=main
+endif
+
+ifdef CONFIG_DEBUG_SYSLOG
+L_CFLAGS += -DCONFIG_DEBUG_SYSLOG
+ifdef CONFIG_DEBUG_SYSLOG_FACILITY
+L_CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
+endif
+endif
+
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
+ifdef CONFIG_DEBUG_FILE
+L_CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+L_CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT
+endif
+
+ifdef CONFIG_FIPS
+L_CFLAGS += -DCONFIG_FIPS
+endif
+
+OBJS += $(SHA1OBJS) $(DESOBJS)
+
+OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
+
+ifdef CONFIG_BGSCAN_SIMPLE
+L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE
+OBJS += bgscan_simple.c
+NEED_BGSCAN=y
+endif
+
+ifdef CONFIG_BGSCAN_LEARN
+L_CFLAGS += -DCONFIG_BGSCAN_LEARN
+OBJS += bgscan_learn.c
+NEED_BGSCAN=y
+endif
+
+ifdef NEED_BGSCAN
+L_CFLAGS += -DCONFIG_BGSCAN
+OBJS += bgscan.c
+endif
+
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+L_CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+L_CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+L_CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.c
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += src/utils/ext_password_test.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += src/utils/ext_password.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
+ifdef NEED_GAS_SERVER
+OBJS += src/common/gas_server.c
+L_CFLAGS += -DCONFIG_GAS_SERVER
+NEED_GAS=y
+endif
+
+ifdef NEED_GAS
+OBJS += src/common/gas.c
+OBJS += gas_query.c
+L_CFLAGS += -DCONFIG_GAS
+NEED_OFFCHANNEL=y
+endif
+
+ifdef NEED_OFFCHANNEL
+OBJS += offchannel.c
+L_CFLAGS += -DCONFIG_OFFCHANNEL
+endif
+
+ifdef NEED_JSON
+OBJS += src/utils/json.c
+L_CFLAGS += -DCONFIG_JSON
+endif
+
+OBJS += src/drivers/driver_common.c
+
+OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c
+OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
+OBJS_t += src/radius/radius_client.c
+OBJS_t += src/radius/radius.c
+ifndef CONFIG_AP
+OBJS_t += src/utils/ip_addr.c
+endif
+OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.c
+OBJS += $(CONFIG_MAIN).c
+
+ifdef CONFIG_PRIVSEP
+OBJS_priv += $(OBJS_d) src/drivers/drivers.c
+OBJS_priv += $(OBJS_l2)
+OBJS_priv += src/utils/os_$(CONFIG_OS).c
+OBJS_priv += src/utils/$(CONFIG_ELOOP).c
+OBJS_priv += src/utils/common.c
+OBJS_priv += src/utils/wpa_debug.c
+OBJS_priv += src/utils/wpabuf.c
+OBJS_priv += wpa_priv.c
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += src/common/ieee802_11_common.c
+endif
+OBJS += src/l2_packet/l2_packet_privsep.c
+OBJS += src/drivers/driver_privsep.c
+EXTRA_progs += wpa_priv
+else
+OBJS += $(OBJS_d) src/drivers/drivers.c
+OBJS += $(OBJS_l2)
+endif
+
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+L_CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED
+OBJS += src/drivers/ndis_events.c
+EXTRALIBS += -loleaut32 -lole32 -luuid
+ifdef PLATFORMSDKLIB
+EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib
+else
+EXTRALIBS += WbemUuid.Lib
+endif
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := wpa_cli
+LOCAL_MODULE_TAGS := debug
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS_c)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := wpa_supplicant
+ifdef CONFIG_DRIVER_CUSTOM
+LOCAL_STATIC_LIBRARIES := libCustomWifi
+endif
+ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
+LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
+endif
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+ifdef CONFIG_EAP_PROXY
+LOCAL_STATIC_LIBRARIES += $(LIB_STATIC_EAP_PROXY)
+LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY)
+endif
+ifeq ($(CONFIG_TLS), openssl)
+LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
+endif
+
+# With BoringSSL we need libkeystore-engine in order to provide access to
+# keystore keys.
+LOCAL_SHARED_LIBRARIES += libkeystore-engine
+
+ifdef CONFIG_DRIVER_NL80211
+ifneq ($(wildcard external/libnl),)
+LOCAL_SHARED_LIBRARIES += libnl
+else
+LOCAL_STATIC_LIBRARIES += libnl_2
+endif
+endif
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+ifeq ($(DBUS), y)
+LOCAL_SHARED_LIBRARIES += libdbus
+endif
+ifeq ($(WPA_SUPPLICANT_USE_BINDER), y)
+LOCAL_SHARED_LIBRARIES += libbinder libutils
+LOCAL_STATIC_LIBRARIES += libwpa_binder libwpa_binder_interface
+endif
+include $(BUILD_EXECUTABLE)
+
+########################
+#
+#include $(CLEAR_VARS)
+#LOCAL_MODULE := eapol_test
+#ifdef CONFIG_DRIVER_CUSTOM
+#LOCAL_STATIC_LIBRARIES := libCustomWifi
+#endif
+#LOCAL_SHARED_LIBRARIES := libc libcrypto libssl
+#LOCAL_CFLAGS := $(L_CFLAGS)
+#LOCAL_SRC_FILES := $(OBJS_t)
+#LOCAL_C_INCLUDES := $(INCLUDES)
+#include $(BUILD_EXECUTABLE)
+#
+########################
+#
+#local_target_dir := $(TARGET_OUT)/etc/wifi
+#
+#include $(CLEAR_VARS)
+#LOCAL_MODULE := wpa_supplicant.conf
+#LOCAL_MODULE_CLASS := ETC
+#LOCAL_MODULE_PATH := $(local_target_dir)
+#LOCAL_SRC_FILES := $(LOCAL_MODULE)
+#include $(BUILD_PREBUILT)
+#
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE = libwpa_client
+LOCAL_CFLAGS = $(L_CFLAGS)
+LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
+LOCAL_C_INCLUDES = $(INCLUDES)
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_COPY_HEADERS_TO := libwpa_client
+LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
+LOCAL_COPY_HEADERS += src/common/qca-vendor.h
+include $(BUILD_SHARED_LIBRARY)
+
+ifeq ($(WPA_SUPPLICANT_USE_BINDER), y)
+### Binder interface library ###
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_binder_interface
+LOCAL_AIDL_INCLUDES := \
+ $(LOCAL_PATH)/binder \
+ frameworks/native/aidl/binder
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/binder
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_SRC_FILES := \
+ binder/binder_constants.cpp \
+ binder/fi/w1/wpa_supplicant/ISupplicant.aidl \
+ binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl \
+ binder/fi/w1/wpa_supplicant/IIface.aidl
+LOCAL_SHARED_LIBRARIES := libbinder
+include $(BUILD_STATIC_LIBRARY)
+
+### Binder service library ###
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_binder
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+LOCAL_SRC_FILES := \
+ binder/binder.cpp binder/binder_manager.cpp \
+ binder/supplicant.cpp binder/iface.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libutils
+LOCAL_STATIC_LIBRARIES := libwpa_binder_interface
+include $(BUILD_STATIC_LIBRARY)
+
+endif # BINDER == y
diff --git a/contrib/wpa/wpa_supplicant/ChangeLog b/contrib/wpa/wpa_supplicant/ChangeLog
index facd90e..89119e7 100644
--- a/contrib/wpa/wpa_supplicant/ChangeLog
+++ b/contrib/wpa/wpa_supplicant/ChangeLog
@@ -1,5 +1,288 @@
ChangeLog for wpa_supplicant
+2019-04-21 - v2.8
+ * SAE changes
+ - added support for SAE Password Identifier
+ - changed default configuration to enable only groups 19, 20, 21
+ (i.e., disable groups 25 and 26) and disable all unsuitable groups
+ completely based on REVmd changes
+ - do not regenerate PWE unnecessarily when the AP uses the
+ anti-clogging token mechanisms
+ - fixed some association cases where both SAE and FT-SAE were enabled
+ on both the station and the selected AP
+ - started to prefer FT-SAE over SAE AKM if both are enabled
+ - started to prefer FT-SAE over FT-PSK if both are enabled
+ - fixed FT-SAE when SAE PMKSA caching is used
+ - reject use of unsuitable groups based on new implementation guidance
+ in REVmd (allow only FFC groups with prime >= 3072 bits and ECC
+ groups with prime >= 256)
+ - minimize timing and memory use differences in PWE derivation
+ [https://w1.fi/security/2019-1/] (CVE-2019-9494)
+ * EAP-pwd changes
+ - minimize timing and memory use differences in PWE derivation
+ [https://w1.fi/security/2019-2/] (CVE-2019-9495)
+ - verify server scalar/element
+ [https://w1.fi/security/2019-4/] (CVE-2019-9499)
+ - fix message reassembly issue with unexpected fragment
+ [https://w1.fi/security/2019-5/]
+ - enforce rand,mask generation rules more strictly
+ - fix a memory leak in PWE derivation
+ - disallow ECC groups with a prime under 256 bits (groups 25, 26, and
+ 27)
+ * fixed CONFIG_IEEE80211R=y (FT) build without CONFIG_FILS=y
+ * Hotspot 2.0 changes
+ - do not indicate release number that is higher than the one
+ AP supports
+ - added support for release number 3
+ - enable PMF automatically for network profiles created from
+ credentials
+ * fixed OWE network profile saving
+ * fixed DPP network profile saving
+ * added support for RSN operating channel validation
+ (CONFIG_OCV=y and network profile parameter ocv=1)
+ * added Multi-AP backhaul STA support
+ * fixed build with LibreSSL
+ * number of MKA/MACsec fixes and extensions
+ * extended domain_match and domain_suffix_match to allow list of values
+ * fixed dNSName matching in domain_match and domain_suffix_match when
+ using wolfSSL
+ * started to prefer FT-EAP-SHA384 over WPA-EAP-SUITE-B-192 AKM if both
+ are enabled
+ * extended nl80211 Connect and external authentication to support
+ SAE, FT-SAE, FT-EAP-SHA384
+ * fixed KEK2 derivation for FILS+FT
+ * extended client_cert file to allow loading of a chain of PEM
+ encoded certificates
+ * extended beacon reporting functionality
+ * extended D-Bus interface with number of new properties
+ * fixed a regression in FT-over-DS with mac80211-based drivers
+ * OpenSSL: allow systemwide policies to be overridden
+ * extended driver flags indication for separate 802.1X and PSK
+ 4-way handshake offload capability
+ * added support for random P2P Device/Interface Address use
+ * extended PEAP to derive EMSK to enable use with ERP/FILS
+ * extended WPS to allow SAE configuration to be added automatically
+ for PSK (wps_cred_add_sae=1)
+ * removed support for the old D-Bus interface (CONFIG_CTRL_IFACE_DBUS)
+ * extended domain_match and domain_suffix_match to allow list of values
+ * added a RSN workaround for misbehaving PMF APs that advertise
+ IGTK/BIP KeyID using incorrect byte order
+ * fixed PTK rekeying with FILS and FT
+
+2018-12-02 - v2.7
+ * fixed WPA packet number reuse with replayed messages and key
+ reinstallation
+ [https://w1.fi/security/2017-1/] (CVE-2017-13077, CVE-2017-13078,
+ CVE-2017-13079, CVE-2017-13080, CVE-2017-13081, CVE-2017-13082,
+ CVE-2017-13086, CVE-2017-13087, CVE-2017-13088)
+ * fixed unauthenticated EAPOL-Key decryption in wpa_supplicant
+ [https://w1.fi/security/2018-1/] (CVE-2018-14526)
+ * added support for FILS (IEEE 802.11ai) shared key authentication
+ * added support for OWE (Opportunistic Wireless Encryption, RFC 8110;
+ and transition mode defined by WFA)
+ * added support for DPP (Wi-Fi Device Provisioning Protocol)
+ * added support for RSA 3k key case with Suite B 192-bit level
+ * fixed Suite B PMKSA caching not to update PMKID during each 4-way
+ handshake
+ * fixed EAP-pwd pre-processing with PasswordHashHash
+ * added EAP-pwd client support for salted passwords
+ * fixed a regression in TDLS prohibited bit validation
+ * started to use estimated throughput to avoid undesired signal
+ strength based roaming decision
+ * MACsec/MKA:
+ - new macsec_linux driver interface support for the Linux
+ kernel macsec module
+ - number of fixes and extensions
+ * added support for external persistent storage of PMKSA cache
+ (PMKSA_GET/PMKSA_ADD control interface commands; and
+ MESH_PMKSA_GET/MESH_PMKSA_SET for the mesh case)
+ * fixed mesh channel configuration pri/sec switch case
+ * added support for beacon report
+ * large number of other fixes, cleanup, and extensions
+ * added support for randomizing local address for GAS queries
+ (gas_rand_mac_addr parameter)
+ * fixed EAP-SIM/AKA/AKA' ext auth cases within TLS tunnel
+ * added option for using random WPS UUID (auto_uuid=1)
+ * added SHA256-hash support for OCSP certificate matching
+ * fixed EAP-AKA' to add AT_KDF into Synchronization-Failure
+ * fixed a regression in RSN pre-authentication candidate selection
+ * added option to configure allowed group management cipher suites
+ (group_mgmt network profile parameter)
+ * removed all PeerKey functionality
+ * fixed nl80211 AP and mesh mode configuration regression with
+ Linux 4.15 and newer
+ * added ap_isolate configuration option for AP mode
+ * added support for nl80211 to offload 4-way handshake into the driver
+ * added support for using wolfSSL cryptographic library
+ * SAE
+ - added support for configuring SAE password separately of the
+ WPA2 PSK/passphrase
+ - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection
+ for SAE;
+ note: this is not backwards compatible, i.e., both the AP and
+ station side implementations will need to be update at the same
+ time to maintain interoperability
+ - added support for Password Identifier
+ - fixed FT-SAE PMKID matching
+ * Hotspot 2.0
+ - added support for fetching of Operator Icon Metadata ANQP-element
+ - added support for Roaming Consortium Selection element
+ - added support for Terms and Conditions
+ - added support for OSEN connection in a shared RSN BSS
+ - added support for fetching Venue URL information
+ * added support for using OpenSSL 1.1.1
+ * FT
+ - disabled PMKSA caching with FT since it is not fully functional
+ - added support for SHA384 based AKM
+ - added support for BIP ciphers BIP-CMAC-256, BIP-GMAC-128,
+ BIP-GMAC-256 in addition to previously supported BIP-CMAC-128
+ - fixed additional IE inclusion in Reassociation Request frame when
+ using FT protocol
+
+2016-10-02 - v2.6
+ * fixed WNM Sleep Mode processing when PMF is not enabled
+ [http://w1.fi/security/2015-6/] (CVE-2015-5310)
+ * fixed EAP-pwd last fragment validation
+ [http://w1.fi/security/2015-7/] (CVE-2015-5315)
+ * fixed EAP-pwd unexpected Confirm message processing
+ [http://w1.fi/security/2015-8/] (CVE-2015-5316)
+ * fixed WPS configuration update vulnerability with malformed passphrase
+ [http://w1.fi/security/2016-1/] (CVE-2016-4476)
+ * fixed configuration update vulnerability with malformed parameters set
+ over the local control interface
+ [http://w1.fi/security/2016-1/] (CVE-2016-4477)
+ * fixed TK configuration to the driver in EAPOL-Key 3/4 retry case
+ * extended channel switch support for P2P GO
+ * started to throttle control interface event message bursts to avoid
+ issues with monitor sockets running out of buffer space
+ * mesh mode fixes/improvements
+ - generate proper AID for peer
+ - enable WMM by default
+ - add VHT support
+ - fix PMKID derivation
+ - improve robustness on various exchanges
+ - fix peer link counting in reconnect case
+ - improve mesh joining behavior
+ - allow DTIM period to be configured
+ - allow HT to be disabled (disable_ht=1)
+ - add MESH_PEER_ADD and MESH_PEER_REMOVE commands
+ - add support for PMKSA caching
+ - add minimal support for SAE group negotiation
+ - allow pairwise/group cipher to be configured in the network profile
+ - use ieee80211w profile parameter to enable/disable PMF and derive
+ a separate TX IGTK if PMF is enabled instead of using MGTK
+ incorrectly
+ - fix AEK and MTK derivation
+ - remove GTKdata and IGTKdata from Mesh Peering Confirm/Close
+ - note: these changes are not fully backwards compatible for secure
+ (RSN) mesh network
+ * fixed PMKID derivation with SAE
+ * added support for requesting and fetching arbitrary ANQP-elements
+ without internal support in wpa_supplicant for the specific element
+ (anqp[265]=<hexdump> in "BSS <BSSID>" command output)
+ * P2P
+ - filter control characters in group client device names to be
+ consistent with other P2P peer cases
+ - support VHT 80+80 MHz and 160 MHz
+ - indicate group completion in P2P Client role after data association
+ instead of already after the WPS provisioning step
+ - improve group-join operation to use SSID, if known, to filter BSS
+ entries
+ - added optional ssid=<hexdump> argument to P2P_CONNECT for join case
+ - added P2P_GROUP_MEMBER command to fetch client interface address
+ * P2PS
+ - fix follow-on PD Response behavior
+ - fix PD Response generation for unknown peer
+ - fix persistent group reporting
+ - add channel policy to PD Request
+ - add group SSID to the P2PS-PROV-DONE event
+ - allow "P2P_CONNECT <addr> p2ps" to be used without specifying the
+ default PIN
+ * BoringSSL
+ - support for OCSP stapling
+ - support building of h20-osu-client
+ * D-Bus
+ - add ExpectDisconnect()
+ - add global config parameters as properties
+ - add SaveConfig()
+ - add VendorElemAdd(), VendorElemGet(), VendorElemRem()
+ * fixed Suite B 192-bit AKM to use proper PMK length
+ (note: this makes old releases incompatible with the fixed behavior)
+ * improved PMF behavior for cases where the AP and STA has different
+ configuration by not trying to connect in some corner cases where the
+ connection cannot succeed
+ * added option to reopen debug log (e.g., to rotate the file) upon
+ receipt of SIGHUP signal
+ * EAP-pwd: added support for Brainpool Elliptic Curves
+ (with OpenSSL 1.0.2 and newer)
+ * fixed EAPOL reauthentication after FT protocol run
+ * fixed FTIE generation for 4-way handshake after FT protocol run
+ * extended INTERFACE_ADD command to allow certain type (sta/ap)
+ interface to be created
+ * fixed and improved various FST operations
+ * added 80+80 MHz and 160 MHz VHT support for IBSS/mesh
+ * fixed SIGNAL_POLL in IBSS and mesh cases
+ * added an option to abort an ongoing scan (used to speed up connection
+ and can also be done with the new ABORT_SCAN command)
+ * TLS client
+ - do not verify CA certificates when ca_cert is not specified
+ - support validating server certificate hash
+ - support SHA384 and SHA512 hashes
+ - add signature_algorithms extension into ClientHello
+ - support TLS v1.2 signature algorithm with SHA384 and SHA512
+ - support server certificate probing
+ - allow specific TLS versions to be disabled with phase2 parameter
+ - support extKeyUsage
+ - support PKCS #5 v2.0 PBES2
+ - support PKCS #5 with PKCS #12 style key decryption
+ - minimal support for PKCS #12
+ - support OCSP stapling (including ocsp_multi)
+ * OpenSSL
+ - support OpenSSL 1.1 API changes
+ - drop support for OpenSSL 0.9.8
+ - drop support for OpenSSL 1.0.0
+ * added support for multiple schedule scan plans (sched_scan_plans)
+ * added support for external server certificate chain validation
+ (tls_ext_cert_check=1 in the network profile phase1 parameter)
+ * made phase2 parser more strict about correct use of auth=<val> and
+ autheap=<val> values
+ * improved GAS offchannel operations with comeback request
+ * added SIGNAL_MONITOR command to request signal strength monitoring
+ events
+ * added command for retrieving HS 2.0 icons with in-memory storage
+ (REQ_HS20_ICON, GET_HS20_ICON, DEL_HS20_ICON commands and
+ RX-HS20-ICON event)
+ * enabled ACS support for AP mode operations with wpa_supplicant
+ * EAP-PEAP: fixed interoperability issue with Windows 2012r2 server
+ ("Invalid Compound_MAC in cryptobinding TLV")
+ * EAP-TTLS: fixed success after fragmented final Phase 2 message
+ * VHT: added interoperability workaround for 80+80 and 160 MHz channels
+ * WNM: workaround for broken AP operating class behavior
+ * added kqueue(2) support for eloop (CONFIG_ELOOP_KQUEUE)
+ * nl80211:
+ - add support for full station state operations
+ - do not add NL80211_ATTR_SMPS_MODE attribute if HT is disabled
+ - add NL80211_ATTR_PREV_BSSID with Connect command
+ - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
+ unencrypted EAPOL frames
+ * added initial MBO support; number of extensions to WNM BSS Transition
+ Management
+ * added support for PBSS/PCP and P2P on 60 GHz
+ * Interworking: add credential realm to EAP-TLS identity
+ * fixed EAPOL-Key Request Secure bit to be 1 if PTK is set
+ * HS 2.0: add support for configuring frame filters
+ * added POLL_STA command to check connectivity in AP mode
+ * added initial functionality for location related operations
+ * started to ignore pmf=1/2 parameter for non-RSN networks
+ * added wps_disabled=1 network profile parameter to allow AP mode to
+ be started without enabling WPS
+ * wpa_cli: added action script support for AP-ENABLED and AP-DISABLED
+ events
+ * improved Public Action frame addressing
+ - add gas_address3 configuration parameter to control Address 3
+ behavior
+ * number of small fixes
+
2015-09-27 - v2.5
* fixed P2P validation of SSID element length before copying it
[http://w1.fi/security/2015-1/] (CVE-2015-1863)
diff --git a/contrib/wpa/wpa_supplicant/README b/contrib/wpa/wpa_supplicant/README
index f9c65d2..bbc86b1 100644
--- a/contrib/wpa/wpa_supplicant/README
+++ b/contrib/wpa/wpa_supplicant/README
@@ -1,7 +1,7 @@
-WPA Supplicant
+wpa_supplicant
==============
-Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
@@ -72,16 +72,18 @@ Supported WPA/IEEE 802.11i features:
* EAP-TTLS/CHAP
* EAP-SIM
* EAP-AKA
+ * EAP-AKA'
* EAP-PSK
* EAP-PAX
* EAP-SAKE
* EAP-IKEv2
* EAP-GPSK
+ * EAP-pwd
* LEAP (note: requires special support from the driver for IEEE 802.11
authentication)
(following methods are supported, but since they do not generate keying
material, they cannot be used with WPA or IEEE 802.1X WEP keying)
- * EAP-MD5-Challenge
+ * EAP-MD5-Challenge
* EAP-MSCHAPv2
* EAP-GTC
* EAP-OTP
@@ -163,18 +165,12 @@ systems. In case of Windows builds, WinPcap is used by default
Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS:
-- OpenSSL (tested with 0.9.7c and 0.9.7d, and 0.9.8 versions; assumed to
+- OpenSSL (tested with 1.0.1 and 1.0.2 versions; assumed to
work with most relatively recent versions; this is likely to be
available with most distributions, http://www.openssl.org/)
- GnuTLS
- internal TLSv1 implementation
-TLS options for EAP-FAST:
-- OpenSSL 0.9.8d _with_ openssl-0.9.8d-tls-extensions.patch applied
- (i.e., the default OpenSSL package does not include support for
- extensions needed for EAP-FAST)
-- internal TLSv1 implementation
-
One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or
EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP
implementation. A configuration file, .config, for compilation is
@@ -308,7 +304,7 @@ Following build time configuration options are used to control IEEE
802.1X/EAPOL and EAP state machines and all EAP methods. Including
TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL
library for TLS implementation. Alternatively, GnuTLS or the internal
-TLSv1 implementation can be used for TLS functionaly.
+TLSv1 implementation can be used for TLS functionality.
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_MD5=y
@@ -320,15 +316,17 @@ CONFIG_EAP_GTC=y
CONFIG_EAP_OTP=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
+CONFIG_EAP_AKA_PRIME=y
CONFIG_EAP_PSK=y
CONFIG_EAP_SAKE=y
CONFIG_EAP_GPSK=y
CONFIG_EAP_PAX=y
CONFIG_EAP_LEAP=y
CONFIG_EAP_IKEV2=y
+CONFIG_EAP_PWD=y
Following option can be used to include GSM SIM/USIM interface for GSM/UMTS
-authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite
+authentication algorithm (for EAP-SIM/EAP-AKA/EAP-AKA'). This requires pcsc-lite
(http://www.linuxnet.com/) for smart card access.
CONFIG_PCSC=y
@@ -409,10 +407,10 @@ Command line options
--------------------
usage:
- wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \
+ wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \
[-G<group>] \
-i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
- [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
+ [-b<br_ifname> [-MN -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
[-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ...
options:
@@ -435,8 +433,8 @@ options:
-q = decrease debugging verbosity (-qq even less)
-u = enable DBus control interface
-v = show version
- -w = wait for interface to be added, if needed
-W = wait for a control interface monitor before starting
+ -M = start describing matching interface
-N = start describing new interface
-m = Configuration file for the P2P Device
@@ -479,6 +477,22 @@ wpa_supplicant \
-c wpa2.conf -i wlan1 -D wext
+If the interfaces on which wpa_supplicant is to run are not known or do
+not exist, wpa_supplicant can match an interface when it arrives. Each
+matched interface is separated with -M argument and the -i argument now
+allows for pattern matching.
+
+As an example, the following command would start wpa_supplicant for a
+specific wired interface called lan0, any interface starting with wlan
+and lastly any other interface. Each match has its own configuration
+file, and for the wired interface a specific driver has also been given.
+
+wpa_supplicant \
+ -M -c wpa_wired.conf -ilan0 -D wired \
+ -M -c wpa1.conf -iwlan* \
+ -M -c wpa2.conf
+
+
If the interface is added in a Linux bridge (e.g., br0), the bridge
interface needs to be configured to wpa_supplicant in addition to the
main interface:
@@ -500,7 +514,7 @@ reloading can be triggered with 'wpa_cli reconfigure' command.
Configuration file can include one or more network blocks, e.g., one
for each used SSID. wpa_supplicant will automatically select the best
-betwork based on the order of network blocks in the configuration
+network based on the order of network blocks in the configuration
file, network security level (WPA/WPA2 is preferred), and signal
strength.
@@ -792,7 +806,7 @@ addresses, etc.
One wpa_cli process in "action" mode needs to be started for each
interface. For example, the following command starts wpa_cli for the
-default ingterface (-i can be used to select the interface in case of
+default interface (-i can be used to select the interface in case of
more than one interface being used at the same time):
wpa_cli -a/sbin/wpa_action.sh -B
@@ -951,6 +965,17 @@ wpa_priv can control multiple interface with one process, but it is
also possible to run multiple wpa_priv processes at the same time, if
desired.
+It should be noted that the interface used between wpa_supplicant and
+wpa_priv does not include all the capabilities of the wpa_supplicant
+driver interface and at times, this interface lacks update especially
+for recent addition. Consequently, use of wpa_priv does come with the
+price of somewhat reduced available functionality. The next section
+describing how wpa_supplicant can be used with reduced privileges
+without having to handle the complexity of separate wpa_priv. While that
+approve does not provide separation for network admin capabilities, it
+does allow other root privileges to be dropped without the drawbacks of
+the wpa_priv process.
+
Linux capabilities instead of privileged process
------------------------------------------------
@@ -1008,8 +1033,8 @@ event message is indicated that the external processing can start. Once
the operation has been completed, "RADIO_WORK done <id>" is used to
indicate that to wpa_supplicant. This allows other radio works to be
performed. If this command is forgotten (e.g., due to the external
-program terminating), wpa_supplicant will time out the radio owrk item
-and send "EXT-RADIO-WORK-TIMEOUT <id>" event ot indicate that this has
+program terminating), wpa_supplicant will time out the radio work item
+and send "EXT-RADIO-WORK-TIMEOUT <id>" event to indicate that this has
happened. "RADIO_WORK done <id>" can also be used to cancel items that
have not yet been started.
diff --git a/contrib/wpa/wpa_supplicant/README-DPP b/contrib/wpa/wpa_supplicant/README-DPP
new file mode 100644
index 0000000..6496733
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/README-DPP
@@ -0,0 +1,195 @@
+Device Provisioning Protocol (DPP)
+==================================
+
+This document describes how the Device Provisioning Protocol (DPP)
+implementation in wpa_supplicant and hostapd can be configured and how
+the STA device and AP can be configured to connect each other using DPP
+Connector mechanism.
+
+Introduction to DPP
+-------------------
+
+Device provisioning Protocol allows enrolling of interface-less devices
+in a secure Wi-Fi network using many methods like QR code based
+authentication( detailed below ), PKEX based authentication etc. In DPP
+a Configurator is used to provide network credentials to the devices.
+The three phases of DPP connection are authentication, configuration and
+network introduction.
+
+Build config setup
+------------------
+
+The following changes must go in the config file used to compile hostapd
+and wpa_supplicant.
+
+wpa_supplicant build config
+---------------------------
+
+Enable DPP and protected management frame in wpa_supplicant build config
+file
+
+CONFIG_IEEE80211W=y
+CONFIG_DPP=y
+
+hostapd build config
+--------------------
+
+Enable DPP and protected management frame in hostapd build config file
+
+CONFIG_IEEE80211W=y
+CONFIG_DPP=y
+
+Configurator build config
+-------------------------
+
+Any STA or AP device can act as a Configurator. Enable DPP and protected
+managment frames in build config. For an AP to act as Configurator,
+Interworking needs to be enabled. For wpa_supplicant it is not required.
+
+CONFIG_INTERWORKING=y
+
+
+Sample supplicant config file before provisioning
+-------------------------------------------------
+
+ctrl_interface=DIR=/var/run/wpa_supplicant
+ctrl_interface_group=0
+update_config=1
+pmf=2
+dpp_config_processing=2
+
+Sample hostapd config file before provisioning
+----------------------------------------------
+
+interface=wlan0
+driver=nl80211
+ctrl_interface=/var/run/hostapd
+ssid=test
+channel=1
+wpa=2
+wpa_key_mgmt=DPP
+ieee80211w=1
+wpa_pairwise=CCMP
+rsn_pairwise=CCMP
+
+
+Pre-requisites
+--------------
+
+It is assumed that an AP and client station are up by running hostapd
+and wpa_supplicant using respective config files.
+
+
+Creating Configurator
+---------------------
+
+Add a Configurator over the control interface (wpa_cli/hostapd_cli)
+
+> dpp_configurator_add
+(returns id)
+
+To get key of Configurator
+> dpp_configurator_get_key <id>
+
+
+How to configure an enrollee using Configurator
+-----------------------------------------------
+
+On enrollee side:
+
+Generate QR code for the device. Store the qr code id returned by the
+command.
+
+> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-channel> key=<key of the device>
+(returns bootstrapping info id)
+
+Get QR Code of device using the bootstrap info id.
+> dpp_bootstrap_get_uri <bootstrap-id>
+
+Make device listen to DPP request (The central frequency of channel 1 is
+2412) in case if enrollee is a client device.
+
+> dpp_listen <frequency>
+
+On Configurator side:
+
+Enter the QR Code in the Configurator.
+> dpp_qr_code "<QR-Code-read-from-enrollee>"
+
+On successfully adding QR Code, a bootstrapping info id is returned.
+
+Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an
+AP. conf is sta-dpp if enrollee is a client)
+> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+
+The DPP values will be printed in the console. Save this values into the
+config file. If the enrollee is an AP, we need to manually write these
+values to the hostapd config file. If the enrollee is a client device,
+these details can be automatically saved to config file using the
+following command.
+
+> save_config
+
+To set values in runtime for AP enrollees
+
+> set dpp_connector <Connector-value-printed-on-console>
+> set dpp_csign <csign-value-on-console>
+> set dpp_netaccesskey <netaccess-value-on-console>
+
+To set values in runtime for client enrollees, set dpp_config_processing
+to 2 in wpa_supplicant conf file.
+
+Once the values are set in run-time (if not set in run-time, but saved
+in config files, they are taken up in next restart), the client device
+will automatically connect to the already provisioned AP and connection
+will be established.
+
+
+Self-configuring a device
+-------------------------
+
+It is possible for a device to configure itself if it is the
+Configurator for the network.
+
+Create a Configurator in the device and use the dpp_configurator_sign
+command to get DPP credentials.
+
+> dpp_configurator_add
+(returns configurator id)
+> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+
+
+Sample AP configuration files after provisioning
+------------------------------------------------
+
+interface=wlan0
+driver=nl80211
+ctrl_interface=/var/run/hostapd
+ssid=test
+channel=1
+wpa=2
+wpa_key_mgmt=DPP
+ieee80211w=1
+wpa_pairwise=CCMP
+rsn_pairwise=CCMP
+dpp_connector=<Connector value provided by Configurator>
+dpp_csign=<C-Sign-Key value provided by Configurator>
+dpp_netaccesskey=<Net access key provided by Configurator>
+
+
+Sample station configuration file after provisioning
+----------------------------------------------------
+
+ctrl_interface=DIR=/var/run/wpa_supplicant
+ctrl_interface_group=0
+update_config=1
+pmf=2
+dpp_config_processing=2
+network={
+ ssid="test"
+ key_mgmt=DPP
+ ieee80211w=2
+ dpp_connector="<Connector value provided by Configurator>"
+ dpp_netaccesskey=<Net access key provided by Configurator>
+ dpp_csign=<C-sign-key value provided by Configurator>
+}
diff --git a/contrib/wpa/wpa_supplicant/README-HS20 b/contrib/wpa/wpa_supplicant/README-HS20
index 161dc06..3342871 100644
--- a/contrib/wpa/wpa_supplicant/README-HS20
+++ b/contrib/wpa/wpa_supplicant/README-HS20
@@ -197,6 +197,20 @@ Credentials can be pre-configured for automatic network selection:
# pre-configured with the credential since the NAI Realm information
# may not be available or fetched.
#
+# required_roaming_consortium: Required Roaming Consortium OI
+# If required_roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that is required to be advertised by the AP for
+# the credential to be considered matching.
+#
+# roaming_consortiums: Roaming Consortium OI(s) memberships
+# This string field contains one or more comma delimited OIs (hexdump)
+# identifying the roaming consortiums of which the provider is a member.
+# The list is sorted from the most preferred one to the least preferred
+# one. A match between the Roaming Consortium OIs advertised by an AP and
+# the OIs in this list indicates that successful authentication is
+# possible.
+# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+#
# eap: Pre-configured EAP method
# This optional field can be used to specify which EAP method will be
# used with this credential. If not set, the EAP method is selected
@@ -229,7 +243,7 @@ Credentials can be pre-configured for automatic network selection:
#
# sp_priority: Credential priority within a provisioning SP
# This is the priority of the credential among all credentials
-# provisionined by the same SP (i.e., for entries that have identical
+# provisioned by the same SP (i.e., for entries that have identical
# provisioning_sp value). The range of this priority is 0-255 with 0
# being the highest and 255 the lower priority.
#
@@ -295,6 +309,7 @@ Credentials can be pre-configured for automatic network selection:
# ca_cert="/etc/wpa_supplicant/ca.pem"
# domain="example.com"
# roaming_consortium=223344
+# roaming_consortiums="112233,4455667788,aabbcc"
# eap=TTLS
# phase2="auth=MSCHAPV2"
#}
@@ -564,3 +579,70 @@ OK
<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
<3>ANQP fetch completed
+
+
+Hotspot 2.0 Rel 2 online signup and OSEN
+----------------------------------------
+
+Following parameters can be used to create a network profile for
+link-layer protected Hotspot 2.0 online signup connection with
+OSEN. Note that ssid and identify (NAI) values need to be set based on
+the information for the selected provider in the OSU Providers list
+ANQP-element.
+
+network={
+ ssid="HS 2.0 OSU"
+ proto=OSEN
+ key_mgmt=OSEN
+ pairwise=CCMP
+ group=GTK_NOT_USED
+ eap=WFA-UNAUTH-TLS
+ identity="anonymous@example.com"
+ ca_cert="osu-ca.pem"
+ ocsp=2
+}
+
+
+Hotspot 2.0 connection with external network selection
+------------------------------------------------------
+
+When a component controlling wpa_supplicant takes care of Interworking
+network selection, following configuration and network profile
+parameters can be used to configure a temporary network profile for a
+Hotspot 2.0 connection (e.g., with SET, ADD_NETWORK, SET_NETWORK, and
+SELECT_NETWORK control interface commands):
+
+interworking=1
+hs20=1
+auto_interworking=0
+
+network={
+ ssid="test-hs20"
+ proto=RSN
+ key_mgmt=WPA-EAP
+ pairwise=CCMP
+ anonymous_identity="anonymous@example.com"
+ identity="hs20-test@example.com"
+ password="password"
+ ca_cert="ca.pem"
+ eap=TTLS
+ phase2="auth=MSCHAPV2"
+ update_identifier=54321
+ roaming_consortium_selection=112233
+ #ocsp=2
+}
+
+
+These parameters are set based on the PPS MO credential and/or NAI Realm
+list ANQP-element:
+
+anonymous_identity: Credential/UsernamePassword/Username with username part
+ replaced with "anonymous"
+identity: Credential/UsernamePassword/Username
+password: Credential/UsernamePassword/Password
+update_identifier: PPS/UpdateIdentifier
+ca_cert: from the downloaded trust root based on PPS information
+eap: Credential/UsernamePassword/EAPMethod or NAI Realm list
+phase2: Credential/UsernamePassword/EAPMethod or NAI Realm list
+roaming_consortium_selection: Matching OI from HomeSP/RoamingConsortiumOI
+ocsp: Credential/CheckAAAServerCertStatus
diff --git a/contrib/wpa/wpa_supplicant/README-P2P b/contrib/wpa/wpa_supplicant/README-P2P
index 6a5b032..55a60a2 100644
--- a/contrib/wpa/wpa_supplicant/README-P2P
+++ b/contrib/wpa/wpa_supplicant/README-P2P
@@ -150,7 +150,8 @@ join-a-group style PD instead of GO Negotiation style PD.
p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps]
[persistent|persistent=<network id>] [join|auth]
- [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto]
+ [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [he] [provdisc] [auto]
+ [ssid=<hexdump>]
Start P2P group formation with a discovered P2P peer. This includes
optional group owner negotiation, group interface setup, provisioning,
@@ -195,11 +196,17 @@ connection.
out whether the peer device is operating as a GO and if so, use
join-a-group operation rather than GO Negotiation.
+"ssid=<hexdump>" can be used to specify the Group SSID for join
+operations. This allows the P2P Client interface to filter scan results
+based on SSID to avoid selecting an incorrect BSS entry in case the same
+P2P Device or Interface address have been used in multiple groups
+recently.
+
P2PS attribute changes to p2p_connect command:
P2PS supports two WPS provisioning methods namely PIN method and P2PS default.
-The remaining paramters hold same role as in legacy P2P. In case of P2PS default
-config method "p2ps" keyword is added in p2p_connect command.
+The remaining parameters hold same role as in legacy P2P. In case of P2PS
+default config method "p2ps" keyword is added in p2p_connect command.
For example:
p2p_connect 02:0a:f5:85:11:00 12345670 p2ps persistent join
@@ -255,7 +262,7 @@ Parameters definition:
session_mac - Mandatory MAC address that owns/initiated the session
p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
- [ht40] [vht]
+ [ht40] [vht] [he]
Set up a P2P group owner manually (i.e., without group owner
negotiation with a specific peer). This is also known as autonomous
@@ -281,7 +288,7 @@ group interface is used as a parameter for this command.
p2p_cancel
Cancel an ongoing P2P group formation and joining-a-group related
-operation. This operations unauthorizes the specific peer device (if any
+operation. This operation unauthorizes the specific peer device (if any
had been authorized to start group formation), stops P2P find (if in
progress), stops pending operations for join-a-group, and removes the
P2P group interface (if one was used) that is in the WPS provisioning
@@ -551,7 +558,7 @@ Remove all local services from internal SD query processing.
Invitation
p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
- [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht] [he]
[pref=<MHz>]
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
@@ -633,12 +640,17 @@ p2p_set managed <0/1>
Disable/enable managed P2P Device operations. This is disabled by
default.
-p2p_set listen_channel <1/6/11>
+p2p_set listen_channel <channel> [<op_class>]
Set P2P Listen channel. This is mainly meant for testing purposes and
changing the Listen channel during normal operations can result in
protocol failures.
+When specifying a social channel on the 2.4 GHz band (1/6/11) there is
+no need to specify the operating class since it defaults to 81. When
+specifying a social channel on the 60 GHz band (2), specify the 60 GHz
+operating class (180).
+
p2p_set ssid_postfix <postfix>
Set postfix string to be added to the automatically generated P2P SSID
@@ -650,7 +662,7 @@ p2p_set per_sta_psk <0/1>
Disabled(default)/enables use of per-client PSK in the P2P groups. This
can be used to request GO to assign a unique PSK for each client during
WPS provisioning. When enabled, this allow clients to be removed from
-the group securily with p2p_remove_client command since that client's
+the group securely with p2p_remove_client command since that client's
PSK is removed at the same time to prevent it from connecting back using
the old PSK. When per-client PSK is not used, the client can still be
disconnected, but it will be able to re-join the group since the PSK it
diff --git a/contrib/wpa/wpa_supplicant/README-Windows.txt b/contrib/wpa/wpa_supplicant/README-Windows.txt
new file mode 100644
index 0000000..7288abd
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/README-Windows.txt
@@ -0,0 +1,299 @@
+wpa_supplicant for Windows
+==========================
+
+Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
+
+
+wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X
+Supplicant on Windows. The current port requires that WinPcap
+(http://winpcap.polito.it/) is installed for accessing packets and the
+driver interface. Both release versions 3.0 and 3.1 are supported.
+
+The current port is still somewhat experimental. It has been tested
+mainly on Windows XP (SP2) with limited set of NDIS drivers. In
+addition, the current version has been reported to work with Windows
+2000.
+
+All security modes have been verified to work (at least complete
+authentication and successfully ping a wired host):
+- plaintext
+- static WEP / open system authentication
+- static WEP / shared key authentication
+- IEEE 802.1X with dynamic WEP keys
+- WPA-PSK, TKIP, CCMP, TKIP+CCMP
+- WPA-EAP, TKIP, CCMP, TKIP+CCMP
+- WPA2-PSK, TKIP, CCMP, TKIP+CCMP
+- WPA2-EAP, TKIP, CCMP, TKIP+CCMP
+
+
+Building wpa_supplicant with mingw
+----------------------------------
+
+The default build setup for wpa_supplicant is to use MinGW and
+cross-compiling from Linux to MinGW/Windows. It should also be
+possible to build this under Windows using the MinGW tools, but that
+is not tested nor supported and is likely to require some changes to
+the Makefile unless cygwin is used.
+
+
+Building wpa_supplicant with MSVC
+---------------------------------
+
+wpa_supplicant can be built with Microsoft Visual C++ compiler. This
+has been tested with Microsoft Visual C++ Toolkit 2003 and Visual
+Studio 2005 using the included nmake.mak as a Makefile for nmake. IDE
+can also be used by creating a project that includes the files and
+defines mentioned in nmake.mak. Example VS2005 solution and project
+files are included in vs2005 subdirectory. This can be used as a
+starting point for building the programs with VS2005 IDE. Visual Studio
+2008 Express Edition is also able to use these project files.
+
+WinPcap development package is needed for the build and this can be
+downloaded from http://www.winpcap.org/install/bin/WpdPack_4_0_2.zip. The
+default nmake.mak expects this to be unpacked into C:\dev\WpdPack so
+that Include and Lib directories are in this directory. The files can be
+stored elsewhere as long as the WINPCAPDIR in nmake.mak is updated to
+match with the selected directory. In case a project file in the IDE is
+used, these Include and Lib directories need to be added to project
+properties as additional include/library directories.
+
+OpenSSL source package can be downloaded from
+http://www.openssl.org/source/openssl-0.9.8i.tar.gz and built and
+installed following instructions in INSTALL.W32. Note that if EAP-FAST
+support will be included in the wpa_supplicant, OpenSSL needs to be
+patched to# support it openssl-0.9.8i-tls-extensions.patch. The example
+nmake.mak file expects OpenSSL to be installed into C:\dev\openssl, but
+this directory can be modified by changing OPENSSLDIR variable in
+nmake.mak.
+
+If you do not need EAP-FAST support, you may also be able to use Win32
+binary installation package of OpenSSL from
+http://www.slproweb.com/products/Win32OpenSSL.html instead of building
+the library yourself. In this case, you will need to copy Include and
+Lib directories in suitable directory, e.g., C:\dev\openssl for the
+default nmake.mak. Copy {Win32OpenSSLRoot}\include into
+C:\dev\openssl\include and make C:\dev\openssl\lib subdirectory with
+files from {Win32OpenSSLRoot}\VC (i.e., libeay*.lib and ssleay*.lib).
+This will end up using dynamically linked OpenSSL (i.e., .dll files are
+needed) for it. Alternative, you can copy files from
+{Win32OpenSSLRoot}\VC\static to create a static build (no OpenSSL .dll
+files needed).
+
+
+Building wpa_supplicant for cygwin
+----------------------------------
+
+wpa_supplicant can be built for cygwin by installing the needed
+development packages for cygwin. This includes things like compiler,
+make, openssl development package, etc. In addition, developer's pack
+for WinPcap (WPdpack.zip) from
+http://winpcap.polito.it/install/default.htm is needed.
+
+.config file should enable only one driver interface,
+CONFIG_DRIVER_NDIS. In addition, include directories may need to be
+added to match the system. An example configuration is available in
+defconfig. The library and include files for WinPcap will either need
+to be installed in compiler/linker default directories or their
+location will need to be adding to .config when building
+wpa_supplicant.
+
+Othen than this, the build should be more or less identical to Linux
+version, i.e., just run make after having created .config file. An
+additional tool, win_if_list.exe, can be built by running "make
+win_if_list".
+
+
+Building wpa_gui
+----------------
+
+wpa_gui uses Qt application framework from Trolltech. It can be built
+with the open source version of Qt4 and MinGW. Following commands can
+be used to build the binary in the Qt 4 Command Prompt:
+
+# go to the root directory of wpa_supplicant source code
+cd wpa_gui-qt4
+qmake -o Makefile wpa_gui.pro
+make
+# the wpa_gui.exe binary is created into 'release' subdirectory
+
+
+Using wpa_supplicant for Windows
+--------------------------------
+
+wpa_supplicant, wpa_cli, and wpa_gui behave more or less identically to
+Linux version, so instructions in README and example wpa_supplicant.conf
+should be applicable for most parts. In addition, there is another
+version of wpa_supplicant, wpasvc.exe, which can be used as a Windows
+service and which reads its configuration from registry instead of
+text file.
+
+When using access points in "hidden SSID" mode, ap_scan=2 mode need to
+be used (see wpa_supplicant.conf for more information).
+
+Windows NDIS/WinPcap uses quite long interface names, so some care
+will be needed when starting wpa_supplicant. Alternatively, the
+adapter description can be used as the interface name which may be
+easier since it is usually in more human-readable
+format. win_if_list.exe can be used to find out the proper interface
+name.
+
+Example steps in starting up wpa_supplicant:
+
+# win_if_list.exe
+ifname: \Device\NPF_GenericNdisWanAdapter
+description: Generic NdisWan adapter
+
+ifname: \Device\NPF_{769E012B-FD17-4935-A5E3-8090C38E25D2}
+description: Atheros Wireless Network Adapter (Microsoft's Packet Scheduler)
+
+ifname: \Device\NPF_{732546E7-E26C-48E3-9871-7537B020A211}
+description: Intel 8255x-based Integrated Fast Ethernet (Microsoft's Packet Scheduler)
+
+
+Since the example configuration used Atheros WLAN card, the middle one
+is the correct interface in this case. The interface name for -i
+command line option is the full string following "ifname:" (the
+"\Device\NPF_" prefix can be removed). In other words, wpa_supplicant
+would be started with the following command:
+
+# wpa_supplicant.exe -i'{769E012B-FD17-4935-A5E3-8090C38E25D2}' -c wpa_supplicant.conf -d
+
+-d optional enables some more debugging (use -dd for even more, if
+needed). It can be left out if debugging information is not needed.
+
+With the alternative mechanism for selecting the interface, this
+command has identical results in this case:
+
+# wpa_supplicant.exe -iAtheros -c wpa_supplicant.conf -d
+
+
+Simple configuration example for WPA-PSK:
+
+#ap_scan=2
+ctrl_interface=
+network={
+ ssid="test"
+ key_mgmt=WPA-PSK
+ proto=WPA
+ pairwise=TKIP
+ psk="secret passphrase"
+}
+
+(remove '#' from the comment out ap_scan line to enable mode in which
+wpa_supplicant tries to associate with the SSID without doing
+scanning; this allows APs with hidden SSIDs to be used)
+
+
+wpa_cli.exe and wpa_gui.exe can be used to interact with the
+wpa_supplicant.exe program in the same way as with Linux. Note that
+ctrl_interface is using UNIX domain sockets when built for cygwin, but
+the native build for Windows uses named pipes and the contents of the
+ctrl_interface configuration item is used to control access to the
+interface. Anyway, this variable has to be included in the configuration
+to enable the control interface.
+
+
+Example SDDL string formats:
+
+(local admins group has permission, but nobody else):
+
+ctrl_interface=SDDL=D:(A;;GA;;;BA)
+
+("A" == "access allowed", "GA" == GENERIC_ALL == all permissions, and
+"BA" == "builtin administrators" == the local admins. The empty fields
+are for flags and object GUIDs, none of which should be required in this
+case.)
+
+(local admins and the local "power users" group have permissions,
+but nobody else):
+
+ctrl_interface=SDDL=D:(A;;GA;;;BA)(A;;GA;;;PU)
+
+(One ACCESS_ALLOWED ACE for GENERIC_ALL for builtin administrators, and
+one ACCESS_ALLOWED ACE for GENERIC_ALL for power users.)
+
+(close to wide open, but you have to be a valid user on
+the machine):
+
+ctrl_interface=SDDL=D:(A;;GA;;;AU)
+
+(One ACCESS_ALLOWED ACE for GENERIC_ALL for the "authenticated users"
+group.)
+
+This one would allow absolutely everyone (including anonymous
+users) -- this is *not* recommended, since named pipes can be attached
+to from anywhere on the network (i.e. there's no "this machine only"
+like there is with 127.0.0.1 sockets):
+
+ctrl_interface=SDDL=D:(A;;GA;;;BU)(A;;GA;;;AN)
+
+(BU == "builtin users", "AN" == "anonymous")
+
+See also [1] for the format of ACEs, and [2] for the possible strings
+that can be used for principal names.
+
+[1]
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/ace_strings.asp
+[2]
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/sid_strings.asp
+
+
+Starting wpa_supplicant as a Windows service (wpasvc.exe)
+---------------------------------------------------------
+
+wpa_supplicant can be started as a Windows service by using wpasvc.exe
+program that is alternative build of wpa_supplicant.exe. Most of the
+core functionality of wpasvc.exe is identical to wpa_supplicant.exe,
+but it is using Windows registry for configuration information instead
+of a text file and command line parameters. In addition, it can be
+registered as a service that can be started automatically or manually
+like any other Windows service.
+
+The root of wpa_supplicant configuration in registry is
+HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant. This level includes global
+parameters and a 'interfaces' subkey with all the interface configuration
+(adapter to confname mapping). Each such mapping is a subkey that has
+'adapter', 'config', and 'ctrl_interface' values.
+
+This program can be run either as a normal command line application,
+e.g., for debugging, with 'wpasvc.exe app' or as a Windows service.
+Service need to be registered with 'wpasvc.exe reg <full path to
+wpasvc.exe>'. Alternatively, 'wpasvc.exe reg' can be used to register
+the service with the current location of wpasvc.exe. After this, wpasvc
+can be started like any other Windows service (e.g., 'net start wpasvc')
+or it can be configured to start automatically through the Services tool
+in administrative tasks. The service can be unregistered with
+'wpasvc.exe unreg'.
+
+If the service is set to start during system bootup to make the
+network connection available before any user has logged in, there may
+be a long (half a minute or so) delay in starting up wpa_supplicant
+due to WinPcap needing a driver called "Network Monitor Driver" which
+is started by default on demand.
+
+To speed up wpa_supplicant start during system bootup, "Network
+Monitor Driver" can be configured to be started sooner by setting its
+startup type to System instead of the default Demand. To do this, open
+up Device Manager, select Show Hidden Devices, expand the "Non
+Plug-and-Play devices" branch, double click "Network Monitor Driver",
+go to the Driver tab, and change the Demand setting to System instead.
+
+Configuration data is in HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs
+key. Each configuration profile has its own key under this. In terms of text
+files, each profile would map to a separate text file with possibly multiple
+networks. Under each profile, there is a networks key that lists all
+networks as a subkey. Each network has set of values in the same way as
+network block in the configuration file. In addition, blobs subkey has
+possible blobs as values.
+
+HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
+ ssid="example"
+ key_mgmt=WPA-PSK
+
+See win_example.reg for an example on how to setup wpasvc.exe
+parameters in registry. It can also be imported to registry as a
+starting point for the configuration.
diff --git a/contrib/wpa/wpa_supplicant/android.config b/contrib/wpa/wpa_supplicant/android.config
new file mode 100644
index 0000000..6536c11
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/android.config
@@ -0,0 +1,545 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# wpa_supplicant 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 cases, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
+#CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+#CONFIG_DRIVER_NL80211=y
+CONFIG_LIBNL20=y
+
+# QCA vendor extensions to nl80211
+CONFIG_DRIVER_NL80211_QCA=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for wired Ethernet drivers
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+#CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-pwd (secure authentication using only a password)
+CONFIG_EAP_PWD=y
+
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+#CONFIG_USIM_SIMULATOR=y
+
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+#CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+# Enable WPS external registrar functionality
+CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# EAP-EKE
+#CONFIG_EAP_EKE=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# udp6 = UDP IPv6 sockets using localhost (::1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+CONFIG_WPA_CLI_EDIT=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+# path is given on command line, not here; this option is just used to
+# select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operating system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+CONFIG_ELOOP=eloop
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Should we use epoll instead of select? Select is used by default.
+#CONFIG_ELOOP_EPOLL=y
+
+# Should we use kqueue instead of select? Select is used by default.
+#CONFIG_ELOOP_KQUEUE=y
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+CONFIG_L2_PACKET=linux
+
+# Disable Linux packet socket workaround applicable for station interface
+# in a bridge for EAPOL frames. This should be uncommented only if the kernel
+# is known to not have the regression issue in packet socket behavior with
+# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
+#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
+
+# IEEE 802.11w (management frame protection), also known as PMF
+# Driver support is also needed for IEEE 802.11w.
+CONFIG_IEEE80211W=y
+
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+#CONFIG_TLSV12=y
+
+# Select which ciphers to use by default with OpenSSL if the user does not
+# specify them.
+#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW"
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for Binder control interface
+# Only applicable for Android platforms.
+#CONFIG_CTRL_IFACE_BINDER=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode
+CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
+CONFIG_ANDROID_LOG=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+
+# Wpa_supplicant's random pool is not necessary on Android. Randomness is
+# already provided by the entropymixer service which ensures sufficient
+# entropy is maintained across reboots. Commit b410eb1913 'Initialize
+# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before
+# either wpa_supplicant or hostapd are run.
+CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+CONFIG_IEEE80211N=y
+
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+CONFIG_WNM=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+CONFIG_HS20=y
+
+# Enable interface matching in wpa_supplicant
+#CONFIG_MATCH_IFACE=y
+
+# Disable roaming in wpa_supplicant
+CONFIG_NO_ROAMING=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+CONFIG_P2P=y
+
+# Enable TDLS support
+CONFIG_TDLS=y
+
+# Wi-Fi Display
+# This can be used to enable Wi-Fi Display extensions for P2P using an external
+# program to control the additional information exchanges in the messages.
+CONFIG_WIFI_DISPLAY=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
+
+# Enable Fast Session Transfer (FST)
+#CONFIG_FST=y
+
+# Support Multi Band Operation
+#CONFIG_MBO=y
+
+# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
+#CONFIG_FILS=y
+
+# Support RSN on IBSS networks
+# This is needed to be able to use mode=1 network profile with proto=RSN and
+# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None).
+#CONFIG_IBSS_RSN=y
+
+# External PMKSA cache control
+# This can be used to enable control interface commands that allow the current
+# PMKSA cache entries to be fetched and new entries to be added.
+#CONFIG_PMKSA_CACHE_EXTERNAL=y
+
+# Mesh Networking (IEEE 802.11s)
+#CONFIG_MESH=y
+
+# Background scanning modules
+# These can be used to request wpa_supplicant to perform background scanning
+# operations for roaming within an ESS (same SSID). See the bgscan parameter in
+# the wpa_supplicant.conf file for more details.
+# Periodic background scans based on signal strength
+#CONFIG_BGSCAN_SIMPLE=y
+# Learn channels used by the network and try to avoid bgscans on other
+# channels (experimental)
+#CONFIG_BGSCAN_LEARN=y
+
+# Opportunistic Wireless Encryption (OWE)
+# Experimental implementation of draft-harkins-owe-07.txt
+#CONFIG_OWE=y
+
+include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/contrib/wpa/wpa_supplicant/ap.c b/contrib/wpa/wpa_supplicant/ap.c
index 7a4f4cf..4e19169 100644
--- a/contrib/wpa/wpa_supplicant/ap.c
+++ b/contrib/wpa/wpa_supplicant/ap.c
@@ -46,40 +46,106 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
#ifdef CONFIG_IEEE80211N
static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
struct hostapd_config *conf,
struct hostapd_hw_modes *mode)
{
#ifdef CONFIG_P2P
u8 center_chan = 0;
u8 channel = conf->channel;
+#endif /* CONFIG_P2P */
if (!conf->secondary_channel)
goto no_vht;
- center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ /* Use the maximum oper channel width if it's given. */
+ if (ssid->max_oper_chwidth)
+ conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+
+ ieee80211_freq_to_chan(ssid->vht_center_freq2,
+ &conf->vht_oper_centr_freq_seg1_idx);
+
+ if (!ssid->p2p_group) {
+ if (!ssid->vht_center_freq1 ||
+ conf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
+ goto no_vht;
+ ieee80211_freq_to_chan(ssid->vht_center_freq1,
+ &conf->vht_oper_centr_freq_seg0_idx);
+ wpa_printf(MSG_DEBUG, "VHT seg0 index %d for AP",
+ conf->vht_oper_centr_freq_seg0_idx);
+ return;
+ }
+
+#ifdef CONFIG_P2P
+ switch (conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ case VHT_CHANWIDTH_80P80MHZ:
+ center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ wpa_printf(MSG_DEBUG,
+ "VHT center channel %u for 80 or 80+80 MHz bandwidth",
+ center_chan);
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+ wpa_printf(MSG_DEBUG,
+ "VHT center channel %u for 160 MHz bandwidth",
+ center_chan);
+ break;
+ default:
+ /*
+ * conf->vht_oper_chwidth might not be set for non-P2P GO cases,
+ * try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
+ * not supported.
+ */
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+ if (center_chan) {
+ wpa_printf(MSG_DEBUG,
+ "VHT center channel %u for auto-selected 160 MHz bandwidth",
+ center_chan);
+ } else {
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
+ channel);
+ wpa_printf(MSG_DEBUG,
+ "VHT center channel %u for auto-selected 80 MHz bandwidth",
+ center_chan);
+ }
+ break;
+ }
if (!center_chan)
goto no_vht;
- /* Use 80 MHz channel */
- conf->vht_oper_chwidth = 1;
conf->vht_oper_centr_freq_seg0_idx = center_chan;
+ wpa_printf(MSG_DEBUG, "VHT seg0 index %d for P2P GO",
+ conf->vht_oper_centr_freq_seg0_idx);
return;
+#endif /* CONFIG_P2P */
no_vht:
- conf->vht_oper_centr_freq_seg0_idx =
- channel + conf->secondary_channel * 2;
-#else /* CONFIG_P2P */
+ wpa_printf(MSG_DEBUG,
+ "No VHT higher bandwidth support for the selected channel %d",
+ conf->channel);
conf->vht_oper_centr_freq_seg0_idx =
conf->channel + conf->secondary_channel * 2;
-#endif /* CONFIG_P2P */
+ conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
}
#endif /* CONFIG_IEEE80211N */
-void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- struct hostapd_config *conf)
+int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
{
+ conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+ &conf->channel);
+
+ if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
+ ssid->frequency);
+ return -1;
+ }
+
/* TODO: enable HT40 if driver supports it;
* drop to 11b if driver does not support 11g */
@@ -93,6 +159,11 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
if (wpa_s->hw.modes) {
struct hostapd_hw_modes *mode = NULL;
int i, no_ht = 0;
+
+ wpa_printf(MSG_DEBUG,
+ "Determining HT/VHT options based on driver capabilities (freq=%u chan=%u)",
+ ssid->frequency, conf->channel);
+
for (i = 0; i < wpa_s->hw.num_modes; i++) {
if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
mode = &wpa_s->hw.modes[i];
@@ -101,27 +172,54 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
}
#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht) {
+ if (ssid->disable_ht)
+ ssid->ht = 0;
+#endif /* CONFIG_HT_OVERRIDES */
+
+ if (!ssid->ht) {
+ wpa_printf(MSG_DEBUG,
+ "HT not enabled in network profile");
conf->ieee80211n = 0;
conf->ht_capab = 0;
no_ht = 1;
}
-#endif /* CONFIG_HT_OVERRIDES */
if (!no_ht && mode && mode->ht_capab) {
+ wpa_printf(MSG_DEBUG,
+ "Enable HT support (p2p_group=%d 11a=%d ht40_hw_capab=%d ssid->ht40=%d)",
+ ssid->p2p_group,
+ conf->hw_mode == HOSTAPD_MODE_IEEE80211A,
+ !!(mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET),
+ ssid->ht40);
conf->ieee80211n = 1;
#ifdef CONFIG_P2P
- if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
+ if (ssid->p2p_group &&
+ conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
(mode->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
- ssid->ht40)
+ ssid->ht40) {
conf->secondary_channel =
wpas_p2p_get_ht40_mode(wpa_s, mode,
conf->channel);
+ wpa_printf(MSG_DEBUG,
+ "HT secondary channel offset %d for P2P group",
+ conf->secondary_channel);
+ }
+#endif /* CONFIG_P2P */
+
+ if (!ssid->p2p_group &&
+ (mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+ conf->secondary_channel = ssid->ht40;
+ wpa_printf(MSG_DEBUG,
+ "HT secondary channel offset %d for AP",
+ conf->secondary_channel);
+ }
+
if (conf->secondary_channel)
conf->ht_capab |=
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
-#endif /* CONFIG_P2P */
/*
* white-list capabilities that won't cause issues
@@ -138,7 +236,8 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
if (mode->vht_capab && ssid->vht) {
conf->ieee80211ac = 1;
- wpas_conf_ap_vht(wpa_s, conf, mode);
+ conf->vht_capab |= mode->vht_capab;
+ wpas_conf_ap_vht(wpa_s, ssid, conf, mode);
}
}
}
@@ -166,6 +265,8 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
}
}
#endif /* CONFIG_IEEE80211N */
+
+ return 0;
}
@@ -179,21 +280,31 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
- if (conf->hw_mode == NUM_HOSTAPD_MODES) {
- wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
- ssid->frequency);
+ if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf))
+ return -1;
+
+ if (ssid->pbss > 1) {
+ wpa_printf(MSG_ERROR, "Invalid pbss value(%d) for AP mode",
+ ssid->pbss);
return -1;
}
+ bss->pbss = ssid->pbss;
- wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+#ifdef CONFIG_ACS
+ if (ssid->acs) {
+ /* Setting channel to 0 in order to enable ACS */
+ conf->channel = 0;
+ wpa_printf(MSG_DEBUG, "Use automatic channel selection");
+ }
+#endif /* CONFIG_ACS */
- if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
+ if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
+ wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
conf->ieee80211h = 1;
conf->ieee80211d = 1;
conf->country[0] = wpa_s->conf->country[0];
conf->country[1] = wpa_s->conf->country[1];
+ conf->country[2] = ' ';
}
#ifdef CONFIG_P2P
@@ -225,16 +336,22 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
conf->supported_rates = list;
}
+#ifdef CONFIG_IEEE80211AX
+ if (ssid->mode == WPAS_MODE_P2P_GO ||
+ ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+ conf->ieee80211ax = ssid->he;
+#endif /* CONFIG_IEEE80211AX */
+
bss->isolate = !wpa_s->conf->p2p_intra_bss;
bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
if (ssid->p2p_group) {
- os_memcpy(bss->ip_addr_go, wpa_s->parent->conf->ip_addr_go, 4);
- os_memcpy(bss->ip_addr_mask, wpa_s->parent->conf->ip_addr_mask,
+ os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4);
+ os_memcpy(bss->ip_addr_mask, wpa_s->p2pdev->conf->ip_addr_mask,
4);
os_memcpy(bss->ip_addr_start,
- wpa_s->parent->conf->ip_addr_start, 4);
- os_memcpy(bss->ip_addr_end, wpa_s->parent->conf->ip_addr_end,
+ wpa_s->p2pdev->conf->ip_addr_start, 4);
+ os_memcpy(bss->ip_addr_end, wpa_s->p2pdev->conf->ip_addr_end,
4);
}
#endif /* CONFIG_P2P */
@@ -254,7 +371,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
bss->wpa = ssid->proto;
- bss->wpa_key_mgmt = ssid->key_mgmt;
+ if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ else
+ bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
if (ssid->psk_set) {
bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
@@ -263,6 +383,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
return -1;
os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
bss->ssid.wpa_psk->group = 1;
+ bss->ssid.wpa_psk_set = 1;
} else if (ssid->passphrase) {
bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
@@ -272,17 +393,34 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i] == 0)
continue;
- wep->key[i] = os_malloc(ssid->wep_key_len[i]);
+ wep->key[i] = os_memdup(ssid->wep_key[i],
+ ssid->wep_key_len[i]);
if (wep->key[i] == NULL)
return -1;
- os_memcpy(wep->key[i], ssid->wep_key[i],
- ssid->wep_key_len[i]);
wep->len[i] = ssid->wep_key_len[i];
}
wep->idx = ssid->wep_tx_keyidx;
wep->keys_set = 1;
}
+ if (wpa_s->conf->go_interworking) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Enable Interworking with access_network_type: %d",
+ wpa_s->conf->go_access_network_type);
+ bss->interworking = wpa_s->conf->go_interworking;
+ bss->access_network_type = wpa_s->conf->go_access_network_type;
+ bss->internet = wpa_s->conf->go_internet;
+ if (wpa_s->conf->go_venue_group) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Venue group: %d Venue type: %d",
+ wpa_s->conf->go_venue_group,
+ wpa_s->conf->go_venue_type);
+ bss->venue_group = wpa_s->conf->go_venue_group;
+ bss->venue_type = wpa_s->conf->go_venue_type;
+ bss->venue_info_set = 1;
+ }
+ }
+
if (ssid->ap_max_inactivity)
bss->ap_max_inactivity = ssid->ap_max_inactivity;
@@ -297,13 +435,17 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
conf->beacon_int = wpa_s->conf->beacon_int;
#ifdef CONFIG_P2P
- if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) {
- wpa_printf(MSG_INFO,
- "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it",
- wpa_s->conf->p2p_go_ctwindow, conf->beacon_int);
- conf->p2p_go_ctwindow = 0;
- } else {
- conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow;
+ if (ssid->mode == WPAS_MODE_P2P_GO ||
+ ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+ if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) {
+ wpa_printf(MSG_INFO,
+ "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it",
+ wpa_s->conf->p2p_go_ctwindow,
+ conf->beacon_int);
+ conf->p2p_go_ctwindow = 0;
+ } else {
+ conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow;
+ }
}
#endif /* CONFIG_P2P */
@@ -358,6 +500,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->ieee80211w = ssid->ieee80211w;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ bss->ocv = ssid->ocv;
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_WPS
/*
* Enable WPS by default for open and WPA/WPA2-Personal network, but
@@ -372,6 +518,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
!(bss->wpa & 2)))
goto no_wps; /* WPS2 does not allow WPA/TKIP-only
* configuration */
+ if (ssid->wps_disabled)
+ goto no_wps;
bss->eap_server = 1;
if (!ssid->ignore_broadcast_ssid)
@@ -400,6 +548,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1;
+ if (ssid->eap.fragment_size != DEFAULT_FRAGMENT_SIZE)
+ bss->fragment_size = ssid->eap.fragment_size;
no_wps:
#endif /* CONFIG_WPS */
@@ -409,6 +559,9 @@ no_wps:
else
bss->max_num_sta = wpa_s->conf->max_num_sta;
+ if (!bss->isolate)
+ bss->isolate = wpa_s->conf->ap_isolate;
+
bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
if (wpa_s->conf->ap_vendor_elements) {
@@ -416,6 +569,9 @@ no_wps:
wpabuf_dup(wpa_s->conf->ap_vendor_elements);
}
+ bss->ftm_responder = wpa_s->conf->ftm_responder;
+ bss->ftm_initiator = wpa_s->conf->ftm_initiator;
+
return 0;
}
@@ -448,14 +604,14 @@ static void ap_wps_event_cb(void *ctx, enum wps_event event,
if (event == WPS_EV_FAIL) {
struct wps_event_fail *fail = &data->fail;
- if (wpa_s->parent && wpa_s->parent != wpa_s &&
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s &&
wpa_s == wpa_s->global->p2p_group_formation) {
/*
* src/ap/wps_hostapd.c has already sent this on the
* main interface, so only send on the parent interface
* here if needed.
*/
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d",
fail->msg, fail->config_error);
}
@@ -530,6 +686,20 @@ static void wpas_ap_configured_cb(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
+ wpa_printf(MSG_DEBUG, "AP interface setup completed - state %s",
+ hostapd_state_text(wpa_s->ap_iface->state));
+ if (wpa_s->ap_iface->state == HAPD_IFACE_DISABLED) {
+ wpa_supplicant_ap_deinit(wpa_s);
+ return;
+ }
+
+#ifdef CONFIG_ACS
+ if (wpa_s->current_ssid && wpa_s->current_ssid->acs) {
+ wpa_s->assoc_freq = wpa_s->ap_iface->freq;
+ wpa_s->current_ssid->frequency = wpa_s->ap_iface->freq;
+ }
+#endif /* CONFIG_ACS */
+
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
if (wpa_s->ap_configured_cb)
@@ -595,22 +765,28 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
params.p2p = 1;
#endif /* CONFIG_P2P */
- if (wpa_s->parent->set_ap_uapsd)
- params.uapsd = wpa_s->parent->ap_uapsd;
+ if (wpa_s->p2pdev->set_ap_uapsd)
+ params.uapsd = wpa_s->p2pdev->ap_uapsd;
else if (params.p2p && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
params.uapsd = 1; /* mandatory for P2P GO */
else
params.uapsd = -1;
- if (ieee80211_is_dfs(params.freq.freq))
+ if (ieee80211_is_dfs(params.freq.freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes))
params.freq.freq = 0; /* set channel after CAC */
+ if (params.p2p)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_GO);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_AP_BSS);
+
if (wpa_drv_associate(wpa_s, &params) < 0) {
wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
return -1;
}
- wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface));
+ wpa_s->ap_iface = hapd_iface = hostapd_alloc_iface();
if (hapd_iface == NULL)
return -1;
hapd_iface->owner = wpa_s;
@@ -668,7 +844,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
}
hapd_iface->bss[i]->msg_ctx = wpa_s;
- hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent;
+ hapd_iface->bss[i]->msg_ctx_parent = wpa_s->p2pdev;
hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx;
@@ -705,6 +881,14 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
+#if defined(CONFIG_P2P) && defined(CONFIG_ACS)
+ if (wpa_s->p2p_go_do_acs) {
+ wpa_s->ap_iface->conf->channel = 0;
+ wpa_s->ap_iface->conf->hw_mode = wpa_s->p2p_go_acs_band;
+ ssid->acs = 1;
+ }
+#endif /* CONFIG_P2P && CONFIG_ACS */
+
if (hostapd_setup_interface(wpa_s->ap_iface)) {
wpa_printf(MSG_ERROR, "Failed to initialize AP interface");
wpa_supplicant_ap_deinit(wpa_s);
@@ -864,7 +1048,10 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
return -1;
if (pin == NULL) {
- unsigned int rpin = wps_generate_pin();
+ unsigned int rpin;
+
+ if (wps_generate_pin(&rpin) < 0)
+ return -1;
ret_len = os_snprintf(buf, buflen, "%08d", rpin);
if (os_snprintf_error(buflen, ret_len))
return -1;
@@ -930,7 +1117,8 @@ const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout)
if (wpa_s->ap_iface == NULL)
return NULL;
hapd = wpa_s->ap_iface->bss[0];
- pin = wps_generate_pin();
+ if (wps_generate_pin(&pin) < 0)
+ return NULL;
os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin);
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(pin_txt);
@@ -1201,13 +1389,16 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
int offset, int width, int cf1, int cf2)
{
- if (!wpa_s->ap_iface)
- return;
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface)
+ return;
wpa_s->assoc_freq = freq;
if (wpa_s->current_ssid)
wpa_s->current_ssid->frequency = freq;
- hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht,
+ hostapd_event_ch_switch(iface->bss[0], freq, ht,
offset, width, cf1, cf2);
}
@@ -1265,8 +1456,8 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
hapd = wpa_s->ap_iface->bss[0];
wps = hapd->wps;
- if (wpa_s->parent->conf->wps_nfc_dh_pubkey == NULL ||
- wpa_s->parent->conf->wps_nfc_dh_privkey == NULL) {
+ if (wpa_s->p2pdev->conf->wps_nfc_dh_pubkey == NULL ||
+ wpa_s->p2pdev->conf->wps_nfc_dh_privkey == NULL) {
wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known");
return -1;
}
@@ -1275,9 +1466,9 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
wpabuf_free(wps->dh_pubkey);
wpabuf_free(wps->dh_privkey);
wps->dh_privkey = wpabuf_dup(
- wpa_s->parent->conf->wps_nfc_dh_privkey);
+ wpa_s->p2pdev->conf->wps_nfc_dh_privkey);
wps->dh_pubkey = wpabuf_dup(
- wpa_s->parent->conf->wps_nfc_dh_pubkey);
+ wpa_s->p2pdev->conf->wps_nfc_dh_pubkey);
if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
wps->dh_ctx = NULL;
wpabuf_free(wps->dh_pubkey);
@@ -1308,66 +1499,175 @@ int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s)
hapd = wpa_s->ap_iface->bss[0];
return hostapd_ctrl_iface_stop_ap(hapd);
}
+
+
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+ size_t len)
+{
+ size_t reply_len = 0, i;
+ char ap_delimiter[] = "---- AP ----\n";
+ char mesh_delimiter[] = "---- mesh ----\n";
+ size_t dlen;
+
+ if (wpa_s->ap_iface) {
+ dlen = os_strlen(ap_delimiter);
+ if (dlen > len - reply_len)
+ return reply_len;
+ os_memcpy(&buf[reply_len], ap_delimiter, dlen);
+ reply_len += dlen;
+
+ for (i = 0; i < wpa_s->ap_iface->num_bss; i++) {
+ reply_len += hostapd_ctrl_iface_pmksa_list(
+ wpa_s->ap_iface->bss[i],
+ &buf[reply_len], len - reply_len);
+ }
+ }
+
+ if (wpa_s->ifmsh) {
+ dlen = os_strlen(mesh_delimiter);
+ if (dlen > len - reply_len)
+ return reply_len;
+ os_memcpy(&buf[reply_len], mesh_delimiter, dlen);
+ reply_len += dlen;
+
+ reply_len += hostapd_ctrl_iface_pmksa_list(
+ wpa_s->ifmsh->bss[0], &buf[reply_len],
+ len - reply_len);
+ }
+
+ return reply_len;
+}
+
+
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
+{
+ size_t i;
+
+ if (wpa_s->ap_iface) {
+ for (i = 0; i < wpa_s->ap_iface->num_bss; i++)
+ hostapd_ctrl_iface_pmksa_flush(wpa_s->ap_iface->bss[i]);
+ }
+
+ if (wpa_s->ifmsh)
+ hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]);
+}
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr,
+ char *buf, size_t len)
+{
+ return hostapd_ctrl_iface_pmksa_list_mesh(wpa_s->ifmsh->bss[0], addr,
+ &buf[0], len);
+}
+
+
+int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct external_pmksa_cache *entry;
+ void *pmksa_cache;
+
+ pmksa_cache = hostapd_ctrl_iface_pmksa_create_entry(wpa_s->own_addr,
+ cmd);
+ if (!pmksa_cache)
+ return -1;
+
+ entry = os_zalloc(sizeof(struct external_pmksa_cache));
+ if (!entry)
+ return -1;
+
+ entry->pmksa_cache = pmksa_cache;
+
+ dl_list_add(&wpa_s->mesh_external_pmksa_cache, &entry->list);
+
+ return 0;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
#endif /* CONFIG_CTRL_IFACE */
#ifdef NEED_AP_MLME
-void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
- hostapd_dfs_radar_detected(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_radar_detected(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width,
radar->cf1, radar->cf2);
}
-void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC started on %d MHz", radar->freq);
- hostapd_dfs_start_cac(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_start_cac(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
-void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
- hostapd_dfs_complete_cac(wpa_s->ap_iface, 1, radar->freq,
+ hostapd_dfs_complete_cac(iface, 1, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
-void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
- hostapd_dfs_complete_cac(wpa_s->ap_iface, 0, radar->freq,
+ hostapd_dfs_complete_cac(iface, 0, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
-void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
- hostapd_dfs_nop_finished(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_nop_finished(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
diff --git a/contrib/wpa/wpa_supplicant/ap.h b/contrib/wpa/wpa_supplicant/ap.h
index 594168c..447b551 100644
--- a/contrib/wpa/wpa_supplicant/ap.h
+++ b/contrib/wpa/wpa_supplicant/ap.h
@@ -76,22 +76,29 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
const struct wpabuf *pw, const u8 *pubkey_hash);
struct hostapd_config;
-void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- struct hostapd_config *conf);
+int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf);
int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
-void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+ size_t len);
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
+int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr,
+ char *buf, size_t len);
+int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd);
+
+void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
struct dfs_event *radar);
-void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar);
-void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar);
-void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar);
-void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
void ap_periodic(struct wpa_supplicant *wpa_s);
diff --git a/contrib/wpa/wpa_supplicant/autoscan.c b/contrib/wpa/wpa_supplicant/autoscan.c
index a2cf7a5..5056a93 100644
--- a/contrib/wpa/wpa_supplicant/autoscan.c
+++ b/contrib/wpa/wpa_supplicant/autoscan.c
@@ -1,6 +1,7 @@
/*
* WPA Supplicant - auto scan
* Copyright (c) 2012, Intel Corporation. All rights reserved.
+ * Copyright 2015 Intel Deutschland GmbH
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,13 +16,6 @@
#include "scan.h"
#include "autoscan.h"
-#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
-extern const struct autoscan_ops autoscan_exponential_ops;
-#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
-
-#ifdef CONFIG_AUTOSCAN_PERIODIC
-extern const struct autoscan_ops autoscan_periodic_ops;
-#endif /* CONFIG_AUTOSCAN_PERIODIC */
static const struct autoscan_ops * autoscan_modules[] = {
#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
@@ -50,9 +44,19 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
size_t nlen;
int i;
const struct autoscan_ops *ops = NULL;
+ struct sched_scan_plan *scan_plans;
- if (wpa_s->autoscan && wpa_s->autoscan_priv)
+ /* Give preference to scheduled scan plans if supported/configured */
+ if (wpa_s->sched_scan_plans) {
+ wpa_printf(MSG_DEBUG,
+ "autoscan: sched_scan_plans set - use it instead");
return 0;
+ }
+
+ if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+ wpa_printf(MSG_DEBUG, "autoscan: Already initialized");
+ return 0;
+ }
if (name == NULL)
return 0;
@@ -79,11 +83,23 @@ int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
return -1;
}
+ scan_plans = os_malloc(sizeof(*wpa_s->sched_scan_plans));
+ if (!scan_plans)
+ return -1;
+
wpa_s->autoscan_params = NULL;
wpa_s->autoscan_priv = ops->init(wpa_s, params);
- if (wpa_s->autoscan_priv == NULL)
+ if (!wpa_s->autoscan_priv) {
+ os_free(scan_plans);
return -1;
+ }
+
+ scan_plans[0].interval = 5;
+ scan_plans[0].iterations = 0;
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = scan_plans;
+ wpa_s->sched_scan_plans_num = 1;
wpa_s->autoscan = ops;
wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
@@ -116,7 +132,10 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s)
wpa_s->autoscan_priv = NULL;
wpa_s->scan_interval = 5;
- wpa_s->sched_scan_interval = 0;
+
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = NULL;
+ wpa_s->sched_scan_plans_num = 0;
}
}
@@ -134,7 +153,7 @@ int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
return -1;
wpa_s->scan_interval = interval;
- wpa_s->sched_scan_interval = interval;
+ wpa_s->sched_scan_plans[0].interval = interval;
request_scan(wpa_s);
}
diff --git a/contrib/wpa/wpa_supplicant/autoscan.h b/contrib/wpa/wpa_supplicant/autoscan.h
index e2a7652..560684f 100644
--- a/contrib/wpa/wpa_supplicant/autoscan.h
+++ b/contrib/wpa/wpa_supplicant/autoscan.h
@@ -27,6 +27,16 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s);
int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
+/* Available autoscan modules */
+
+#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+extern const struct autoscan_ops autoscan_exponential_ops;
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+extern const struct autoscan_ops autoscan_periodic_ops;
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+
#else /* CONFIG_AUTOSCAN */
static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
diff --git a/contrib/wpa/wpa_supplicant/bgscan.c b/contrib/wpa/wpa_supplicant/bgscan.c
index f74cdbf..1ea6401 100644
--- a/contrib/wpa/wpa_supplicant/bgscan.c
+++ b/contrib/wpa/wpa_supplicant/bgscan.c
@@ -13,12 +13,6 @@
#include "config_ssid.h"
#include "bgscan.h"
-#ifdef CONFIG_BGSCAN_SIMPLE
-extern const struct bgscan_ops bgscan_simple_ops;
-#endif /* CONFIG_BGSCAN_SIMPLE */
-#ifdef CONFIG_BGSCAN_LEARN
-extern const struct bgscan_ops bgscan_learn_ops;
-#endif /* CONFIG_BGSCAN_LEARN */
static const struct bgscan_ops * bgscan_modules[] = {
#ifdef CONFIG_BGSCAN_SIMPLE
@@ -40,8 +34,6 @@ int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
const struct bgscan_ops *ops = NULL;
bgscan_deinit(wpa_s);
- if (name == NULL)
- return -1;
params = os_strchr(name, ':');
if (params == NULL) {
diff --git a/contrib/wpa/wpa_supplicant/bgscan.h b/contrib/wpa/wpa_supplicant/bgscan.h
index 9131e4e..3df1550 100644
--- a/contrib/wpa/wpa_supplicant/bgscan.h
+++ b/contrib/wpa/wpa_supplicant/bgscan.h
@@ -39,6 +39,15 @@ void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
int current_signal, int current_noise,
int current_txrate);
+/* Available bgscan modules */
+
+#ifdef CONFIG_BGSCAN_SIMPLE
+extern const struct bgscan_ops bgscan_simple_ops;
+#endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+extern const struct bgscan_ops bgscan_learn_ops;
+#endif /* CONFIG_BGSCAN_LEARN */
+
#else /* CONFIG_BGSCAN */
static inline int bgscan_init(struct wpa_supplicant *wpa_s,
diff --git a/contrib/wpa/wpa_supplicant/bgscan_learn.c b/contrib/wpa/wpa_supplicant/bgscan_learn.c
index a320cc4..cb732f7 100644
--- a/contrib/wpa/wpa_supplicant/bgscan_learn.c
+++ b/contrib/wpa/wpa_supplicant/bgscan_learn.c
@@ -320,9 +320,6 @@ static int bgscan_learn_get_params(struct bgscan_learn_data *data,
{
const char *pos;
- if (params == NULL)
- return 0;
-
data->short_interval = atoi(params);
pos = os_strchr(params, ':');
diff --git a/contrib/wpa/wpa_supplicant/bgscan_simple.c b/contrib/wpa/wpa_supplicant/bgscan_simple.c
index a467cc5..41a26df 100644
--- a/contrib/wpa/wpa_supplicant/bgscan_simple.c
+++ b/contrib/wpa/wpa_supplicant/bgscan_simple.c
@@ -56,12 +56,7 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
} else {
if (data->scan_interval == data->short_interval) {
data->short_scan_count++;
- /*
- * Spend at most the duration of a long scan interval
- * scanning at the short scan interval. After that,
- * revert to the long scan interval.
- */
- if (data->short_scan_count > data->max_short_scans) {
+ if (data->short_scan_count >= data->max_short_scans) {
data->scan_interval = data->long_interval;
wpa_printf(MSG_DEBUG, "bgscan simple: Backing "
"off to long scan interval");
@@ -85,9 +80,6 @@ static int bgscan_simple_get_params(struct bgscan_simple_data *data,
{
const char *pos;
- if (params == NULL)
- return 0;
-
data->short_interval = atoi(params);
pos = os_strchr(params, ':');
diff --git a/contrib/wpa/wpa_supplicant/binder/.clang-format b/contrib/wpa/wpa_supplicant/binder/.clang-format
new file mode 100644
index 0000000..dbfdabf
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/.clang-format
@@ -0,0 +1,9 @@
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Mozilla
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+AccessModifierOffset: -8
+AlignAfterOpenBracket: AlwaysBreak
+SortIncludes: false
diff --git a/contrib/wpa/wpa_supplicant/binder/binder.cpp b/contrib/wpa/wpa_supplicant/binder/binder.cpp
new file mode 100644
index 0000000..750e878
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/binder.cpp
@@ -0,0 +1,104 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "binder_manager.h"
+
+extern "C" {
+#include "binder.h"
+#include "binder_i.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/includes.h"
+}
+
+void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_global *global = (wpa_global *)eloop_ctx;
+ struct wpas_binder_priv *priv = (wpas_binder_priv *)sock_ctx;
+
+ wpa_printf(
+ MSG_DEBUG, "Processing binder events on FD %d", priv->binder_fd);
+ android::IPCThreadState::self()->handlePolledCommands();
+}
+
+struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global)
+{
+ struct wpas_binder_priv *priv;
+ wpa_supplicant_binder::BinderManager *binder_manager;
+
+ priv = (wpas_binder_priv *)os_zalloc(sizeof(*priv));
+ if (!priv)
+ return NULL;
+ priv->global = global;
+
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
+ android::IPCThreadState::self()->disableBackgroundScheduling(true);
+ android::IPCThreadState::self()->setupPolling(&priv->binder_fd);
+ wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd);
+ if (priv->binder_fd < 0)
+ goto err;
+ /* Look for read events from the binder socket in the eloop. */
+ if (eloop_register_read_sock(
+ priv->binder_fd, wpas_binder_sock_handler, global, priv) < 0)
+ goto err;
+
+ binder_manager = wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ goto err;
+ binder_manager->registerBinderService(global);
+ /* We may not need to store this binder manager reference in the
+ * global data strucure because we've made it a singleton class. */
+ priv->binder_manager = (void *)binder_manager;
+
+ return priv;
+
+err:
+ wpas_binder_deinit(priv);
+ return NULL;
+}
+
+void wpas_binder_deinit(struct wpas_binder_priv *priv)
+{
+ if (!priv)
+ return;
+
+ wpa_supplicant_binder::BinderManager::destroyInstance();
+ eloop_unregister_read_sock(priv->binder_fd);
+ android::IPCThreadState::shutdown();
+}
+
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->binder)
+ return 1;
+
+ wpa_supplicant_binder::BinderManager *binder_manager =
+ wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ return 1;
+
+ return binder_manager->registerInterface(wpa_s);
+}
+
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->binder)
+ return 1;
+
+ wpa_supplicant_binder::BinderManager *binder_manager =
+ wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ return 1;
+
+ return binder_manager->unregisterInterface(wpa_s);
+}
diff --git a/contrib/wpa/wpa_supplicant/binder/binder.h b/contrib/wpa/wpa_supplicant/binder/binder.h
new file mode 100644
index 0000000..019e327
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/binder.h
@@ -0,0 +1,46 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_H
+#define WPA_SUPPLICANT_BINDER_BINDER_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif /* _cplusplus */
+
+/**
+ * This is the binder RPC interface entry point to the wpa_supplicant core.
+ * This initializes the binder driver & BinderManager instance and then forwards
+ * all the notifcations from the supplicant core to the BinderManager.
+ */
+struct wpas_binder_priv;
+struct wpa_global;
+
+struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global);
+void wpas_binder_deinit(struct wpas_binder_priv *priv);
+
+#ifdef CONFIG_CTRL_IFACE_BINDER
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s);
+#else /* CONFIG_CTRL_IFACE_BINDER */
+static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+#endif /* CONFIG_CTRL_IFACE_BINDER */
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_H */
diff --git a/contrib/wpa/wpa_supplicant/binder/binder_constants.cpp b/contrib/wpa/wpa_supplicant/binder/binder_constants.cpp
new file mode 100644
index 0000000..0d452b1
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/binder_constants.cpp
@@ -0,0 +1,18 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "binder_constants.h"
+
+namespace wpa_supplicant_binder {
+namespace binder_constants {
+
+const char kServiceName[] = "wpa_supplicant";
+
+} /* namespace binder_constants */
+} /* namespace wpa_supplicant_binder */
diff --git a/contrib/wpa/wpa_supplicant/binder/binder_constants.h b/contrib/wpa/wpa_supplicant/binder/binder_constants.h
new file mode 100644
index 0000000..a4d9b55
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/binder_constants.h
@@ -0,0 +1,21 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H
+#define WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H
+
+namespace wpa_supplicant_binder {
+namespace binder_constants {
+
+extern const char kServiceName[];
+
+} /* namespace binder_constants */
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H */
diff --git a/contrib/wpa/wpa_supplicant/binder/binder_i.h b/contrib/wpa/wpa_supplicant/binder/binder_i.h
new file mode 100644
index 0000000..5140d6d
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/binder_i.h
@@ -0,0 +1,28 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_I_H
+#define BINDER_I_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif // _cplusplus
+
+struct wpas_binder_priv
+{
+ int binder_fd;
+ struct wpa_global *global;
+ void *binder_manager;
+};
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* BINDER_I_H */
diff --git a/contrib/wpa/wpa_supplicant/binder/binder_manager.cpp b/contrib/wpa/wpa_supplicant/binder/binder_manager.cpp
new file mode 100644
index 0000000..27e8ded
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/binder_manager.cpp
@@ -0,0 +1,100 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IServiceManager.h>
+
+#include "binder_constants.h"
+#include "binder_manager.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+}
+
+namespace wpa_supplicant_binder {
+
+BinderManager *BinderManager::instance_ = NULL;
+
+BinderManager *BinderManager::getInstance()
+{
+ if (!instance_)
+ instance_ = new BinderManager();
+ return instance_;
+}
+
+void BinderManager::destroyInstance()
+{
+ if (instance_)
+ delete instance_;
+ instance_ = NULL;
+}
+
+int BinderManager::registerBinderService(struct wpa_global *global)
+{
+ /* Create the main binder service object and register with
+ * system service manager. */
+ supplicant_object_ = new Supplicant(global);
+ android::String16 service_name(binder_constants::kServiceName);
+ android::defaultServiceManager()->addService(
+ service_name, android::IInterface::asBinder(supplicant_object_));
+ return 0;
+}
+
+int BinderManager::registerInterface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return 1;
+
+ /* Using the corresponding wpa_supplicant pointer as key to our
+ * object map. */
+ const void *iface_key = wpa_s;
+
+ /* Return failure if we already have an object for that iface_key. */
+ if (iface_object_map_.find(iface_key) != iface_object_map_.end())
+ return 1;
+
+ iface_object_map_[iface_key] = new Iface(wpa_s);
+ if (!iface_object_map_[iface_key].get())
+ return 1;
+
+ wpa_s->binder_object_key = iface_key;
+
+ return 0;
+}
+
+int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return 1;
+
+ const void *iface_key = wpa_s;
+ if (iface_object_map_.find(iface_key) == iface_object_map_.end())
+ return 1;
+
+ /* Delete the corresponding iface object from our map. */
+ iface_object_map_.erase(iface_key);
+ wpa_s->binder_object_key = NULL;
+ return 0;
+}
+
+int BinderManager::getIfaceBinderObjectByKey(
+ const void *iface_object_key,
+ android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
+{
+ if (!iface_object_key || !iface_object)
+ return 1;
+
+ if (iface_object_map_.find(iface_object_key) == iface_object_map_.end())
+ return 1;
+
+ *iface_object = iface_object_map_[iface_object_key];
+ return 0;
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/contrib/wpa/wpa_supplicant/binder/binder_manager.h b/contrib/wpa/wpa_supplicant/binder/binder_manager.h
new file mode 100644
index 0000000..d8b7dd0
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/binder_manager.h
@@ -0,0 +1,58 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
+#define WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
+
+#include <map>
+#include <string>
+
+#include "iface.h"
+#include "supplicant.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+namespace wpa_supplicant_binder {
+
+/**
+ * BinderManager is responsible for managing the lifetime of all
+ * binder objects created by wpa_supplicant. This is a singleton
+ * class which is created by the supplicant core and can be used
+ * to get references to the binder objects.
+ */
+class BinderManager
+{
+public:
+ static BinderManager *getInstance();
+ static void destroyInstance();
+ int registerBinderService(struct wpa_global *global);
+ int registerInterface(struct wpa_supplicant *wpa_s);
+ int unregisterInterface(struct wpa_supplicant *wpa_s);
+ int getIfaceBinderObjectByKey(
+ const void *iface_object_key,
+ android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
+
+private:
+ BinderManager() = default;
+ ~BinderManager() = default;
+
+ /* Singleton instance of this class. */
+ static BinderManager *instance_;
+ /* The main binder service object. */
+ android::sp<Supplicant> supplicant_object_;
+ /* Map of all the interface specific binder objects controlled by
+ * wpa_supplicant. This map is keyed in by the corresponding
+ * wpa_supplicant structure pointer. */
+ std::map<const void *, android::sp<Iface>> iface_object_map_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H */
diff --git a/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl b/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
new file mode 100644
index 0000000..ea11d42
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
@@ -0,0 +1,16 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+/**
+ * Interface exposed by wpa_supplicant for each network interface it controls.
+ */
+interface IIface {
+}
diff --git a/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
new file mode 100644
index 0000000..1cbee20a
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
@@ -0,0 +1,59 @@
+/*
+ * WPA Supplicant - binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+import fi.w1.wpa_supplicant.IIface;
+
+/**
+ * Interface exposed by the wpa_supplicant binder service registered
+ * with the service manager with name: fi.w1.wpa_supplicant.
+ */
+interface ISupplicant {
+ /* Error values returned by the service to RPC method calls. */
+ const int ERROR_INVALID_ARGS = 1;
+ const int ERROR_UNKNOWN = 2;
+ const int ERROR_IFACE_EXISTS = 3;
+ const int ERROR_IFACE_UNKNOWN = 4;
+
+ /**
+ * Registers a wireless interface in wpa_supplicant.
+ *
+ * @param args A dictionary with arguments used to add the interface to
+ * wpa_supplicant.
+ * The dictionary may contain the following entries:
+ * Ifname(String) Name of the network interface to control, e.g.,
+ * wlan0.
+ * BridgeIfname(String) Name of the bridge interface to control, e.g.,
+ * br0.
+ * Driver(String) Driver name which the interface uses, e.g., nl80211.
+ * ConfigFile(String) Configuration file path.
+ *
+ * @return Binder object representing the interface.
+ */
+ IIface CreateInterface(in PersistableBundle args);
+
+ /**
+ * Deregisters a wireless interface from wpa_supplicant.
+ *
+ * @param ifname Name of the network interface, e.g., wlan0
+ */
+ void RemoveInterface(in @utf8InCpp String ifname);
+
+ /**
+ * Gets a binder object for the interface corresponding to ifname
+ * which wpa_supplicant already controls.
+ *
+ * @param ifname Name of the network interface, e.g., wlan0
+ *
+ * @return Binder object representing the interface.
+ */
+ IIface GetInterface(in @utf8InCpp String ifname);
+}
diff --git a/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl b/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
new file mode 100644
index 0000000..d624d91
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
@@ -0,0 +1,20 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+
+/**
+ * Callback Interface exposed by the wpa_supplicant service. Clients need
+ * to host an instance of this binder object and pass a reference of the object
+ * to wpa_supplicant via the registerCallbacksObject method.
+ */
+interface ISupplicantCallbacks {
+}
diff --git a/contrib/wpa/wpa_supplicant/binder/iface.cpp b/contrib/wpa/wpa_supplicant/binder/iface.cpp
new file mode 100644
index 0000000..c61b3b0
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/iface.cpp
@@ -0,0 +1,16 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "iface.h"
+
+namespace wpa_supplicant_binder {
+
+Iface::Iface(struct wpa_supplicant *wpa_s) : wpa_s_(wpa_s) {}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/contrib/wpa/wpa_supplicant/binder/iface.h b/contrib/wpa/wpa_supplicant/binder/iface.h
new file mode 100644
index 0000000..c0ee12c
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/iface.h
@@ -0,0 +1,42 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_IFACE_H
+#define WPA_SUPPLICANT_BINDER_IFACE_H
+
+#include "fi/w1/wpa_supplicant/BnIface.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of Iface binder object. Each unique binder
+ * object is used for control operations on a specific interface
+ * controlled by wpa_supplicant.
+ */
+class Iface : public fi::w1::wpa_supplicant::BnIface
+{
+public:
+ Iface(struct wpa_supplicant *wpa_s);
+ virtual ~Iface() = default;
+
+private:
+ /* Raw pointer to the structure maintained by the core for this
+ * interface. */
+ struct wpa_supplicant *wpa_s_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_IFACE_H */
diff --git a/contrib/wpa/wpa_supplicant/binder/supplicant.cpp b/contrib/wpa/wpa_supplicant/binder/supplicant.cpp
new file mode 100644
index 0000000..76569b1
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/supplicant.cpp
@@ -0,0 +1,127 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "supplicant.h"
+#include "binder_manager.h"
+
+namespace wpa_supplicant_binder {
+
+Supplicant::Supplicant(struct wpa_global *global) : wpa_global_(global) {}
+
+android::binder::Status Supplicant::CreateInterface(
+ const android::os::PersistableBundle &params,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+ android::String16 driver, ifname, confname, bridge_ifname;
+
+ /* Check if required Ifname argument is missing */
+ if (!params.getString(android::String16("Ifname"), &ifname))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_INVALID_ARGS,
+ android::String8("Ifname missing in params."));
+ /* Retrieve the remaining params from the dictionary */
+ params.getString(android::String16("Driver"), &driver);
+ params.getString(android::String16("ConfigFile"), &confname);
+ params.getString(android::String16("BridgeIfname"), &bridge_ifname);
+
+ /*
+ * Try to get the wpa_supplicant record for this iface, return
+ * an error if we already control it.
+ */
+ if (wpa_supplicant_get_iface(
+ wpa_global_, android::String8(ifname).string()) != NULL)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_EXISTS,
+ android::String8("wpa_supplicant already controls this "
+ "interface."));
+
+ android::binder::Status status;
+ struct wpa_supplicant *wpa_s = NULL;
+ struct wpa_interface iface;
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.driver = os_strdup(android::String8(driver).string());
+ iface.ifname = os_strdup(android::String8(ifname).string());
+ iface.confname = os_strdup(android::String8(confname).string());
+ iface.bridge_ifname =
+ os_strdup(android::String8(bridge_ifname).string());
+ /* Otherwise, have wpa_supplicant attach to it. */
+ wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL);
+ /* The supplicant core creates a corresponding binder object via
+ * BinderManager when |wpa_supplicant_add_iface| is called. */
+ if (!wpa_s || !wpa_s->binder_object_key) {
+ status = android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8(
+ "wpa_supplicant couldn't grab this interface."));
+ } else {
+ BinderManager *binder_manager = BinderManager::getInstance();
+
+ if (!binder_manager ||
+ binder_manager->getIfaceBinderObjectByKey(
+ wpa_s->binder_object_key, aidl_return))
+ status =
+ android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8("wpa_supplicant encountered a "
+ "binder error."));
+ else
+ status = android::binder::Status::ok();
+ }
+ os_free((void *)iface.driver);
+ os_free((void *)iface.ifname);
+ os_free((void *)iface.confname);
+ os_free((void *)iface.bridge_ifname);
+ return status;
+}
+
+android::binder::Status Supplicant::RemoveInterface(const std::string &ifname)
+{
+ struct wpa_supplicant *wpa_s;
+
+ wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_UNKNOWN,
+ android::String8("wpa_supplicant does not control this "
+ "interface."));
+ if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8(
+ "wpa_supplicant couldn't remove this interface."));
+ return android::binder::Status::ok();
+}
+
+android::binder::Status Supplicant::GetInterface(
+ const std::string &ifname,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+ struct wpa_supplicant *wpa_s;
+
+ wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+ if (!wpa_s || !wpa_s->binder_object_key)
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_IFACE_UNKNOWN,
+ android::String8(
+ "wpa_supplicant does not control this interface."));
+
+ BinderManager *binder_manager = BinderManager::getInstance();
+ if (!binder_manager ||
+ binder_manager->getIfaceBinderObjectByKey(
+ wpa_s->binder_object_key, aidl_return))
+ return android::binder::Status::fromServiceSpecificError(
+ ERROR_UNKNOWN,
+ android::String8(
+ "wpa_supplicant encountered a binder error."));
+
+ return android::binder::Status::ok();
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/contrib/wpa/wpa_supplicant/binder/supplicant.h b/contrib/wpa/wpa_supplicant/binder/supplicant.h
new file mode 100644
index 0000000..136b99b
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/binder/supplicant.h
@@ -0,0 +1,55 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_SUPPLICANT_H
+#define WPA_SUPPLICANT_BINDER_SUPPLICANT_H
+
+#include "fi/w1/wpa_supplicant/BnSupplicant.h"
+#include "fi/w1/wpa_supplicant/IIface.h"
+#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of the supplicant binder object. This binder
+ * object is used core for global control operations on
+ * wpa_supplicant.
+ */
+class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant
+{
+public:
+ Supplicant(struct wpa_global *global);
+ virtual ~Supplicant() = default;
+
+ android::binder::Status CreateInterface(
+ const android::os::PersistableBundle &params,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override;
+ android::binder::Status
+ RemoveInterface(const std::string &ifname) override;
+ android::binder::Status GetInterface(
+ const std::string &ifname,
+ android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override;
+
+private:
+ /* Raw pointer to the global structure maintained by the core. */
+ struct wpa_global *wpa_global_;
+ /* All the callback objects registered by the clients. */
+ std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallbacks>>
+ callbacks_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_SUPPLICANT_H */
diff --git a/contrib/wpa/wpa_supplicant/bss.c b/contrib/wpa/wpa_supplicant/bss.c
index 1051ee3..9b19f37 100644
--- a/contrib/wpa/wpa_supplicant/bss.c
+++ b/contrib/wpa/wpa_supplicant/bss.c
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "drivers/driver.h"
+#include "eap_peer/eap.h"
#include "wpa_supplicant_i.h"
#include "config.h"
#include "notify.h"
@@ -60,6 +61,9 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
anqp = os_zalloc(sizeof(*anqp));
if (anqp == NULL)
return NULL;
+#ifdef CONFIG_INTERWORKING
+ dl_list_init(&anqp->anqp_elems);
+#endif /* CONFIG_INTERWORKING */
anqp->users = 1;
return anqp;
}
@@ -80,6 +84,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
#ifdef CONFIG_INTERWORKING
+ dl_list_init(&n->anqp_elems);
ANQP_DUP(capability_list);
ANQP_DUP(venue_name);
ANQP_DUP(network_auth_type);
@@ -88,6 +93,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
ANQP_DUP(nai_realm);
ANQP_DUP(anqp_3gpp);
ANQP_DUP(domain_name);
+ ANQP_DUP(fils_realm_info);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
ANQP_DUP(hs20_capability_list);
@@ -96,6 +102,8 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
ANQP_DUP(hs20_connection_capability);
ANQP_DUP(hs20_operating_class);
ANQP_DUP(hs20_osu_providers_list);
+ ANQP_DUP(hs20_operator_icon_metadata);
+ ANQP_DUP(hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
#undef ANQP_DUP
@@ -141,6 +149,10 @@ int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
*/
static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
{
+#ifdef CONFIG_INTERWORKING
+ struct wpa_bss_anqp_elem *elem;
+#endif /* CONFIG_INTERWORKING */
+
if (anqp == NULL)
return;
@@ -159,6 +171,14 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
wpabuf_free(anqp->nai_realm);
wpabuf_free(anqp->anqp_3gpp);
wpabuf_free(anqp->domain_name);
+ wpabuf_free(anqp->fils_realm_info);
+
+ while ((elem = dl_list_first(&anqp->anqp_elems,
+ struct wpa_bss_anqp_elem, list))) {
+ dl_list_del(&elem->list);
+ wpabuf_free(elem->payload);
+ os_free(elem);
+ }
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
wpabuf_free(anqp->hs20_capability_list);
@@ -167,6 +187,8 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
wpabuf_free(anqp->hs20_connection_capability);
wpabuf_free(anqp->hs20_operating_class);
wpabuf_free(anqp->hs20_osu_providers_list);
+ wpabuf_free(anqp->hs20_operator_icon_metadata);
+ wpabuf_free(anqp->hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
os_free(anqp);
@@ -198,8 +220,8 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
}
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- const char *reason)
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const char *reason)
{
if (wpa_s->last_scan_res) {
unsigned int i;
@@ -251,9 +273,9 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
}
-static void calculate_update_time(const struct os_reltime *fetch_time,
- unsigned int age_ms,
- struct os_reltime *update_time)
+void calculate_update_time(const struct os_reltime *fetch_time,
+ unsigned int age_ms,
+ struct os_reltime *update_time)
{
os_time_t usec;
@@ -288,6 +310,47 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
}
+static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+#ifdef CONFIG_WPS
+ struct wpa_ssid *ssid;
+ struct wpabuf *wps_ie;
+ int pbc = 0, ret;
+
+ wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ if (!wps_ie)
+ return 0;
+
+ if (wps_is_selected_pbc_registrar(wps_ie)) {
+ pbc = 1;
+ } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
+ wpabuf_free(wps_ie);
+ return 0;
+ }
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+ continue;
+ if (ssid->ssid_len &&
+ (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
+ continue;
+
+ if (pbc)
+ ret = eap_is_wps_pbc_enrollee(&ssid->eap);
+ else
+ ret = eap_is_wps_pin_enrollee(&ssid->eap);
+ wpabuf_free(wps_ie);
+ return ret;
+ }
+ wpabuf_free(wps_ie);
+#endif /* CONFIG_WPS */
+
+ return 0;
+}
+
+
static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
struct wpa_ssid *ssid;
@@ -326,7 +389,8 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
struct wpa_bss *bss;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- if (!wpa_bss_known(wpa_s, bss)) {
+ if (!wpa_bss_known(wpa_s, bss) &&
+ !wpa_bss_is_wps_candidate(wpa_s, bss)) {
wpa_bss_remove(wpa_s, bss, __func__);
return 0;
}
@@ -537,6 +601,42 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
{
u32 changes;
+ if (bss->last_update_idx == wpa_s->bss_update_idx) {
+ struct os_reltime update_time;
+
+ /*
+ * Some drivers (e.g., cfg80211) include multiple BSS entries
+ * for the same BSS if that BSS's channel changes. The BSS list
+ * implementation in wpa_supplicant does not do that and we need
+ * to filter out the obsolete results here to make sure only the
+ * most current BSS information remains in the table.
+ */
+ wpa_printf(MSG_DEBUG, "BSS: " MACSTR
+ " has multiple entries in the scan results - select the most current one",
+ MAC2STR(bss->bssid));
+ calculate_update_time(fetch_time, res->age, &update_time);
+ wpa_printf(MSG_DEBUG,
+ "Previous last_update: %u.%06u (freq %d%s)",
+ (unsigned int) bss->last_update.sec,
+ (unsigned int) bss->last_update.usec,
+ bss->freq,
+ (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
+ wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
+ (unsigned int) update_time.sec,
+ (unsigned int) update_time.usec,
+ res->freq,
+ (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
+ if ((bss->flags & WPA_BSS_ASSOCIATED) ||
+ (!(res->flags & WPA_SCAN_ASSOCIATED) &&
+ !os_reltime_before(&bss->last_update, &update_time))) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore this BSS entry since the previous update looks more current");
+ return bss;
+ }
+ wpa_printf(MSG_DEBUG,
+ "Accept this BSS entry since it looks more current than the previous update");
+ }
+
changes = wpa_bss_compare_res(bss, res);
if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
@@ -784,7 +884,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
struct wpa_bss *bss, *n;
os_get_reltime(&wpa_s->last_scan);
- if (!new_scan)
+ if ((info && info->aborted) || !new_scan)
return; /* do not expire entries without new scan */
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
@@ -1004,20 +1104,7 @@ struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
*/
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
{
- const u8 *end, *pos;
-
- pos = (const u8 *) (bss + 1);
- end = pos + bss->ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
+ return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
}
@@ -1037,8 +1124,8 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
pos = (const u8 *) (bss + 1);
end = pos + bss->ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1074,8 +1161,8 @@ const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
pos += bss->ie_len;
end = pos + bss->beacon_ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1110,8 +1197,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
pos = (const u8 *) (bss + 1);
end = pos + bss->ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1155,8 +1242,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
pos += bss->ie_len;
end = pos + bss->beacon_ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1234,3 +1321,26 @@ int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
*rates = r;
return len;
}
+
+
+#ifdef CONFIG_FILS
+const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss)
+{
+ const u8 *ie;
+
+ if (bss) {
+ ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+ if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7))
+ return ie + 4;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_FILS */
+
+
+int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
+{
+ return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
+ capab);
+}
diff --git a/contrib/wpa/wpa_supplicant/bss.h b/contrib/wpa/wpa_supplicant/bss.h
index b215380..3ce8cd3 100644
--- a/contrib/wpa/wpa_supplicant/bss.h
+++ b/contrib/wpa/wpa_supplicant/bss.h
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,12 @@ struct wpa_scan_res;
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+struct wpa_bss_anqp_elem {
+ struct dl_list list;
+ u16 infoid;
+ struct wpabuf *payload;
+};
+
/**
* struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
*/
@@ -34,6 +40,8 @@ struct wpa_bss_anqp {
struct wpabuf *nai_realm;
struct wpabuf *anqp_3gpp;
struct wpabuf *domain_name;
+ struct wpabuf *fils_realm_info;
+ struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
struct wpabuf *hs20_capability_list;
@@ -42,6 +50,8 @@ struct wpa_bss_anqp {
struct wpabuf *hs20_connection_capability;
struct wpabuf *hs20_operating_class;
struct wpabuf *hs20_osu_providers_list;
+ struct wpabuf *hs20_operator_icon_metadata;
+ struct wpabuf *hs20_osu_providers_nai_list;
#endif /* CONFIG_HS20 */
};
@@ -106,6 +116,8 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res,
struct os_reltime *fetch_time);
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const char *reason);
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan);
int wpa_bss_init(struct wpa_supplicant *wpa_s);
@@ -135,16 +147,33 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
+const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss);
+int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab);
static inline int bss_is_dmg(const struct wpa_bss *bss)
{
return bss->freq > 45000;
}
+/**
+ * Test whether a BSS is a PBSS.
+ * This checks whether a BSS is a DMG-band PBSS. PBSS is used for P2P DMG
+ * network.
+ */
+static inline int bss_is_pbss(struct wpa_bss *bss)
+{
+ return bss_is_dmg(bss) &&
+ (bss->caps & IEEE80211_CAP_DMG_MASK) == IEEE80211_CAP_DMG_PBSS;
+}
+
static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level)
{
if (bss != NULL && new_level < 0)
bss->level = new_level;
}
+void calculate_update_time(const struct os_reltime *fetch_time,
+ unsigned int age_ms,
+ struct os_reltime *update_time);
+
#endif /* BSS_H */
diff --git a/contrib/wpa/wpa_supplicant/config.c b/contrib/wpa/wpa_supplicant/config.c
index b1adab7..2058175 100644
--- a/contrib/wpa/wpa_supplicant/config.c
+++ b/contrib/wpa/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "common.h"
#include "utils/uuid.h"
#include "utils/ip_addr.h"
+#include "common/ieee802_1x_defs.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -32,7 +33,11 @@ struct parse_data {
/* Configuration variable name */
char *name;
- /* Parser function for this variable */
+ /* Parser function for this variable. The parser functions return 0 or 1
+ * to indicate success. Value 0 indicates that the parameter value may
+ * have changed while value 1 means that the value did not change.
+ * Error cases (failure to parse the string) are indicated by returning
+ * -1. */
int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
int line, const char *value);
@@ -59,7 +64,7 @@ static int wpa_config_parse_str(const struct parse_data *data,
struct wpa_ssid *ssid,
int line, const char *value)
{
- size_t res_len, *dst_len;
+ size_t res_len, *dst_len, prev_len;
char **dst, *tmp;
if (os_strcmp(value, "NULL") == 0) {
@@ -105,6 +110,21 @@ static int wpa_config_parse_str(const struct parse_data *data,
set:
dst = (char **) (((u8 *) ssid) + (long) data->param1);
dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+
+ if (data->param2)
+ prev_len = *dst_len;
+ else if (*dst)
+ prev_len = os_strlen(*dst);
+ else
+ prev_len = 0;
+ if ((*dst == NULL && tmp == NULL) ||
+ (*dst && tmp && prev_len == res_len &&
+ os_memcmp(*dst, tmp, res_len) == 0)) {
+ /* No change to the previously configured value */
+ os_free(tmp);
+ return 1;
+ }
+
os_free(*dst);
*dst = tmp;
if (data->param2)
@@ -190,6 +210,9 @@ static int wpa_config_parse_int(const struct parse_data *data,
line, value);
return -1;
}
+
+ if (*dst == val)
+ return 1;
*dst = val;
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
@@ -374,6 +397,50 @@ static char * wpa_config_write_bssid(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_bssid_hint(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+ os_strcmp(value, "any") == 0) {
+ ssid->bssid_hint_set = 0;
+ wpa_printf(MSG_MSGDUMP, "BSSID hint any");
+ return 0;
+ }
+ if (hwaddr_aton(value, ssid->bssid_hint)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID hint '%s'.",
+ line, value);
+ return -1;
+ }
+ ssid->bssid_hint_set = 1;
+ wpa_hexdump(MSG_MSGDUMP, "BSSID hint", ssid->bssid_hint, ETH_ALEN);
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_hint(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value;
+ int res;
+
+ if (!ssid->bssid_hint_set)
+ return NULL;
+
+ value = os_malloc(20);
+ if (!value)
+ return NULL;
+ res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid_hint));
+ if (os_snprintf_error(20, res)) {
+ os_free(value);
+ return NULL;
+ }
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -456,9 +523,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
(u8 *) value, len);
+ if (has_ctrl_char((u8 *) value, len)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid passphrase character",
+ line);
+ return -1;
+ }
if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
- os_memcmp(ssid->passphrase, value, len) == 0)
- return 0;
+ os_memcmp(ssid->passphrase, value, len) == 0) {
+ /* No change to the previously configured value */
+ return 1;
+ }
ssid->psk_set = 0;
str_clear_free(ssid->passphrase);
ssid->passphrase = dup_binstr(value, len);
@@ -569,6 +644,8 @@ static int wpa_config_parse_proto(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->proto == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
ssid->proto = val;
return errors ? -1 : 0;
@@ -658,6 +735,10 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
val |= WPA_KEY_MGMT_FT_PSK;
else if (os_strcmp(start, "FT-EAP") == 0)
val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#ifdef CONFIG_SHA384
+ else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
@@ -687,6 +768,26 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ else if (os_strcmp(start, "FILS-SHA256") == 0)
+ val |= WPA_KEY_MGMT_FILS_SHA256;
+ else if (os_strcmp(start, "FILS-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FILS_SHA384;
+#ifdef CONFIG_IEEE80211R
+ else if (os_strcmp(start, "FT-FILS-SHA256") == 0)
+ val |= WPA_KEY_MGMT_FT_FILS_SHA256;
+ else if (os_strcmp(start, "FT-FILS-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FT_FILS_SHA384;
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ else if (os_strcmp(start, "OWE") == 0)
+ val |= WPA_KEY_MGMT_OWE;
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ else if (os_strcmp(start, "DPP") == 0)
+ val |= WPA_KEY_MGMT_DPP;
+#endif /* CONFIG_DPP */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -705,6 +806,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->key_mgmt == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
ssid->key_mgmt = val;
return errors ? -1 : 0;
@@ -793,6 +896,18 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
}
pos += ret;
}
+
+#ifdef CONFIG_SHA384
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ ret = os_snprintf(pos, end - pos, "%sFT-EAP-SHA384",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
@@ -887,6 +1002,71 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
}
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sFILS-SHA256",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "%sFILS-SHA384",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_DPP
+ if (ssid->key_mgmt & WPA_KEY_MGMT_DPP) {
+ ret = os_snprintf(pos, end - pos, "%sDPP",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_OWE
+ if (ssid->key_mgmt & WPA_KEY_MGMT_OWE) {
+ ret = os_snprintf(pos, end - pos, "%sOWE",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_OWE */
+
if (pos == buf) {
os_free(buf);
buf = NULL;
@@ -899,6 +1079,9 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
static int wpa_config_parse_cipher(int line, const char *value)
{
+#ifdef CONFIG_NO_WPA
+ return -1;
+#else /* CONFIG_NO_WPA */
int val = wpa_parse_cipher(value);
if (val < 0) {
wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
@@ -911,12 +1094,16 @@ static int wpa_config_parse_cipher(int line, const char *value)
return -1;
}
return val;
+#endif /* CONFIG_NO_WPA */
}
#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_cipher(int cipher)
{
+#ifdef CONFIG_NO_WPA
+ return NULL;
+#else /* CONFIG_NO_WPA */
char *buf = os_zalloc(50);
if (buf == NULL)
return NULL;
@@ -927,6 +1114,7 @@ static char * wpa_config_write_cipher(int cipher)
}
return buf;
+#endif /* CONFIG_NO_WPA */
}
#endif /* NO_CONFIG_WRITE */
@@ -945,6 +1133,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
return -1;
}
+ if (ssid->pairwise_cipher == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
ssid->pairwise_cipher = val;
return 0;
@@ -981,6 +1171,8 @@ static int wpa_config_parse_group(const struct parse_data *data,
return -1;
}
+ if (ssid->group_cipher == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
ssid->group_cipher = val;
return 0;
@@ -996,6 +1188,40 @@ static char * wpa_config_write_group(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_group_mgmt(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ int val;
+
+ val = wpa_config_parse_cipher(line, value);
+ if (val == -1)
+ return -1;
+
+ if (val & ~WPA_ALLOWED_GROUP_MGMT_CIPHERS) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: not allowed group management cipher (0x%x).",
+ line, val);
+ return -1;
+ }
+
+ if (ssid->group_mgmt_cipher == val)
+ return 1;
+ wpa_printf(MSG_MSGDUMP, "group_mgmt: 0x%x", val);
+ ssid->group_mgmt_cipher = val;
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_group_mgmt(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_cipher(ssid->group_mgmt_cipher);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
static int wpa_config_parse_auth_alg(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -1042,6 +1268,8 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
errors++;
}
+ if (!errors && ssid->auth_alg == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
ssid->auth_alg = val;
return errors ? -1 : 0;
@@ -1296,6 +1524,32 @@ static int wpa_config_parse_eap(const struct parse_data *data,
methods[num_methods].method = EAP_TYPE_NONE;
num_methods++;
+ if (!errors && ssid->eap.eap_methods) {
+ struct eap_method_type *prev_m;
+ size_t i, j, prev_methods, match = 0;
+
+ prev_m = ssid->eap.eap_methods;
+ for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
+ prev_m[i].method != EAP_TYPE_NONE; i++) {
+ /* Count the methods */
+ }
+ prev_methods = i + 1;
+
+ for (i = 0; prev_methods == num_methods && i < prev_methods;
+ i++) {
+ for (j = 0; j < num_methods; j++) {
+ if (prev_m[i].vendor == methods[j].vendor &&
+ prev_m[i].method == methods[j].method) {
+ match++;
+ break;
+ }
+ }
+ }
+ if (match == num_methods) {
+ os_free(methods);
+ return 1;
+ }
+ }
wpa_hexdump(MSG_MSGDUMP, "eap methods",
(u8 *) methods, num_methods * sizeof(*methods));
os_free(ssid->eap.eap_methods);
@@ -1348,6 +1602,8 @@ static int wpa_config_parse_password(const struct parse_data *data,
u8 *hash;
if (os_strcmp(value, "NULL") == 0) {
+ if (!ssid->eap.password)
+ return 1; /* Already unset */
wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = NULL;
@@ -1411,6 +1667,12 @@ static int wpa_config_parse_password(const struct parse_data *data,
wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+ if (ssid->eap.password && ssid->eap.password_len == 16 &&
+ os_memcmp(ssid->eap.password, hash, 16) == 0 &&
+ (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+ bin_clear_free(hash, 16);
+ return 1;
+ }
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = hash;
ssid->eap.password_len = 16;
@@ -1734,6 +1996,140 @@ static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
#endif /* CONFIG_MESH */
+#ifdef CONFIG_MACSEC
+
+static int wpa_config_parse_mka_cak(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ size_t len;
+
+ len = os_strlen(value);
+ if (len > 2 * MACSEC_CAK_MAX_LEN ||
+ (len != 2 * 16 && len != 2 * 32) ||
+ hexstr2bin(value, ssid->mka_cak, len / 2)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
+ line, value);
+ return -1;
+ }
+ ssid->mka_cak_len = len / 2;
+ ssid->mka_psk_set |= MKA_PSK_SET_CAK;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak,
+ ssid->mka_cak_len);
+ return 0;
+}
+
+
+static int wpa_config_parse_mka_ckn(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ size_t len;
+
+ len = os_strlen(value);
+ if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */
+ len < 2 || /* too short */
+ len % 2 != 0 /* not an integral number of bytes */) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
+ line, value);
+ return -1;
+ }
+ ssid->mka_ckn_len = len / 2;
+ if (hexstr2bin(value, ssid->mka_ckn, ssid->mka_ckn_len)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
+ line, value);
+ return -1;
+ }
+
+ ssid->mka_psk_set |= MKA_PSK_SET_CKN;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn,
+ ssid->mka_ckn_len);
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_mka_cak(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
+ return NULL;
+
+ return wpa_config_write_string_hex(ssid->mka_cak, ssid->mka_cak_len);
+}
+
+
+static char * wpa_config_write_mka_ckn(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
+ return NULL;
+ return wpa_config_write_string_hex(ssid->mka_ckn, ssid->mka_ckn_len);
+}
+
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MACSEC */
+
+
+#ifdef CONFIG_OCV
+
+static int wpa_config_parse_ocv(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ char *end;
+
+ ssid->ocv = strtol(value, &end, 0);
+ if (*end || ssid->ocv < 0 || ssid->ocv > 1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid ocv value '%s'.",
+ line, value);
+ return -1;
+ }
+ if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION)
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_ocv(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value = os_malloc(20);
+
+ if (!value)
+ return NULL;
+ os_snprintf(value, 20, "%d", ssid->ocv);
+ value[20 - 1] = '\0';
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_OCV */
+
+
+static int wpa_config_parse_peerkey(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ wpa_printf(MSG_INFO, "NOTE: Obsolete peerkey parameter ignored");
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_peerkey(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
/* Helper macros for network block parser */
#ifdef OFFSET
@@ -1825,22 +2221,34 @@ static const struct parse_data ssid_fields[] = {
{ STR_RANGE(ssid, 0, SSID_MAX_LEN) },
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
+ { FUNC(bssid_hint) },
{ FUNC(bssid_blacklist) },
{ FUNC(bssid_whitelist) },
{ FUNC_KEY(psk) },
{ INT(mem_only_psk) },
+ { STR_KEY(sae_password) },
+ { STR(sae_password_id) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
{ INT(bg_scan_period) },
{ FUNC(pairwise) },
{ FUNC(group) },
+ { FUNC(group_mgmt) },
{ FUNC(auth_alg) },
{ FUNC(scan_freq) },
{ FUNC(freq_list) },
+ { INT_RANGE(ht, 0, 1) },
+ { INT_RANGE(vht, 0, 1) },
+ { INT_RANGE(ht40, -1, 1) },
+ { INT_RANGE(max_oper_chwidth, VHT_CHANWIDTH_USE_HT,
+ VHT_CHANWIDTH_80P80MHZ) },
+ { INT(vht_center_freq1) },
+ { INT(vht_center_freq2) },
#ifdef IEEE8021X_EAPOL
{ FUNC(eap) },
{ STR_LENe(identity) },
{ STR_LENe(anonymous_identity) },
+ { STR_LENe(imsi_identity) },
{ FUNC_KEY(password) },
{ STRe(ca_cert) },
{ STRe(ca_path) },
@@ -1849,6 +2257,7 @@ static const struct parse_data ssid_fields[] = {
{ STR_KEYe(private_key_passwd) },
{ STRe(dh_file) },
{ STRe(subject_match) },
+ { STRe(check_cert_subject) },
{ STRe(altsubject_match) },
{ STRe(domain_suffix_match) },
{ STRe(domain_match) },
@@ -1859,6 +2268,7 @@ static const struct parse_data ssid_fields[] = {
{ STR_KEYe(private_key2_passwd) },
{ STRe(dh_file2) },
{ STRe(subject_match2) },
+ { STRe(check_cert_subject2) },
{ STRe(altsubject_match2) },
{ STRe(domain_suffix_match2) },
{ STRe(domain_match2) },
@@ -1897,6 +2307,7 @@ static const struct parse_data ssid_fields[] = {
#ifdef CONFIG_MESH
{ INT_RANGE(mode, 0, 5) },
{ INT_RANGE(no_auto_peer, 0, 1) },
+ { INT_RANGE(mesh_rssi_threshold, -255, 1) },
#else /* CONFIG_MESH */
{ INT_RANGE(mode, 0, 4) },
#endif /* CONFIG_MESH */
@@ -1906,10 +2317,16 @@ static const struct parse_data ssid_fields[] = {
#ifdef CONFIG_IEEE80211W
{ INT_RANGE(ieee80211w, 0, 2) },
#endif /* CONFIG_IEEE80211W */
- { INT_RANGE(peerkey, 0, 1) },
+#ifdef CONFIG_OCV
+ { FUNC(ocv) },
+#endif /* CONFIG_OCV */
+ { FUNC(peerkey) /* obsolete - removed */ },
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
{ INT_RANGE(fixed_freq, 0, 1) },
+#ifdef CONFIG_ACS
+ { INT_RANGE(acs, 0, 1) },
+#endif /* CONFIG_ACS */
#ifdef CONFIG_MESH
{ FUNC(mesh_basic_rates) },
{ INT(dot11MeshMaxRetries) },
@@ -1918,6 +2335,7 @@ static const struct parse_data ssid_fields[] = {
{ INT(dot11MeshHoldingTimeout) },
#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
+ { INT(group_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
#ifdef CONFIG_P2P
@@ -1931,6 +2349,8 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(disable_sgi, 0, 1) },
{ INT_RANGE(disable_ldpc, 0, 1) },
{ INT_RANGE(ht40_intolerant, 0, 1) },
+ { INT_RANGE(tx_stbc, -1, 1) },
+ { INT_RANGE(rx_stbc, -1, 3) },
{ INT_RANGE(disable_max_amsdu, -1, 1) },
{ INT_RANGE(ampdu_factor, -1, 3) },
{ INT_RANGE(ampdu_density, -1, 7) },
@@ -1962,11 +2382,31 @@ static const struct parse_data ssid_fields[] = {
{ INT(beacon_int) },
#ifdef CONFIG_MACSEC
{ INT_RANGE(macsec_policy, 0, 1) },
+ { INT_RANGE(macsec_integ_only, 0, 1) },
+ { INT_RANGE(macsec_replay_protect, 0, 1) },
+ { INT(macsec_replay_window) },
+ { INT_RANGE(macsec_port, 1, 65534) },
+ { INT_RANGE(mka_priority, 0, 255) },
+ { FUNC_KEY(mka_cak) },
+ { FUNC_KEY(mka_ckn) },
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
{ INT(update_identifier) },
+ { STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) },
#endif /* CONFIG_HS20 */
{ INT_RANGE(mac_addr, 0, 2) },
+ { INT_RANGE(pbss, 0, 2) },
+ { INT_RANGE(wps_disabled, 0, 1) },
+ { INT_RANGE(fils_dh_group, 0, 65535) },
+#ifdef CONFIG_DPP
+ { STR(dpp_connector) },
+ { STR_LEN(dpp_netaccesskey) },
+ { INT(dpp_netaccesskey_expiry) },
+ { STR_LEN(dpp_csign) },
+#endif /* CONFIG_DPP */
+ { INT_RANGE(owe_group, 0, 65535) },
+ { INT_RANGE(owe_only, 0, 1) },
+ { INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
};
#undef OFFSET
@@ -2078,6 +2518,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
os_free(eap->eap_methods);
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
+ os_free(eap->imsi_identity);
bin_clear_free(eap->password, eap->password_len);
os_free(eap->ca_cert);
os_free(eap->ca_path);
@@ -2086,6 +2527,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
str_clear_free(eap->private_key_passwd);
os_free(eap->dh_file);
os_free(eap->subject_match);
+ os_free(eap->check_cert_subject);
os_free(eap->altsubject_match);
os_free(eap->domain_suffix_match);
os_free(eap->domain_match);
@@ -2096,6 +2538,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
str_clear_free(eap->private_key2_passwd);
os_free(eap->dh_file2);
os_free(eap->subject_match2);
+ os_free(eap->check_cert_subject2);
os_free(eap->altsubject_match2);
os_free(eap->domain_suffix_match2);
os_free(eap->domain_match2);
@@ -2136,6 +2579,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->ssid);
str_clear_free(ssid->passphrase);
os_free(ssid->ext_psk);
+ str_clear_free(ssid->sae_password);
+ os_free(ssid->sae_password_id);
#ifdef IEEE8021X_EAPOL
eap_peer_config_free(&ssid->eap);
#endif /* IEEE8021X_EAPOL */
@@ -2152,6 +2597,12 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
#ifdef CONFIG_MESH
os_free(ssid->mesh_basic_rates);
#endif /* CONFIG_MESH */
+#ifdef CONFIG_HS20
+ os_free(ssid->roaming_consortium_selection);
+#endif /* CONFIG_HS20 */
+ os_free(ssid->dpp_connector);
+ bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
+ os_free(ssid->dpp_csign);
while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
list))) {
dl_list_del(&psk->list);
@@ -2271,6 +2722,11 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->bgscan);
os_free(config->wowlan_triggers);
os_free(config->fst_group_id);
+ os_free(config->sched_scan_plans);
+#ifdef CONFIG_MBO
+ os_free(config->non_pref_chan);
+#endif /* CONFIG_MBO */
+
os_free(config);
}
@@ -2400,6 +2856,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
+ ssid->ht = 1;
#ifdef IEEE8021X_EAPOL
ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
@@ -2411,12 +2868,15 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT;
+ ssid->mesh_rssi_threshold = DEFAULT_MESH_RSSI_THRESHOLD;
#endif /* CONFIG_MESH */
#ifdef CONFIG_HT_OVERRIDES
ssid->disable_ht = DEFAULT_DISABLE_HT;
ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
ssid->disable_sgi = DEFAULT_DISABLE_SGI;
ssid->disable_ldpc = DEFAULT_DISABLE_LDPC;
+ ssid->tx_stbc = DEFAULT_TX_STBC;
+ ssid->rx_stbc = DEFAULT_RX_STBC;
ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
@@ -2443,7 +2903,11 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_MACSEC
+ ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
+#endif /* CONFIG_MACSEC */
ssid->mac_addr = -1;
+ ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH;
}
@@ -2453,7 +2917,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
* @var: Variable name, e.g., "ssid"
* @value: Variable value
* @line: Line number in configuration file or 0 if not used
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success with possible change in the value, 1 on success with
+ * no change to previously configured value, or -1 on failure
*
* This function can be used to set network configuration variables based on
* both the configuration file and management interface input. The value
@@ -2474,7 +2939,8 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
if (os_strcmp(var, field->name) != 0)
continue;
- if (field->parser(field, ssid, line, value)) {
+ ret = field->parser(field, ssid, line, value);
+ if (ret < 0) {
if (line) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse %s '%s'.", line, var, value);
@@ -2573,9 +3039,8 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
return props;
err:
- value = *props;
- while (value)
- os_free(value++);
+ for (i = 0; props[i]; i++)
+ os_free(props[i]);
os_free(props);
return NULL;
#endif /* NO_CONFIG_WRITE */
@@ -2604,8 +3069,19 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
for (i = 0; i < NUM_SSID_FIELDS; i++) {
const struct parse_data *field = &ssid_fields[i];
- if (os_strcmp(var, field->name) == 0)
- return field->writer(field, ssid);
+ if (os_strcmp(var, field->name) == 0) {
+ char *ret = field->writer(field, ssid);
+
+ if (ret && has_newline(ret)) {
+ wpa_printf(MSG_ERROR,
+ "Found newline in value for %s; not returning it",
+ var);
+ os_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+ }
}
return NULL;
@@ -2742,11 +3218,64 @@ static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred,
}
+static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred,
+ const char *value)
+{
+ u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
+ size_t roaming_consortiums_len[MAX_ROAMING_CONS];
+ unsigned int num_roaming_consortiums = 0;
+ const char *pos, *end;
+ size_t len;
+
+ os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums));
+ os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len));
+
+ for (pos = value;;) {
+ end = os_strchr(pos, ',');
+ len = end ? (size_t) (end - pos) : os_strlen(pos);
+ if (!end && len == 0)
+ break;
+ if (len == 0 || (len & 1) != 0 ||
+ len / 2 > MAX_ROAMING_CONS_OI_LEN ||
+ hexstr2bin(pos,
+ roaming_consortiums[num_roaming_consortiums],
+ len / 2) < 0) {
+ wpa_printf(MSG_INFO,
+ "Invalid roaming_consortiums entry: %s",
+ pos);
+ return -1;
+ }
+ roaming_consortiums_len[num_roaming_consortiums] = len / 2;
+ num_roaming_consortiums++;
+
+ if (!end)
+ break;
+
+ if (num_roaming_consortiums >= MAX_ROAMING_CONS) {
+ wpa_printf(MSG_INFO,
+ "Too many roaming_consortiums OIs");
+ return -1;
+ }
+
+ pos = end + 1;
+ }
+
+ os_memcpy(cred->roaming_consortiums, roaming_consortiums,
+ sizeof(roaming_consortiums));
+ os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len,
+ sizeof(roaming_consortiums_len));
+ cred->num_roaming_consortiums = num_roaming_consortiums;
+
+ return 0;
+}
+
+
int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
const char *value, int line)
{
char *val;
size_t len;
+ int res;
if (os_strcmp(var, "temporary") == 0) {
cred->temporary = atoi(value);
@@ -2790,6 +3319,8 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
if (os_strcmp(var, "password") == 0 &&
os_strncmp(value, "ext:", 4) == 0) {
+ if (has_newline(value))
+ return -1;
str_clear_free(cred->password);
cred->password = os_strdup(value);
cred->ext_password = 1;
@@ -2840,9 +3371,14 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
}
val = wpa_config_parse_string(value, &len);
- if (val == NULL) {
+ if (val == NULL ||
+ (os_strcmp(var, "excluded_ssid") != 0 &&
+ os_strcmp(var, "roaming_consortium") != 0 &&
+ os_strcmp(var, "required_roaming_consortium") != 0 &&
+ has_newline(val))) {
wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
"value '%s'.", line, var, value);
+ os_free(val);
return -1;
}
@@ -2962,6 +3498,16 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
return 0;
}
+ if (os_strcmp(var, "roaming_consortiums") == 0) {
+ res = wpa_config_set_cred_roaming_consortiums(cred, val);
+ if (res < 0)
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid roaming_consortiums",
+ line);
+ os_free(val);
+ return res;
+ }
+
if (os_strcmp(var, "excluded_ssid") == 0) {
struct excluded_ssid *e;
@@ -3273,6 +3819,31 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
return buf;
}
+ if (os_strcmp(var, "roaming_consortiums") == 0) {
+ size_t buflen;
+ char *buf, *pos;
+ size_t i;
+
+ if (!cred->num_roaming_consortiums)
+ return NULL;
+ buflen = cred->num_roaming_consortiums *
+ MAX_ROAMING_CONS_OI_LEN * 2 + 1;
+ buf = os_malloc(buflen);
+ if (!buf)
+ return NULL;
+ pos = buf;
+ for (i = 0; i < cred->num_roaming_consortiums; i++) {
+ if (i > 0)
+ *pos++ = ',';
+ pos += wpa_snprintf_hex(
+ pos, buf + buflen - pos,
+ cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]);
+ }
+ *pos = '\0';
+ return buf;
+ }
+
if (os_strcmp(var, "excluded_ssid") == 0) {
unsigned int i;
char *buf, *end, *pos;
@@ -3530,6 +4101,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
config->max_num_sta = DEFAULT_MAX_NUM_STA;
+ config->ap_isolate = DEFAULT_AP_ISOLATE;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
config->wmm_ac_params[0] = ac_be;
@@ -3540,11 +4112,20 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
config->cert_in_cb = DEFAULT_CERT_IN_CB;
+ config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+
+#ifdef CONFIG_MBO
+ config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
+ config->disassoc_imminent_rssi_threshold =
+ DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD;
+ config->oce = DEFAULT_OCE_SUPPORT;
+#endif /* CONFIG_MBO */
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
if (driver_param)
config->driver_param = os_strdup(driver_param);
+ config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
return config;
}
@@ -3646,6 +4227,12 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
return -1;
}
+ if (has_newline(pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline",
+ line, data->name);
+ return -1;
+ }
+
tmp = os_strdup(pos);
if (tmp == NULL)
return -1;
@@ -3684,22 +4271,12 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
{
- size_t len;
struct wpabuf **dst, *tmp;
- len = os_strlen(pos);
- if (len & 0x01)
+ tmp = wpabuf_parse_bin(pos);
+ if (!tmp)
return -1;
- tmp = wpabuf_alloc(len / 2);
- if (tmp == NULL)
- return -1;
-
- if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
- wpabuf_free(tmp);
- return -1;
- }
-
dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
wpabuf_free(*dst);
*dst = tmp;
@@ -3955,6 +4532,21 @@ static int wpa_config_process_p2p_no_go_freq(
return 0;
}
+
+static int wpa_config_process_p2p_device_persistent_mac_addr(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ if (hwaddr_aton2(pos, config->p2p_device_persistent_mac_addr) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid p2p_device_persistent_mac_addr '%s'",
+ line, pos);
+ return -1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_P2P */
@@ -4154,6 +4746,7 @@ static const struct global_parse_data global_fields[] = {
{ FUNC_NO_VAR(load_dynamic_eap), 0 },
#ifdef CONFIG_WPS
{ FUNC(uuid), CFG_CHANGED_UUID },
+ { INT_RANGE(auto_uuid, 0, 1), 0 },
{ STR_RANGE(device_name, 0, WPS_DEV_NAME_MAX_LEN),
CFG_CHANGED_DEVICE_NAME },
{ STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
@@ -4164,6 +4757,7 @@ static const struct global_parse_data global_fields[] = {
{ FUNC(os_version), CFG_CHANGED_OS_VERSION },
{ STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
{ INT_RANGE(wps_cred_processing, 0, 2), 0 },
+ { INT_RANGE(wps_cred_add_sae, 0, 1), 0 },
{ FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
@@ -4186,6 +4780,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
{ INT(p2p_go_ht40), 0 },
{ INT(p2p_go_vht), 0 },
+ { INT(p2p_go_he), 0 },
{ INT(p2p_disabled), 0 },
{ INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
{ INT(p2p_no_group_iface), 0 },
@@ -4195,6 +4790,9 @@ static const struct global_parse_data global_fields[] = {
{ IPV4(ip_addr_start), 0 },
{ IPV4(ip_addr_end), 0 },
{ INT_RANGE(p2p_cli_probe, 0, 1), 0 },
+ { INT(p2p_device_random_mac_addr), 0 },
+ { FUNC(p2p_device_persistent_mac_addr), 0 },
+ { INT(p2p_interface_random_mac_addr), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
@@ -4203,6 +4801,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(filter_ssids, 0, 1), 0 },
{ INT_RANGE(filter_rssi, -100, 0), 0 },
{ INT(max_num_sta), 0 },
+ { INT_RANGE(ap_isolate, 0, 1), 0 },
{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
#ifdef CONFIG_HS20
{ INT_RANGE(hs20, 0, 1), 0 },
@@ -4210,6 +4809,11 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(interworking, 0, 1), 0 },
{ FUNC(hessid), 0 },
{ INT_RANGE(access_network_type, 0, 15), 0 },
+ { INT_RANGE(go_interworking, 0, 1), 0 },
+ { INT_RANGE(go_access_network_type, 0, 15), 0 },
+ { INT_RANGE(go_internet, 0, 1), 0 },
+ { INT_RANGE(go_venue_group, 0, 255), 0 },
+ { INT_RANGE(go_venue_type, 0, 255), 0 },
{ INT_RANGE(pbc_in_m1, 0, 1), 0 },
{ STR(autoscan), 0 },
{ INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff),
@@ -4230,9 +4834,10 @@ static const struct global_parse_data global_fields[] = {
{ FUNC(freq_list), 0 },
{ INT(scan_cur_freq), 0 },
{ INT(sched_scan_interval), 0 },
+ { INT(sched_scan_start_delay), 0 },
{ INT(tdls_external_control), 0},
{ STR(osu_dir), 0 },
- { STR(wowlan_triggers), 0 },
+ { STR(wowlan_triggers), CFG_CHANGED_WOWLAN_TRIGGERS },
{ INT(p2p_search_delay), 0},
{ INT(mac_addr), 0 },
{ INT(rand_addr_lifetime), 0 },
@@ -4246,6 +4851,23 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
{ INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
#endif /* CONFIG_FST */
+ { INT_RANGE(cert_in_cb, 0, 1), 0 },
+ { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
+ { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
+#ifdef CONFIG_MBO
+ { STR(non_pref_chan), 0 },
+ { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
+ MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
+ { INT_RANGE(disassoc_imminent_rssi_threshold, -120, 0), 0 },
+ { INT_RANGE(oce, 0, 3), 0 },
+#endif /* CONFIG_MBO */
+ { INT(gas_address3), 0 },
+ { INT_RANGE(ftm_responder, 0, 1), 0 },
+ { INT_RANGE(ftm_initiator, 0, 1), 0 },
+ { INT(gas_rand_addr_lifetime), 0 },
+ { INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
+ { INT_RANGE(dpp_config_processing, 0, 2), 0 },
+ { INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
};
#undef FUNC
@@ -4304,6 +4926,23 @@ int wpa_config_get_value(const char *name, struct wpa_config *config,
}
+int wpa_config_get_num_global_field_names(void)
+{
+ return NUM_GLOBAL_FIELDS;
+}
+
+
+const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
+{
+ if (i >= NUM_GLOBAL_FIELDS)
+ return NULL;
+
+ if (no_var)
+ *no_var = !global_fields[i].param1;
+ return global_fields[i].name;
+}
+
+
int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
{
size_t i;
diff --git a/contrib/wpa/wpa_supplicant/config.h b/contrib/wpa/wpa_supplicant/config.h
index 627f38b..abbd8c9 100644
--- a/contrib/wpa/wpa_supplicant/config.h
+++ b/contrib/wpa/wpa_supplicant/config.h
@@ -32,6 +32,7 @@
#define DEFAULT_BSS_EXPIRATION_AGE 180
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
#define DEFAULT_MAX_NUM_STA 128
+#define DEFAULT_AP_ISOLATE 0
#define DEFAULT_ACCESS_NETWORK_TYPE 15
#define DEFAULT_SCAN_CUR_FREQ 0
#define DEFAULT_P2P_SEARCH_DELAY 500
@@ -39,6 +40,10 @@
#define DEFAULT_KEY_MGMT_OFFLOAD 1
#define DEFAULT_CERT_IN_CB 1
#define DEFAULT_P2P_GO_CTWINDOW 0
+#define DEFAULT_WPA_RSC_RELAXATION 1
+#define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED
+#define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75
+#define DEFAULT_OCE_SUPPORT OCE_STA
#include "config_ssid.h"
#include "wps/wps.h"
@@ -46,6 +51,9 @@
#include "common/ieee802_11_common.h"
+#define MAX_ROAMING_CONS 36
+#define MAX_ROAMING_CONS_OI_LEN 15
+
struct wpa_cred {
/**
* next - Next credential in the list
@@ -220,10 +228,43 @@ struct wpa_cred {
*/
size_t roaming_consortium_len;
+ /**
+ * required_roaming_consortium - Required Roaming Consortium OI
+ *
+ * If required_roaming_consortium_len is non-zero, this field contains
+ * the Roaming Consortium OI that is required to be advertised by the AP
+ * for the credential to be considered matching.
+ */
u8 required_roaming_consortium[15];
+
+ /**
+ * required_roaming_consortium_len - Length of required_roaming_consortium
+ */
size_t required_roaming_consortium_len;
/**
+ * roaming_consortiums - Roaming Consortium OI(s) memberships
+ *
+ * This field contains one or more OIs identifying the roaming
+ * consortiums of which the provider is a member. The list is sorted
+ * from the most preferred one to the least preferred one. A match
+ * between the Roaming Consortium OIs advertised by an AP and the OIs
+ * in this list indicates that successful authentication is possible.
+ * (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+ */
+ u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
+
+ /**
+ * roaming_consortiums_len - Length on roaming_consortiums[i]
+ */
+ size_t roaming_consortiums_len[MAX_ROAMING_CONS];
+
+ /**
+ * num_roaming_consortiums - Number of entries in roaming_consortiums
+ */
+ unsigned int num_roaming_consortiums;
+
+ /**
* eap_method - EAP method to use
*
* Pre-configured EAP method to use with this credential or %NULL to
@@ -331,6 +372,8 @@ struct wpa_cred {
#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
#define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15)
#define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16)
+#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17)
+#define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -622,6 +665,13 @@ struct wpa_config {
u8 uuid[16];
/**
+ * auto_uuid - Automatic UUID behavior
+ * 0 = generate static value based on the local MAC address (default)
+ * 1 = generate a random UUID every time wpa_supplicant starts
+ */
+ int auto_uuid;
+
+ /**
* device_name - Device Name (WPS)
* User-friendly description of device; up to 32 octets encoded in
* UTF-8
@@ -695,6 +745,16 @@ struct wpa_config {
*/
int wps_cred_processing;
+ /**
+ * wps_cred_add_sae - Whether to enable SAE automatically for WPS
+ *
+ * 0 = only add the explicitly listed WPA2-PSK configuration
+ * 1 = add both the WPA2-PSK and SAE configuration and enable PMF so
+ * that the station gets configured in WPA3-Personal transition mode
+ * (supports both WPA2-Personal (PSK) and WPA3-Personal (SAE) APs).
+ */
+ int wps_cred_add_sae;
+
#define MAX_SEC_DEVICE_TYPES 5
/**
* sec_device_types - Secondary Device Types (P2P)
@@ -761,12 +821,17 @@ struct wpa_config {
* frequency list of the local device and the peer device.
*
* @P2P_GO_FREQ_MOVE_STAY: Prefer to stay on the current frequency.
+ *
+ * @P2P_GO_FREQ_MOVE_SCM_ECSA: Same as
+ * P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS but a transition is possible only
+ * if all the group members advertise eCSA support.
*/
enum {
P2P_GO_FREQ_MOVE_SCM = 0,
P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS = 1,
P2P_GO_FREQ_MOVE_STAY = 2,
- P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_STAY,
+ P2P_GO_FREQ_MOVE_SCM_ECSA = 3,
+ P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_SCM_ECSA,
} p2p_go_freq_change_policy;
#define DEFAULT_P2P_GO_FREQ_MOVE P2P_GO_FREQ_MOVE_STAY
@@ -825,6 +890,20 @@ struct wpa_config {
unsigned int max_num_sta;
/**
+ * ap_isolate - Whether to use client isolation feature
+ *
+ * Client isolation can be used to prevent low-level bridging of
+ * frames between associated stations in the BSS. By default,
+ * this bridging is allowed (ap_isolate=0); except in P2P GO case,
+ * where p2p_intra_bss parameter is used to determine whether to allow
+ * intra-BSS forwarding (ap_isolate = !p2p_intra_bss).
+ *
+ * 0 = do not enable AP isolation
+ * 1 = enable AP isolation
+ */
+ int ap_isolate;
+
+ /**
* freq_list - Array of allowed scan frequencies or %NULL for all
*
* This is an optional zero-terminated array of frequencies in
@@ -846,7 +925,7 @@ struct wpa_config {
unsigned int changed_parameters;
/**
- * disassoc_low_ack - Disassocicate stations with massive packet loss
+ * disassoc_low_ack - Disassociate stations with massive packet loss
*/
int disassoc_low_ack;
@@ -864,6 +943,34 @@ struct wpa_config {
*/
int access_network_type;
+ /**
+ * go_interworking - Whether Interworking for P2P GO is enabled
+ */
+ int go_interworking;
+
+ /**
+ * go_access_network_type - P2P GO Access Network Type
+ *
+ * This indicates which access network type to advertise if Interworking
+ * is enabled for P2P GO.
+ */
+ int go_access_network_type;
+
+ /**
+ * go_internet - Interworking: Internet connectivity (0 or 1)
+ */
+ int go_internet;
+
+ /**
+ * go_venue_group - Interworking: Venue group
+ */
+ int go_venue_group;
+
+ /**
+ * go_venue_type: Interworking: Venue type
+ */
+ int go_venue_type;
+
/**
* hessid - Homogenous ESS identifier
*
@@ -982,6 +1089,16 @@ struct wpa_config {
int p2p_go_vht;
/**
+ * p2p_go_he - Default mode for 11ax HE enable when operating as GO
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_he;
+
+ /**
* p2p_go_ctwindow - CTWindow to use when operating as GO
*
* By default: 0 (no CTWindow). Values 0-127 can be used to indicate
@@ -1031,7 +1148,8 @@ struct wpa_config {
*
* By default, PMF is disabled unless enabled by the per-network
* ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
- * this default behavior.
+ * this default behavior for RSN network (this is not applicable for
+ * non-RSN cases).
*/
enum mfp_options pmf;
@@ -1087,6 +1205,15 @@ struct wpa_config {
unsigned int sched_scan_interval;
/**
+ * sched_scan_start_delay - Schedule scan start delay before first scan
+ *
+ * Delay (in seconds) before scheduling first scan plan cycle. The
+ * driver may ignore this parameter and start immediately (or at any
+ * other time), if this feature is not supported.
+ */
+ unsigned int sched_scan_start_delay;
+
+ /**
* tdls_external_control - External control for TDLS setup requests
*
* Enable TDLS mode where external programs are given the control
@@ -1247,6 +1374,159 @@ struct wpa_config {
* interface.
*/
int fst_llt;
+
+ /**
+ * wpa_rsc_relaxation - RSC relaxation on GTK installation
+ *
+ * Values:
+ * 0 - use the EAPOL-Key RSC value on GTK installation
+ * 1 - use the null RSC if a bogus RSC value is detected in message 3
+ * of 4-Way Handshake or message 1 of Group Key Handshake.
+ */
+ int wpa_rsc_relaxation;
+
+ /**
+ * sched_scan_plans - Scan plans for scheduled scan
+ *
+ * Each scan plan specifies the interval between scans and the number of
+ * iterations. The last scan plan only specifies the scan interval and
+ * will be run infinitely.
+ *
+ * format: <interval:iterations> <interval2:iterations2> ... <interval>
+ */
+ char *sched_scan_plans;
+
+#ifdef CONFIG_MBO
+ /**
+ * non_pref_chan - Non-preferred channels list, separated by spaces.
+ *
+ * format: op_class:chan:preference:reason<:detail>
+ * Detail is optional.
+ */
+ char *non_pref_chan;
+
+ /**
+ * mbo_cell_capa - Cellular capabilities for MBO
+ */
+ enum mbo_cellular_capa mbo_cell_capa;
+
+ /**
+ * disassoc_imminent_rssi_threshold - RSSI threshold of candidate AP
+ * when disassociation imminent is set.
+ */
+ int disassoc_imminent_rssi_threshold;
+
+ /**
+ * oce - Enable OCE in STA and/or STA-CFON mode
+ * - Set BIT(0) to enable OCE in non-AP STA mode
+ * - Set BIT(1) to enable OCE in STA-CFON mode
+ */
+ unsigned int oce;
+#endif /* CONFIG_MBO */
+
+ /**
+ * gas_address3 - GAS Address3 field behavior
+ *
+ * Values:
+ * 0 - P2P specification (Address3 = AP BSSID)
+ * 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+ * sent to not-associated AP; if associated, AP BSSID)
+ */
+ int gas_address3;
+
+ /**
+ * ftm_responder - Publish FTM (fine timing measurement)
+ * responder functionality
+ *
+ * Values:
+ * 0 - do not publish FTM responder functionality (Default)
+ * 1 - publish FTM responder functionality in
+ * bit 70 of Extended Capabilities element
+ * Note, actual FTM responder operation is managed outside
+ * wpa_supplicant.
+ */
+ int ftm_responder;
+
+ /**
+ * ftm_initiator - Publish FTM (fine timing measurement)
+ * initiator functionality
+ *
+ * Values:
+ * 0 - do not publish FTM initiator functionality (Default)
+ * 1 - publish FTM initiator functionality in
+ * bit 71 of Extended Capabilities element
+ * Note, actual FTM initiator operation is managed outside
+ * wpa_supplicant.
+ */
+ int ftm_initiator;
+
+ /**
+ * gas_rand_addr_lifetime - Lifetime of random MAC address for ANQP in
+ * seconds
+ */
+ unsigned int gas_rand_addr_lifetime;
+
+ /**
+ * gas_rand_mac_addr - GAS MAC address policy
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address
+ * 2 = like 1, but maintain OUI (with local admin bit set)
+ */
+ int gas_rand_mac_addr;
+
+ /**
+ * dpp_config_processing - How to process DPP configuration
+ *
+ * 0 = report received configuration to an external program for
+ * processing; do not generate any network profile internally
+ * 1 = report received configuration to an external program and generate
+ * a network profile internally, but do not automatically connect
+ * to the created (disabled) profile; the network profile id is
+ * reported to external programs
+ * 2 = report received configuration to an external program, generate
+ * a network profile internally, try to connect to the created
+ * profile automatically
+ */
+ int dpp_config_processing;
+
+ /**
+ * coloc_intf_reporting - Colocated interference reporting
+ *
+ * dot11CoLocIntfReportingActivated
+ * 0 = disabled (false)
+ * 1 = enabled (true)
+ */
+ int coloc_intf_reporting;
+
+ /**
+ * p2p_device_random_mac_addr - P2P Device MAC address policy default
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address on creating the interface if there is no
+ * persistent groups.
+ *
+ * By default, permanent MAC address is used.
+ */
+ int p2p_device_random_mac_addr;
+
+ /**
+ * p2p_device_persistent_mac_addr - Record last used MAC address
+ *
+ * If there are saved persistent groups, P2P cannot generate another
+ * random MAC address, and need to restore to last used MAC address.
+ */
+ u8 p2p_device_persistent_mac_addr[ETH_ALEN];
+
+ /**
+ * p2p_interface_random_mac_addr - P2P Interface MAC address policy default
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address on creating the interface.
+ *
+ * By default, permanent MAC address is used.
+ */
+ int p2p_interface_random_mac_addr;
};
@@ -1305,6 +1585,9 @@ void wpa_config_debug_dump_networks(struct wpa_config *config);
/* Prototypes for common functions from config.c */
int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
+int wpa_config_get_num_global_field_names(void);
+
+const char * wpa_config_get_global_field_name(unsigned int i, int *no_var);
/* Prototypes for backend specific functions from the selected config_*.c */
diff --git a/contrib/wpa/wpa_supplicant/config_file.c b/contrib/wpa/wpa_supplicant/config_file.c
index fb438ea..26f6ee1 100644
--- a/contrib/wpa/wpa_supplicant/config_file.c
+++ b/contrib/wpa/wpa_supplicant/config_file.c
@@ -19,6 +19,7 @@
#include "config.h"
#include "base64.h"
#include "uuid.h"
+#include "common/ieee802_1x_defs.h"
#include "p2p/p2p.h"
#include "eap_peer/eap_methods.h"
#include "eap_peer/eap.h"
@@ -136,9 +137,13 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
wpa_config_update_psk(ssid);
}
+ if (ssid->disabled == 2)
+ ssid->p2p_persistent_group = 1;
+
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
- !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
- !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+ !(ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256 |
+ WPA_CIPHER_NONE))) {
/* Group cipher cannot be stronger than the pairwise cipher. */
wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
" list since it was not allowed for pairwise "
@@ -155,6 +160,15 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
errors++;
}
+#ifdef CONFIG_OCV
+ if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: PMF needs to be enabled whenever using OCV",
+ line);
+ errors++;
+ }
+#endif /* CONFIG_OCV */
+
return errors;
}
@@ -308,7 +322,7 @@ static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
encoded_len += len;
}
- if (!end) {
+ if (!end || !encoded) {
wpa_printf(MSG_ERROR, "Line %d: blob was not terminated "
"properly", *line);
os_free(encoded);
@@ -393,7 +407,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
if (f == NULL) {
wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
"error: %s", name, strerror(errno));
- os_free(config);
+ if (config != cfgp)
+ os_free(config);
return NULL;
}
@@ -459,7 +474,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
#ifndef WPA_IGNORE_CONFIG_ERRORS
if (errors) {
- wpa_config_free(config);
+ if (config != cfgp)
+ wpa_config_free(config);
config = NULL;
head = NULL;
}
@@ -477,7 +493,7 @@ static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid)
if (value == NULL)
return;
fprintf(f, "\t%s=%s\n", field, value);
- os_free(value);
+ str_clear_free(value);
}
@@ -499,6 +515,17 @@ static void write_bssid(FILE *f, struct wpa_ssid *ssid)
}
+static void write_bssid_hint(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "bssid_hint");
+
+ if (!value)
+ return;
+ fprintf(f, "\tbssid_hint=%s\n", value);
+ os_free(value);
+}
+
+
static void write_psk(FILE *f, struct wpa_ssid *ssid)
{
char *value;
@@ -578,6 +605,22 @@ static void write_group(FILE *f, struct wpa_ssid *ssid)
}
+static void write_group_mgmt(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!ssid->group_mgmt_cipher)
+ return;
+
+ value = wpa_config_get(ssid, "group_mgmt");
+ if (!value)
+ return;
+ if (value[0])
+ fprintf(f, "\tgroup_mgmt=%s\n", value);
+ os_free(value);
+}
+
+
static void write_auth_alg(FILE *f, struct wpa_ssid *ssid)
{
char *value;
@@ -662,6 +705,40 @@ static void write_psk_list(FILE *f, struct wpa_ssid *ssid)
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MACSEC
+
+static void write_mka_cak(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
+ return;
+
+ value = wpa_config_get(ssid, "mka_cak");
+ if (!value)
+ return;
+ fprintf(f, "\tmka_cak=%s\n", value);
+ os_free(value);
+}
+
+
+static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
+ return;
+
+ value = wpa_config_get(ssid, "mka_ckn");
+ if (!value)
+ return;
+ fprintf(f, "\tmka_ckn=%s\n", value);
+ os_free(value);
+}
+
+#endif /* CONFIG_MACSEC */
+
+
static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
{
int i;
@@ -675,15 +752,19 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(ssid);
INT(scan_ssid);
write_bssid(f, ssid);
+ write_bssid_hint(f, ssid);
write_str(f, "bssid_blacklist", ssid);
write_str(f, "bssid_whitelist", ssid);
write_psk(f, ssid);
INT(mem_only_psk);
+ STR(sae_password);
+ STR(sae_password_id);
write_proto(f, ssid);
write_key_mgmt(f, ssid);
INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
write_pairwise(f, ssid);
write_group(f, ssid);
+ write_group_mgmt(f, ssid);
write_auth_alg(f, ssid);
STR(bgscan);
STR(autoscan);
@@ -692,6 +773,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
write_eap(f, ssid);
STR(identity);
STR(anonymous_identity);
+ STR(imsi_identity);
STR(password);
STR(ca_cert);
STR(ca_path);
@@ -700,6 +782,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(private_key_passwd);
STR(dh_file);
STR(subject_match);
+ STR(check_cert_subject);
STR(altsubject_match);
STR(domain_suffix_match);
STR(domain_match);
@@ -710,6 +793,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(private_key2_passwd);
STR(dh_file2);
STR(subject_match2);
+ STR(check_cert_subject2);
STR(altsubject_match2);
STR(domain_suffix_match2);
STR(domain_match2);
@@ -747,10 +831,21 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(no_auto_peer);
INT(frequency);
INT(fixed_freq);
+#ifdef CONFIG_ACS
+ INT(acs);
+#endif /* CONFIG_ACS */
write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
- INT(peerkey);
INT(mixed_cell);
+ INT(vht);
+ INT_DEF(ht, 1);
+ INT(ht40);
+ INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH);
+ INT(vht_center_freq1);
+ INT(vht_center_freq2);
+ INT(pbss);
+ INT(wps_disabled);
+ INT(fils_dh_group);
#ifdef CONFIG_IEEE80211W
write_int(f, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
@@ -766,9 +861,17 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(beacon_int);
#ifdef CONFIG_MACSEC
INT(macsec_policy);
+ write_mka_cak(f, ssid);
+ write_mka_ckn(f, ssid);
+ INT(macsec_integ_only);
+ INT(macsec_replay_protect);
+ INT(macsec_replay_window);
+ INT(macsec_port);
+ INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
INT(update_identifier);
+ STR(roaming_consortium_selection);
#endif /* CONFIG_HS20 */
write_int(f, "mac_addr", ssid->mac_addr, -1);
#ifdef CONFIG_MESH
@@ -777,15 +880,28 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(dot11MeshRetryTimeout, DEFAULT_MESH_RETRY_TIMEOUT);
INT_DEF(dot11MeshConfirmTimeout, DEFAULT_MESH_CONFIRM_TIMEOUT);
INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
+ INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD);
#endif /* CONFIG_MESH */
INT(wpa_ptk_rekey);
+ INT(group_rekey);
INT(ignore_broadcast_ssid);
+#ifdef CONFIG_DPP
+ STR(dpp_connector);
+ STR(dpp_netaccesskey);
+ INT(dpp_netaccesskey_expiry);
+ STR(dpp_csign);
+#endif /* CONFIG_DPP */
+ INT(owe_group);
+ INT(owe_only);
+ INT(multi_ap_backhaul_sta);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
INT_DEF(disable_sgi, DEFAULT_DISABLE_SGI);
INT_DEF(disable_ldpc, DEFAULT_DISABLE_LDPC);
INT(ht40_intolerant);
+ INT_DEF(tx_stbc, DEFAULT_TX_STBC);
+ INT_DEF(rx_stbc, DEFAULT_RX_STBC);
INT_DEF(disable_max_amsdu, DEFAULT_DISABLE_MAX_AMSDU);
INT_DEF(ampdu_factor, DEFAULT_AMPDU_FACTOR);
INT_DEF(ampdu_density, DEFAULT_AMPDU_DENSITY);
@@ -942,6 +1058,20 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
fprintf(f, "\n");
}
+ if (cred->num_roaming_consortiums) {
+ size_t j;
+
+ fprintf(f, "\troaming_consortiums=\"");
+ for (i = 0; i < cred->num_roaming_consortiums; i++) {
+ if (i > 0)
+ fprintf(f, ",");
+ for (j = 0; j < cred->roaming_consortiums_len[i]; j++)
+ fprintf(f, "%02x",
+ cred->roaming_consortiums[i][j]);
+ }
+ fprintf(f, "\"\n");
+ }
+
if (cred->sim_num != DEFAULT_USER_SELECTED_SIM)
fprintf(f, "\tsim_num=%d\n", cred->sim_num);
}
@@ -1032,6 +1162,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
uuid_bin2str(config->uuid, buf, sizeof(buf));
fprintf(f, "uuid=%s\n", buf);
}
+ if (config->auto_uuid)
+ fprintf(f, "auto_uuid=%d\n", config->auto_uuid);
if (config->device_name)
fprintf(f, "device_name=%s\n", config->device_name);
if (config->manufacturer)
@@ -1057,6 +1189,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->wps_cred_processing)
fprintf(f, "wps_cred_processing=%d\n",
config->wps_cred_processing);
+ if (config->wps_cred_add_sae)
+ fprintf(f, "wps_cred_add_sae=%d\n",
+ config->wps_cred_add_sae);
if (config->wps_vendor_ext_m1) {
int i, len = wpabuf_len(config->wps_vendor_ext_m1);
const u8 *p = wpabuf_head_u8(config->wps_vendor_ext_m1);
@@ -1069,6 +1204,17 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
}
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
+ {
+ int i;
+ char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+
+ for (i = 0; i < config->num_sec_device_types; i++) {
+ buf = wps_dev_type_bin2str(config->sec_device_type[i],
+ _buf, sizeof(_buf));
+ if (buf)
+ fprintf(f, "sec_device_type=%s\n", buf);
+ }
+ }
if (config->p2p_listen_reg_class)
fprintf(f, "p2p_listen_reg_class=%d\n",
config->p2p_listen_reg_class);
@@ -1121,6 +1267,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "p2p_go_ht40=%d\n", config->p2p_go_ht40);
if (config->p2p_go_vht)
fprintf(f, "p2p_go_vht=%d\n", config->p2p_go_vht);
+ if (config->p2p_go_he)
+ fprintf(f, "p2p_go_he=%d\n", config->p2p_go_he);
if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow);
if (config->p2p_disabled)
@@ -1136,6 +1284,22 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE)
fprintf(f, "p2p_go_freq_change_policy=%u\n",
config->p2p_go_freq_change_policy);
+ if (WPA_GET_BE32(config->ip_addr_go))
+ fprintf(f, "ip_addr_go=%u.%u.%u.%u\n",
+ config->ip_addr_go[0], config->ip_addr_go[1],
+ config->ip_addr_go[2], config->ip_addr_go[3]);
+ if (WPA_GET_BE32(config->ip_addr_mask))
+ fprintf(f, "ip_addr_mask=%u.%u.%u.%u\n",
+ config->ip_addr_mask[0], config->ip_addr_mask[1],
+ config->ip_addr_mask[2], config->ip_addr_mask[3]);
+ if (WPA_GET_BE32(config->ip_addr_start))
+ fprintf(f, "ip_addr_start=%u.%u.%u.%u\n",
+ config->ip_addr_start[0], config->ip_addr_start[1],
+ config->ip_addr_start[2], config->ip_addr_start[3]);
+ if (WPA_GET_BE32(config->ip_addr_end))
+ fprintf(f, "ip_addr_end=%u.%u.%u.%u\n",
+ config->ip_addr_end[0], config->ip_addr_end[1],
+ config->ip_addr_end[2], config->ip_addr_end[3]);
#endif /* CONFIG_P2P */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
@@ -1152,8 +1316,12 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
config->bss_expiration_scan_count);
if (config->filter_ssids)
fprintf(f, "filter_ssids=%d\n", config->filter_ssids);
+ if (config->filter_rssi)
+ fprintf(f, "filter_rssi=%d\n", config->filter_rssi);
if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
+ if (config->ap_isolate != DEFAULT_AP_ISOLATE)
+ fprintf(f, "ap_isolate=%u\n", config->ap_isolate);
if (config->disassoc_low_ack)
fprintf(f, "disassoc_low_ack=%d\n", config->disassoc_low_ack);
#ifdef CONFIG_HS20
@@ -1168,6 +1336,17 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->access_network_type != DEFAULT_ACCESS_NETWORK_TYPE)
fprintf(f, "access_network_type=%d\n",
config->access_network_type);
+ if (config->go_interworking)
+ fprintf(f, "go_interworking=%d\n", config->go_interworking);
+ if (config->go_access_network_type)
+ fprintf(f, "go_access_network_type=%d\n",
+ config->go_access_network_type);
+ if (config->go_internet)
+ fprintf(f, "go_internet=%d\n", config->go_internet);
+ if (config->go_venue_group)
+ fprintf(f, "go_venue_group=%d\n", config->go_venue_group);
+ if (config->go_venue_type)
+ fprintf(f, "go_venue_type=%d\n", config->go_venue_type);
#endif /* CONFIG_INTERWORKING */
if (config->pbc_in_m1)
fprintf(f, "pbc_in_m1=%d\n", config->pbc_in_m1);
@@ -1203,7 +1382,7 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->sae_groups) {
int i;
fprintf(f, "sae_groups=");
- for (i = 0; config->sae_groups[i] >= 0; i++) {
+ for (i = 0; config->sae_groups[i] > 0; i++) {
fprintf(f, "%s%d", i > 0 ? " " : "",
config->sae_groups[i]);
}
@@ -1241,6 +1420,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "sched_scan_interval=%u\n",
config->sched_scan_interval);
+ if (config->sched_scan_start_delay)
+ fprintf(f, "sched_scan_start_delay=%u\n",
+ config->sched_scan_start_delay);
+
if (config->external_sim)
fprintf(f, "external_sim=%d\n", config->external_sim);
@@ -1255,6 +1438,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->bgscan)
fprintf(f, "bgscan=\"%s\"\n", config->bgscan);
+ if (config->autoscan)
+ fprintf(f, "autoscan=%s\n", config->autoscan);
+
if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY)
fprintf(f, "p2p_search_delay=%u\n",
config->p2p_search_delay);
@@ -1299,6 +1485,65 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->wps_priority)
fprintf(f, "wps_priority=%d\n", config->wps_priority);
+
+ if (config->wpa_rsc_relaxation != DEFAULT_WPA_RSC_RELAXATION)
+ fprintf(f, "wpa_rsc_relaxation=%d\n",
+ config->wpa_rsc_relaxation);
+
+ if (config->sched_scan_plans)
+ fprintf(f, "sched_scan_plans=%s\n", config->sched_scan_plans);
+
+#ifdef CONFIG_MBO
+ if (config->non_pref_chan)
+ fprintf(f, "non_pref_chan=%s\n", config->non_pref_chan);
+ if (config->mbo_cell_capa != DEFAULT_MBO_CELL_CAPA)
+ fprintf(f, "mbo_cell_capa=%u\n", config->mbo_cell_capa);
+ if (config->disassoc_imminent_rssi_threshold !=
+ DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD)
+ fprintf(f, "disassoc_imminent_rssi_threshold=%d\n",
+ config->disassoc_imminent_rssi_threshold);
+ if (config->oce != DEFAULT_OCE_SUPPORT)
+ fprintf(f, "oce=%u\n", config->oce);
+#endif /* CONFIG_MBO */
+
+ if (config->gas_address3)
+ fprintf(f, "gas_address3=%d\n", config->gas_address3);
+
+ if (config->ftm_responder)
+ fprintf(f, "ftm_responder=%d\n", config->ftm_responder);
+ if (config->ftm_initiator)
+ fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator);
+
+ if (config->osu_dir)
+ fprintf(f, "osu_dir=%s\n", config->osu_dir);
+
+ if (config->fst_group_id)
+ fprintf(f, "fst_group_id=%s\n", config->fst_group_id);
+ if (config->fst_priority)
+ fprintf(f, "fst_priority=%d\n", config->fst_priority);
+ if (config->fst_llt)
+ fprintf(f, "fst_llt=%d\n", config->fst_llt);
+
+ if (config->gas_rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME)
+ fprintf(f, "gas_rand_addr_lifetime=%u\n",
+ config->gas_rand_addr_lifetime);
+ if (config->gas_rand_mac_addr)
+ fprintf(f, "gas_rand_mac_addr=%d\n", config->gas_rand_mac_addr);
+ if (config->dpp_config_processing)
+ fprintf(f, "dpp_config_processing=%d\n",
+ config->dpp_config_processing);
+ if (config->coloc_intf_reporting)
+ fprintf(f, "coloc_intf_reporting=%d\n",
+ config->coloc_intf_reporting);
+ if (config->p2p_device_random_mac_addr)
+ fprintf(f, "p2p_device_random_mac_addr=%d\n",
+ config->p2p_device_random_mac_addr);
+ if (!is_zero_ether_addr(config->p2p_device_persistent_mac_addr))
+ fprintf(f, "p2p_device_persistent_mac_addr=" MACSTR "\n",
+ MAC2STR(config->p2p_device_persistent_mac_addr));
+ if (config->p2p_interface_random_mac_addr)
+ fprintf(f, "p2p_interface_random_mac_addr=%d\n",
+ config->p2p_interface_random_mac_addr);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/contrib/wpa/wpa_supplicant/config_ssid.h b/contrib/wpa/wpa_supplicant/config_ssid.h
index 7ef326c..1b2b1f1 100644
--- a/contrib/wpa/wpa_supplicant/config_ssid.h
+++ b/contrib/wpa/wpa_supplicant/config_ssid.h
@@ -28,14 +28,18 @@
#define DEFAULT_MESH_RETRY_TIMEOUT 40
#define DEFAULT_MESH_CONFIRM_TIMEOUT 40
#define DEFAULT_MESH_HOLDING_TIMEOUT 40
+#define DEFAULT_MESH_RSSI_THRESHOLD 1 /* no change */
#define DEFAULT_DISABLE_HT 0
#define DEFAULT_DISABLE_HT40 0
#define DEFAULT_DISABLE_SGI 0
#define DEFAULT_DISABLE_LDPC 0
+#define DEFAULT_TX_STBC -1 /* no change */
+#define DEFAULT_RX_STBC -1 /* no change */
#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
#define DEFAULT_AMPDU_FACTOR -1 /* no change */
#define DEFAULT_AMPDU_DENSITY -1 /* no change */
#define DEFAULT_USER_SELECTED_SIM 1
+#define DEFAULT_MAX_OPER_CHWIDTH -1
struct psk_list_entry {
struct dl_list list;
@@ -146,6 +150,19 @@ struct wpa_ssid {
int bssid_set;
/**
+ * bssid_hint - BSSID hint
+ *
+ * If set, this is configured to the driver as a preferred initial BSSID
+ * while connecting to this network.
+ */
+ u8 bssid_hint[ETH_ALEN];
+
+ /**
+ * bssid_hint_set - Whether BSSID hint is configured for this network
+ */
+ int bssid_hint_set;
+
+ /**
* go_p2p_dev_addr - GO's P2P Device Address or all zeros if not set
*/
u8 go_p2p_dev_addr[ETH_ALEN];
@@ -170,6 +187,24 @@ struct wpa_ssid {
char *passphrase;
/**
+ * sae_password - SAE password
+ *
+ * This parameter can be used to set a password for SAE. By default, the
+ * passphrase value is used if this separate parameter is not used, but
+ * passphrase follows the WPA-PSK constraints (8..63 characters) even
+ * though SAE passwords do not have such constraints.
+ */
+ char *sae_password;
+
+ /**
+ * sae_password_id - SAE password identifier
+ *
+ * This parameter can be used to identify a specific SAE password. If
+ * not included, the default SAE password is used instead.
+ */
+ char *sae_password_id;
+
+ /**
* ext_psk - PSK/passphrase name in external storage
*
* If this is set, PSK/passphrase will be fetched from external storage
@@ -196,6 +231,15 @@ struct wpa_ssid {
int group_cipher;
/**
+ * group_mgmt_cipher - Bitfield of allowed group management ciphers
+ *
+ * This is a bitfield of WPA_CIPHER_AES_128_CMAC and WPA_CIPHER_BIP_*
+ * values. If 0, no constraint is used for the cipher, i.e., whatever
+ * the AP uses is accepted.
+ */
+ int group_mgmt_cipher;
+
+ /**
* key_mgmt - Bitfield of allowed key management protocols
*
* WPA_KEY_MGMT_*
@@ -360,6 +404,19 @@ struct wpa_ssid {
} mode;
/**
+ * pbss - Whether to use PBSS. Relevant to DMG networks only.
+ * 0 = do not use PBSS
+ * 1 = use PBSS
+ * 2 = don't care (not allowed in AP mode)
+ * Used together with mode configuration. When mode is AP, it
+ * means to start a PCP instead of a regular AP. When mode is INFRA it
+ * means connect to a PCP instead of AP. In this mode you can also
+ * specify 2 (don't care) meaning connect to either AP or PCP.
+ * P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in DMG network.
+ */
+ int pbss;
+
+ /**
* disabled - Whether this network is currently disabled
*
* 0 = this network can be used (default).
@@ -379,17 +436,6 @@ struct wpa_ssid {
int disabled_for_connect;
/**
- * peerkey - Whether PeerKey handshake for direct links is allowed
- *
- * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
- * enabled.
- *
- * 0 = disabled (default)
- * 1 = enabled
- */
- int peerkey;
-
- /**
* id_str - Network identifier string for external scripts
*
* This value is passed to external ctrl_iface monitors in
@@ -414,6 +460,17 @@ struct wpa_ssid {
enum mfp_options ieee80211w;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ /**
+ * ocv - Enable/disable operating channel validation
+ *
+ * If this parameter is set to 1, stations will exchange OCI element
+ * to cryptographically verify the operating channel. Setting this
+ * parameter to 0 disables this option. Default value: 0.
+ */
+ int ocv;
+#endif /* CONFIG_OCV */
+
/**
* frequency - Channel frequency in megahertz (MHz) for IBSS
*
@@ -431,6 +488,18 @@ struct wpa_ssid {
*/
int fixed_freq;
+#ifdef CONFIG_ACS
+ /**
+ * ACS - Automatic Channel Selection for AP mode
+ *
+ * If present, it will be handled together with frequency.
+ * frequency will be used to determine hardware mode only, when it is
+ * used for both hardware mode and channel when used alone. This will
+ * force the channel to be set to 0, thus enabling ACS.
+ */
+ int acs;
+#endif /* CONFIG_ACS */
+
/**
* mesh_basic_rates - BSS Basic rate set for mesh network
*
@@ -445,10 +514,18 @@ struct wpa_ssid {
int dot11MeshConfirmTimeout; /* msec */
int dot11MeshHoldingTimeout; /* msec */
+ int ht;
int ht40;
int vht;
+ int he;
+
+ int max_oper_chwidth;
+
+ unsigned int vht_center_freq1;
+ unsigned int vht_center_freq2;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
@@ -458,6 +535,14 @@ struct wpa_ssid {
int wpa_ptk_rekey;
/**
+ * group_rekey - Group rekeying time in seconds
+ *
+ * This value, if non-zero, is used as the dot11RSNAConfigGroupRekeyTime
+ * parameter when operating in Authenticator role in IBSS.
+ */
+ int group_rekey;
+
+ /**
* scan_freq - Array of frequencies to scan or %NULL for all
*
* This is an optional zero-terminated array of frequencies in
@@ -613,6 +698,22 @@ struct wpa_ssid {
* By default (empty string): Use whatever the OS has configured.
*/
char *ht_mcs;
+
+ /**
+ * tx_stbc - Indicate STBC support for TX streams
+ *
+ * Value: -1..1, by default (-1): use whatever the OS or card has
+ * configured. See IEEE Std 802.11-2016, 9.4.2.56.2.
+ */
+ int tx_stbc;
+
+ /**
+ * rx_stbc - Indicate STBC support for RX streams
+ *
+ * Value: -1..3, by default (-1): use whatever the OS or card has
+ * configured. See IEEE Std 802.11-2016, 9.4.2.56.2.
+ */
+ int rx_stbc;
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
@@ -691,10 +792,100 @@ struct wpa_ssid {
* determine whether to use a secure session or not.
*/
int macsec_policy;
+
+ /**
+ * macsec_integ_only - Determines how MACsec are transmitted
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Encrypt traffic (default)
+ * 1: Integrity only
+ */
+ int macsec_integ_only;
+
+ /**
+ * macsec_replay_protect - Enable MACsec replay protection
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Replay protection disabled (default)
+ * 1: Replay protection enabled
+ */
+ int macsec_replay_protect;
+
+ /**
+ * macsec_replay_window - MACsec replay protection window
+ *
+ * A window in which replay is tolerated, to allow receipt of frames
+ * that have been misordered by the network.
+ *
+ * This setting applies only when MACsec replay protection active, i.e.,
+ * - macsec_replay_protect is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: No replay window, strict check (default)
+ * 1..2^32-1: number of packets that could be misordered
+ */
+ u32 macsec_replay_window;
+
+ /**
+ * macsec_port - MACsec port (in SCI)
+ *
+ * Port component of the SCI.
+ *
+ * Range: 1-65534 (default: 1)
+ */
+ int macsec_port;
+
+ /**
+ * mka_priority - Priority of MKA Actor
+ *
+ * Range: 0-255 (default: 255)
+ */
+ int mka_priority;
+
+ /**
+ * mka_ckn - MKA pre-shared CKN
+ */
+#define MACSEC_CKN_MAX_LEN 32
+ size_t mka_ckn_len;
+ u8 mka_ckn[MACSEC_CKN_MAX_LEN];
+
+ /**
+ * mka_cak - MKA pre-shared CAK
+ */
+#define MACSEC_CAK_MAX_LEN 32
+ size_t mka_cak_len;
+ u8 mka_cak[MACSEC_CAK_MAX_LEN];
+
+#define MKA_PSK_SET_CKN BIT(0)
+#define MKA_PSK_SET_CAK BIT(1)
+#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
+ /**
+ * mka_psk_set - Whether mka_ckn and mka_cak are set
+ */
+ u8 mka_psk_set;
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
int update_identifier;
+
+ /**
+ * roaming_consortium_selection - Roaming Consortium Selection
+ *
+ * The matching Roaming Consortium OI that was used to generate this
+ * network profile.
+ */
+ u8 *roaming_consortium_selection;
+
+ /**
+ * roaming_consortium_selection_len - roaming_consortium_selection len
+ */
+ size_t roaming_consortium_selection_len;
#endif /* CONFIG_HS20 */
unsigned int wps_run;
@@ -719,6 +910,101 @@ struct wpa_ssid {
* this MBSS will trigger a peering attempt.
*/
int no_auto_peer;
+
+ /**
+ * mesh_rssi_threshold - Set mesh parameter mesh_rssi_threshold (dBm)
+ *
+ * -255..-1 = threshold value in dBm
+ * 0 = not using RSSI threshold
+ * 1 = do not change driver default
+ */
+ int mesh_rssi_threshold;
+
+ /**
+ * wps_disabled - WPS disabled in AP mode
+ *
+ * 0 = WPS enabled and configured (default)
+ * 1 = WPS disabled
+ */
+ int wps_disabled;
+
+ /**
+ * fils_dh_group - FILS DH Group
+ *
+ * 0 = PFS disabled with FILS shared key authentication
+ * 1-65535 DH Group to use for FILS PFS
+ */
+ int fils_dh_group;
+
+ /**
+ * dpp_connector - DPP Connector (signedConnector as string)
+ */
+ char *dpp_connector;
+
+ /**
+ * dpp_netaccesskey - DPP netAccessKey (own private key)
+ */
+ u8 *dpp_netaccesskey;
+
+ /**
+ * dpp_netaccesskey_len - DPP netAccessKey length in octets
+ */
+ size_t dpp_netaccesskey_len;
+
+ /**
+ * net_access_key_expiry - DPP netAccessKey expiry in UNIX time stamp
+ *
+ * 0 indicates no expiration.
+ */
+ unsigned int dpp_netaccesskey_expiry;
+
+ /**
+ * dpp_csign - C-sign-key (Configurator public key)
+ */
+ u8 *dpp_csign;
+
+ /**
+ * dpp_csign_len - C-sign-key length in octets
+ */
+ size_t dpp_csign_len;
+
+ /**
+ * owe_group - OWE DH Group
+ *
+ * 0 = use default (19) first and then try all supported groups one by
+ * one if AP rejects the selected group
+ * 1-65535 DH Group to use for OWE
+ *
+ * Groups 19 (NIST P-256), 20 (NIST P-384), and 21 (NIST P-521) are
+ * currently supported.
+ */
+ int owe_group;
+
+ /**
+ * owe_only - OWE-only mode (disable transition mode)
+ *
+ * 0 = enable transition mode (allow connection to either OWE or open
+ * BSS)
+ * 1 = disable transition mode (allow connection only with OWE)
+ */
+ int owe_only;
+
+ /**
+ * owe_transition_bss_select_count - OWE transition BSS select count
+ *
+ * This is an internally used variable (i.e., not used in external
+ * configuration) to track the number of selection attempts done for
+ * OWE BSS in transition mode. This allows fallback to an open BSS if
+ * the selection attempts for OWE BSS exceed the configured threshold.
+ */
+ int owe_transition_bss_select_count;
+
+ /**
+ * multi_ap_backhaul_sta - Multi-AP backhaul STA
+ * 0 = normal (non-Multi-AP) station
+ * 1 = Multi-AP backhaul station
+ */
+ int multi_ap_backhaul_sta;
};
#endif /* CONFIG_SSID_H */
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface.c b/contrib/wpa/wpa_supplicant/ctrl_iface.c
index 25dcdf7..198ac56 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,10 +15,14 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
+#include "utils/module_tests.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#ifdef CONFIG_DPP
+#include "common/dpp.h"
+#endif /* CONFIG_DPP */
#include "crypto/tls.h"
#include "ap/hostapd.h"
#include "eap_peer/eap.h"
@@ -51,14 +55,18 @@
#include "offchannel.h"
#include "drivers/driver.h"
#include "mesh.h"
+#include "dpp_supplicant.h"
+#include "sme.h"
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+ const char *input,
char *buf, int len);
static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
char *val);
+
static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
{
char *pos;
@@ -310,6 +318,102 @@ static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
}
+static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct wpabuf *lci;
+
+ if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = NULL;
+ return 0;
+ }
+
+ lci = wpabuf_parse_bin(cmd);
+ if (!lci)
+ return -1;
+
+ if (os_get_reltime(&wpa_s->lci_time)) {
+ wpabuf_free(lci);
+ return -1;
+ }
+
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = lci;
+
+ return 0;
+}
+
+
+static int
+wpas_ctrl_set_relative_rssi(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int relative_rssi;
+
+ if (os_strcmp(cmd, "disable") == 0) {
+ wpa_s->srp.relative_rssi_set = 0;
+ return 0;
+ }
+
+ relative_rssi = atoi(cmd);
+ if (relative_rssi < 0 || relative_rssi > 100)
+ return -1;
+ wpa_s->srp.relative_rssi = relative_rssi;
+ wpa_s->srp.relative_rssi_set = 1;
+ return 0;
+}
+
+
+static int wpas_ctrl_set_relative_band_adjust(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ char *pos;
+ int adjust_rssi;
+
+ /* <band>:adjust_value */
+ pos = os_strchr(cmd, ':');
+ if (!pos)
+ return -1;
+ pos++;
+ adjust_rssi = atoi(pos);
+ if (adjust_rssi < -100 || adjust_rssi > 100)
+ return -1;
+
+ if (os_strncmp(cmd, "2G", 2) == 0)
+ wpa_s->srp.relative_adjust_band = WPA_SETBAND_2G;
+ else if (os_strncmp(cmd, "5G", 2) == 0)
+ wpa_s->srp.relative_adjust_band = WPA_SETBAND_5G;
+ else
+ return -1;
+
+ wpa_s->srp.relative_adjust_rssi = adjust_rssi;
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct wpabuf *ric_ies;
+
+ if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
+ wpabuf_free(wpa_s->ric_ies);
+ wpa_s->ric_ies = NULL;
+ return 0;
+ }
+
+ ric_ies = wpabuf_parse_bin(cmd);
+ if (!ric_ies)
+ return -1;
+
+ wpabuf_free(wpa_s->ric_ies);
+ wpa_s->ric_ies = ric_ies;
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -336,16 +440,29 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
-1, -1, -1, atoi(value));
} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
- atoi(value)))
+ atoi(value))) {
ret = -1;
+ } else {
+ value[-1] = '=';
+ wpa_config_process_global(wpa_s->conf, cmd, -1);
+ }
} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
0) {
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
- atoi(value)))
+ atoi(value))) {
ret = -1;
+ } else {
+ value[-1] = '=';
+ wpa_config_process_global(wpa_s->conf, cmd, -1);
+ }
} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
- if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
+ if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
+ atoi(value))) {
ret = -1;
+ } else {
+ value[-1] = '=';
+ wpa_config_process_global(wpa_s->conf, cmd, -1);
+ }
} else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
wpa_s->wps_fragment_size = atoi(value);
#ifdef CONFIG_WPS_TESTING
@@ -371,6 +488,20 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wps_corrupt_pkhash = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
wps_corrupt_pkhash);
+ } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) {
+ if (value[0] == '\0') {
+ wps_force_auth_types_in_use = 0;
+ } else {
+ wps_force_auth_types = strtol(value, NULL, 0);
+ wps_force_auth_types_in_use = 1;
+ }
+ } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) {
+ if (value[0] == '\0') {
+ wps_force_encr_types_in_use = 0;
+ } else {
+ wps_force_encr_types = strtol(value, NULL, 0);
+ wps_force_encr_types_in_use = 1;
+ }
#endif /* CONFIG_WPS_TESTING */
} else if (os_strcasecmp(cmd, "ampdu") == 0) {
if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
@@ -378,7 +509,6 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_TDLS
#ifdef CONFIG_TDLS_TESTING
} else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
- extern unsigned int tdls_testing;
tdls_testing = strtol(value, NULL, 0);
wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
#endif /* CONFIG_TDLS_TESTING */
@@ -452,6 +582,59 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = set_disallow_aps(wpa_s, value);
} else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
wpa_s->no_keep_alive = !!atoi(value);
+#ifdef CONFIG_DPP
+ } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
+ os_free(wpa_s->dpp_configurator_params);
+ wpa_s->dpp_configurator_params = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
+ wpa_s->dpp_init_max_tries = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
+ wpa_s->dpp_init_retry_time = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
+ wpa_s->dpp_resp_wait_time = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
+ wpa_s->dpp_resp_max_tries = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
+ wpa_s->dpp_resp_retry_time = atoi(value);
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcasecmp(cmd, "dpp_pkex_own_mac_override") == 0) {
+ if (hwaddr_aton(value, dpp_pkex_own_mac_override))
+ ret = -1;
+ } else if (os_strcasecmp(cmd, "dpp_pkex_peer_mac_override") == 0) {
+ if (hwaddr_aton(value, dpp_pkex_peer_mac_override))
+ ret = -1;
+ } else if (os_strcasecmp(cmd, "dpp_pkex_ephemeral_key_override") == 0) {
+ size_t hex_len = os_strlen(value);
+
+ if (hex_len >
+ 2 * sizeof(dpp_pkex_ephemeral_key_override))
+ ret = -1;
+ else if (hexstr2bin(value, dpp_pkex_ephemeral_key_override,
+ hex_len / 2))
+ ret = -1;
+ else
+ dpp_pkex_ephemeral_key_override_len = hex_len / 2;
+ } else if (os_strcasecmp(cmd, "dpp_protocol_key_override") == 0) {
+ size_t hex_len = os_strlen(value);
+
+ if (hex_len > 2 * sizeof(dpp_protocol_key_override))
+ ret = -1;
+ else if (hexstr2bin(value, dpp_protocol_key_override,
+ hex_len / 2))
+ ret = -1;
+ else
+ dpp_protocol_key_override_len = hex_len / 2;
+ } else if (os_strcasecmp(cmd, "dpp_nonce_override") == 0) {
+ size_t hex_len = os_strlen(value);
+
+ if (hex_len > 2 * sizeof(dpp_nonce_override))
+ ret = -1;
+ else if (hexstr2bin(value, dpp_nonce_override, hex_len / 2))
+ ret = -1;
+ else
+ dpp_nonce_override_len = hex_len / 2;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_DPP */
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
wpa_s->ext_mgmt_frame_handling = !!atoi(value);
@@ -467,13 +650,116 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->extra_roc_dur = atoi(value);
} else if (os_strcasecmp(cmd, "test_failure") == 0) {
wpa_s->test_failure = atoi(value);
+ } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
+ wpa_s->p2p_go_csa_on_inv = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
+ wpa_s->ignore_auth_resp = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
+ wpa_s->ignore_assoc_disallow = !!atoi(value);
+ wpa_drv_ignore_assoc_disallow(wpa_s,
+ wpa_s->ignore_assoc_disallow);
+ } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
+ wpa_s->reject_btm_req_reason = atoi(value);
+ } else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
+ os_free(wpa_s->get_pref_freq_list_override);
+ if (!value[0])
+ wpa_s->get_pref_freq_list_override = NULL;
+ else
+ wpa_s->get_pref_freq_list_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "sae_commit_override") == 0) {
+ wpabuf_free(wpa_s->sae_commit_override);
+ if (value[0] == '\0')
+ wpa_s->sae_commit_override = NULL;
+ else
+ wpa_s->sae_commit_override = wpabuf_parse_bin(value);
+#ifdef CONFIG_DPP
+ } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
+ os_free(wpa_s->dpp_config_obj_override);
+ if (value[0] == '\0')
+ wpa_s->dpp_config_obj_override = NULL;
+ else
+ wpa_s->dpp_config_obj_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
+ os_free(wpa_s->dpp_discovery_override);
+ if (value[0] == '\0')
+ wpa_s->dpp_discovery_override = NULL;
+ else
+ wpa_s->dpp_discovery_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
+ os_free(wpa_s->dpp_groups_override);
+ if (value[0] == '\0')
+ wpa_s->dpp_groups_override = NULL;
+ else
+ wpa_s->dpp_groups_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd,
+ "dpp_ignore_netaccesskey_mismatch") == 0) {
+ wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
+ dpp_test = atoi(value);
+#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_FILS
+ } else if (os_strcasecmp(cmd, "disable_fils") == 0) {
+ wpa_s->disable_fils = !!atoi(value);
+ wpa_drv_disable_fils(wpa_s, wpa_s->disable_fils);
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+#endif /* CONFIG_FILS */
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strcmp(cmd, "blob") == 0) {
ret = wpas_ctrl_set_blob(wpa_s, value);
#endif /* CONFIG_NO_CONFIG_BLOBS */
} else if (os_strcasecmp(cmd, "setband") == 0) {
ret = wpas_ctrl_set_band(wpa_s, value);
+#ifdef CONFIG_MBO
+ } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
+ ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
+ if (ret == 0) {
+ value[-1] = '=';
+ wpa_config_process_global(wpa_s->conf, cmd, -1);
+ }
+ } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
+ wpas_mbo_update_cell_capa(wpa_s, atoi(value));
+ } else if (os_strcasecmp(cmd, "oce") == 0) {
+ wpa_s->conf->oce = atoi(value);
+ if (wpa_s->conf->oce) {
+ if ((wpa_s->conf->oce & OCE_STA) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
+ wpa_s->enable_oce = OCE_STA;
+
+ if ((wpa_s->conf->oce & OCE_STA_CFON) &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
+ /* TODO: Need to add STA-CFON support */
+ wpa_printf(MSG_ERROR,
+ "OCE STA-CFON feature is not yet supported");
+ return -1;
+ }
+ } else {
+ wpa_s->enable_oce = 0;
+ }
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+#endif /* CONFIG_MBO */
+ } else if (os_strcasecmp(cmd, "lci") == 0) {
+ ret = wpas_ctrl_iface_set_lci(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) {
+ ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value));
+ } else if (os_strcasecmp(cmd, "relative_rssi") == 0) {
+ ret = wpas_ctrl_set_relative_rssi(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "relative_band_adjust") == 0) {
+ ret = wpas_ctrl_set_relative_band_adjust(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "ric_ies") == 0) {
+ ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "roaming") == 0) {
+ ret = wpa_drv_roaming(wpa_s, atoi(value), NULL);
+#ifdef CONFIG_WNM
+ } else if (os_strcasecmp(cmd, "coloc_intf_elems") == 0) {
+ struct wpabuf *elems;
+
+ elems = wpabuf_parse_bin(value);
+ if (!elems)
+ return -1;
+ wnm_set_coloc_intf_elems(wpa_s, elems);
+#endif /* CONFIG_WNM */
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -519,6 +805,12 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_TESTING_GET_GTK */
} else if (os_strcmp(cmd, "tls_library") == 0) {
res = tls_get_library_version(buf, buflen);
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcmp(cmd, "anonce") == 0) {
+ return wpa_snprintf_hex(buf, buflen,
+ wpa_sm_get_anonce(wpa_s->wpa),
+ WPA_NONCE_LEN);
+#endif /* CONFIG_TESTING_OPTIONS */
} else {
res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
}
@@ -552,27 +844,6 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
#endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_PEERKEY
-/* MLME-STKSTART.request(peer) */
-static int wpa_supplicant_ctrl_iface_stkstart(
- struct wpa_supplicant *wpa_s, char *addr)
-{
- u8 peer[ETH_ALEN];
-
- if (hwaddr_aton(addr, peer)) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
- "address '%s'", addr);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
- MAC2STR(peer));
-
- return wpa_sm_stkstart(wpa_s->wpa, peer);
-}
-#endif /* CONFIG_PEERKEY */
-
-
#ifdef CONFIG_TDLS
static int wpa_supplicant_ctrl_iface_tdls_discover(
@@ -897,8 +1168,11 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_AP
u8 *_p2p_dev_addr = NULL;
#endif /* CONFIG_AP */
+ char *pos;
+ int multi_ap = 0;
- if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
+ if (!cmd || os_strcmp(cmd, "any") == 0 ||
+ os_strncmp(cmd, "any ", 4) == 0) {
_bssid = NULL;
#ifdef CONFIG_P2P
} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
@@ -910,18 +1184,29 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
}
_p2p_dev_addr = p2p_dev_addr;
#endif /* CONFIG_P2P */
+ } else if (os_strncmp(cmd, "multi_ap=", 9) == 0) {
+ _bssid = NULL;
+ multi_ap = atoi(cmd + 9);
} else if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
cmd);
return -1;
}
+ if (cmd) {
+ pos = os_strstr(cmd, " multi_ap=");
+ if (pos) {
+ pos += 10;
+ multi_ap = atoi(pos);
+ }
+ }
+
#ifdef CONFIG_AP
if (wpa_s->ap_iface)
return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
#endif /* CONFIG_AP */
- return wpas_wps_start_pbc(wpa_s, _bssid, 0);
+ return wpas_wps_start_pbc(wpa_s, _bssid, 0, multi_ap);
}
@@ -940,7 +1225,8 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
if (os_strcmp(cmd, "any") == 0)
_bssid = NULL;
else if (os_strcmp(cmd, "get") == 0) {
- ret = wps_generate_pin();
+ if (wps_generate_pin((unsigned int *) &ret) < 0)
+ return -1;
goto done;
} else if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
@@ -1833,6 +2119,10 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
"mode=P2P GO - group "
"formation\n");
break;
+ case WPAS_MODE_MESH:
+ ret = os_snprintf(pos, end - pos,
+ "mode=mesh\n");
+ break;
default:
ret = 0;
break;
@@ -1842,6 +2132,18 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
pos += ret;
}
+ if (wpa_s->connection_set &&
+ (wpa_s->connection_ht || wpa_s->connection_vht ||
+ wpa_s->connection_he)) {
+ ret = os_snprintf(pos, end - pos,
+ "wifi_generation=%u\n",
+ wpa_s->connection_he ? 6 :
+ (wpa_s->connection_vht ? 5 : 4));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
@@ -1851,6 +2153,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_AP */
pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
}
+#ifdef CONFIG_SME
#ifdef CONFIG_SAE
if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
#ifdef CONFIG_AP
@@ -1864,6 +2167,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
pos += ret;
}
#endif /* CONFIG_SAE */
+#endif /* CONFIG_SME */
ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
wpa_supplicant_state_txt(wpa_s->wpa_state));
if (os_snprintf_error(end - pos, ret))
@@ -1985,6 +2289,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
pos += res;
}
+#ifdef CONFIG_MACSEC
+ res = ieee802_1x_kay_get_status(wpa_s->kay, pos, end - pos);
+ if (res > 0)
+ pos += res;
+#endif /* CONFIG_MACSEC */
+
sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
if (sess_id) {
char *start = pos;
@@ -2018,6 +2328,13 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_WPS */
+ if (wpa_s->ieee80211ac) {
+ ret = os_snprintf(pos, end - pos, "ieee80211ac=1\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef ANDROID
/*
* Allow using the STATUS command with default behavior, say for debug,
@@ -2374,6 +2691,59 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
}
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sFILS-SHA256",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "%sFILS-SHA384",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+ if (data.key_mgmt & WPA_KEY_MGMT_OWE) {
+ ret = os_snprintf(pos, end - pos, "%sOWE",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP
+ if (data.key_mgmt & WPA_KEY_MGMT_DPP) {
+ ret = os_snprintf(pos, end - pos, "%sDPP",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_DPP */
+
if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
ret = os_snprintf(pos, end - pos, "%sOSEN",
pos == start ? "" : "+");
@@ -2449,7 +2819,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2, *osen_ie, *p2p, *mesh;
+ const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe;
mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -2480,6 +2850,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(
if (osen_ie)
pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
osen_ie, 2 + osen_ie[1]);
+ owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+ if (owe) {
+ ret = os_snprintf(pos, end - pos,
+ ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
ret = os_snprintf(pos, end - pos, "[WEP]");
@@ -2545,6 +2923,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(
pos += ret;
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_FILS
+ if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
+ ret = os_snprintf(pos, end - pos, "[FILS]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
#ifdef CONFIG_FST
if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
ret = os_snprintf(pos, end - pos, "[FST]");
@@ -2553,6 +2939,12 @@ static int wpa_supplicant_ctrl_iface_scan_result(
pos += ret;
}
#endif /* CONFIG_FST */
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) {
+ ret = os_snprintf(pos, end - pos, "[UTF-8]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\t%s",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -2703,6 +3095,40 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove(
return 0;
}
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(cmd, addr) < 0)
+ return -1;
+
+ return wpas_mesh_peer_remove(wpa_s, addr);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_add(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ int duration;
+ char *pos;
+
+ pos = os_strstr(cmd, " duration=");
+ if (pos) {
+ *pos = '\0';
+ duration = atoi(pos + 10);
+ } else {
+ duration = -1;
+ }
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ return wpas_mesh_peer_add(wpa_s, addr, duration);
+}
+
#endif /* CONFIG_MESH */
@@ -2738,9 +3164,8 @@ static int wpa_supplicant_ctrl_iface_select_network(
if (pos) {
int *freqs = freq_range_to_channel_list(wpa_s, pos + 6);
if (freqs) {
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- os_free(wpa_s->manual_scan_freqs);
- wpa_s->manual_scan_freqs = freqs;
+ os_free(wpa_s->select_network_scan_freqs);
+ wpa_s->select_network_scan_freqs = freqs;
}
}
@@ -2832,15 +3257,10 @@ static int wpa_supplicant_ctrl_iface_add_network(
wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
- ssid = wpa_config_add_network(wpa_s->conf);
+ ssid = wpa_supplicant_add_network(wpa_s);
if (ssid == NULL)
return -1;
- wpas_notify_network_added(wpa_s, ssid);
-
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
-
ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
if (os_snprintf_error(buflen, ret))
return -1;
@@ -2853,7 +3273,7 @@ static int wpa_supplicant_ctrl_iface_remove_network(
{
int id;
struct wpa_ssid *ssid;
- int was_disabled;
+ int result;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
@@ -2889,54 +3309,17 @@ static int wpa_supplicant_ctrl_iface_remove_network(
id = atoi(cmd);
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid)
- wpas_notify_network_removed(wpa_s, ssid);
- if (ssid == NULL) {
+ result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
"id=%d", id);
return -1;
}
-
- if (wpa_s->last_ssid == ssid)
- wpa_s->last_ssid = NULL;
-
- if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- /*
- * Invalidate the EAP session cache if the current or
- * previously used network is removed.
- */
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
- }
-
- if (ssid == wpa_s->current_ssid) {
- wpa_sm_set_config(wpa_s->wpa, NULL);
- eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-
- if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
- wpa_s->own_disconnect_req = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- }
-
- was_disabled = ssid->disabled;
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (result == -2) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
"network id=%d", id);
return -1;
}
-
- if (!was_disabled && wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
- "network from filters");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
-
return 0;
}
@@ -2945,22 +3328,30 @@ static int wpa_supplicant_ctrl_iface_update_network(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
char *name, char *value)
{
- if (wpa_config_set(ssid, name, value, 0) < 0) {
+ int ret;
+
+ ret = wpa_config_set(ssid, name, value, 0);
+ if (ret < 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
"variable '%s'", name);
return -1;
}
+ if (ret == 1)
+ return 0; /* No change to the previously configured value */
if (os_strcmp(name, "bssid") != 0 &&
- os_strcmp(name, "priority") != 0)
+ os_strcmp(name, "bssid_hint") != 0 &&
+ os_strcmp(name, "priority") != 0) {
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
- /*
- * Invalidate the EAP session cache if anything in the current
- * or previously used configuration changes.
- */
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ if (wpa_s->current_ssid == ssid ||
+ wpa_s->current_ssid == NULL) {
+ /*
+ * Invalidate the EAP session cache if anything in the
+ * current or previously used configuration changes.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
}
if ((os_strcmp(name, "psk") == 0 &&
@@ -3585,6 +3976,66 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
pos += ret;
}
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_OWE
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
+ ret = os_snprintf(pos, end - pos, " OWE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
+ ret = os_snprintf(pos, end - pos, " DPP");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_FILS
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, " FILS-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, " FILS-SHA384");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, " FT-FILS-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, " FT-FILS-SHA384");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
+ ret = os_snprintf(pos, end - pos, " FT-PSK");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, " SAE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
return pos - buf;
}
@@ -3687,6 +4138,26 @@ static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (wpa_is_fils_supported(wpa_s)) {
+ ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITHOUT_PFS",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+#ifdef CONFIG_FILS_SK_PFS
+ if (wpa_is_fils_sk_pfs_supported(wpa_s)) {
+ ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITH_PFS",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+#endif /* CONFIG_FILS */
+
return pos - buf;
}
@@ -3935,6 +4406,56 @@ static int wpa_supplicant_ctrl_iface_get_capability(
}
#endif /* CONFIG_FIPS */
+#ifdef CONFIG_ACS
+ if (os_strcmp(field, "acs") == 0) {
+ res = os_snprintf(buf, buflen, "ACS");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_ACS */
+
+#ifdef CONFIG_FILS
+ if (os_strcmp(field, "fils") == 0) {
+#ifdef CONFIG_FILS_SK_PFS
+ if (wpa_is_fils_supported(wpa_s) &&
+ wpa_is_fils_sk_pfs_supported(wpa_s)) {
+ res = os_snprintf(buf, buflen, "FILS FILS-SK-PFS");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ if (wpa_is_fils_supported(wpa_s)) {
+ res = os_snprintf(buf, buflen, "FILS");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+ }
+#endif /* CONFIG_FILS */
+
+ if (os_strcmp(field, "multibss") == 0 && wpa_s->multi_bss_support) {
+ res = os_snprintf(buf, buflen, "MULTIBSS-STA");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+
+#ifdef CONFIG_DPP
+ if (os_strcmp(field, "dpp") == 0) {
+#ifdef CONFIG_DPP2
+ res = os_snprintf(buf, buflen, "DPP=2");
+#else /* CONFIG_DPP2 */
+ res = os_snprintf(buf, buflen, "DPP=1");
+#endif /* CONFIG_DPP2 */
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_DPP */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -3977,13 +4498,85 @@ static char * anqp_add_hex(char *pos, char *end, const char *title,
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_FILS
+static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end)
+{
+ char *start = pos;
+ const u8 *ie, *ie_end;
+ u16 info, realms;
+ int ret;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+ if (!ie)
+ return 0;
+ ie_end = ie + 2 + ie[1];
+ ie += 2;
+ if (ie_end - ie < 2)
+ return -1;
+
+ info = WPA_GET_LE16(ie);
+ ie += 2;
+ ret = os_snprintf(pos, end - pos, "fils_info=%04x\n", info);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ if (info & BIT(7)) {
+ /* Cache Identifier Included */
+ if (ie_end - ie < 2)
+ return -1;
+ ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n",
+ ie[0], ie[1]);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie += 2;
+ }
+
+ if (info & BIT(8)) {
+ /* HESSID Included */
+ if (ie_end - ie < ETH_ALEN)
+ return -1;
+ ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n",
+ MAC2STR(ie));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie += ETH_ALEN;
+ }
+
+ realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3;
+ if (realms) {
+ if (ie_end - ie < realms * 2)
+ return -1;
+ ret = os_snprintf(pos, end - pos, "fils_realms=");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, end - pos, ie, realms * 2);
+ if (ret <= 0)
+ return 0;
+ pos += ret;
+ ie += realms * 2;
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ return pos - start;
+}
+#endif /* CONFIG_FILS */
+
+
static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
unsigned long mask, char *buf, size_t buflen)
{
size_t i;
int ret;
char *pos, *end;
- const u8 *ie, *ie2, *osen_ie;
+ const u8 *ie, *ie2, *osen_ie, *mesh, *owe;
pos = buf;
end = buf + buflen;
@@ -4092,18 +4685,30 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
return 0;
pos += ret;
+ mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
+
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
if (ie)
pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
2 + ie[1]);
ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
if (ie2)
- pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
+ pos = wpa_supplicant_ie_txt(pos, end,
+ mesh ? "RSN" : "WPA2", ie2,
2 + ie2[1]);
osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
if (osen_ie)
pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
osen_ie, 2 + osen_ie[1]);
+ owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+ if (owe) {
+ ret = os_snprintf(
+ pos, end - pos,
+ ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
if (!ie && !ie2 && !osen_ie &&
(bss->caps & IEEE80211_CAP_PRIVACY)) {
@@ -4112,6 +4717,14 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
return 0;
pos += ret;
}
+
+ if (mesh) {
+ ret = os_snprintf(pos, end - pos, "[MESH]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
if (bss_is_dmg(bss)) {
const char *s;
ret = os_snprintf(pos, end - pos, "[DMG]");
@@ -4165,6 +4778,28 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos += ret;
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_FILS
+ if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
+ ret = os_snprintf(pos, end - pos, "[FILS]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_FST
+ if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
+ ret = os_snprintf(pos, end - pos, "[FST]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_FST */
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) {
+ ret = os_snprintf(pos, end - pos, "[UTF-8]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\n");
if (os_snprintf_error(end - pos, ret))
@@ -4195,9 +4830,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_P2P_SCAN) {
ie = (const u8 *) (bss + 1);
ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
+ if (ret >= end - pos)
return 0;
- pos += ret;
+ if (ret > 0)
+ pos += ret;
}
#endif /* CONFIG_P2P */
@@ -4231,6 +4867,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_INTERWORKING
if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
struct wpa_bss_anqp *anqp = bss->anqp;
+ struct wpa_bss_anqp_elem *elem;
+
pos = anqp_add_hex(pos, end, "anqp_capability_list",
anqp->capability_list);
pos = anqp_add_hex(pos, end, "anqp_venue_name",
@@ -4246,6 +4884,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
pos = anqp_add_hex(pos, end, "anqp_domain_name",
anqp->domain_name);
+ pos = anqp_add_hex(pos, end, "anqp_fils_realm_info",
+ anqp->fils_realm_info);
#ifdef CONFIG_HS20
pos = anqp_add_hex(pos, end, "hs20_capability_list",
anqp->hs20_capability_list);
@@ -4259,7 +4899,20 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
anqp->hs20_operating_class);
pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
anqp->hs20_osu_providers_list);
+ pos = anqp_add_hex(pos, end, "hs20_operator_icon_metadata",
+ anqp->hs20_operator_icon_metadata);
+ pos = anqp_add_hex(pos, end, "hs20_osu_providers_nai_list",
+ anqp->hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
+
+ dl_list_for_each(elem, &anqp->anqp_elems,
+ struct wpa_bss_anqp_elem, list) {
+ char title[20];
+
+ os_snprintf(title, sizeof(title), "anqp[%u]",
+ elem->infoid);
+ pos = anqp_add_hex(pos, end, title, elem->payload);
+ }
}
#endif /* CONFIG_INTERWORKING */
@@ -4267,9 +4920,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (mask & WPA_BSS_MASK_MESH_SCAN) {
ie = (const u8 *) (bss + 1);
ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
+ if (ret >= end - pos)
return 0;
- pos += ret;
+ if (ret > 0)
+ pos += ret;
}
#endif /* CONFIG_MESH */
@@ -4297,6 +4951,44 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
#endif /* CONFIG_FST */
+ if (mask & WPA_BSS_MASK_UPDATE_IDX) {
+ ret = os_snprintf(pos, end - pos, "update_idx=%u\n",
+ bss->last_update_idx);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ if ((mask & WPA_BSS_MASK_BEACON_IE) && bss->beacon_ie_len) {
+ ret = os_snprintf(pos, end - pos, "beacon_ie=");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ ie = (const u8 *) (bss + 1);
+ ie += bss->ie_len;
+ for (i = 0; i < bss->beacon_ie_len; i++) {
+ ret = os_snprintf(pos, end - pos, "%02x", *ie++);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+#ifdef CONFIG_FILS
+ if (mask & WPA_BSS_MASK_FILS_INDICATION) {
+ ret = print_fils_indication(bss, pos, end);
+ if (ret < 0)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
+
if (mask & WPA_BSS_MASK_DELIM) {
ret = os_snprintf(pos, end - pos, "====\n");
if (os_snprintf_error(end - pos, ret))
@@ -4387,6 +5079,8 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
bss = dl_list_entry(next, struct wpa_bss,
list_id);
}
+ } else if (os_strncmp(cmd, "CURRENT", 7) == 0) {
+ bss = wpa_s->current_bss;
#ifdef CONFIG_P2P
} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
if (hwaddr_aton(cmd + 13, bssid) == 0)
@@ -4402,10 +5096,11 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
bss = NULL;
dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
{
- if (i-- == 0) {
+ if (i == 0) {
bss = tmp;
break;
}
+ i--;
}
}
@@ -4676,7 +5371,7 @@ static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
return -1;
}
- if (isblank(*last)) {
+ if (isblank((unsigned char) *last)) {
i++;
break;
}
@@ -4848,6 +5543,30 @@ static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
}
+static int parse_freq(int chwidth, int freq2)
+{
+ if (freq2 < 0)
+ return -1;
+ if (freq2)
+ return VHT_CHANWIDTH_80P80MHZ;
+
+ switch (chwidth) {
+ case 0:
+ case 20:
+ case 40:
+ return VHT_CHANWIDTH_USE_HT;
+ case 80:
+ return VHT_CHANWIDTH_80MHZ;
+ case 160:
+ return VHT_CHANWIDTH_160MHZ;
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
+ chwidth);
+ return -1;
+ }
+}
+
+
static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
@@ -4864,7 +5583,10 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
int go_intent = -1;
int freq = 0;
int pd;
- int ht40, vht;
+ int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
+ size_t group_ssid_len = 0;
+ int he;
if (!wpa_s->global->p2p_init_wpa_s)
return -1;
@@ -4877,7 +5599,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] [vht] [auto] */
+ * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -4908,6 +5630,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
+ he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -4925,11 +5648,41 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
return -1;
}
+ pos2 = os_strstr(pos, " freq2=");
+ if (pos2)
+ freq2 = atoi(pos2 + 7);
+
+ pos2 = os_strstr(pos, " max_oper_chwidth=");
+ if (pos2)
+ chwidth = atoi(pos2 + 18);
+
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
+
+ pos2 = os_strstr(pos, " ssid=");
+ if (pos2) {
+ char *end;
+
+ pos2 += 6;
+ end = os_strchr(pos2, ' ');
+ if (!end)
+ group_ssid_len = os_strlen(pos2) / 2;
+ else
+ group_ssid_len = (end - pos2) / 2;
+ if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN ||
+ hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0)
+ return -1;
+ group_ssid = _group_ssid;
+ }
+
if (os_strncmp(pos, "pin", 3) == 0) {
/* Request random PIN (to be displayed) and enable the PIN */
wps_method = WPS_PIN_DISPLAY;
} else if (os_strncmp(pos, "pbc", 3) == 0) {
wps_method = WPS_PBC;
+ } else if (os_strstr(pos, "p2ps") != NULL) {
+ wps_method = WPS_P2PS;
} else {
pin = pos;
pos = os_strchr(pin, ' ');
@@ -4938,8 +5691,6 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
*pos++ = '\0';
if (os_strncmp(pos, "display", 7) == 0)
wps_method = WPS_PIN_DISPLAY;
- else if (os_strncmp(pos, "p2ps", 4) == 0)
- wps_method = WPS_P2PS;
}
if (!wps_pin_str_valid(pin)) {
os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
@@ -4949,8 +5700,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
- auth, go_intent, freq, persistent_id, pd,
- ht40, vht);
+ auth, go_intent, freq, freq2, persistent_id,
+ pd, ht40, vht, max_oper_chwidth, he,
+ group_ssid, group_ssid_len);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -5505,7 +6257,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
- int ht40, vht;
+ int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -5542,9 +6294,22 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
+ he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
- return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
- pref_freq);
+ pos = os_strstr(cmd, "freq2=");
+ if (pos)
+ freq2 = atoi(pos + 6);
+
+ pos = os_strstr(cmd, " max_oper_chwidth=");
+ if (pos)
+ chwidth = atoi(pos + 18);
+
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
+
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
+ max_oper_chwidth, pref_freq, he);
}
@@ -5591,7 +6356,9 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
- int id, int freq, int ht40, int vht)
+ int id, int freq, int vht_center_freq2,
+ int ht40, int vht, int vht_chwidth,
+ int he)
{
struct wpa_ssid *ssid;
@@ -5603,8 +6370,9 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
- NULL, 0, 0);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
+ vht_center_freq2, 0, ht40, vht,
+ vht_chwidth, he, NULL, 0, 0);
}
@@ -5613,17 +6381,31 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
int freq = 0, persistent = 0, group_id = -1;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ int he = wpa_s->conf->p2p_go_he;
+ int max_oper_chwidth, chwidth = 0, freq2 = 0;
char *token, *context = NULL;
+#ifdef CONFIG_ACS
+ int acs = 0;
+#endif /* CONFIG_ACS */
while ((token = str_token(cmd, " ", &context))) {
- if (sscanf(token, "freq=%d", &freq) == 1 ||
- sscanf(token, "persistent=%d", &group_id) == 1) {
+ if (sscanf(token, "freq2=%d", &freq2) == 1 ||
+ sscanf(token, "persistent=%d", &group_id) == 1 ||
+ sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
+ continue;
+#ifdef CONFIG_ACS
+ } else if (os_strcmp(token, "freq=acs") == 0) {
+ acs = 1;
+#endif /* CONFIG_ACS */
+ } else if (sscanf(token, "freq=%d", &freq) == 1) {
continue;
} else if (os_strcmp(token, "ht40") == 0) {
ht40 = 1;
} else if (os_strcmp(token, "vht") == 0) {
vht = 1;
ht40 = 1;
+ } else if (os_strcmp(token, "he") == 0) {
+ he = 1;
} else if (os_strcmp(token, "persistent") == 0) {
persistent = 1;
} else {
@@ -5634,18 +6416,81 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
}
}
+#ifdef CONFIG_ACS
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ (acs || freq == 2 || freq == 5)) {
+ if (freq == 2 && wpa_s->best_24_freq <= 0) {
+ wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211G;
+ wpa_s->p2p_go_do_acs = 1;
+ freq = 0;
+ } else if (freq == 5 && wpa_s->best_5_freq <= 0) {
+ wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211A;
+ wpa_s->p2p_go_do_acs = 1;
+ freq = 0;
+ } else {
+ wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211ANY;
+ wpa_s->p2p_go_do_acs = 1;
+ }
+ } else {
+ wpa_s->p2p_go_do_acs = 0;
+ }
+#endif /* CONFIG_ACS */
+
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
+
if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id,
- freq, ht40, vht);
+ freq, freq2, ht40, vht,
+ max_oper_chwidth, he);
+
+ return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
+ max_oper_chwidth, he);
+}
+
+
+static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
+ char *buf, size_t buflen)
+{
+ u8 dev_addr[ETH_ALEN];
+ struct wpa_ssid *ssid;
+ int res;
+ const u8 *iaddr;
+
+ ssid = wpa_s->current_ssid;
+ if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
+ hwaddr_aton(cmd, dev_addr))
+ return -1;
+
+ iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
+ if (!iaddr)
+ return -1;
+ res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+}
+
- return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht);
+static int wpas_find_p2p_dev_addr_bss(struct wpa_global *global,
+ const u8 *p2p_dev_addr)
+{
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (wpa_bss_get_p2p_dev_addr(wpa_s, p2p_dev_addr))
+ return 1;
+ }
+
+ return 0;
}
static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
- u8 addr[ETH_ALEN], *addr_ptr;
+ u8 addr[ETH_ALEN], *addr_ptr, group_capab;
int next, res;
const struct p2p_peer_info *info;
char *pos, *end;
@@ -5674,6 +6519,16 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
if (info == NULL)
return -1;
+ group_capab = info->group_capab;
+
+ if (group_capab &&
+ !wpas_find_p2p_dev_addr_bss(wpa_s->global, info->p2p_device_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Could not find any BSS with p2p_dev_addr "
+ MACSTR ", hence override group_capab from 0x%x to 0",
+ MAC2STR(info->p2p_device_addr), group_capab);
+ group_capab = 0;
+ }
pos = buf;
end = buf + buflen;
@@ -5699,7 +6554,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
info->serial_number,
info->config_methods,
info->dev_capab,
- info->group_capab,
+ group_capab,
info->level);
if (os_snprintf_error(end - pos, res))
return pos - buf;
@@ -5797,8 +6652,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
}
if (os_strcmp(cmd, "listen_channel") == 0) {
- return p2p_set_listen_channel(wpa_s->global->p2p, 81,
- atoi(param), 1);
+ char *pos;
+ u8 channel, op_class;
+
+ channel = atoi(param);
+ pos = os_strchr(param, ' ');
+ op_class = pos ? atoi(pos) : 81;
+
+ return p2p_set_listen_channel(wpa_s->global->p2p, op_class,
+ channel, 1);
}
if (os_strcmp(cmd, "ssid_postfix") == 0) {
@@ -5973,6 +6835,20 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
return 0;
}
+ if (os_strcmp(cmd, "override_pref_op_chan") == 0) {
+ int op_class, chan;
+
+ op_class = atoi(param);
+ param = os_strchr(param, ':');
+ if (!param)
+ return -1;
+ param++;
+ chan = atoi(param);
+ p2p_set_override_pref_op_chan(wpa_s->global->p2p, op_class,
+ chan);
+ return 0;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
@@ -5984,6 +6860,12 @@ static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
{
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->force_long_sd = 0;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(wpa_s->get_pref_freq_list_override);
+ wpa_s->get_pref_freq_list_override = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
+
wpas_p2p_stop_find(wpa_s);
wpa_s->parent->p2ps_method_config_any = 0;
if (wpa_s->global->p2p)
@@ -6059,6 +6941,21 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
return 0;
}
+
+static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int freq = 0, period = 0, interval = 0, count = 0;
+
+ if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
+ {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
+ return -1;
+ }
+
+ return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
+}
+
#endif /* CONFIG_P2P */
@@ -6176,6 +7073,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
u16 id[MAX_ANQP_INFO_ID];
size_t num_id = 0;
u32 subtypes = 0;
+ u32 mbo_subtypes = 0;
used = hwaddr_aton2(dst, dst_addr);
if (used < 0)
@@ -6193,6 +7091,16 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
#else /* CONFIG_HS20 */
return -1;
#endif /* CONFIG_HS20 */
+ } else if (os_strncmp(pos, "mbo:", 4) == 0) {
+#ifdef CONFIG_MBO
+ int num = atoi(pos + 4);
+
+ if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE)
+ return -1;
+ mbo_subtypes |= BIT(num);
+#else /* CONFIG_MBO */
+ return -1;
+#endif /* CONFIG_MBO */
} else {
id[num_id] = atoi(pos);
if (id[num_id])
@@ -6204,10 +7112,11 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
pos++;
}
- if (num_id == 0)
+ if (num_id == 0 && !subtypes && !mbo_subtypes)
return -1;
- return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
+ return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+ mbo_subtypes);
}
@@ -6378,7 +7287,7 @@ static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (subtypes == 0)
return -1;
- return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+ return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
}
@@ -6401,7 +7310,7 @@ static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
ret = hs20_anqp_send_req(wpa_s, addr,
BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
- buf, len);
+ buf, len, 0);
os_free(buf);
@@ -6447,14 +7356,59 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
ret = hs20_anqp_send_req(wpa_s, dst_addr,
BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
- buf, len);
+ buf, len, 0);
os_free(buf);
return ret;
}
-static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
+static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
+ int buflen)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *ctx = NULL, *icon, *poffset, *psize;
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+ cmd += used;
+
+ icon = str_token(cmd, " ", &ctx);
+ poffset = str_token(cmd, " ", &ctx);
+ psize = str_token(cmd, " ", &ctx);
+ if (!icon || !poffset || !psize)
+ return -1;
+
+ wpa_s->fetch_osu_icon_in_progress = 0;
+ return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
+ reply, buflen);
+}
+
+
+static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *icon;
+
+ if (!cmd[0])
+ return hs20_del_icon(wpa_s, NULL, NULL);
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+
+ while (cmd[used] == ' ')
+ used++;
+ icon = cmd[used] ? &cmd[used] : NULL;
+
+ return hs20_del_icon(wpa_s, dst_addr, icon);
+}
+
+
+static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
{
u8 dst_addr[ETH_ALEN];
int used;
@@ -6470,7 +7424,7 @@ static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
wpa_s->fetch_osu_icon_in_progress = 0;
return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
- (u8 *) icon, os_strlen(icon));
+ (u8 *) icon, os_strlen(icon), inmem);
}
#endif /* CONFIG_HS20 */
@@ -6499,6 +7453,9 @@ static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
autoscan_init(wpa_s, 1);
else if (state == WPA_SCANNING)
wpa_supplicant_reinit_autoscan(wpa_s);
+ else
+ wpa_printf(MSG_DEBUG, "No autoscan update in state %s",
+ wpa_supplicant_state_txt(state));
return 0;
}
@@ -6560,14 +7517,42 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
{
- int query_reason;
+ int query_reason, list = 0;
+ char *btm_candidates = NULL;
query_reason = atoi(cmd);
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
- query_reason);
+ cmd = os_strchr(cmd, ' ');
+ if (cmd) {
+ if (os_strncmp(cmd, " list", 5) == 0)
+ list = 1;
+ else
+ btm_candidates = cmd;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s",
+ query_reason, list ? " candidate list" : "");
- return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+ return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason,
+ btm_candidates,
+ list);
+}
+
+
+static int wpas_ctrl_iface_coloc_intf_report(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ struct wpabuf *elems;
+ int ret;
+
+ elems = wpabuf_parse_bin(cmd);
+ if (!elems)
+ return -1;
+
+ ret = wnm_send_coloc_intf_report(wpa_s, 0, elems);
+ wpabuf_free(elems);
+ return ret;
}
#endif /* CONFIG_WNM */
@@ -6603,10 +7588,17 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
pos += ret;
}
- if (si.center_frq1 > 0 && si.center_frq2 > 0) {
- ret = os_snprintf(pos, end - pos,
- "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
- si.center_frq1, si.center_frq2);
+ if (si.center_frq1 > 0) {
+ ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n",
+ si.center_frq1);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (si.center_frq2 > 0) {
+ ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n",
+ si.center_frq2);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
@@ -6632,6 +7624,68 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
}
+static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ const char *pos;
+ int threshold = 0;
+ int hysteresis = 0;
+
+ if (wpa_s->bgscan && wpa_s->bgscan_priv) {
+ wpa_printf(MSG_DEBUG,
+ "Reject SIGNAL_MONITOR command - bgscan is active");
+ return -1;
+ }
+ pos = os_strstr(cmd, "THRESHOLD=");
+ if (pos)
+ threshold = atoi(pos + 10);
+ pos = os_strstr(cmd, "HYSTERESIS=");
+ if (pos)
+ hysteresis = atoi(pos + 11);
+ return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type if_type,
+ unsigned int *num,
+ unsigned int *freq_list)
+{
+ char *pos = wpa_s->get_pref_freq_list_override;
+ char *end;
+ unsigned int count = 0;
+
+ /* Override string format:
+ * <if_type1>:<freq1>,<freq2>,... <if_type2>:... */
+
+ while (pos) {
+ if (atoi(pos) == (int) if_type)
+ break;
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+ if (!pos)
+ return -1;
+ pos = os_strchr(pos, ':');
+ if (!pos)
+ return -1;
+ pos++;
+ end = os_strchr(pos, ' ');
+ while (pos && (!end || pos < end) && count < *num) {
+ freq_list[count++] = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos)
+ pos++;
+ }
+
+ *num = count;
+ return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static int wpas_ctrl_iface_get_pref_freq_list(
struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
{
@@ -6661,7 +7715,7 @@ static int wpas_ctrl_iface_get_pref_freq_list(
wpa_printf(MSG_DEBUG,
"CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)",
- iface_type, buf);
+ iface_type, cmd);
ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list);
if (ret)
@@ -6679,6 +7733,34 @@ static int wpas_ctrl_iface_get_pref_freq_list(
}
+static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) wpa_s->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (wpa_s->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -6736,13 +7818,13 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
/* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
vendor_id = strtoul(cmd, &pos, 16);
- if (!isblank(*pos))
+ if (!isblank((unsigned char) *pos))
return -EINVAL;
subcmd = strtoul(pos, &pos, 10);
if (*pos != '\0') {
- if (!isblank(*pos++))
+ if (!isblank((unsigned char) *pos++))
return -EINVAL;
data_len = os_strlen(pos);
}
@@ -6790,10 +7872,21 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
+ if (wpas_abort_ongoing_scan(wpa_s) == 0)
+ wpa_s->ignore_post_flush_scan_res = 1;
+
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ /*
+ * Avoid possible auto connect re-connection on getting
+ * disconnected due to state flush.
+ */
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ }
+
#ifdef CONFIG_P2P
+ wpas_p2p_group_remove(p2p_wpa_s, "*");
wpas_p2p_cancel(p2p_wpa_s);
p2p_ctrl_flush(p2p_wpa_s);
- wpas_p2p_group_remove(p2p_wpa_s, "*");
wpas_p2p_service_flush(p2p_wpa_s);
p2p_wpa_s->global->p2p_disabled = 0;
p2p_wpa_s->global->p2p_per_sta_psk = 0;
@@ -6803,12 +7896,15 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;
p2p_wpa_s->global->pending_p2ps_group = 0;
+ p2p_wpa_s->global->pending_p2ps_group_freq = 0;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS_TESTING
wps_version_number = 0x20;
wps_testing_dummy_cred = 0;
wps_corrupt_pkhash = 0;
+ wps_force_auth_types_in_use = 0;
+ wps_force_encr_types_in_use = 0;
#endif /* CONFIG_WPS_TESTING */
#ifdef CONFIG_WPS
wpa_s->wps_fragment_size = 0;
@@ -6818,9 +7914,24 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->after_wps = 0;
wpa_s->known_wps_freq = 0;
+#ifdef CONFIG_DPP
+ wpas_dpp_deinit(wpa_s);
+ wpa_s->dpp_init_max_tries = 0;
+ wpa_s->dpp_init_retry_time = 0;
+ wpa_s->dpp_resp_wait_time = 0;
+ wpa_s->dpp_resp_max_tries = 0;
+ wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
+ os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
+ dpp_pkex_ephemeral_key_override_len = 0;
+ dpp_protocol_key_override_len = 0;
+ dpp_nonce_override_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_DPP */
+
#ifdef CONFIG_TDLS
#ifdef CONFIG_TDLS_TESTING
- extern unsigned int tdls_testing;
tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
@@ -6866,7 +7977,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->next_ssid = NULL;
#ifdef CONFIG_INTERWORKING
+#ifdef CONFIG_HS20
hs20_cancel_fetch_osu(wpa_s);
+ hs20_del_icon(wpa_s, NULL, NULL);
+#endif /* CONFIG_HS20 */
#endif /* CONFIG_INTERWORKING */
wpa_s->ext_mgmt_frame_handling = 0;
@@ -6874,11 +7988,32 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->extra_roc_dur = 0;
wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
+ wpa_s->p2p_go_csa_on_inv = 0;
+ wpa_s->ignore_auth_resp = 0;
+ wpa_s->ignore_assoc_disallow = 0;
+ wpa_s->testing_resend_assoc = 0;
+ wpa_s->reject_btm_req_reason = 0;
+ wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
+ os_free(wpa_s->get_pref_freq_list_override);
+ wpa_s->get_pref_freq_list_override = NULL;
+ wpabuf_free(wpa_s->sae_commit_override);
+ wpa_s->sae_commit_override = NULL;
+#ifdef CONFIG_DPP
+ os_free(wpa_s->dpp_config_obj_override);
+ wpa_s->dpp_config_obj_override = NULL;
+ os_free(wpa_s->dpp_discovery_override);
+ wpa_s->dpp_discovery_override = NULL;
+ os_free(wpa_s->dpp_groups_override);
+ wpa_s->dpp_groups_override = NULL;
+ dpp_test = DPP_TEST_DISABLED;
+#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
wpa_s->disconnected = 0;
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ os_free(wpa_s->select_network_scan_freqs);
+ wpa_s->select_network_scan_freqs = NULL;
wpa_bss_flush(wpa_s);
if (!dl_list_empty(&wpa_s->bss)) {
@@ -6892,6 +8027,17 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
wpa_s->wnmsleep_used = 0;
+
+#ifdef CONFIG_SME
+ wpa_s->sme.last_unprot_disconnect.sec = 0;
+#endif /* CONFIG_SME */
+
+ wpabuf_free(wpa_s->ric_ies);
+ wpa_s->ric_ies = NULL;
+
+ wpa_supplicant_update_channel_list(wpa_s, NULL);
+
+ free_bss_tmp_disallowed(wpa_s);
}
@@ -6948,6 +8094,13 @@ static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
work, NULL);
+ /*
+ * work->type points to a buffer in ework, so need to replace
+ * that here with a fixed string to avoid use of freed memory
+ * in debug prints.
+ */
+ work->type = "freed-ext-work";
+ work->ctx = NULL;
os_free(ework);
return;
}
@@ -7182,6 +8335,19 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
goto done;
}
+ pos = os_strstr(params, "bssid=");
+ if (pos) {
+ u8 bssid[ETH_ALEN];
+
+ pos += 6;
+ if (hwaddr_aton(pos, bssid)) {
+ wpa_printf(MSG_ERROR, "Invalid BSSID %s", pos);
+ *reply_len = -1;
+ goto done;
+ }
+ os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN);
+ }
+
pos = params;
while (pos && *pos != '\0') {
if (os_strncmp(pos, "ssid ", 5) == 0) {
@@ -7397,6 +8563,194 @@ static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
}
+static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf;
+ int freq = 0, datarate = 0, ssi_signal = 0;
+ union wpa_event_data event;
+
+ if (!wpa_s->ext_mgmt_frame_handling)
+ return -1;
+
+ /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
+
+ pos = cmd;
+ param = os_strstr(pos, "freq=");
+ if (param) {
+ param += 5;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " datarate=");
+ if (param) {
+ param += 10;
+ datarate = atoi(param);
+ }
+
+ param = os_strstr(pos, " ssi_signal=");
+ if (param) {
+ param += 12;
+ ssi_signal = atoi(param);
+ }
+
+ param = os_strstr(pos, " frame=");
+ if (param == NULL)
+ return -1;
+ param += 7;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.freq = freq;
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.datarate = datarate;
+ wpa_s->ext_mgmt_frame_handling = 0;
+ wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
+ wpa_s->ext_mgmt_frame_handling = 1;
+
+ os_free(buf);
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s,
+ char *param)
+{
+ struct wpa_scan_res *res;
+ struct os_reltime now;
+ char *pos, *end;
+ int ret = -1;
+
+ if (!param)
+ return -1;
+
+ if (os_strcmp(param, "START") == 0) {
+ wpa_bss_update_start(wpa_s);
+ return 0;
+ }
+
+ if (os_strcmp(param, "END") == 0) {
+ wpa_bss_update_end(wpa_s, NULL, 1);
+ return 0;
+ }
+
+ if (os_strncmp(param, "BSS ", 4) != 0)
+ return -1;
+ param += 3;
+
+ res = os_zalloc(sizeof(*res) + os_strlen(param) / 2);
+ if (!res)
+ return -1;
+
+ pos = os_strstr(param, " flags=");
+ if (pos)
+ res->flags = strtol(pos + 7, NULL, 16);
+
+ pos = os_strstr(param, " bssid=");
+ if (pos && hwaddr_aton(pos + 7, res->bssid))
+ goto fail;
+
+ pos = os_strstr(param, " freq=");
+ if (pos)
+ res->freq = atoi(pos + 6);
+
+ pos = os_strstr(param, " beacon_int=");
+ if (pos)
+ res->beacon_int = atoi(pos + 12);
+
+ pos = os_strstr(param, " caps=");
+ if (pos)
+ res->caps = strtol(pos + 6, NULL, 16);
+
+ pos = os_strstr(param, " qual=");
+ if (pos)
+ res->qual = atoi(pos + 6);
+
+ pos = os_strstr(param, " noise=");
+ if (pos)
+ res->noise = atoi(pos + 7);
+
+ pos = os_strstr(param, " level=");
+ if (pos)
+ res->level = atoi(pos + 7);
+
+ pos = os_strstr(param, " tsf=");
+ if (pos)
+ res->tsf = strtoll(pos + 5, NULL, 16);
+
+ pos = os_strstr(param, " age=");
+ if (pos)
+ res->age = atoi(pos + 5);
+
+ pos = os_strstr(param, " est_throughput=");
+ if (pos)
+ res->est_throughput = atoi(pos + 16);
+
+ pos = os_strstr(param, " snr=");
+ if (pos)
+ res->snr = atoi(pos + 5);
+
+ pos = os_strstr(param, " parent_tsf=");
+ if (pos)
+ res->parent_tsf = strtoll(pos + 7, NULL, 16);
+
+ pos = os_strstr(param, " tsf_bssid=");
+ if (pos && hwaddr_aton(pos + 11, res->tsf_bssid))
+ goto fail;
+
+ pos = os_strstr(param, " ie=");
+ if (pos) {
+ pos += 4;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+ res->ie_len = (end - pos) / 2;
+ if (hexstr2bin(pos, (u8 *) (res + 1), res->ie_len))
+ goto fail;
+ }
+
+ pos = os_strstr(param, " beacon_ie=");
+ if (pos) {
+ pos += 11;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+ res->beacon_ie_len = (end - pos) / 2;
+ if (hexstr2bin(pos, ((u8 *) (res + 1)) + res->ie_len,
+ res->beacon_ie_len))
+ goto fail;
+ }
+
+ os_get_reltime(&now);
+ wpa_bss_update_scan_res(wpa_s, res, &now);
+ ret = 0;
+fail:
+ os_free(res);
+
+ return ret;
+}
+
+
static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos, *param;
@@ -7427,6 +8781,8 @@ static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
wpa_supplicant_event(wpa_s, ev, &event);
os_free(event.freq_range.range);
return 0;
+ } else if (os_strcmp(cmd, "SCAN_RES") == 0) {
+ return wpas_ctrl_iface_driver_scan_res(wpa_s, param);
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
cmd);
@@ -7496,33 +8852,47 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len)
#define HWSIM_PACKETLEN 1500
#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
-void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
const struct ether_header *eth;
struct iphdr ip;
const u8 *pos;
unsigned int i;
+ char extra[30];
- if (len != HWSIM_PACKETLEN)
+ if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore unexpected length %d",
+ (int) len);
return;
+ }
eth = (const struct ether_header *) buf;
os_memcpy(&ip, eth + 1, sizeof(ip));
pos = &buf[sizeof(*eth) + sizeof(ip)];
if (ip.ihl != 5 || ip.version != 4 ||
- ntohs(ip.tot_len) != HWSIM_IP_LEN)
+ ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore unexpect IP header");
return;
+ }
- for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
- if (*pos != (u8) i)
+ for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+ if (*pos != (u8) i) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore mismatching payload");
return;
+ }
pos++;
}
-
- wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
- MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+ extra[0] = '\0';
+ if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+ wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
+ MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -7530,6 +8900,8 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
char *cmd)
{
int enabled = atoi(cmd);
+ char *pos;
+ const char *ifname;
if (!enabled) {
if (wpa_s->l2_test) {
@@ -7543,7 +8915,13 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
if (wpa_s->l2_test)
return 0;
- wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
+ pos = os_strstr(cmd, " ifname=");
+ if (pos)
+ ifname = pos + 8;
+ else
+ ifname = wpa_s->ifname;
+
+ wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr,
ETHERTYPE_IP, wpas_data_test_rx,
wpa_s, 1);
if (wpa_s->l2_test == NULL)
@@ -7558,7 +8936,7 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
{
u8 dst[ETH_ALEN], src[ETH_ALEN];
- char *pos;
+ char *pos, *pos2;
int used;
long int val;
u8 tos;
@@ -7567,11 +8945,12 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
struct iphdr *ip;
u8 *dpos;
unsigned int i;
+ size_t send_len = HWSIM_IP_LEN;
if (wpa_s->l2_test == NULL)
return -1;
- /* format: <dst> <src> <tos> */
+ /* format: <dst> <src> <tos> [len=<length>] */
pos = cmd;
used = hwaddr_aton2(pos, dst);
@@ -7585,11 +8964,19 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
pos += used;
- val = strtol(pos, NULL, 0);
+ val = strtol(pos, &pos2, 0);
if (val < 0 || val > 0xff)
return -1;
tos = val;
+ pos = os_strstr(pos2, " len=");
+ if (pos) {
+ i = atoi(pos + 5);
+ if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
+ return -1;
+ send_len = i;
+ }
+
eth = (struct ether_header *) &buf[2];
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
@@ -7600,17 +8987,17 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
ip->version = 4;
ip->ttl = 64;
ip->tos = tos;
- ip->tot_len = htons(HWSIM_IP_LEN);
+ ip->tot_len = htons(send_len);
ip->protocol = 1;
ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
- for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
+ for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
- HWSIM_PACKETLEN) < 0)
+ sizeof(struct ether_header) + send_len) < 0)
return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
@@ -7664,8 +9051,6 @@ done:
static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
char *pos;
wpa_trace_fail_after = atoi(cmd);
@@ -7688,9 +9073,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
wpa_trace_fail_func);
#else /* WPA_TRACE_BFD */
@@ -7702,8 +9084,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
char *pos;
wpa_trace_test_fail_after = atoi(cmd);
@@ -7726,9 +9106,6 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
wpa_trace_test_fail_func);
#else /* WPA_TRACE_BFD */
@@ -7736,62 +9113,137 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
#endif /* WPA_TRACE_BFD */
}
-#endif /* CONFIG_TESTING_OPTIONS */
+
+static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int i, count = (intptr_t) timeout_ctx;
+
+ wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
+ count);
+ for (i = 0; i < count; i++) {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
+ i + 1, count);
+ }
+}
-static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
{
- unsigned int i;
- char buf[30];
+ int count;
- wpa_printf(MSG_DEBUG, "Update vendor elements");
+ count = atoi(cmd);
+ if (count <= 0)
+ return -1;
- for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
- if (wpa_s->vendor_elem[i]) {
- int res;
+ return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
+ (void *) (intptr_t) count);
+}
- res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
- if (!os_snprintf_error(sizeof(buf), res)) {
- wpa_hexdump_buf(MSG_DEBUG, buf,
- wpa_s->vendor_elem[i]);
- }
+
+static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ len = os_strlen(cmd);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ if (len == 0) {
+ buf = NULL;
+ } else {
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
}
}
-#ifdef CONFIG_P2P
- if (wpa_s->parent == wpa_s &&
- wpa_s->global->p2p &&
- !wpa_s->global->p2p_disabled)
- p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
-#endif /* CONFIG_P2P */
+ wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
+ return 0;
}
-static struct wpa_supplicant *
-wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
- enum wpa_vendor_elem_frame frame)
+static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
{
- switch (frame) {
-#ifdef CONFIG_P2P
- case VENDOR_ELEM_PROBE_REQ_P2P:
- case VENDOR_ELEM_PROBE_RESP_P2P:
- case VENDOR_ELEM_PROBE_RESP_P2P_GO:
- case VENDOR_ELEM_BEACON_P2P_GO:
- case VENDOR_ELEM_P2P_PD_REQ:
- case VENDOR_ELEM_P2P_PD_RESP:
- case VENDOR_ELEM_P2P_GO_NEG_REQ:
- case VENDOR_ELEM_P2P_GO_NEG_RESP:
- case VENDOR_ELEM_P2P_GO_NEG_CONF:
- case VENDOR_ELEM_P2P_INV_REQ:
- case VENDOR_ELEM_P2P_INV_RESP:
- case VENDOR_ELEM_P2P_ASSOC_REQ:
- return wpa_s->parent;
-#endif /* CONFIG_P2P */
- default:
- return wpa_s;
- }
+ u8 zero[WPA_TK_MAX_LEN];
+
+ if (wpa_s->last_tk_alg == WPA_ALG_NONE)
+ return -1;
+
+ wpa_printf(MSG_INFO, "TESTING: Reset PN");
+ os_memset(zero, 0, sizeof(zero));
+
+ /* First, use a zero key to avoid any possible duplicate key avoidance
+ * in the driver. */
+ if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
+ wpa_s->last_tk_key_idx, 1, zero, 6,
+ zero, wpa_s->last_tk_len) < 0)
+ return -1;
+
+ /* Set the previously configured key to reset its TSC/RSC */
+ return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
+ wpa_s->last_tk_key_idx, 1, zero, 6,
+ wpa_s->last_tk, wpa_s->last_tk_len);
+}
+
+
+static int wpas_ctrl_key_request(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos = cmd;
+ int error, pairwise;
+
+ error = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pairwise = atoi(pos);
+ wpa_sm_key_request(wpa_s->wpa, error, pairwise);
+ return 0;
+}
+
+
+static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+ struct wpa_driver_associate_params params;
+ int ret;
+
+ os_memset(&params, 0, sizeof(params));
+ params.bssid = wpa_s->bssid;
+ params.ssid = wpa_s->sme.ssid;
+ params.ssid_len = wpa_s->sme.ssid_len;
+ params.freq.freq = wpa_s->sme.freq;
+ if (wpa_s->last_assoc_req_wpa_ie) {
+ params.wpa_ie = wpabuf_head(wpa_s->last_assoc_req_wpa_ie);
+ params.wpa_ie_len = wpabuf_len(wpa_s->last_assoc_req_wpa_ie);
+ }
+ params.pairwise_suite = wpa_s->pairwise_cipher;
+ params.group_suite = wpa_s->group_cipher;
+ params.mgmt_group_suite = wpa_s->mgmt_group_cipher;
+ params.key_mgmt_suite = wpa_s->key_mgmt;
+ params.wpa_proto = wpa_s->wpa_proto;
+ params.mgmt_frame_protection = wpa_s->sme.mfp;
+ params.rrm_used = wpa_s->rrm.rrm_used;
+ if (wpa_s->sme.prev_bssid_set)
+ params.prev_bssid = wpa_s->sme.prev_bssid;
+ wpa_printf(MSG_INFO, "TESTING: Resend association request");
+ ret = wpa_drv_associate(wpa_s, &params);
+ wpa_s->testing_resend_assoc = 1;
+ return ret;
+#else /* CONFIG_SME */
+ return -1;
+#endif /* CONFIG_SME */
}
+#endif /* CONFIG_TESTING_OPTIONS */
+
static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
{
@@ -7804,7 +9256,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
frame = atoi(pos);
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
pos = os_strchr(pos, ' ');
if (pos == NULL)
@@ -7835,7 +9287,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
if (wpa_s->vendor_elem[frame] == NULL) {
wpa_s->vendor_elem[frame] = buf;
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -7846,7 +9298,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
wpabuf_free(buf);
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -7859,7 +9311,7 @@ static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
if (wpa_s->vendor_elem[frame] == NULL)
return 0;
@@ -7877,12 +9329,12 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
size_t len;
u8 *buf;
struct ieee802_11_elems elems;
- u8 *ie, *end;
+ int res;
frame = atoi(pos);
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
pos = os_strchr(pos, ' ');
if (pos == NULL)
@@ -7892,7 +9344,7 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
if (*pos == '*') {
wpabuf_free(wpa_s->vendor_elem[frame]);
wpa_s->vendor_elem[frame] = NULL;
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -7920,65 +9372,149 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
}
- ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
- end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
-
- for (; ie + 1 < end; ie += 2 + ie[1]) {
- if (ie + len > end)
- break;
- if (os_memcmp(ie, buf, len) != 0)
- continue;
-
- if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
- wpabuf_free(wpa_s->vendor_elem[frame]);
- wpa_s->vendor_elem[frame] = NULL;
- } else {
- os_memmove(ie, ie + len,
- end - (ie + len));
- wpa_s->vendor_elem[frame]->used -= len;
- }
- os_free(buf);
- wpas_ctrl_vendor_elem_update(wpa_s);
- return 0;
- }
-
+ res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
os_free(buf);
-
- return -1;
+ return res;
}
static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
{
struct wpa_supplicant *wpa_s = ctx;
+ size_t len;
+ const u8 *data;
- if (neighbor_rep) {
- wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
- "length=%u",
- (unsigned int) wpabuf_len(neighbor_rep));
- wpabuf_free(neighbor_rep);
- } else {
+ /*
+ * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
+ * BSSID[6]
+ * BSSID Information[4]
+ * Operating Class[1]
+ * Channel Number[1]
+ * PHY Type[1]
+ * Optional Subelements[variable]
+ */
+#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
+
+ if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
+ goto out;
}
+
+ data = wpabuf_head_u8(neighbor_rep);
+ len = wpabuf_len(neighbor_rep);
+
+ while (len >= 2 + NR_IE_MIN_LEN) {
+ const u8 *nr;
+ char lci[256 * 2 + 1];
+ char civic[256 * 2 + 1];
+ u8 nr_len = data[1];
+ const u8 *pos = data, *end;
+
+ if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
+ nr_len < NR_IE_MIN_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%u",
+ data[0], nr_len);
+ goto out;
+ }
+
+ if (2U + nr_len > len) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
+ data[0], len, nr_len);
+ goto out;
+ }
+ pos += 2;
+ end = pos + nr_len;
+
+ nr = pos;
+ pos += NR_IE_MIN_LEN;
+
+ lci[0] = '\0';
+ civic[0] = '\0';
+ while (end - pos > 2) {
+ u8 s_id, s_len;
+
+ s_id = *pos++;
+ s_len = *pos++;
+ if (s_len > end - pos)
+ goto out;
+ if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
+ /* Measurement Token[1] */
+ /* Measurement Report Mode[1] */
+ /* Measurement Type[1] */
+ /* Measurement Report[variable] */
+ switch (pos[2]) {
+ case MEASURE_TYPE_LCI:
+ if (lci[0])
+ break;
+ wpa_snprintf_hex(lci, sizeof(lci),
+ pos, s_len);
+ break;
+ case MEASURE_TYPE_LOCATION_CIVIC:
+ if (civic[0])
+ break;
+ wpa_snprintf_hex(civic, sizeof(civic),
+ pos, s_len);
+ break;
+ }
+ }
+
+ pos += s_len;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+ "bssid=" MACSTR
+ " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
+ MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
+ nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
+ nr[ETH_ALEN + 6],
+ lci[0] ? " lci=" : "", lci,
+ civic[0] ? " civic=" : "", civic);
+
+ data = end;
+ len -= 2 + nr_len;
+ }
+
+out:
+ wpabuf_free(neighbor_rep);
}
-static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
- char *cmd)
+static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
+ char *cmd)
{
- struct wpa_ssid ssid;
- struct wpa_ssid *ssid_p = NULL;
- int ret = 0;
+ struct wpa_ssid_value ssid, *ssid_p = NULL;
+ int ret, lci = 0, civic = 0;
+ char *ssid_s;
- if (os_strncmp(cmd, " ssid=", 6) == 0) {
- ssid.ssid_len = os_strlen(cmd + 6);
- if (ssid.ssid_len > SSID_MAX_LEN)
+ ssid_s = os_strstr(cmd, "ssid=");
+ if (ssid_s) {
+ if (ssid_parse(ssid_s + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: Send Neighbor Report: bad SSID");
return -1;
- ssid.ssid = (u8 *) (cmd + 6);
+ }
+
ssid_p = &ssid;
+
+ /*
+ * Move cmd after the SSID text that may include "lci" or
+ * "civic".
+ */
+ cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
+ if (cmd)
+ cmd++;
+
}
- ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
+ if (cmd && os_strstr(cmd, "lci"))
+ lci = 1;
+
+ if (cmd && os_strstr(cmd, "civic"))
+ civic = 1;
+
+ ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
wpas_ctrl_neighbor_rep_cb,
wpa_s);
@@ -8041,13 +9577,6 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
return -1;
}
- if ((wpa_s->mac_addr_rand_supported & type) != type) {
- wpa_printf(MSG_INFO,
- "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
- type, wpa_s->mac_addr_rand_supported);
- return -1;
- }
-
if (enable > 1) {
wpa_printf(MSG_INFO,
"CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
@@ -8063,10 +9592,7 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
}
} else if (wpa_s->sched_scanning &&
(type & MAC_ADDR_RAND_SCHED_SCAN)) {
- /* simulate timeout to restart the sched scan */
- wpa_s->sched_scan_timed_out = 1;
- wpa_s->prev_sched_ssid = NULL;
- wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpas_scan_restart_sched_scan(wpa_s);
}
return 0;
}
@@ -8084,25 +9610,25 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
}
if (type & MAC_ADDR_RAND_SCAN) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+ addr, mask))
+ return -1;
}
if (type & MAC_ADDR_RAND_SCHED_SCAN) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+ addr, mask))
+ return -1;
- if (wpa_s->sched_scanning && !wpa_s->pno) {
- /* simulate timeout to restart the sched scan */
- wpa_s->sched_scan_timed_out = 1;
- wpa_s->prev_sched_ssid = NULL;
- wpa_supplicant_cancel_sched_scan(wpa_s);
- }
+ if (wpa_s->sched_scanning && !wpa_s->pno)
+ wpas_scan_restart_sched_scan(wpa_s);
}
if (type & MAC_ADDR_RAND_PNO) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+ addr, mask))
+ return -1;
+
if (wpa_s->pno) {
wpas_stop_pno(wpa_s);
wpas_start_pno(wpa_s);
@@ -8113,6 +9639,271 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
}
+static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ size_t reply_len;
+
+ reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
+#ifdef CONFIG_AP
+ reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
+ buflen - reply_len);
+#endif /* CONFIG_AP */
+ return reply_len;
+}
+
+
+static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
+{
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+#ifdef CONFIG_AP
+ wpas_ap_pmksa_cache_flush(wpa_s);
+#endif /* CONFIG_AP */
+}
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+
+static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s,
+ const char *cmd, char *buf, size_t buflen)
+{
+ struct rsn_pmksa_cache_entry *entry;
+ struct wpa_ssid *ssid;
+ char *pos, *pos2, *end;
+ int ret;
+ struct os_reltime now;
+
+ ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+ if (!ssid)
+ return -1;
+
+ pos = buf;
+ end = buf + buflen;
+
+ os_get_reltime(&now);
+
+ /*
+ * Entry format:
+ * <BSSID> <PMKID> <PMK> <reauth_time in seconds>
+ * <expiration in seconds> <akmp> <opportunistic>
+ * [FILS Cache Identifier]
+ */
+
+ for (entry = wpa_sm_pmksa_cache_head(wpa_s->wpa); entry;
+ entry = entry->next) {
+ if (entry->network_ctx != ssid)
+ continue;
+
+ pos2 = pos;
+ ret = os_snprintf(pos2, end - pos2, MACSTR " ",
+ MAC2STR(entry->aa));
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmkid,
+ PMKID_LEN);
+
+ ret = os_snprintf(pos2, end - pos2, " ");
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmk,
+ entry->pmk_len);
+
+ ret = os_snprintf(pos2, end - pos2, " %d %d %d %d",
+ (int) (entry->reauth_time - now.sec),
+ (int) (entry->expiration - now.sec),
+ entry->akmp,
+ entry->opportunistic);
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ if (entry->fils_cache_id_set) {
+ ret = os_snprintf(pos2, end - pos2, " %02x%02x",
+ entry->fils_cache_id[0],
+ entry->fils_cache_id[1]);
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+ }
+
+ ret = os_snprintf(pos2, end - pos2, "\n");
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ pos = pos2;
+ }
+
+ return pos - buf;
+}
+
+
+static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ struct rsn_pmksa_cache_entry *entry;
+ struct wpa_ssid *ssid;
+ char *pos, *pos2;
+ int ret = -1;
+ struct os_reltime now;
+ int reauth_time = 0, expiration = 0, i;
+
+ /*
+ * Entry format:
+ * <network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds>
+ * <expiration in seconds> <akmp> <opportunistic>
+ * [FILS Cache Identifier]
+ */
+
+ ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+ if (!ssid)
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ return -1;
+
+ if (hwaddr_aton(pos, entry->aa))
+ goto fail;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ if (hexstr2bin(pos, entry->pmkid, PMKID_LEN) < 0)
+ goto fail;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ pos2 = os_strchr(pos, ' ');
+ if (!pos2)
+ goto fail;
+ entry->pmk_len = (pos2 - pos) / 2;
+ if (entry->pmk_len < PMK_LEN || entry->pmk_len > PMK_LEN_MAX ||
+ hexstr2bin(pos, entry->pmk, entry->pmk_len) < 0)
+ goto fail;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration,
+ &entry->akmp, &entry->opportunistic) != 4)
+ goto fail;
+ for (i = 0; i < 4; i++) {
+ pos = os_strchr(pos, ' ');
+ if (!pos) {
+ if (i < 3)
+ goto fail;
+ break;
+ }
+ pos++;
+ }
+ if (pos) {
+ if (hexstr2bin(pos, entry->fils_cache_id,
+ FILS_CACHE_ID_LEN) < 0)
+ goto fail;
+ entry->fils_cache_id_set = 1;
+ }
+ os_get_reltime(&now);
+ entry->expiration = now.sec + expiration;
+ entry->reauth_time = now.sec + reauth_time;
+
+ entry->network_ctx = ssid;
+
+ wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+ entry = NULL;
+ ret = 0;
+fail:
+ os_free(entry);
+ return ret;
+}
+
+
+#ifdef CONFIG_MESH
+
+static int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s,
+ const char *cmd, char *buf,
+ size_t buflen)
+{
+ u8 spa[ETH_ALEN];
+
+ if (!wpa_s->ifmsh)
+ return -1;
+
+ if (os_strcasecmp(cmd, "any") == 0)
+ return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen);
+
+ if (hwaddr_aton(cmd, spa))
+ return -1;
+
+ return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen);
+}
+
+
+static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ /*
+ * We do not check mesh interface existance because PMKSA should be
+ * stored before wpa_s->ifmsh creation to suppress commit message
+ * creation.
+ */
+ return wpas_ap_pmksa_cache_add_external(wpa_s, cmd);
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
+#ifdef CONFIG_FILS
+static int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct fils_hlp_req *req;
+ const char *pos;
+
+ /* format: <dst> <packet starting from ethertype> */
+
+ req = os_zalloc(sizeof(*req));
+ if (!req)
+ return -1;
+
+ if (hwaddr_aton(cmd, req->dst))
+ goto fail;
+
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ goto fail;
+ pos++;
+ req->pkt = wpabuf_parse_bin(pos);
+ if (!req->pkt)
+ goto fail;
+
+ dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list);
+ return 0;
+fail:
+ wpabuf_free(req->pkt);
+ os_free(req);
+ return -1;
+}
+#endif /* CONFIG_FILS */
+
+
static int wpas_ctrl_cmd_debug_level(const char *cmd)
{
if (os_strcmp(cmd, "PING") == 0 ||
@@ -8134,7 +9925,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
int reply_len;
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
- os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+ os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+ os_strncmp(buf, "PMKSA_ADD ", 10) == 0 ||
+ os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) {
if (wpa_debug_show_keys)
wpa_dbg(wpa_s, MSG_DEBUG,
"Control interface command '%s'", buf);
@@ -8143,7 +9936,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
"Control interface command '%s [REMOVED]'",
os_strncmp(buf, WPA_CTRL_RSP,
os_strlen(WPA_CTRL_RSP)) == 0 ?
- WPA_CTRL_RSP : "SET_NETWORK");
+ WPA_CTRL_RSP :
+ (os_strncmp(buf, "SET_NETWORK ", 12) == 0 ?
+ "SET_NETWORK" : "key-add"));
} else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) {
wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
@@ -8179,15 +9974,35 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len += eapol_sm_get_mib(wpa_s->eapol,
reply + reply_len,
reply_size - reply_len);
+#ifdef CONFIG_MACSEC
+ reply_len += ieee802_1x_kay_get_mib(
+ wpa_s->kay, reply + reply_len,
+ reply_size - reply_len);
+#endif /* CONFIG_MACSEC */
}
} else if (os_strncmp(buf, "STATUS", 6) == 0) {
reply_len = wpa_supplicant_ctrl_iface_status(
wpa_s, buf + 6, reply, reply_size);
} else if (os_strcmp(buf, "PMKSA") == 0) {
- reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
- reply_size);
+ reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
- wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+ wpas_ctrl_iface_pmksa_flush(wpa_s);
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ } else if (os_strncmp(buf, "PMKSA_GET ", 10) == 0) {
+ reply_len = wpas_ctrl_iface_pmksa_get(wpa_s, buf + 10,
+ reply, reply_size);
+ } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
+ if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0)
+ reply_len = -1;
+#ifdef CONFIG_MESH
+ } else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) {
+ reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15,
+ reply, reply_size);
+ } else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) {
+ if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0)
+ reply_len = -1;
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
} else if (os_strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
@@ -8224,11 +10039,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
reply_len = -1;
#endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_PEERKEY
- } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
- if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
- reply_len = -1;
-#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211R
} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
@@ -8355,6 +10165,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
buf + 18))
reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
+ reply_len = -1;
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
@@ -8389,6 +10205,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
+ reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
+ reply_size);
} else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
reply_len = -1;
@@ -8454,6 +10273,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
+ if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
+ if (wpas_p2p_lo_stop(wpa_s))
+ reply_len = -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -8507,10 +10332,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
- if (hs20_icon_request(wpa_s, buf + 18) < 0)
+ if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
+ if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
+ reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
+ if (del_hs20_icon(wpa_s, buf + 14) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "FETCH_OSU") == 0) {
- if (hs20_fetch_osu(wpa_s) < 0)
+ if (hs20_fetch_osu(wpa_s, 0) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
+ if (hs20_fetch_osu(wpa_s, 1) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
hs20_cancel_fetch_osu(wpa_s);
@@ -8549,16 +10385,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = wpa_supplicant_ctrl_iface_list_networks(
wpa_s, NULL, reply, reply_size);
} else if (os_strcmp(buf, "DISCONNECT") == 0) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- wpa_s->reassociate = 0;
- wpa_s->disconnected = 1;
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_cancel_scan(wpa_s);
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpas_request_disconnection(wpa_s);
} else if (os_strcmp(buf, "SCAN") == 0) {
wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
@@ -8566,6 +10393,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
+ } else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
+ if (wpas_abort_ongoing_scan(wpa_s) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
reply_len = -1;
@@ -8624,9 +10454,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
reply_len = wpa_supplicant_global_iface_list(
wpa_s->global, reply, reply_size);
- } else if (os_strcmp(buf, "INTERFACES") == 0) {
+ } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
reply_len = wpa_supplicant_global_iface_interfaces(
- wpa_s->global, reply, reply_size);
+ wpa_s->global, buf + 10, reply, reply_size);
} else if (os_strncmp(buf, "BSS ", 4) == 0) {
reply_len = wpa_supplicant_ctrl_iface_bss(
wpa_s, buf + 4, reply, reply_size);
@@ -8707,6 +10537,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
reply_size);
+ } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) {
+ if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14))
+ reply_len = -1;
} else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
reply_size);
@@ -8715,6 +10548,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_AUTOSCAN */
+ } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+ reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
+ reply_size);
#ifdef ANDROID
} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
@@ -8733,6 +10569,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
reply_len = -1;
+ } else if (os_strncmp(buf, "COLOC_INTF_REPORT ", 18) == 0) {
+ if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18))
+ reply_len = -1;
#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "FLUSH") == 0) {
wpa_supplicant_ctrl_iface_flush(wpa_s);
@@ -8745,6 +10584,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
wpas_ctrl_iface_mgmt_tx_done(wpa_s);
+ } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
+ if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
reply_len = -1;
@@ -8770,6 +10612,27 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "GET_FAIL") == 0) {
reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
+ if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
+ if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "RESET_PN") == 0) {
+ if (wpas_ctrl_reset_pn(wpa_s) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "KEY_REQUEST ", 12) == 0) {
+ if (wpas_ctrl_key_request(wpa_s, buf + 12) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "RESEND_ASSOC") == 0) {
+ if (wpas_ctrl_resend_assoc(wpa_s) < 0)
+ reply_len = -1;
+#ifdef CONFIG_IEEE80211W
+ } else if (os_strcmp(buf, "UNPROT_DEAUTH") == 0) {
+ sme_event_unprot_disconnect(
+ wpa_s, wpa_s->bssid, NULL,
+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -8781,7 +10644,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
- if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
+ if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
reply_len = -1;
} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
wpas_ctrl_iface_erp_flush(wpa_s);
@@ -8791,6 +10654,98 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) {
reply_len = wpas_ctrl_iface_get_pref_freq_list(
wpa_s, buf + 19, reply, reply_size);
+#ifdef CONFIG_FILS
+ } else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) {
+ if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) {
+ wpas_flush_fils_hlp_req(wpa_s);
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_DPP
+ } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
+ int res;
+
+ res = wpas_dpp_qr_code(wpa_s, buf + 12);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
+ int res;
+
+ res = dpp_bootstrap_gen(wpa_s->dpp, buf + 18);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
+ if (dpp_bootstrap_remove(wpa_s->dpp, buf + 21) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
+ const char *uri;
+
+ uri = dpp_bootstrap_get_uri(wpa_s->dpp, atoi(buf + 22));
+ if (!uri) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%s", uri);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
+ reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19),
+ reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
+ if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
+ if (wpas_dpp_listen(wpa_s, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
+ wpas_dpp_stop(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
+ int res;
+
+ res = dpp_configurator_add(wpa_s->dpp, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
+ if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
+ if (wpas_dpp_configurator_sign(wpa_s, buf + 21) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
+ reply_len = dpp_configurator_get_key_id(wpa_s->dpp,
+ atoi(buf + 25),
+ reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
+ int res;
+
+ res = wpas_dpp_pkex_add(wpa_s, buf + 12);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
+ if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0)
+ reply_len = -1;
+#endif /* CONFIG_DPP */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -8814,10 +10769,11 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
struct wpa_supplicant *wpa_s;
unsigned int create_iface = 0;
u8 mac_addr[ETH_ALEN];
+ enum wpa_driver_if_type type = WPA_IF_STATION;
/*
* <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
- * TAB<bridge_ifname>[TAB<create>]
+ * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
@@ -8885,9 +10841,22 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
if (!extra[0])
break;
- if (os_strcmp(extra, "create") == 0)
+ if (os_strcmp(extra, "create") == 0) {
create_iface = 1;
- else {
+ if (!pos)
+ break;
+
+ if (os_strcmp(pos, "sta") == 0) {
+ type = WPA_IF_STATION;
+ } else if (os_strcmp(pos, "ap") == 0) {
+ type = WPA_IF_AP_BSS;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "INTERFACE_ADD unsupported interface type: '%s'",
+ pos);
+ return -1;
+ }
+ } else {
wpa_printf(MSG_DEBUG,
"INTERFACE_ADD unsupported extra parameter: '%s'",
extra);
@@ -8900,7 +10869,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
iface.ifname);
if (!global->ifaces)
return -1;
- if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname,
+ if (wpa_drv_if_add(global->ifaces, type, iface.ifname,
NULL, NULL, NULL, mac_addr, NULL) < 0) {
wpa_printf(MSG_ERROR,
"CTRL_IFACE interface creation failed");
@@ -9009,18 +10978,31 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+ const char *input,
char *buf, int len)
{
int res;
char *pos, *end;
struct wpa_supplicant *wpa_s;
+ int show_ctrl = 0;
+
+ if (input)
+ show_ctrl = !!os_strstr(input, "ctrl");
wpa_s = global->ifaces;
pos = buf;
end = buf + len;
while (wpa_s) {
- res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
+ if (show_ctrl)
+ res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n",
+ wpa_s->ifname,
+ wpa_s->conf->ctrl_interface ?
+ wpa_s->conf->ctrl_interface : "N/A");
+ else
+ res = os_snprintf(pos, end - pos, "%s\n",
+ wpa_s->ifname);
+
if (os_snprintf_error(end - pos, res)) {
*pos = '\0';
break;
@@ -9073,12 +11055,16 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
"P2P_CANCEL",
"P2P_PRESENCE_REQ",
"P2P_EXT_LISTEN",
+#ifdef CONFIG_AP
+ "STA-FIRST",
+#endif /* CONFIG_AP */
NULL
};
static const char * prefix[] = {
#ifdef ANDROID
"DRIVER ",
#endif /* ANDROID */
+ "GET_CAPABILITY ",
"GET_NETWORK ",
"REMOVE_NETWORK ",
"P2P_FIND ",
@@ -9086,6 +11072,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
"P2P_LISTEN ",
"P2P_GROUP_REMOVE ",
"P2P_GROUP_ADD ",
+ "P2P_GROUP_MEMBER ",
"P2P_PROV_DISC ",
"P2P_SERV_DISC_REQ ",
"P2P_SERV_DISC_CANCEL_REQ ",
@@ -9109,6 +11096,10 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
"NFC_REPORT_HANDOVER ",
"P2P_ASP_PROVISION ",
"P2P_ASP_PROVISION_RESP ",
+#ifdef CONFIG_AP
+ "STA ",
+ "STA-NEXT ",
+#endif /* CONFIG_AP */
NULL
};
int found = 0;
@@ -9409,9 +11400,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
reply_len = wpa_supplicant_global_iface_list(
global, reply, reply_size);
- } else if (os_strcmp(buf, "INTERFACES") == 0) {
+ } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
reply_len = wpa_supplicant_global_iface_interfaces(
- global, reply, reply_size);
+ global, buf + 10, reply, reply_size);
#ifdef CONFIG_FST
} else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11,
@@ -9457,7 +11448,6 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
reply_size);
#ifdef CONFIG_MODULE_TESTS
} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
- int wpas_module_tests(void);
if (wpas_module_tests() < 0)
reply_len = -1;
#endif /* CONFIG_MODULE_TESTS */
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c b/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
index 54e0e2f..9c0a47e 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -319,13 +319,12 @@ static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len)
}
os_free(dst->rsp_buf);
- dst->rsp_buf = os_malloc(send_len);
+ dst->rsp_buf = os_memdup(send_buf, send_len);
if (dst->rsp_buf == NULL) {
ctrl_close_pipe(dst);
os_free(reply);
return;
}
- os_memcpy(dst->rsp_buf, send_buf, send_len);
os_free(reply);
if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
@@ -739,13 +738,12 @@ static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst,
}
os_free(dst->rsp_buf);
- dst->rsp_buf = os_malloc(send_len);
+ dst->rsp_buf = os_memdup(send_buf, send_len);
if (dst->rsp_buf == NULL) {
global_close_pipe(dst);
os_free(reply);
return;
}
- os_memcpy(dst->rsp_buf, send_buf, send_len);
os_free(reply);
if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c b/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
index 76f69f2..8a6057a 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -48,13 +48,33 @@ struct ctrl_iface_priv {
u8 cookie[COOKIE_LEN];
};
+struct ctrl_iface_global_priv {
+ int sock;
+ struct wpa_ctrl_dst *ctrl_dst;
+ u8 cookie[COOKIE_LEN];
+};
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+ const char *ifname, int sock,
+ struct wpa_ctrl_dst **head,
int level, const char *buf,
size_t len);
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+static void wpas_ctrl_iface_free_dst(struct wpa_ctrl_dst *dst)
+{
+ struct wpa_ctrl_dst *prev;
+
+ while (dst) {
+ prev = dst;
+ dst = dst->next;
+ os_free(prev);
+ }
+}
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head,
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 *from,
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -73,8 +93,8 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
os_memcpy(&dst->addr, from, sizeof(*from));
dst->addrlen = fromlen;
dst->debug_level = MSG_INFO;
- dst->next = priv->ctrl_dst;
- priv->ctrl_dst = dst;
+ dst->next = *head;
+ *head = dst;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)),
@@ -87,7 +107,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
}
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+static int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head,
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 *from,
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
@@ -100,7 +120,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
char addr[INET6_ADDRSTRLEN];
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
- dst = priv->ctrl_dst;
+ dst = *head;
while (dst) {
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
if (from->sin6_port == dst->addr.sin6_port &&
@@ -118,7 +138,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
ntohs(from->sin_port));
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
if (prev == NULL)
- priv->ctrl_dst = dst->next;
+ *head = dst->next;
else
prev->next = dst->next;
os_free(dst);
@@ -199,7 +219,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
- char buf[256], *pos;
+ char buf[4096], *pos;
int res;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 from;
@@ -282,14 +302,16 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
pos++;
if (os_strcmp(pos, "ATTACH") == 0) {
- if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+ if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+ &from, fromlen))
reply_len = 1;
else {
new_attached = 1;
reply_len = 2;
}
} else if (os_strcmp(pos, "DETACH") == 0) {
- if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+ if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
+ &from, fromlen))
reply_len = 1;
else
reply_len = 2;
@@ -327,9 +349,28 @@ static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
- if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+
+ if (!wpa_s)
return;
- wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+
+ if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
+ struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
+
+ if (priv->ctrl_dst) {
+ wpa_supplicant_ctrl_iface_send(
+ wpa_s,
+ type != WPA_MSG_PER_INTERFACE ?
+ NULL : wpa_s->ifname,
+ priv->sock, &priv->ctrl_dst, level, txt, len);
+ }
+ }
+
+ if (type == WPA_MSG_ONLY_GLOBAL || !wpa_s->ctrl_iface)
+ return;
+
+ wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
+ &wpa_s->ctrl_iface->ctrl_dst,
+ level, txt, len);
}
@@ -337,7 +378,9 @@ struct ctrl_iface_priv *
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
struct ctrl_iface_priv *priv;
+ char port_str[40];
int port = WPA_CTRL_IFACE_PORT;
+ char *pos;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 addr;
int domain = PF_INET6;
@@ -356,6 +399,17 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->ctrl_interface == NULL)
return priv;
+ pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:");
+ if (pos) {
+ pos += 4;
+ port = atoi(pos);
+ if (port <= 0) {
+ wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s",
+ wpa_s->conf->ctrl_interface);
+ goto fail;
+ }
+ }
+
priv->sock = socket(domain, SOCK_DGRAM, 0);
if (priv->sock < 0) {
wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
@@ -392,6 +446,15 @@ try_again:
goto fail;
}
+ /* Update the ctrl_interface value to match the selected port */
+ os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
+ os_free(wpa_s->conf->ctrl_interface);
+ wpa_s->conf->ctrl_interface = os_strdup(port_str);
+ if (!wpa_s->conf->ctrl_interface) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
+ goto fail;
+ }
+
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
@@ -412,8 +475,6 @@ fail:
void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
{
- struct wpa_ctrl_dst *dst, *prev;
-
if (priv->sock > -1) {
eloop_unregister_read_sock(priv->sock);
if (priv->ctrl_dst) {
@@ -430,22 +491,19 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
priv->sock = -1;
}
- dst = priv->ctrl_dst;
- while (dst) {
- prev = dst;
- dst = dst->next;
- os_free(prev);
- }
+ wpas_ctrl_iface_free_dst(priv->ctrl_dst);
os_free(priv);
}
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+ const char *ifname, int sock,
+ struct wpa_ctrl_dst **head,
int level, const char *buf,
size_t len)
{
struct wpa_ctrl_dst *dst, *next;
- char levelstr[10];
+ char levelstr[64];
int idx;
char *sbuf;
int llen;
@@ -453,11 +511,15 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
char addr[INET6_ADDRSTRLEN];
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
- dst = priv->ctrl_dst;
- if (priv->sock < 0 || dst == NULL)
+ dst = *head;
+ if (sock < 0 || dst == NULL)
return;
- os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+ if (ifname)
+ os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
+ ifname, level);
+ else
+ os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
llen = os_strlen(levelstr);
sbuf = os_malloc(llen + len);
@@ -481,7 +543,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
inet_ntoa(dst->addr.sin_addr),
ntohs(dst->addr.sin_port));
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
- if (sendto(priv->sock, sbuf, llen + len, 0,
+ if (sendto(sock, sbuf, llen + len, 0,
(struct sockaddr *) &dst->addr,
sizeof(dst->addr)) < 0) {
wpa_printf(MSG_ERROR,
@@ -490,7 +552,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
dst->errors++;
if (dst->errors > 10) {
wpa_supplicant_ctrl_iface_detach(
- priv, &dst->addr,
+ head, &dst->addr,
dst->addrlen);
}
} else
@@ -513,12 +575,6 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
/* Global ctrl_iface */
-struct ctrl_iface_global_priv {
- int sock;
- u8 cookie[COOKIE_LEN];
-};
-
-
static char *
wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
size_t *reply_len)
@@ -544,11 +600,15 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_global *global = eloop_ctx;
struct ctrl_iface_global_priv *priv = sock_ctx;
- char buf[256], *pos;
+ char buf[4096], *pos;
int res;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+ struct sockaddr_in6 from;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
struct sockaddr_in from;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
socklen_t fromlen = sizeof(from);
- char *reply;
+ char *reply = NULL;
size_t reply_len;
u8 cookie[COOKIE_LEN];
@@ -561,6 +621,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
}
#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+#ifndef CONFIG_CTRL_IFACE_UDP_IPV6
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -572,6 +633,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
buf[res] = '\0';
@@ -603,17 +665,34 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
while (*pos == ' ')
pos++;
- reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
- &reply_len);
+ if (os_strcmp(pos, "ATTACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
+ &from, fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else if (os_strcmp(pos, "DETACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
+ &from, fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else {
+ reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
+ &reply_len);
+ }
done:
if (reply) {
sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
fromlen);
os_free(reply);
- } else if (reply_len) {
+ } else if (reply_len == 1) {
sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
fromlen);
+ } else if (reply_len == 2) {
+ sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
+ fromlen);
}
}
@@ -623,6 +702,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
{
struct ctrl_iface_global_priv *priv;
struct sockaddr_in addr;
+ char *pos;
int port = WPA_GLOBAL_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
@@ -637,6 +717,17 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
wpa_printf(MSG_DEBUG, "Global control interface '%s'",
global->params.ctrl_interface);
+ pos = os_strstr(global->params.ctrl_interface, "udp:");
+ if (pos) {
+ pos += 4;
+ port = atoi(pos);
+ if (port <= 0) {
+ wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s",
+ global->params.ctrl_interface);
+ goto fail;
+ }
+ }
+
priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
if (priv->sock < 0) {
wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
@@ -655,7 +746,7 @@ try_again:
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
port++;
if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
- WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+ WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
goto try_again;
wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
goto fail;
@@ -668,6 +759,7 @@ try_again:
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
global, priv);
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
return priv;
@@ -686,5 +778,7 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
eloop_unregister_read_sock(priv->sock);
close(priv->sock);
}
+
+ wpas_ctrl_iface_free_dst(priv->ctrl_dst);
os_free(priv);
}
diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c b/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
index 11f2814..71fe7ed 100644
--- a/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
+++ b/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c
@@ -15,7 +15,6 @@
#include <fcntl.h>
#ifdef __linux__
#include <sys/ioctl.h>
-#include <linux/sockios.h>
#endif /* __linux__ */
#ifdef ANDROID
#include <cutils/sockets.h>
@@ -24,6 +23,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/list.h"
+#include "common/ctrl_iface_common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "config.h"
#include "wpa_supplicant_i.h"
@@ -31,27 +31,13 @@
/* Per-interface ctrl_iface */
-/**
- * struct wpa_ctrl_dst - Internal data structure of control interface monitors
- *
- * This structure is used to store information about registered control
- * interface monitors into struct wpa_supplicant. This data is private to
- * ctrl_iface_unix.c and should not be touched directly from other files.
- */
-struct wpa_ctrl_dst {
- struct dl_list list;
- struct sockaddr_un addr;
- socklen_t addrlen;
- int debug_level;
- int errors;
-};
-
-
struct ctrl_iface_priv {
struct wpa_supplicant *wpa_s;
int sock;
struct dl_list ctrl_dst;
int android_control_socket;
+ struct dl_list msg_queue;
+ unsigned int throttle_count;
};
@@ -60,6 +46,17 @@ struct ctrl_iface_global_priv {
int sock;
struct dl_list ctrl_dst;
int android_control_socket;
+ struct dl_list msg_queue;
+ unsigned int throttle_count;
+};
+
+struct ctrl_iface_msg {
+ struct dl_list list;
+ struct wpa_supplicant *wpa_s;
+ int level;
+ enum wpa_msg_type type;
+ const char *txt;
+ size_t len;
};
@@ -92,7 +89,7 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0)
sndbuf = -1;
- if (ioctl(sock, SIOCOUTQ, &outq) < 0)
+ if (ioctl(sock, TIOCOUTQ, &outq) < 0)
outq = -1;
wpa_printf(level,
@@ -103,81 +100,29 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf,
static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen, int global)
{
- struct wpa_ctrl_dst *dst;
- char addr_txt[200];
-
- 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;
- dl_list_add(ctrl_dst, &dst->list);
- printf_encode(addr_txt, sizeof(addr_txt),
- (u8 *) from->sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path));
- wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s",
- global ? "global " : "", addr_txt);
- return 0;
+ return ctrl_iface_attach(ctrl_dst, from, fromlen, NULL);
}
static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen)
{
- struct wpa_ctrl_dst *dst;
-
- dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
- if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path))
- == 0) {
- char addr_txt[200];
- printf_encode(addr_txt, sizeof(addr_txt),
- (u8 *) from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s",
- addr_txt);
- dl_list_del(&dst->list);
- os_free(dst);
- return 0;
- }
- }
- return -1;
+ return ctrl_iface_detach(ctrl_dst, from, fromlen);
}
static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
- struct sockaddr_un *from,
+ struct sockaddr_storage *from,
socklen_t fromlen,
char *level)
{
- struct wpa_ctrl_dst *dst;
-
wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
- dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
- if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - offsetof(struct sockaddr_un, sun_path))
- == 0) {
- char addr_txt[200];
- dst->debug_level = atoi(level);
- printf_encode(addr_txt, sizeof(addr_txt),
- (u8 *) from->sun_path, fromlen -
- offsetof(struct sockaddr_un, sun_path));
- wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s",
- dst->debug_level, addr_txt);
- return 0;
- }
- }
-
- return -1;
+ return ctrl_iface_level(&priv->ctrl_dst, from, fromlen, level);
}
@@ -188,7 +133,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
struct ctrl_iface_priv *priv = sock_ctx;
char buf[4096];
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply = NULL, *reply_buf = NULL;
size_t reply_len = 0;
@@ -334,33 +279,209 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
}
+static int wpas_ctrl_iface_throttle(int sock)
+{
+#ifdef __linux__
+ socklen_t optlen;
+ int sndbuf, outq;
+
+ optlen = sizeof(sndbuf);
+ sndbuf = 0;
+ if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 ||
+ ioctl(sock, TIOCOUTQ, &outq) < 0 ||
+ sndbuf <= 0 || outq < 0)
+ return 0;
+ return outq > sndbuf / 2;
+#else /* __linux__ */
+ return 0;
+#endif /* __linux__ */
+}
+
+
+static void wpas_ctrl_msg_send_pending_global(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *gpriv;
+ struct ctrl_iface_msg *msg;
+
+ gpriv = global->ctrl_iface;
+ while (gpriv && !dl_list_empty(&gpriv->msg_queue) &&
+ !wpas_ctrl_iface_throttle(gpriv->sock)) {
+ msg = dl_list_first(&gpriv->msg_queue, struct ctrl_iface_msg,
+ list);
+ if (!msg)
+ break;
+ dl_list_del(&msg->list);
+ wpa_supplicant_ctrl_iface_send(
+ msg->wpa_s,
+ msg->type != WPA_MSG_PER_INTERFACE ?
+ NULL : msg->wpa_s->ifname,
+ gpriv->sock, &gpriv->ctrl_dst, msg->level,
+ msg->txt, msg->len, NULL, gpriv);
+ os_free(msg);
+ }
+}
+
+
+static void wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+ struct ctrl_iface_msg *msg;
+
+ priv = wpa_s->ctrl_iface;
+ while (priv && !dl_list_empty(&priv->msg_queue) &&
+ !wpas_ctrl_iface_throttle(priv->sock)) {
+ msg = dl_list_first(&priv->msg_queue, struct ctrl_iface_msg,
+ list);
+ if (!msg)
+ break;
+ dl_list_del(&msg->list);
+ wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock,
+ &priv->ctrl_dst, msg->level,
+ msg->txt, msg->len, priv, NULL);
+ os_free(msg);
+ }
+}
+
+
+static void wpas_ctrl_msg_queue_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct ctrl_iface_priv *priv;
+ struct ctrl_iface_global_priv *gpriv;
+ int sock = -1, gsock = -1;
+
+ wpas_ctrl_msg_send_pending_global(wpa_s->global);
+ wpas_ctrl_msg_send_pending_iface(wpa_s);
+
+ priv = wpa_s->ctrl_iface;
+ if (priv && !dl_list_empty(&priv->msg_queue))
+ sock = priv->sock;
+
+ gpriv = wpa_s->global->ctrl_iface;
+ if (gpriv && !dl_list_empty(&gpriv->msg_queue))
+ gsock = gpriv->sock;
+
+ if (sock > -1 || gsock > -1) {
+ /* Continue pending message transmission from a timeout */
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle pending event message transmission for (sock %d gsock %d)",
+ sock, gsock);
+ eloop_register_timeout(0, 20000, wpas_ctrl_msg_queue_timeout,
+ wpa_s, NULL);
+ }
+}
+
+
+static void wpas_ctrl_msg_queue(struct dl_list *queue,
+ struct wpa_supplicant *wpa_s, int level,
+ enum wpa_msg_type type,
+ const char *txt, size_t len)
+{
+ struct ctrl_iface_msg *msg;
+
+ msg = os_zalloc(sizeof(*msg) + len);
+ if (!msg)
+ return;
+
+ msg->wpa_s = wpa_s;
+ msg->level = level;
+ msg->type = type;
+ os_memcpy(msg + 1, txt, len);
+ msg->txt = (const char *) (msg + 1);
+ msg->len = len;
+ dl_list_add_tail(queue, &msg->list);
+ eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
+ eloop_register_timeout(0, 0, wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
+}
+
+
+static void wpas_ctrl_msg_queue_limit(unsigned int throttle_count,
+ struct dl_list *queue)
+{
+ struct ctrl_iface_msg *msg;
+
+ if (throttle_count < 2000)
+ return;
+
+ msg = dl_list_first(queue, struct ctrl_iface_msg, list);
+ if (msg) {
+ wpa_printf(MSG_DEBUG, "CTRL: Dropped oldest pending message");
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
+}
+
+
static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
enum wpa_msg_type type,
const char *txt, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct ctrl_iface_priv *priv;
+ struct ctrl_iface_global_priv *gpriv;
if (wpa_s == NULL)
return;
- if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
- struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
- if (!dl_list_empty(&priv->ctrl_dst)) {
+ gpriv = wpa_s->global->ctrl_iface;
+
+ if (type != WPA_MSG_NO_GLOBAL && gpriv &&
+ !dl_list_empty(&gpriv->ctrl_dst)) {
+ if (!dl_list_empty(&gpriv->msg_queue) ||
+ wpas_ctrl_iface_throttle(gpriv->sock)) {
+ if (gpriv->throttle_count == 0) {
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle global event message for sock %d",
+ gpriv->sock);
+ }
+ gpriv->throttle_count++;
+ wpas_ctrl_msg_queue_limit(gpriv->throttle_count,
+ &gpriv->msg_queue);
+ wpas_ctrl_msg_queue(&gpriv->msg_queue, wpa_s, level,
+ type, txt, len);
+ } else {
+ if (gpriv->throttle_count) {
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle %u global event message(s) for sock %d",
+ gpriv->throttle_count, gpriv->sock);
+ }
+ gpriv->throttle_count = 0;
wpa_supplicant_ctrl_iface_send(
wpa_s,
type != WPA_MSG_PER_INTERFACE ?
NULL : wpa_s->ifname,
- priv->sock, &priv->ctrl_dst, level, txt, len,
- NULL, priv);
+ gpriv->sock, &gpriv->ctrl_dst, level,
+ txt, len, NULL, gpriv);
}
}
- if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL)
- return;
- wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
- &wpa_s->ctrl_iface->ctrl_dst,
- level, txt, len, wpa_s->ctrl_iface,
- NULL);
+ priv = wpa_s->ctrl_iface;
+
+ if (type != WPA_MSG_ONLY_GLOBAL && priv) {
+ if (!dl_list_empty(&priv->msg_queue) ||
+ wpas_ctrl_iface_throttle(priv->sock)) {
+ if (priv->throttle_count == 0) {
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle event message for sock %d",
+ priv->sock);
+ }
+ priv->throttle_count++;
+ wpas_ctrl_msg_queue_limit(priv->throttle_count,
+ &priv->msg_queue);
+ wpas_ctrl_msg_queue(&priv->msg_queue, wpa_s, level,
+ type, txt, len);
+ } else {
+ if (priv->throttle_count) {
+ wpa_printf(MSG_MSGDUMP,
+ "CTRL: Had to throttle %u event message(s) for sock %d",
+ priv->throttle_count, priv->sock);
+ }
+ priv->throttle_count = 0;
+ wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock,
+ &priv->ctrl_dst, level,
+ txt, len, priv, NULL);
+ }
+ }
}
@@ -449,8 +570,8 @@ static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
}
}
- if (gid_set && chown(dir, -1, gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ if (gid_set && lchown(dir, -1, gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s",
dir, (int) gid, strerror(errno));
goto fail;
}
@@ -517,8 +638,8 @@ static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
}
}
- if (gid_set && chown(fname, -1, gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ if (gid_set && lchown(fname, -1, gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s",
fname, (int) gid, strerror(errno));
goto fail;
}
@@ -578,6 +699,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
if (priv == NULL)
return NULL;
dl_list_init(&priv->ctrl_dst);
+ dl_list_init(&priv->msg_queue);
priv->wpa_s = wpa_s;
priv->sock = -1;
@@ -671,6 +793,8 @@ static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
{
struct wpa_ctrl_dst *dst, *prev;
+ struct ctrl_iface_msg *msg, *prev_msg;
+ struct ctrl_iface_global_priv *gpriv;
if (priv->sock > -1) {
char *fname;
@@ -724,8 +848,26 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
free_dst:
dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
- list)
+ list) {
+ dl_list_del(&dst->list);
os_free(dst);
+ }
+ dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue,
+ struct ctrl_iface_msg, list) {
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
+ gpriv = priv->wpa_s->global->ctrl_iface;
+ if (gpriv) {
+ dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue,
+ struct ctrl_iface_msg, list) {
+ if (msg->wpa_s == priv->wpa_s) {
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
+ }
+ }
+ eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL);
os_free(priv);
}
@@ -785,33 +927,31 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
int _errno;
- char addr_txt[200];
+ char txt[200];
if (level < dst->debug_level)
continue;
- printf_encode(addr_txt, sizeof(addr_txt),
- (u8 *) dst->addr.sun_path, dst->addrlen -
- offsetof(struct sockaddr_un, sun_path));
msg.msg_name = (void *) &dst->addr;
msg.msg_namelen = dst->addrlen;
wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len);
if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
- wpa_printf(MSG_MSGDUMP,
- "CTRL_IFACE monitor sent successfully to %s",
- addr_txt);
+ sockaddr_print(MSG_MSGDUMP,
+ "CTRL_IFACE monitor sent successfully to",
+ &dst->addr, dst->addrlen);
dst->errors = 0;
continue;
}
_errno = errno;
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s",
- addr_txt, errno, strerror(errno));
+ os_snprintf(txt, sizeof(txt), "CTRL_IFACE monitor: %d (%s) for",
+ _errno, strerror(_errno));
+ sockaddr_print(MSG_DEBUG, txt, &dst->addr, dst->addrlen);
dst->errors++;
if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
- wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages",
- addr_txt);
+ sockaddr_print(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages:",
+ &dst->addr, dst->addrlen);
wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
dst->addrlen);
}
@@ -845,9 +985,12 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
{
char buf[256];
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
+ if (priv->sock == -1)
+ return;
+
for (;;) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
"attach", priv->wpa_s->ifname);
@@ -905,7 +1048,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
struct ctrl_iface_global_priv *priv = sock_ctx;
char buf[4096];
int res;
- struct sockaddr_un from;
+ struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply = NULL, *reply_buf = NULL;
size_t reply_len;
@@ -1092,9 +1235,9 @@ static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
(int) gid);
}
- if (chown(ctrl, -1, gid) < 0) {
+ if (lchown(ctrl, -1, gid) < 0) {
wpa_printf(MSG_ERROR,
- "chown[global_ctrl_interface=%s,gid=%d]: %s",
+ "lchown[global_ctrl_interface=%s,gid=%d]: %s",
ctrl, (int) gid, strerror(errno));
goto fail;
}
@@ -1155,6 +1298,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
if (priv == NULL)
return NULL;
dl_list_init(&priv->ctrl_dst);
+ dl_list_init(&priv->msg_queue);
priv->global = global;
priv->sock = -1;
@@ -1204,6 +1348,7 @@ void
wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
{
struct wpa_ctrl_dst *dst, *prev;
+ struct ctrl_iface_msg *msg, *prev_msg;
if (priv->sock >= 0) {
eloop_unregister_read_sock(priv->sock);
@@ -1212,7 +1357,14 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
if (priv->global->params.ctrl_interface)
unlink(priv->global->params.ctrl_interface);
dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
- list)
+ list) {
+ dl_list_del(&dst->list);
os_free(dst);
+ }
+ dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue,
+ struct ctrl_iface_msg, list) {
+ dl_list_del(&msg->list);
+ os_free(msg);
+ }
os_free(priv);
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/Makefile b/contrib/wpa/wpa_supplicant/dbus/Makefile
index f355ebe..4d87004 100644
--- a/contrib/wpa/wpa_supplicant/dbus/Makefile
+++ b/contrib/wpa/wpa_supplicant/dbus/Makefile
@@ -36,7 +36,6 @@ CFLAGS += -DCONFIG_WPS
endif
CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
-CFLAGS += -DCONFIG_CTRL_IFACE_DBUS
ifndef DBUS_LIBS
DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
@@ -54,8 +53,6 @@ CFLAGS += $(DBUS_INCLUDE)
LIB_OBJS= \
dbus_common.o \
- dbus_old.o \
- dbus_old_handlers.o \
dbus_new.o \
dbus_new_handlers.o \
dbus_new_helpers.o \
@@ -63,7 +60,6 @@ LIB_OBJS= \
dbus_dict_helpers.o
ifdef CONFIG_WPS
-LIB_OBJS += dbus_old_handlers_wps.o
LIB_OBJS += dbus_new_handlers_wps.o
endif
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
index c091234..e81b495 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
@@ -3,11 +3,6 @@
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
- <allow own="fi.epitest.hostap.WPASupplicant"/>
-
- <allow send_destination="fi.epitest.hostap.WPASupplicant"/>
- <allow send_interface="fi.epitest.hostap.WPASupplicant"/>
-
<allow own="fi.w1.wpa_supplicant1"/>
<allow send_destination="fi.w1.wpa_supplicant1"/>
@@ -15,13 +10,8 @@
<allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
</policy>
<policy context="default">
- <deny own="fi.epitest.hostap.WPASupplicant"/>
- <deny send_destination="fi.epitest.hostap.WPASupplicant"/>
- <deny send_interface="fi.epitest.hostap.WPASupplicant"/>
-
<deny own="fi.w1.wpa_supplicant1"/>
<deny send_destination="fi.w1.wpa_supplicant1"/>
- <deny send_interface="fi.w1.wpa_supplicant1"/>
<deny receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
</policy>
</busconfig>
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_common.c b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
index 7ef6cad..efa6c7b 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_common.c
@@ -16,7 +16,6 @@
#include "dbus_common.h"
#include "dbus_common_i.h"
#include "dbus_new.h"
-#include "dbus_old.h"
#include "../wpa_supplicant_i.h"
@@ -351,9 +350,6 @@ struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
wpas_dbus_ctrl_iface_init(priv) < 0 ||
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-#ifdef CONFIG_CTRL_IFACE_DBUS
- wpa_supplicant_dbus_ctrl_iface_init(priv) < 0 ||
-#endif /* CONFIG_CTRL_IFACE_DBUS */
wpas_dbus_init_common_finish(priv) < 0) {
wpas_dbus_deinit(priv);
return NULL;
@@ -372,9 +368,5 @@ void wpas_dbus_deinit(struct wpas_dbus_priv *priv)
wpas_dbus_ctrl_iface_deinit(priv);
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-#ifdef CONFIG_CTRL_IFACE_DBUS
- /* TODO: is any deinit needed? */
-#endif /* CONFIG_CTRL_IFACE_DBUS */
-
wpas_dbus_deinit_common(priv);
}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_common_i.h b/contrib/wpa/wpa_supplicant/dbus/dbus_common_i.h
index a551ccd..95eb4bc 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_common_i.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_common_i.h
@@ -13,6 +13,8 @@
#include <dbus/dbus.h>
+struct wpa_dbus_property_desc;
+
struct wpas_dbus_priv {
DBusConnection *con;
int should_dispatch;
@@ -20,9 +22,13 @@ struct wpas_dbus_priv {
u32 next_objid;
int dbus_new_initialized;
-#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP)
+#if defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+ struct wpa_dbus_property_desc *all_interface_properties;
+ int globals_start;
+#if defined(CONFIG_AP)
int dbus_noc_refcnt;
-#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */
+#endif /* CONFIG_AP */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
};
#endif /* DBUS_COMMON_I_H */
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c
index a0c44eb..e4e9b8d 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -205,24 +205,6 @@ dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
/**
- * Add a byte entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- * wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The byte value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
- const char *key, const char value)
-{
- return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
- &value);
-}
-
-
-/**
* Add a boolean entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
@@ -317,62 +299,6 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
/**
- * Add a 64-bit integer entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- * wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The 64-bit integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
- const char *key,
- const dbus_int64_t value)
-{
- return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
- &value);
-}
-
-
-/**
- * Add a 64-bit unsigned integer entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- * wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The 64-bit unsigned integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
- const char *key,
- const dbus_uint64_t value)
-{
- return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
- &value);
-}
-
-
-/**
- * Add a double-precision floating point entry to the dict.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- * wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The double-precision floating point value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
- const char *key, const double value)
-{
- return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
- &value);
-}
-
-
-/**
* Add a DBus object path entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h
index b068431..94a0efd 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -26,9 +26,6 @@ const char * wpa_dbus_type_as_string(const int type);
dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
const char *key, const char *value);
-dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
- const char *key, const char value);
-
dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
const char *key,
const dbus_bool_t value);
@@ -49,18 +46,6 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
const char *key,
const dbus_uint32_t value);
-dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
- const char *key,
- const dbus_int64_t value);
-
-dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
- const char *key,
- const dbus_uint64_t value);
-
-dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
- const char *key,
- const double value);
-
dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
const char *key,
const char *value);
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
index 67d0e28..fc2fc2e 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c
@@ -13,6 +13,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
+#include "ap/sta_info.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
#include "../bss.h"
@@ -128,7 +129,8 @@ void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv)
* Notify listeners about event related with interface
*/
static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
- const char *sig_name, int properties)
+ const char *sig_name,
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -230,7 +232,7 @@ void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success)
*/
static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
const char *bss_obj_path,
- const char *sig_name, int properties)
+ const char *sig_name, dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -364,7 +366,7 @@ void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
*/
static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
int id, const char *sig_name,
- int properties)
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -793,6 +795,144 @@ nomem:
#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_MESH
+
+void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_MESH,
+ "MeshGroupStarted");
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
+ (const char *) ssid->ssid,
+ ssid->ssid_len) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s,
+ const u8 *meshid, u8 meshid_len,
+ int reason)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_MESH,
+ "MeshGroupRemoved");
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
+ (const char *) meshid,
+ meshid_len) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "DisconnectReason",
+ reason) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_MESH,
+ "MeshPeerConnected");
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "PeerAddress",
+ (const char *) peer_addr,
+ ETH_ALEN) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int reason)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_MESH,
+ "MeshPeerDisconnected");
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "PeerAddress",
+ (const char *) peer_addr,
+ ETH_ALEN) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "DisconnectReason",
+ reason) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_MESH */
+
+
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth, const char *subject,
const char *altsubject[],
@@ -939,6 +1079,79 @@ void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
}
+/**
+ * wpas_dbus_signal_station - Send an event signal related to a station object
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: Station object path
+ * @sig_name: signal name - StationAdded or StationRemoved
+ * @properties: Whether to add second argument with object properties
+ *
+ * Notify listeners about event related with station.
+ */
+static void wpas_dbus_signal_station(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path,
+ const char *sig_name,
+ dbus_bool_t properties)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ wpa_printf(MSG_DEBUG, "dbus: STA signal %s", sig_name);
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &station_obj_path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(iface, station_obj_path,
+ WPAS_DBUS_NEW_IFACE_STA,
+ &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_station_added - Send a Station added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: new Station object path
+ *
+ * Notify listeners about adding new Station
+ */
+static void wpas_dbus_signal_station_added(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path)
+{
+ wpas_dbus_signal_station(wpa_s, station_obj_path, "StationAdded", TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_station_removed - Send a Station removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: Station object path
+ *
+ * Notify listeners about removing Station
+ */
+static void wpas_dbus_signal_station_removed(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path)
+{
+ wpas_dbus_signal_station(wpa_s, station_obj_path, "StationRemoved",
+ FALSE);
+}
+
+
#ifdef CONFIG_P2P
/**
@@ -1207,7 +1420,7 @@ static int match_group_where_peer_is_client(struct p2p_group *group,
cfg->ssid_len);
if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
wpas_dbus_signal_peer_groups_changed(
- data->wpa_s->parent, data->info->p2p_device_addr);
+ data->wpa_s->p2pdev, data->info->p2p_device_addr);
return 0;
}
@@ -1224,7 +1437,7 @@ static void signal_peer_groups_changed(struct p2p_peer_info *info,
wpa_s_go = wpas_get_p2p_client_iface(data->wpa_s,
info->p2p_device_addr);
if (wpa_s_go != NULL && wpa_s_go == data->wpa_s) {
- wpas_dbus_signal_peer_groups_changed(data->wpa_s->parent,
+ wpas_dbus_signal_peer_groups_changed(data->wpa_s->p2pdev,
info->p2p_device_addr);
return;
}
@@ -1254,14 +1467,14 @@ static void peer_groups_changed(struct wpa_supplicant *wpa_s)
* irrespective of the role (client/GO) of the current device
*
* @wpa_s: %wpa_supplicant network interface data
- * @ssid: SSID object
* @client: this device is P2P client
- * @network_id: network id of the group started, use instead of ssid->id
- * to account for persistent groups
+ * @persistent: 0 - non persistent group, 1 - persistent group
+ * @ip: When group role is client, it contains local IP address, netmask, and
+ * GO's IP address, if assigned; otherwise, NULL
*/
void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id)
+ int client, int persistent,
+ const u8 *ip)
{
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
@@ -1300,8 +1513,16 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
wpa_s->dbus_new_path) ||
!wpa_dbus_dict_append_string(&dict_iter, "role",
client ? "client" : "GO") ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) ||
!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
wpa_s->dbus_groupobj_path) ||
+ (ip &&
+ (!wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddr",
+ (char *) ip, 4) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
+ (char *) ip + 4, 4) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
+ (char *) ip + 8, 4))) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
} else {
@@ -1736,7 +1957,7 @@ void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
*/
static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
int id, const char *sig_name,
- int properties)
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -1881,6 +2102,9 @@ void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"GroupFormationFailure");
@@ -1922,6 +2146,9 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s,
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"InvitationReceived");
@@ -1950,6 +2177,7 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s,
}
dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
}
@@ -1993,6 +2221,9 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
case WPAS_DBUS_PROP_BSSS:
prop = "BSSs";
break;
+ case WPAS_DBUS_PROP_STATIONS:
+ prop = "Stations";
+ break;
case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
prop = "CurrentAuthMode";
break;
@@ -2000,6 +2231,26 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
prop = "DisconnectReason";
flush = TRUE;
break;
+ case WPAS_DBUS_PROP_AUTH_STATUS_CODE:
+ prop = "AuthStatusCode";
+ flush = TRUE;
+ break;
+ case WPAS_DBUS_PROP_ASSOC_STATUS_CODE:
+ prop = "AssocStatusCode";
+ flush = TRUE;
+ break;
+ case WPAS_DBUS_PROP_ROAM_TIME:
+ prop = "RoamTime";
+ break;
+ case WPAS_DBUS_PROP_ROAM_COMPLETE:
+ prop = "RoamComplete";
+ break;
+ case WPAS_DBUS_PROP_SESSION_LENGTH:
+ prop = "SessionLength";
+ break;
+ case WPAS_DBUS_PROP_BSS_TM_STATUS:
+ prop = "BSSTMStatus";
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -2082,6 +2333,41 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
/**
+ * wpas_dbus_sta_signal_prop_changed - Signals change of STA property
+ * @wpa_s: %wpa_supplicant network interface data
+ * @property: indicates which property has changed
+ * @address: unique BSS identifier
+ *
+ * Sends PropertyChanged signals with path, interface, and arguments depending
+ * on which property has changed.
+ */
+void wpas_dbus_sta_signal_prop_changed(struct wpa_supplicant *wpa_s,
+ enum wpas_dbus_bss_prop property,
+ u8 address[ETH_ALEN])
+{
+ char path[WPAS_DBUS_OBJECT_PATH_MAX];
+ char *prop;
+
+ switch (property) {
+ case WPAS_DBUS_STA_PROP_ADDRESS:
+ prop = "Address";
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
+ __func__, property);
+ return;
+ }
+
+ os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(address));
+
+ wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
+ WPAS_DBUS_NEW_IFACE_STA, prop);
+}
+
+
+/**
* wpas_dbus_signal_debug_level_changed - Signals change of debug param
* @global: wpa_global structure
*
@@ -2172,41 +2458,54 @@ static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
END_ARGS
}
},
+ { "ExpectDisconnect", WPAS_DBUS_NEW_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_expect_disconnect,
+ {
+ END_ARGS
+ }
+ },
{ NULL, NULL, NULL, { END_ARGS } }
};
static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
{ "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
wpas_dbus_getter_debug_level,
- wpas_dbus_setter_debug_level
+ wpas_dbus_setter_debug_level,
+ NULL
},
{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
wpas_dbus_getter_debug_timestamp,
- wpas_dbus_setter_debug_timestamp
+ wpas_dbus_setter_debug_timestamp,
+ NULL
},
{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
wpas_dbus_getter_debug_show_keys,
- wpas_dbus_setter_debug_show_keys
+ wpas_dbus_setter_debug_show_keys,
+ NULL
},
{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
wpas_dbus_getter_interfaces,
+ NULL,
NULL
},
{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
wpas_dbus_getter_eap_methods,
+ NULL,
NULL
},
{ "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
wpas_dbus_getter_global_capabilities,
+ NULL,
NULL
},
#ifdef CONFIG_WIFI_DISPLAY
{ "WFDIEs", WPAS_DBUS_NEW_INTERFACE, "ay",
wpas_dbus_getter_global_wfd_ies,
- wpas_dbus_setter_global_wfd_ies
+ wpas_dbus_setter_global_wfd_ies,
+ NULL
},
#endif /* CONFIG_WIFI_DISPLAY */
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
@@ -2234,12 +2533,50 @@ static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
};
+static char * uscore_to_dbus(const char *uscore)
+{
+ const char *p = uscore;
+ char *str, *s;
+ dbus_bool_t last_was_uscore = TRUE;
+
+ s = str = os_zalloc(os_strlen(uscore) + 1);
+ if (!str)
+ return NULL;
+ while (p && *p) {
+ if (*p == '_') {
+ last_was_uscore = TRUE;
+ } else {
+ *s++ = last_was_uscore ? toupper(*p) : *p;
+ last_was_uscore = FALSE;
+ }
+ p++;
+ }
+
+ return str;
+}
+
+
+static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv);
+
+
+static void wpa_dbus_ctrl_iface_props_deinit(struct wpas_dbus_priv *priv)
+{
+ int idx = priv->globals_start;
+
+ /* Free all allocated property values */
+ while (priv->all_interface_properties[idx].dbus_property)
+ os_free((char *)
+ priv->all_interface_properties[idx++].dbus_property);
+ os_free((char *) priv->all_interface_properties);
+}
+
+
/**
* wpas_dbus_ctrl_iface_init - Initialize dbus control interface
* @global: Pointer to global data from wpa_supplicant_init()
* Returns: 0 on success or -1 on failure
*
- * Initialize the dbus control interface for wpa_supplicantand and start
+ * Initialize the dbus control interface for wpa_supplicant and start
* receiving commands from external programs over the bus.
*/
int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
@@ -2247,11 +2584,18 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
struct wpa_dbus_object_desc *obj_desc;
int ret;
+ ret = wpa_dbus_ctrl_iface_props_init(priv);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to init interface properties");
+ return -1;
+ }
+
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
wpa_printf(MSG_ERROR,
"Not enough memory to create object description");
- return -1;
+ goto error;
}
wpas_dbus_register(obj_desc, priv->global, NULL,
@@ -2264,31 +2608,36 @@ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv)
ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
WPAS_DBUS_NEW_SERVICE,
obj_desc);
- if (ret < 0)
+ if (ret < 0) {
free_dbus_object_desc(obj_desc);
- else
- priv->dbus_new_initialized = 1;
+ goto error;
+ }
- return ret;
+ priv->dbus_new_initialized = 1;
+ return 0;
+
+error:
+ wpa_dbus_ctrl_iface_props_deinit(priv);
+ return -1;
}
/**
* wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
* wpa_supplicant
- * @iface: Pointer to dbus private data from wpas_dbus_init()
+ * @priv: Pointer to dbus private data from wpas_dbus_init()
*
* Deinitialize the dbus control interface that was initialized with
* wpas_dbus_ctrl_iface_init().
*/
-void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface)
+void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *priv)
{
- if (!iface->dbus_new_initialized)
+ if (!priv->dbus_new_initialized)
return;
wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'",
WPAS_DBUS_NEW_PATH);
- dbus_connection_unregister_object_path(iface->con,
- WPAS_DBUS_NEW_PATH);
+ dbus_connection_unregister_object_path(priv->con, WPAS_DBUS_NEW_PATH);
+ wpa_dbus_ctrl_iface_props_deinit(priv);
}
@@ -2301,13 +2650,15 @@ static void wpa_dbus_free(void *ptr)
static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
{ "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
wpas_dbus_getter_network_properties,
- wpas_dbus_setter_network_properties
+ wpas_dbus_setter_network_properties,
+ NULL
},
{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
wpas_dbus_getter_enabled,
- wpas_dbus_setter_enabled
+ wpas_dbus_setter_enabled,
+ NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -2446,53 +2797,89 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
wpas_dbus_getter_bss_ssid,
+ NULL,
NULL
},
{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
wpas_dbus_getter_bss_bssid,
+ NULL,
NULL
},
{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
wpas_dbus_getter_bss_privacy,
+ NULL,
NULL
},
{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
wpas_dbus_getter_bss_mode,
+ NULL,
NULL
},
{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
wpas_dbus_getter_bss_signal,
+ NULL,
NULL
},
{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
wpas_dbus_getter_bss_frequency,
+ NULL,
NULL
},
{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
wpas_dbus_getter_bss_rates,
+ NULL,
NULL
},
{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
wpas_dbus_getter_bss_wpa,
+ NULL,
NULL
},
{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
wpas_dbus_getter_bss_rsn,
+ NULL,
NULL
},
{ "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
wpas_dbus_getter_bss_wps,
+ NULL,
NULL
},
{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
wpas_dbus_getter_bss_ies,
+ NULL,
NULL
},
{ "Age", WPAS_DBUS_NEW_IFACE_BSS, "u",
wpas_dbus_getter_bss_age,
+ NULL,
+ NULL
+ },
+ {
+ "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_roam_time,
+ NULL,
+ NULL
+ },
+ {
+ "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+ wpas_dbus_getter_roam_complete,
+ NULL,
NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ {
+ "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_session_length,
+ NULL,
+ NULL
+ },
+ {
+ "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_bss_tm_status,
+ NULL,
+ NULL
+ },
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -2618,6 +3005,157 @@ err:
}
+static const struct wpa_dbus_property_desc wpas_dbus_sta_properties[] = {
+ { "Address", WPAS_DBUS_NEW_IFACE_STA, "ay",
+ wpas_dbus_getter_sta_address,
+ NULL, NULL
+ },
+ { "AID", WPAS_DBUS_NEW_IFACE_STA, "q",
+ wpas_dbus_getter_sta_aid,
+ NULL, NULL
+ },
+ { "Capabilities", WPAS_DBUS_NEW_IFACE_STA, "q",
+ wpas_dbus_getter_sta_caps,
+ NULL, NULL
+ },
+ { "RxPackets", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_rx_packets,
+ NULL, NULL
+ },
+ { "TxPackets", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_tx_packets,
+ NULL, NULL
+ },
+ { "RxBytes", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_rx_bytes,
+ NULL, NULL
+ },
+ { "TxBytes", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_tx_bytes,
+ NULL, NULL
+ },
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static const struct wpa_dbus_signal_desc wpas_dbus_sta_signals[] = {
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+ { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_STA,
+ {
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * wpas_dbus_unregister_sta - Unregister a connected station from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @sta: station MAC address
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters STA representing object from dbus.
+ */
+int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (!wpa_s || !wpa_s->global)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (!ctrl_iface)
+ return 0;
+
+ os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta));
+
+ wpa_printf(MSG_DEBUG, "dbus: Unregister STA object '%s'",
+ station_obj_path);
+ if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
+ station_obj_path)) {
+ wpa_printf(MSG_ERROR, "dbus: Cannot unregister STA object %s",
+ station_obj_path);
+ return -1;
+ }
+
+ wpas_dbus_signal_station_removed(wpa_s, station_obj_path);
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS);
+
+ return 0;
+}
+
+
+/**
+ * wpas_dbus_register_sta - Register a connected station with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @sta: station MAC address
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers STA representing object with dbus.
+ */
+int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ struct sta_handler_args *arg;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!wpa_s || !wpa_s->global)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (!ctrl_iface)
+ return 0;
+
+ os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta));
+
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
+ goto err;
+ }
+
+ arg = os_zalloc(sizeof(struct sta_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for handler");
+ goto err;
+ }
+ arg->wpa_s = wpa_s;
+ arg->sta = sta;
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+ wpas_dbus_sta_properties, wpas_dbus_sta_signals);
+
+ wpa_printf(MSG_DEBUG, "dbus: Register STA object '%s'",
+ station_obj_path);
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, station_obj_path,
+ wpa_s->ifname, obj_desc)) {
+ wpa_printf(MSG_ERROR,
+ "Cannot register STA dbus object %s",
+ station_obj_path);
+ goto err;
+ }
+
+ wpas_dbus_signal_station_added(wpa_s, station_obj_path);
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS);
+
+ return 0;
+
+err:
+ free_dbus_object_desc(obj_desc);
+ return -1;
+}
+
+
static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) wpas_dbus_handler_scan,
@@ -2991,132 +3529,281 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "TDLSChannelSwitch", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_channel_switch,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "TDLSCancelChannelSwitch", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_tdls_cancel_channel_switch,
+ {
+ { "peer_address", "s", ARG_IN },
+ END_ARGS
+ }
+ },
#endif /* CONFIG_TDLS */
+ { "VendorElemAdd", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_add,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "VendorElemGet", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_get,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "VendorElemRem", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_remove,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_IN },
+ END_ARGS
+ }
+ },
+#ifndef CONFIG_NO_CONFIG_WRITE
+ { "SaveConfig", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_save_config,
+ {
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ { "AbortScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_abort_scan,
+ {
+ END_ARGS
+ }
+ },
{ NULL, NULL, NULL, { END_ARGS } }
};
static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
{ "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
wpas_dbus_getter_capabilities,
+ NULL,
NULL
},
{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_state,
+ NULL,
NULL
},
{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
wpas_dbus_getter_scanning,
+ NULL,
NULL
},
{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_ap_scan,
- wpas_dbus_setter_ap_scan
+ wpas_dbus_setter_ap_scan,
+ NULL
},
{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_bss_expire_age,
- wpas_dbus_setter_bss_expire_age
+ wpas_dbus_setter_bss_expire_age,
+ NULL
},
{ "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_bss_expire_count,
- wpas_dbus_setter_bss_expire_count
+ wpas_dbus_setter_bss_expire_count,
+ NULL
},
{ "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_country,
- wpas_dbus_setter_country
+ wpas_dbus_setter_country,
+ NULL
},
{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_ifname,
+ NULL,
NULL
},
{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_driver,
+ NULL,
NULL
},
{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_bridge_ifname,
+ NULL,
+ NULL
+ },
+ { "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_config_file,
+ NULL,
NULL
},
{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
wpas_dbus_getter_current_bss,
+ NULL,
NULL
},
{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
wpas_dbus_getter_current_network,
+ NULL,
NULL
},
{ "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_current_auth_mode,
+ NULL,
NULL
},
{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
wpas_dbus_getter_blobs,
+ NULL,
NULL
},
{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
wpas_dbus_getter_bsss,
+ NULL,
NULL
},
{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
wpas_dbus_getter_networks,
+ NULL,
NULL
},
{ "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
wpas_dbus_getter_fast_reauth,
- wpas_dbus_setter_fast_reauth
+ wpas_dbus_setter_fast_reauth,
+ NULL
},
{ "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
wpas_dbus_getter_scan_interval,
- wpas_dbus_setter_scan_interval
+ wpas_dbus_setter_scan_interval,
+ NULL
},
{ "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_pkcs11_engine_path,
+ NULL,
NULL
},
{ "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_pkcs11_module_path,
+ NULL,
NULL
},
#ifdef CONFIG_WPS
{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
wpas_dbus_getter_process_credentials,
- wpas_dbus_setter_process_credentials
+ wpas_dbus_setter_process_credentials,
+ NULL
},
{ "ConfigMethods", WPAS_DBUS_NEW_IFACE_WPS, "s",
wpas_dbus_getter_config_methods,
- wpas_dbus_setter_config_methods
+ wpas_dbus_setter_config_methods,
+ NULL
+ },
+ {
+ "DeviceName", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_device_name,
+ wpas_dbus_setter_wps_device_name,
+ NULL
+ },
+ {
+ "Manufacturer", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_manufacturer,
+ wpas_dbus_setter_wps_manufacturer,
+ NULL
+ },
+ {
+ "ModelName", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_device_model_name,
+ wpas_dbus_setter_wps_device_model_name,
+ NULL
+ },
+ {
+ "ModelNumber", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_device_model_number,
+ wpas_dbus_setter_wps_device_model_number,
+ NULL
+ },
+ {
+ "SerialNumber", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_device_serial_number,
+ wpas_dbus_setter_wps_device_serial_number,
+ NULL
+ },
+ {
+ "DeviceType", WPAS_DBUS_NEW_IFACE_WPS, "ay",
+ wpas_dbus_getter_wps_device_device_type,
+ wpas_dbus_setter_wps_device_device_type,
+ NULL
},
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
{ "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
wpas_dbus_getter_p2p_device_config,
- wpas_dbus_setter_p2p_device_config
+ wpas_dbus_setter_p2p_device_config,
+ NULL
},
{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
wpas_dbus_getter_p2p_peers,
+ NULL,
NULL
},
{ "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
wpas_dbus_getter_p2p_role,
+ NULL,
NULL
},
{ "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
wpas_dbus_getter_p2p_group,
+ NULL,
NULL
},
{ "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
wpas_dbus_getter_p2p_peergo,
+ NULL,
NULL
},
{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
wpas_dbus_getter_persistent_groups,
+ NULL,
NULL
},
#endif /* CONFIG_P2P */
{ "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
wpas_dbus_getter_disconnect_reason,
+ NULL,
+ NULL
+ },
+ { "AuthStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_auth_status_code,
+ NULL,
+ NULL
+ },
+ { "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_assoc_status_code,
+ NULL,
+ NULL
+ },
+#ifdef CONFIG_MESH
+ { "MeshPeers", WPAS_DBUS_NEW_IFACE_MESH, "aay",
+ wpas_dbus_getter_mesh_peers,
+ NULL,
+ NULL
+ },
+ { "MeshGroup", WPAS_DBUS_NEW_IFACE_MESH, "ay",
+ wpas_dbus_getter_mesh_group,
+ NULL,
NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+#endif /* CONFIG_MESH */
+ { "Stations", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
+ wpas_dbus_getter_stas,
+ NULL,
+ NULL
+ },
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
@@ -3206,6 +3893,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
END_ARGS
}
},
+ { "DeviceFoundProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
{ "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
{ "path", "o", ARG_OUT },
@@ -3378,6 +4072,19 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
END_ARGS
}
},
+ { "StationAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "StationRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
{
{ "path", "o", ARG_OUT },
@@ -3386,10 +4093,107 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
END_ARGS
}
},
+#ifdef CONFIG_MESH
+ { "MeshGroupStarted", WPAS_DBUS_NEW_IFACE_MESH,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "MeshGroupRemoved", WPAS_DBUS_NEW_IFACE_MESH,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "MeshPeerConnected", WPAS_DBUS_NEW_IFACE_MESH,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "MeshPeerDisconnected", WPAS_DBUS_NEW_IFACE_MESH,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_MESH */
{ NULL, NULL, { END_ARGS } }
};
+static int wpa_dbus_ctrl_iface_props_init(struct wpas_dbus_priv *priv)
+{
+ size_t all_size;
+ unsigned int i, j, count, num_const, num_globals;
+ const char *global_name;
+ static const char * const ignored_globals[] = {
+ "bss_expiration_age", "bss_expiration_scan_count",
+ "ap_scan", "country", "fast_reauth",
+ "pkcs11_engine_path", "pkcs11_module_path"
+ };
+
+ /* wpas_dbus_interface_properties terminates with a NULL element */
+ num_const = ARRAY_SIZE(wpas_dbus_interface_properties) - 1;
+
+ num_globals = wpa_config_get_num_global_field_names();
+ priv->globals_start = num_const;
+
+ /* allocate enough for all properties + terminating NULL element */
+ all_size = (num_globals + num_const + 1) *
+ sizeof(wpas_dbus_interface_properties[0]);
+ priv->all_interface_properties = os_zalloc(all_size);
+ if (!priv->all_interface_properties) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory for interface properties");
+ return -1;
+ }
+
+ /* Copy constant interface properties to the start of the array */
+ os_memcpy(priv->all_interface_properties,
+ wpas_dbus_interface_properties,
+ sizeof(wpas_dbus_interface_properties));
+
+ /* Dynamically construct interface global properties */
+ for (i = 0, count = num_const; i < num_globals; i++) {
+ struct wpa_dbus_property_desc *desc;
+ int no_var = 0;
+
+ /* ignore globals that are actually just methods */
+ global_name = wpa_config_get_global_field_name(i, &no_var);
+ if (no_var)
+ continue;
+ /* Ignore fields already explicitly exposed */
+ for (j = 0; j < ARRAY_SIZE(ignored_globals); j++) {
+ if (os_strcmp(global_name, ignored_globals[j]) == 0)
+ break;
+ }
+ if (j < ARRAY_SIZE(ignored_globals))
+ continue;
+
+ desc = &priv->all_interface_properties[count++];
+ desc->dbus_property = uscore_to_dbus(global_name);
+ if (!desc->dbus_property) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory for D-Bus property name");
+ goto error;
+ }
+ desc->dbus_interface = WPAS_DBUS_NEW_IFACE_INTERFACE;
+ desc->type = "s";
+ desc->getter = wpas_dbus_getter_iface_global;
+ desc->setter = wpas_dbus_setter_iface_global;
+ desc->data = global_name;
+ }
+
+ return 0;
+
+error:
+ wpa_dbus_ctrl_iface_props_deinit(priv);
+ return -1;
+}
+
+
/**
* wpas_dbus_register_interface - Register an interface with D-Bus
* @wpa_s: wpa_supplicant interface structure
@@ -3397,7 +4201,6 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
*/
int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
{
-
struct wpa_dbus_object_desc *obj_desc = NULL;
struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
int next;
@@ -3423,7 +4226,7 @@ int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
}
wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
- wpas_dbus_interface_properties,
+ ctrl_iface->all_interface_properties,
wpas_dbus_interface_signals);
wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
@@ -3489,65 +4292,85 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
{ "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_device_name,
+ NULL,
NULL
},
{ "Manufacturer", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_manufacturer,
+ NULL,
NULL
},
{ "ModelName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_modelname,
+ NULL,
NULL
},
{ "ModelNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_modelnumber,
+ NULL,
NULL
},
{ "SerialNumber", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
wpas_dbus_getter_p2p_peer_serialnumber,
+ NULL,
NULL
},
{ "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
wpas_dbus_getter_p2p_peer_primary_device_type,
+ NULL,
NULL
},
{ "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q",
wpas_dbus_getter_p2p_peer_config_method,
+ NULL,
NULL
},
{ "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i",
wpas_dbus_getter_p2p_peer_level,
+ NULL,
NULL
},
{ "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
wpas_dbus_getter_p2p_peer_device_capability,
+ NULL,
NULL
},
{ "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
wpas_dbus_getter_p2p_peer_group_capability,
+ NULL,
NULL
},
{ "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
wpas_dbus_getter_p2p_peer_secondary_device_types,
+ NULL,
NULL
},
{ "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
wpas_dbus_getter_p2p_peer_vendor_extension,
+ NULL,
NULL
},
{ "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
wpas_dbus_getter_p2p_peer_ies,
+ NULL,
NULL
},
{ "DeviceAddress", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
wpas_dbus_getter_p2p_peer_device_address,
+ NULL,
NULL
},
{ "Groups", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ao",
wpas_dbus_getter_p2p_peer_groups,
+ NULL,
NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { "VSIE", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ wpas_dbus_getter_p2p_peer_vsie,
+ NULL,
+ NULL
+ },
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
@@ -3569,12 +4392,13 @@ static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
* In case of peer objects, it would be emitted by either
* the "interface object" or by "peer objects"
* @sig_name: signal name - DeviceFound
+ * @properties: Whether to add a second argument with object properties
*
- * Notify listeners about event related with newly found p2p peer device
+ * Notify listeners about event related with p2p peer device
*/
static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
const u8 *dev_addr, const char *interface,
- const char *sig_name)
+ const char *sig_name, dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -3602,7 +4426,10 @@ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
dbus_message_iter_init_append(msg, &iter);
path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
+ &path) ||
+ (properties && !wpa_dbus_get_object_properties(
+ iface, peer_obj_path, WPAS_DBUS_NEW_IFACE_P2P_PEER,
+ &iter)))
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
else
dbus_connection_send(iface->con, msg, NULL);
@@ -3623,7 +4450,11 @@ void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
{
wpas_dbus_signal_peer(wpa_s, dev_addr,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- "DeviceFound");
+ "DeviceFound", FALSE);
+
+ wpas_dbus_signal_peer(wpa_s, dev_addr,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "DeviceFoundProperties", TRUE);
}
/**
@@ -3638,7 +4469,7 @@ void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
{
wpas_dbus_signal_peer(wpa_s, dev_addr,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- "DeviceLost");
+ "DeviceLost", FALSE);
}
/**
@@ -3761,7 +4592,13 @@ void wpas_dbus_signal_p2p_find_stopped(struct wpa_supplicant *wpa_s)
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
- if (iface == NULL || !wpa_s->dbus_new_path)
+ if (iface == NULL)
+ return;
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
+ if (!wpa_s->dbus_new_path)
return;
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
@@ -3805,41 +4642,50 @@ void wpas_dbus_signal_peer_groups_changed(struct wpa_supplicant *wpa_s,
static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
{ "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
wpas_dbus_getter_p2p_group_members,
+ NULL,
NULL
},
{ "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
wpas_dbus_getter_p2p_group,
+ NULL,
NULL
},
{ "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
wpas_dbus_getter_p2p_role,
+ NULL,
NULL
},
{ "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
wpas_dbus_getter_p2p_group_ssid,
+ NULL,
NULL
},
{ "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
wpas_dbus_getter_p2p_group_bssid,
+ NULL,
NULL
},
{ "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
wpas_dbus_getter_p2p_group_frequency,
+ NULL,
NULL
},
{ "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
wpas_dbus_getter_p2p_group_passphrase,
+ NULL,
NULL
},
{ "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
wpas_dbus_getter_p2p_group_psk,
+ NULL,
NULL
},
{ "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
wpas_dbus_getter_p2p_group_vendor_ext,
- wpas_dbus_setter_p2p_group_vendor_ext
+ wpas_dbus_setter_p2p_group_vendor_ext,
+ NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
@@ -3966,9 +4812,10 @@ static const struct wpa_dbus_property_desc
wpas_dbus_persistent_group_properties[] = {
{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
wpas_dbus_getter_persistent_group_properties,
- wpas_dbus_setter_persistent_group_properties
+ wpas_dbus_setter_persistent_group_properties,
+ NULL
},
- { NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, NULL, NULL, NULL, NULL }
};
/* No signals intended for persistent group objects */
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h
index 6d240ff..42db389 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h
@@ -28,7 +28,14 @@ enum wpas_dbus_prop {
WPAS_DBUS_PROP_CURRENT_NETWORK,
WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
WPAS_DBUS_PROP_BSSS,
+ WPAS_DBUS_PROP_STATIONS,
WPAS_DBUS_PROP_DISCONNECT_REASON,
+ WPAS_DBUS_PROP_AUTH_STATUS_CODE,
+ WPAS_DBUS_PROP_ASSOC_STATUS_CODE,
+ WPAS_DBUS_PROP_ROAM_TIME,
+ WPAS_DBUS_PROP_ROAM_COMPLETE,
+ WPAS_DBUS_PROP_SESSION_LENGTH,
+ WPAS_DBUS_PROP_BSS_TM_STATUS,
};
enum wpas_dbus_bss_prop {
@@ -44,6 +51,10 @@ enum wpas_dbus_bss_prop {
WPAS_DBUS_BSS_PROP_AGE,
};
+enum wpas_dbus_sta_prop {
+ WPAS_DBUS_STA_PROP_ADDRESS,
+};
+
#define WPAS_DBUS_OBJECT_PATH_MAX 150
#define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1"
@@ -60,9 +71,14 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
#define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS"
+#define WPAS_DBUS_NEW_STAS_PART "Stations"
+#define WPAS_DBUS_NEW_IFACE_STA WPAS_DBUS_NEW_INTERFACE ".Station"
+
#define WPAS_DBUS_NEW_IFACE_P2PDEVICE \
WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
+#define WPAS_DBUS_NEW_IFACE_MESH WPAS_DBUS_NEW_IFACE_INTERFACE ".Mesh"
+
/*
* Groups correspond to P2P groups where this device is a GO (owner)
*/
@@ -160,6 +176,8 @@ int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN], unsigned int id);
int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN], unsigned int id);
+int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta);
+int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta);
void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
const char *name);
void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
@@ -189,8 +207,8 @@ void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
const u8 *src, u16 dev_passwd_id,
u8 go_intent);
void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id);
+ int client, int persistent,
+ const u8 *ip);
void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
const char *reason);
void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
@@ -237,6 +255,15 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *dev_addr,
const u8 *bssid, int id,
int op_freq);
+void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s,
+ const u8 *meshid, u8 meshid_len,
+ int reason);
+void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr);
+void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int reason);
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
@@ -333,6 +360,18 @@ static inline int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
return 0;
}
+static inline int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ return 0;
+}
+
+static inline int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ return 0;
+}
+
static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
const char *name)
{
@@ -400,8 +439,8 @@ static inline void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
static inline void
wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id)
+ int client, int persistent,
+ const u8 *ip)
{
}
@@ -552,6 +591,31 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s,
{
}
+static inline
+void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+}
+
+static inline
+void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s,
+ const u8 *meshid, u8 meshid_len,
+ int reason)
+{
+}
+
+static inline
+void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr)
+{
+}
+
+static inline
+void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int reason)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
#endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c
index 67562a5..6c36d91 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -15,6 +15,9 @@
#include "eap_peer/eap_methods.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ap_drv_ops.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
#include "../driver_i.h"
@@ -22,12 +25,17 @@
#include "../bss.h"
#include "../scan.h"
#include "../autoscan.h"
+#include "../ap.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
#include "dbus_common_i.h"
#include "drivers/driver.h"
+#ifdef CONFIG_MESH
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#endif /* CONFIG_MESH */
static const char * const debug_strings[] = {
"excessive", "msgdump", "debug", "info", "warning", "error", NULL
@@ -435,7 +443,8 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
for (i = 0; i < array_len; i++) {
if (!dbus_message_iter_append_basic(&array_iter, type,
- array + i * element_size)) {
+ (const char *) array +
+ i * element_size)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: failed to construct message 2.5",
__func__);
@@ -516,6 +525,27 @@ dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
/**
+ * wpas_dbus_string_property_getter - Get string type property
+ * @iter: Message iter to use when appending arguments
+ * @val: Pointer to place holding property value, can be %NULL
+ * @error: On failure an error describing the failure
+ * Returns: TRUE if the request was successful, FALSE if it failed
+ *
+ * Generic getter for string type properties. %NULL is converted to an empty
+ * string.
+ */
+dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
+ const void *val,
+ DBusError *error)
+{
+ if (!val)
+ val = "";
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+ &val, error);
+}
+
+
+/**
* wpas_dbus_handler_create_interface - Request registration of a network iface
* @message: Pointer to incoming dbus message
* @global: %wpa_supplicant global data structure
@@ -711,9 +741,9 @@ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
*
* Getter for "DebugLevel" property.
*/
-dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_level(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
const char *str;
int idx = wpa_debug_level;
@@ -737,9 +767,9 @@ dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
*
* Getter for "DebugTimestamp" property.
*/
-dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_timestamp(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&wpa_debug_timestamp, error);
@@ -756,9 +786,9 @@ dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
*
* Getter for "DebugShowKeys" property.
*/
-dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_debug_show_keys(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&wpa_debug_show_keys, error);
@@ -774,8 +804,9 @@ dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
*
* Setter for "DebugLevel" property.
*/
-dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_level(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
const char *str = NULL;
@@ -812,9 +843,9 @@ dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
*
* Setter for "DebugTimestamp" property.
*/
-dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_timestamp(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
dbus_bool_t val;
@@ -838,9 +869,9 @@ dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
*
* Setter for "DebugShowKeys" property.
*/
-dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_debug_show_keys(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
dbus_bool_t val;
@@ -867,9 +898,9 @@ dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
* by dbus clients to return list of registered interfaces objects
* paths
*/
-dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_interfaces(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
struct wpa_supplicant *wpa_s;
@@ -912,8 +943,9 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
* Getter for "EapMethods" property. Handles requests
* by dbus clients to return list of strings with supported EAP methods
*/
-dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_eap_methods(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
char **eap_methods;
size_t num_items = 0;
@@ -948,12 +980,25 @@ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
* return a list of strings with supported capabilities like AP, RSN IBSS,
* and P2P that are determined at compile time.
*/
-dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_global_capabilities(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+ const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL };
size_t num_items = 0;
+#ifdef CONFIG_FILS
+ struct wpa_global *global = user_data;
+ struct wpa_supplicant *wpa_s;
+ int fils_supported = 0, fils_sk_pfs_supported = 0;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (wpa_is_fils_supported(wpa_s))
+ fils_supported = 1;
+ if (wpa_is_fils_sk_pfs_supported(wpa_s))
+ fils_sk_pfs_supported = 1;
+ }
+#endif /* CONFIG_FILS */
#ifdef CONFIG_AP
capabilities[num_items++] = "ap";
@@ -967,6 +1012,24 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
#ifdef CONFIG_INTERWORKING
capabilities[num_items++] = "interworking";
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_IEEE80211W
+ capabilities[num_items++] = "pmf";
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_MESH
+ capabilities[num_items++] = "mesh";
+#endif /* CONFIG_MESH */
+#ifdef CONFIG_FILS
+ if (fils_supported)
+ capabilities[num_items++] = "fils";
+ if (fils_sk_pfs_supported)
+ capabilities[num_items++] = "fils_sk_pfs";
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ capabilities[num_items++] = "ft";
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SHA384
+ capabilities[num_items++] = "sha384";
+#endif /* CONFIG_SHA384 */
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -1049,12 +1112,11 @@ static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
}
if (len != 0) {
- ssid = os_malloc(len);
+ ssid = os_memdup(val, len);
if (ssid == NULL) {
*reply = wpas_dbus_error_no_memory(message);
return -1;
}
- os_memcpy(ssid, val, len);
} else {
/* Allow zero-length SSIDs */
ssid = NULL;
@@ -1393,6 +1455,27 @@ out:
}
+/*
+ * wpas_dbus_handler_abort_scan - Request an ongoing scan to be aborted
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: Abort failed or no scan in progress DBus error message on failure
+ * or NULL otherwise.
+ *
+ * Handler function for "AbortScan" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ if (wpas_abort_ongoing_scan(wpa_s) < 0)
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+ "Abort failed or no scan in progress");
+
+ return NULL;
+}
+
+
/**
* wpas_dbus_handler_signal_poll - Request immediate signal properties
* @message: Pointer to incoming dbus message
@@ -1472,10 +1555,7 @@ DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
if (wpa_s->current_ssid != NULL) {
- wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-
+ wpas_request_disconnection(wpa_s);
return NULL;
}
@@ -1504,7 +1584,7 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
dbus_message_iter_init(message, &iter);
if (wpa_s->dbus_new_path)
- ssid = wpa_config_add_network(wpa_s->conf);
+ ssid = wpa_supplicant_add_network(wpa_s);
if (ssid == NULL) {
wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
__func__);
@@ -1513,9 +1593,6 @@ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
"wpa_supplicant could not add a network on this interface.");
goto err;
}
- wpas_notify_network_added(wpa_s, ssid);
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
dbus_error_init(&error);
if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
@@ -1580,6 +1657,27 @@ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
/**
+ * wpas_dbus_handler_expect_disconnect - ExpectDisconnect
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: NULL
+ *
+ * Handler function for notifying system there will be a expected disconnect.
+ * This will prevent wpa_supplicant from adding blacklists upon next disconnect..
+ */
+DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
+ struct wpa_global *global)
+{
+ struct wpa_supplicant *wpa_s = global->ifaces;
+
+ for (; wpa_s; wpa_s = wpa_s->next)
+ if (wpa_s->wpa_state >= WPA_ASSOCIATED)
+ wpa_s->own_disconnect_req = 1;
+ return NULL;
+}
+
+
+/**
* wpas_dbus_handler_reattach - Reattach to current AP
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
@@ -1641,8 +1739,7 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
const char *op;
char *iface, *net_id;
int id;
- struct wpa_ssid *ssid;
- int was_disabled;
+ int result;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
DBUS_TYPE_INVALID);
@@ -1665,27 +1762,12 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
goto out;
}
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL) {
+ result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
reply = wpas_dbus_error_network_unknown(message);
goto out;
}
-
- was_disabled = ssid->disabled;
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- else if (!was_disabled && wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG,
- "Stop ongoing sched_scan to remove network from filters");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (result == -2) {
wpa_printf(MSG_ERROR,
"%s[dbus]: error occurred when removing network %d",
__func__, id);
@@ -1854,7 +1936,7 @@ out:
os_free(iface);
return reply;
#else /* IEEE8021X_EAPOL */
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+ wpa_printf(MSG_DEBUG, "dbus: 802.1X not included");
return wpas_dbus_error_unknown_error(message, "802.1X not included");
#endif /* IEEE8021X_EAPOL */
}
@@ -1901,13 +1983,12 @@ DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
goto err;
}
- blob->data = os_malloc(blob_len);
+ blob->data = os_memdup(blob_data, blob_len);
blob->name = os_strdup(blob_name);
if (!blob->data || !blob->name) {
reply = wpas_dbus_error_no_memory(message);
goto err;
}
- os_memcpy(blob->data, blob_data, blob_len);
blob->len = blob_len;
wpa_config_set_blob(wpa_s->conf, blob);
@@ -2268,9 +2349,188 @@ DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
return NULL;
}
+/*
+ * wpas_dbus_handler_tdls_channel_switch - Enable channel switching with TDLS peer
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSChannelSwitch" method call of network interface.
+ */
+DBusMessage *
+wpas_dbus_handler_tdls_channel_switch(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter, iter_dict;
+ struct wpa_dbus_dict_entry entry;
+ u8 peer[ETH_ALEN];
+ struct hostapd_freq_params freq_params;
+ u8 oper_class = 0;
+ int ret;
+ int is_peer_present = 0;
+
+ if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Only supported with external setup");
+ return wpas_dbus_error_unknown_error(message, "TDLS is not using external setup");
+ }
+
+ os_memset(&freq_params, 0, sizeof(freq_params));
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (os_strcmp(entry.key, "PeerAddress") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (hwaddr_aton(entry.str_value, peer)) {
+ wpa_printf(MSG_DEBUG,
+ "tdls_chanswitch: Invalid address '%s'",
+ entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
+ return wpas_dbus_error_invalid_args(message,
+ NULL);
+ }
+
+ is_peer_present = 1;
+ } else if (os_strcmp(entry.key, "OperClass") == 0 &&
+ entry.type == DBUS_TYPE_BYTE) {
+ oper_class = entry.byte_value;
+ } else if (os_strcmp(entry.key, "Frequency") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ freq_params.freq = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "SecChannelOffset") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ freq_params.sec_channel_offset = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "CenterFrequency1") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ freq_params.center_freq1 = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "CenterFrequency2") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ freq_params.center_freq2 = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "Bandwidth") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ freq_params.bandwidth = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "HT") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ freq_params.ht_enabled = entry.bool_value;
+ } else if (os_strcmp(entry.key, "VHT") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ freq_params.vht_enabled = entry.bool_value;
+ } else {
+ wpa_dbus_dict_entry_clear(&entry);
+ return wpas_dbus_error_invalid_args(message, NULL);
+ }
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (oper_class == 0) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Invalid op class provided");
+ return wpas_dbus_error_invalid_args(
+ message, "Invalid op class provided");
+ }
+
+ if (freq_params.freq == 0) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Invalid freq provided");
+ return wpas_dbus_error_invalid_args(message,
+ "Invalid freq provided");
+ }
+
+ if (is_peer_present == 0) {
+ wpa_printf(MSG_DEBUG,
+ "tdls_chanswitch: peer address not provided");
+ return wpas_dbus_error_invalid_args(
+ message, "peer address not provided");
+ }
+
+ wpa_printf(MSG_DEBUG, "dbus: TDLS_CHAN_SWITCH " MACSTR
+ " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
+ MAC2STR(peer), oper_class, freq_params.freq,
+ freq_params.center_freq1, freq_params.center_freq2,
+ freq_params.bandwidth, freq_params.sec_channel_offset,
+ freq_params.ht_enabled ? " HT" : "",
+ freq_params.vht_enabled ? " VHT" : "");
+
+ ret = wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
+ &freq_params);
+ if (ret)
+ return wpas_dbus_error_unknown_error(
+ message, "error processing TDLS channel switch");
+
+ return NULL;
+}
+
+/*
+ * wpas_dbus_handler_tdls_cancel_channel_switch - Disable channel switching with TDLS peer
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "TDLSCancelChannelSwitch" method call of network
+ * interface.
+ */
+DBusMessage *
+wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 peer[ETH_ALEN];
+ DBusMessage *error_reply;
+ int ret;
+
+ if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
+ return error_reply;
+
+ wpa_printf(MSG_DEBUG, "dbus: TDLS_CANCEL_CHAN_SWITCH " MACSTR,
+ MAC2STR(peer));
+
+ ret = wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
+ if (ret)
+ return wpas_dbus_error_unknown_error(
+ message, "error canceling TDLS channel switch");
+
+ return NULL;
+}
+
#endif /* CONFIG_TDLS */
+#ifndef CONFIG_NO_CONFIG_WRITE
+/**
+ * wpas_dbus_handler_save_config - Save configuration to configuration file
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on Success, Otherwise errror message
+ *
+ * Handler function for "SaveConfig" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ int ret;
+
+ if (!wpa_s->conf->update_config) {
+ return wpas_dbus_error_unknown_error(
+ message,
+ "Not allowed to update configuration (update_config=0)");
+ }
+
+ ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
+ if (ret)
+ return wpas_dbus_error_unknown_error(
+ message, "Failed to update configuration");
+ return NULL;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
/**
* wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
* @message: Pointer to incoming dbus message
@@ -2338,8 +2598,9 @@ DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
*
* Getter for "Capabilities" property of an interface.
*/
-dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_capabilities(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_driver_capa capa;
@@ -2436,6 +2697,28 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
goto nomem;
}
+ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt",
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array) ||
+ (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "aes-128-cmac")) ||
+ (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "bip-gmac-128")) ||
+ (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "bip-gmac-256")) ||
+ (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "bip-cmac-256")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto nomem;
+
/***** key management */
if (res < 0) {
const char *args[] = {
@@ -2585,14 +2868,21 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
&iter_array) ||
!wpa_dbus_dict_string_array_add_element(
&iter_array, "infrastructure") ||
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "ad-hoc") ||
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ad-hoc")) ||
(res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "ap")) ||
(res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+ !wpa_s->conf->p2p_disabled &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "p2p")) ||
+#ifdef CONFIG_MESH
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_MESH) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "mesh")) ||
+#endif /* CONFIG_MESH */
!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
@@ -2629,8 +2919,9 @@ nomem:
*
* Getter for "State" property.
*/
-dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_state(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *str_state;
@@ -2669,8 +2960,9 @@ dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
*
* Getter for "scanning" property.
*/
-dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_scanning(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
@@ -2689,8 +2981,9 @@ dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
*
* Getter function for "ApScan" property.
*/
-dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_ap_scan(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
@@ -2709,8 +3002,9 @@ dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
*
* Setter function for "ApScan" property.
*/
-dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_ap_scan(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t ap_scan;
@@ -2738,9 +3032,9 @@ dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
*
* Getter function for "FastReauth" property.
*/
-dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_fast_reauth(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
@@ -2760,9 +3054,9 @@ dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
*
* Setter function for "FastReauth" property.
*/
-dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_fast_reauth(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t fast_reauth;
@@ -2786,9 +3080,9 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
* Getter for "DisconnectReason" property. The reason is negative if it is
* locally generated.
*/
-dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_disconnect_reason(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_int32_t reason = wpa_s->disconnect_reason;
@@ -2799,6 +3093,139 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
/**
+ * wpas_dbus_getter_auth_status_code - Get most recent auth status code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "AuthStatusCode" property.
+ */
+dbus_bool_t wpas_dbus_getter_auth_status_code(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t reason = wpa_s->auth_status_code;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &reason, error);
+}
+
+
+/**
+ * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "AssocStatusCode" property.
+ */
+dbus_bool_t wpas_dbus_getter_assoc_status_code(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t status_code = wpa_s->assoc_status_code;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &status_code, error);
+}
+
+
+/**
+ * wpas_dbus_getter_roam_time - Get most recent roam time
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RoamTime" property.
+ */
+dbus_bool_t wpas_dbus_getter_roam_time(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 +
+ wpa_s->roam_time.usec / 1000;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &roam_time, error);
+}
+
+
+/**
+ * wpas_dbus_getter_roam_complete - Get most recent roam success or failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RoamComplete" property.
+ */
+dbus_bool_t wpas_dbus_getter_roam_complete(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time);
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+ &roam_complete, error);
+}
+
+
+/**
+ * wpas_dbus_getter_session_length - Get most recent BSS session length
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "SessionLength" property.
+ */
+dbus_bool_t wpas_dbus_getter_session_length(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 +
+ wpa_s->session_length.usec / 1000;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &session_length, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request
+ * status code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "BSSTMStatus" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_tm_status(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_WNM
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status;
+#else /* CONFIG_WNM */
+ dbus_uint32_t bss_tm_status = 0;
+#endif /* CONFIG_WNM */
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &bss_tm_status, error);
+}
+
+
+/**
* wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -2807,9 +3234,9 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
*
* Getter function for "BSSExpireAge" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_expire_age(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
@@ -2828,9 +3255,9 @@ dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
*
* Setter function for "BSSExpireAge" property.
*/
-dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_bss_expire_age(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t expire_age;
@@ -2857,9 +3284,9 @@ dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
*
* Getter function for "BSSExpireCount" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_expire_count(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
@@ -2878,9 +3305,9 @@ dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
*
* Setter function for "BSSExpireCount" property.
*/
-dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_bss_expire_count(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_uint32_t expire_count;
@@ -2907,8 +3334,9 @@ dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
*
* Getter function for "Country" property.
*/
-dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_country(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char country[3];
@@ -2932,8 +3360,9 @@ dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
*
* Setter function for "Country" property.
*/
-dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_country(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *country;
@@ -2970,9 +3399,9 @@ dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
*
* Getter function for "ScanInterval" property.
*/
-dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_scan_interval(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_int32_t scan_interval = wpa_s->scan_interval;
@@ -2991,9 +3420,9 @@ dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
*
* Setter function for "ScanInterval" property.
*/
-dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_scan_interval(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_int32_t scan_interval;
@@ -3020,14 +3449,13 @@ dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
*
* Getter for "Ifname" property.
*/
-dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_ifname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *ifname = wpa_s->ifname;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &ifname, error);
+ return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error);
}
@@ -3040,11 +3468,11 @@ dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
*
* Getter for "Driver" property.
*/
-dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_driver(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *driver;
if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
@@ -3054,9 +3482,8 @@ dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
return FALSE;
}
- driver = wpa_s->driver->name;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &driver, error);
+ return wpas_dbus_string_property_getter(iter, wpa_s->driver->name,
+ error);
}
@@ -3069,9 +3496,9 @@ dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
*
* Getter for "CurrentBSS" property.
*/
-dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_current_bss(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
@@ -3097,9 +3524,9 @@ dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
*
* Getter for "CurrentNetwork" property.
*/
-dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_current_network(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
@@ -3125,9 +3552,9 @@ dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
*
* Getter for "CurrentAuthMode" property.
*/
-dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_current_auth_mode(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
const char *eap_mode;
@@ -3143,9 +3570,11 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
"EAP-%s", eap_mode);
auth_mode = eap_mode_buf;
- } else {
+ } else if (wpa_s->current_ssid) {
auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
wpa_s->current_ssid->proto);
+ } else {
+ auth_mode = "UNKNOWN";
}
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
@@ -3162,15 +3591,33 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
*
* Getter for "BridgeIfname" property.
*/
-dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bridge_ifname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *bridge_ifname = wpa_s->bridge_ifname;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &bridge_ifname, error);
+ return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname,
+ error);
+}
+
+
+/**
+ * wpas_dbus_getter_config_file - Get interface configuration file path
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "ConfigFile" property.
+ */
+dbus_bool_t wpas_dbus_getter_config_file(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->confname, error);
}
@@ -3183,8 +3630,9 @@ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
*
* Getter for "BSSs" property.
*/
-dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bsss(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_bss *bss;
@@ -3240,8 +3688,9 @@ out:
*
* Getter for "Networks" property.
*/
-dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_networks(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_ssid *ssid;
@@ -3303,19 +3752,15 @@ out:
*
* Getter for "PKCS11EnginePath" property.
*/
-dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *pkcs11_engine_path;
- if (wpa_s->conf->pkcs11_engine_path == NULL)
- pkcs11_engine_path = "";
- else
- pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &pkcs11_engine_path, error);
+ return wpas_dbus_string_property_getter(iter,
+ wpa_s->conf->pkcs11_engine_path,
+ error);
}
@@ -3328,19 +3773,15 @@ dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
*
* Getter for "PKCS11ModulePath" property.
*/
-dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_pkcs11_module_path(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *pkcs11_module_path;
- if (wpa_s->conf->pkcs11_module_path == NULL)
- pkcs11_module_path = "";
- else
- pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &pkcs11_module_path, error);
+ return wpas_dbus_string_property_getter(iter,
+ wpa_s->conf->pkcs11_module_path,
+ error);
}
@@ -3353,8 +3794,9 @@ dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
*
* Getter for "Blobs" property.
*/
-dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_blobs(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
@@ -3406,6 +3848,393 @@ dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
}
+dbus_bool_t wpas_dbus_getter_iface_global(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ int ret;
+ char buf[250];
+ char *p = buf;
+
+ if (!property_desc->data) {
+ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+ "Unhandled interface property %s",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf,
+ sizeof(buf));
+ if (ret < 0)
+ *p = '\0';
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p,
+ error);
+}
+
+
+dbus_bool_t wpas_dbus_setter_iface_global(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ const char *new_value = NULL;
+ char buf[250];
+ size_t combined_len;
+ int ret;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &new_value))
+ return FALSE;
+
+ combined_len = os_strlen(property_desc->data) + os_strlen(new_value) +
+ 3;
+ if (combined_len >= sizeof(buf)) {
+ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+ "Interface property %s value too large",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ if (!new_value[0])
+ new_value = "NULL";
+
+ ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data,
+ new_value);
+ if (os_snprintf_error(combined_len, ret)) {
+ dbus_set_error(error, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
+ "Failed to construct new interface property %s",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
+ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+ "Failed to set interface property %s",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ wpa_supplicant_update_config(wpa_s);
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_stas - Get connected stations for an interface
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: a list of stations
+ *
+ * Getter for "Stations" property.
+ */
+dbus_bool_t wpas_dbus_getter_stas(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ struct sta_info *sta = NULL;
+ char **paths = NULL;
+ unsigned int i = 0, num = 0;
+ dbus_bool_t success = FALSE;
+
+ if (!wpa_s->dbus_new_path) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: no D-Bus interface", __func__);
+ return FALSE;
+ }
+
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ struct hostapd_data *hapd;
+
+ hapd = wpa_s->ap_iface->bss[0];
+ sta = hapd->sta_list;
+ num = hapd->num_sta;
+ }
+#endif /* CONFIG_AP */
+
+ paths = os_calloc(num, sizeof(char *));
+ if (!paths) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ /* Loop through scan results and append each result's object path */
+ for (; sta; sta = sta->next) {
+ paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+ if (!paths[i]) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
+ goto out;
+ }
+ /* Construct the object path for this BSS. */
+ os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta->addr));
+ }
+
+ success = wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_OBJECT_PATH,
+ paths, num,
+ error);
+
+out:
+ while (i)
+ os_free(paths[--i]);
+ os_free(paths);
+ return success;
+}
+
+
+/**
+ * wpas_dbus_getter_sta_address - Return the address of a connected station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Address" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_address(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ sta->addr, ETH_ALEN,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_sta_aid - Return the AID of a connected station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "AID" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_aid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+ &sta->aid,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_sta_caps - Return the capabilities of a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Capabilities" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_caps(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+ &sta->capability,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_rx_packets - Return the received packets for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RxPackets" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_rx_packets(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.rx_packets,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "TxPackets" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_tx_packets(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.tx_packets,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "TxBytes" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_tx_bytes(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.tx_bytes,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_rx_bytes - Return the received bytes for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RxBytes" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_rx_bytes(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.rx_bytes,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
DBusError *error, const char *func_name)
{
@@ -3432,8 +4261,9 @@ static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
*
* Getter for "BSSID" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_bssid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3457,8 +4287,9 @@ dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
*
* Getter for "SSID" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_ssid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3482,8 +4313,9 @@ dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
*
* Getter for "Privacy" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_privacy(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3508,12 +4340,14 @@ dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
*
* Getter for "Mode" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_mode(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
const char *mode;
+ const u8 *mesh;
res = get_bss_helper(args, error, __func__);
if (!res)
@@ -3527,9 +4361,15 @@ dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
case IEEE80211_CAP_DMG_AP:
mode = "infrastructure";
break;
+ default:
+ mode = "";
+ break;
}
} else {
- if (res->caps & IEEE80211_CAP_IBSS)
+ mesh = wpa_bss_get_ie(res, WLAN_EID_MESH_ID);
+ if (mesh)
+ mode = "mesh";
+ else if (res->caps & IEEE80211_CAP_IBSS)
mode = "ad-hoc";
else
mode = "infrastructure";
@@ -3549,8 +4389,9 @@ dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
*
* Getter for "Level" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_signal(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3575,8 +4416,9 @@ dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
*
* Getter for "Frequency" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_frequency(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3607,8 +4449,9 @@ static int cmp_u8s_desc(const void *a, const void *b)
*
* Getter for "Rates" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_rates(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3647,14 +4490,14 @@ dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
}
-static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
- struct wpa_ie_data *ie_data,
- DBusError *error)
+static dbus_bool_t wpas_dbus_get_bss_security_prop(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error)
{
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[9]; /* max 9 key managements may be supported */
+ const char *key_mgmt[15]; /* max 15 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -3664,7 +4507,12 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
goto nomem;
- /* KeyMgmt */
+ /*
+ * KeyMgmt
+ *
+ * When adding a new entry here, please take care to extend key_mgmt[]
+ * and keep documentation in doc/dbus.doxygen up to date.
+ */
n = 0;
if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
key_mgmt[n++] = "wpa-psk";
@@ -3686,6 +4534,22 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
key_mgmt[n++] = "wpa-eap-suite-b-192";
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
+ key_mgmt[n++] = "wpa-fils-sha256";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
+ key_mgmt[n++] = "wpa-fils-sha384";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
+ key_mgmt[n++] = "wpa-ft-fils-sha256";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
+ key_mgmt[n++] = "wpa-ft-fils-sha384";
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_SAE
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE)
+ key_mgmt[n++] = "sae";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
+ key_mgmt[n++] = "ft-sae";
+#endif /* CONFIG_SAE */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
@@ -3780,8 +4644,9 @@ nomem:
*
* Getter for "WPA" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_wpa(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3800,7 +4665,7 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
return FALSE;
}
- return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
+ return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
}
@@ -3813,8 +4678,9 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
*
* Getter for "RSN" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_rsn(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3833,7 +4699,7 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
return FALSE;
}
- return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
+ return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
}
@@ -3846,8 +4712,9 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
*
* Getter for "WPS" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_wps(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3902,8 +4769,9 @@ nomem:
*
* Getter for "IEs" property.
*/
-dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_ies(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3927,8 +4795,9 @@ dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
*
* Getter for BSS age
*/
-dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_bss_age(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
@@ -3956,8 +4825,9 @@ dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
*
* Getter for "enabled" property of a configured network.
*/
-dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_enabled(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
@@ -3976,8 +4846,9 @@ dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
*
* Setter for "Enabled" property of a configured network.
*/
-dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_enabled(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
struct wpa_supplicant *wpa_s;
@@ -4009,9 +4880,9 @@ dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
*
* Getter for "Properties" property of a configured network.
*/
-dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_network_properties(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
DBusMessageIter variant_iter, dict_iter;
@@ -4071,9 +4942,9 @@ out:
*
* Setter for "Properties" property of a configured network.
*/
-dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_network_properties(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
struct wpa_ssid *ssid = net->ssid;
@@ -4211,3 +5082,244 @@ out:
}
#endif /* CONFIG_AP */
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 *ielems;
+ int len;
+ struct ieee802_11_elems elems;
+ dbus_int32_t frame_id;
+ DBusMessageIter iter, array;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ielems, &len);
+ if (!ielems || len == 0) {
+ return dbus_message_new_error(
+ message, DBUS_ERROR_INVALID_ARGS, "Invalid value");
+ }
+
+ if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Parse error");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+ if (!wpa_s->vendor_elem[frame_id]) {
+ wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len);
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+ }
+
+ if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Resize error");
+ }
+
+ wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len);
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ dbus_int32_t frame_id;
+ const u8 *elem;
+ size_t elem_len;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+ if (!wpa_s->vendor_elem[frame_id]) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "ID value does not exist");
+ }
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ return wpas_dbus_error_no_memory(message);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]);
+ elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+ &elem, elem_len) ||
+ !dbus_message_iter_close_container(&iter, &array_iter)) {
+ dbus_message_unref(reply);
+ reply = wpas_dbus_error_no_memory(message);
+ }
+
+ return reply;
+}
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 *ielems;
+ int len;
+ struct ieee802_11_elems elems;
+ DBusMessageIter iter, array;
+ dbus_int32_t frame_id;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ielems, &len);
+ if (!ielems || len == 0) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid value");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+
+ if (len == 1 && *ielems == '*') {
+ wpabuf_free(wpa_s->vendor_elem[frame_id]);
+ wpa_s->vendor_elem[frame_id] = NULL;
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+ }
+
+ if (!wpa_s->vendor_elem[frame_id]) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "ID value does not exist");
+ }
+
+ if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Parse error");
+ }
+
+ if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0)
+ return NULL;
+
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Not found");
+}
+
+
+#ifdef CONFIG_MESH
+
+/**
+ * wpas_dbus_getter_mesh_peers - Get connected mesh peers
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "MeshPeers" property.
+ */
+dbus_bool_t wpas_dbus_getter_mesh_peers(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+ DBusMessageIter variant_iter, array_iter;
+ int i;
+ DBusMessageIter inner_array_iter;
+
+ if (!wpa_s->ifmsh)
+ return FALSE;
+ hapd = wpa_s->ifmsh->bss[0];
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING,
+ &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter))
+ return FALSE;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!dbus_message_iter_open_container(
+ &array_iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &inner_array_iter))
+ return FALSE;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if (!dbus_message_iter_append_basic(&inner_array_iter,
+ DBUS_TYPE_BYTE,
+ &(sta->addr[i])))
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container(
+ &array_iter, &inner_array_iter))
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_mesh_group - Get mesh group
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "MeshGroup" property.
+ */
+dbus_bool_t wpas_dbus_getter_mesh_group(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (!wpa_s->ifmsh || !ssid)
+ return FALSE;
+
+ if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ (char *) ssid->ssid,
+ ssid->ssid_len, error)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: error constructing reply", __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif /* CONFIG_MESH */
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
index 50f72ec..d922ce1 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -10,6 +10,8 @@
#ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H
#define CTRL_IFACE_DBUS_NEW_HANDLERS_H
+#include "dbus_new_helpers.h"
+
struct network_handler_args {
struct wpa_supplicant *wpa_s;
struct wpa_ssid *ssid;
@@ -20,6 +22,11 @@ struct bss_handler_args {
unsigned int id;
};
+struct sta_handler_args {
+ struct wpa_supplicant *wpa_s;
+ const u8 *sta;
+};
+
dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
const int type,
const void *val,
@@ -41,6 +48,10 @@ dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
size_t array_len,
DBusError *error);
+dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
+ const void *val,
+ DBusError *error);
+
DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
struct wpa_global *global);
@@ -50,43 +61,27 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
struct wpa_global *global);
-dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
+ struct wpa_global *global);
+
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_level);
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_timestamp);
+DECLARE_ACCESSOR(wpas_dbus_getter_debug_show_keys);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_level);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_timestamp);
+DECLARE_ACCESSOR(wpas_dbus_setter_debug_show_keys);
+DECLARE_ACCESSOR(wpas_dbus_getter_interfaces);
+DECLARE_ACCESSOR(wpas_dbus_getter_eap_methods);
+DECLARE_ACCESSOR(wpas_dbus_getter_global_capabilities);
+DECLARE_ACCESSOR(wpas_dbus_getter_iface_global);
+DECLARE_ACCESSOR(wpas_dbus_setter_iface_global);
DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -146,150 +141,65 @@ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
struct wpa_supplicant *wpa_s);
-dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_capabilities);
+DECLARE_ACCESSOR(wpas_dbus_getter_state);
+DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
+DECLARE_ACCESSOR(wpas_dbus_getter_ap_scan);
+DECLARE_ACCESSOR(wpas_dbus_setter_ap_scan);
+DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth);
+DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth);
+DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason);
+DECLARE_ACCESSOR(wpas_dbus_getter_disassociate_reason);
+DECLARE_ACCESSOR(wpas_dbus_getter_auth_status_code);
+DECLARE_ACCESSOR(wpas_dbus_getter_assoc_status_code);
+DECLARE_ACCESSOR(wpas_dbus_getter_roam_time);
+DECLARE_ACCESSOR(wpas_dbus_getter_roam_complete);
+DECLARE_ACCESSOR(wpas_dbus_getter_session_length);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_tm_status);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age);
+DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_age);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_count);
+DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_count);
+DECLARE_ACCESSOR(wpas_dbus_getter_country);
+DECLARE_ACCESSOR(wpas_dbus_setter_country);
+DECLARE_ACCESSOR(wpas_dbus_getter_scan_interval);
+DECLARE_ACCESSOR(wpas_dbus_setter_scan_interval);
+DECLARE_ACCESSOR(wpas_dbus_getter_ifname);
+DECLARE_ACCESSOR(wpas_dbus_getter_driver);
+DECLARE_ACCESSOR(wpas_dbus_getter_bridge_ifname);
+DECLARE_ACCESSOR(wpas_dbus_getter_config_file);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_bss);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_network);
+DECLARE_ACCESSOR(wpas_dbus_getter_current_auth_mode);
+DECLARE_ACCESSOR(wpas_dbus_getter_bsss);
+DECLARE_ACCESSOR(wpas_dbus_getter_networks);
+DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
+DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
+DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
+DECLARE_ACCESSOR(wpas_dbus_getter_stas);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_rx_packets);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_tx_packets);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_tx_bytes);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_rx_bytes);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_bssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_ssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_privacy);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_mode);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_signal);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_frequency);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_rates);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_wpa);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_rsn);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_wps);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_ies);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_age);
+DECLARE_ACCESSOR(wpas_dbus_getter_enabled);
+DECLARE_ACCESSOR(wpas_dbus_setter_enabled);
+DECLARE_ACCESSOR(wpas_dbus_getter_network_properties);
+DECLARE_ACCESSOR(wpas_dbus_setter_network_properties);
DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -297,20 +207,25 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
struct wpa_supplicant *wpa_s);
-dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_process_credentials);
+DECLARE_ACCESSOR(wpas_dbus_setter_process_credentials);
+DECLARE_ACCESSOR(wpas_dbus_getter_config_methods);
+DECLARE_ACCESSOR(wpas_dbus_setter_config_methods);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_name);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_model_name);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_model_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_model_number);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_model_number);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_serial_number);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_serial_number);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_device_type);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_device_type);
+
+DECLARE_ACCESSOR(wpas_dbus_getter_mesh_peers);
+DECLARE_ACCESSOR(wpas_dbus_getter_mesh_group);
DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -320,6 +235,22 @@ DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage *
+wpas_dbus_handler_tdls_channel_switch(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage *
+wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_remove(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
const char *arg);
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 67c079e..8cdd885 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -28,6 +28,18 @@
#include "../p2p_supplicant.h"
#include "../wifi_display.h"
+
+static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry)
+{
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE ||
+ entry.array_len != 4)
+ return 0;
+
+ return 1;
+}
+
+
/**
* Parses out the mac address from the peer object path.
* @peer_path - object path of the form
@@ -78,6 +90,7 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
int num_req_dev_types = 0;
unsigned int i;
u8 *req_dev_types = NULL;
+ unsigned int freq = 0;
dbus_message_iter_init(message, &iter);
entry.key = NULL;
@@ -122,6 +135,10 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
type = P2P_FIND_PROGRESSIVE;
else
goto error_clear;
+ } else if (os_strcmp(entry.key, "freq") == 0 &&
+ (entry.type == DBUS_TYPE_INT32 ||
+ entry.type == DBUS_TYPE_UINT32)) {
+ freq = entry.uint32_value;
} else
goto error_clear;
wpa_dbus_dict_entry_clear(&entry);
@@ -129,8 +146,11 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
wpa_s = wpa_s->global->p2p_init_wpa_s;
- wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL, 0, 0, NULL, 0);
+ if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
+ req_dev_types, NULL, 0, 0, NULL, freq))
+ reply = wpas_dbus_error_unknown_error(
+ message, "Could not start P2P find");
+
os_free(req_dev_types);
return reply;
@@ -364,13 +384,14 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
- NULL, 0, 0)) {
+ 0, 0, 0, NULL, 0, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
- } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0))
+ } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0,
+ 0, 0))
goto inv_args;
out:
@@ -484,6 +505,7 @@ DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ wpas_p2p_stop_find(wpa_s);
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->force_long_sd = 0;
p2p_flush(wpa_s->global->p2p);
@@ -511,6 +533,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
int new_pin;
char *err_msg = NULL;
char *iface = NULL;
+ int ret;
if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
return reply;
@@ -582,13 +605,19 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, -1, 0, 0, 0);
+ go_intent, freq, 0, -1, 0, 0, 0, 0, 0,
+ NULL, 0);
if (new_pin >= 0) {
char npin[9];
char *generated_pin;
- os_snprintf(npin, sizeof(npin), "%08d", new_pin);
+ ret = os_snprintf(npin, sizeof(npin), "%08d", new_pin);
+ if (os_snprintf_error(sizeof(npin), ret)) {
+ reply = wpas_dbus_error_unknown_error(message,
+ "invalid PIN");
+ goto out;
+ }
generated_pin = npin;
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING,
@@ -733,8 +762,8 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
if (ssid == NULL || ssid->disabled != 2)
goto err;
- if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
- 0) {
+ if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
+ 0, 0) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -807,9 +836,9 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
* P2P Device property accessor methods.
*/
-dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_device_config(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, dict_iter;
@@ -866,6 +895,35 @@ dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
goto err_no_mem;
}
+ /* GO IP address */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_go) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
+ (char *) wpa_s->conf->ip_addr_go,
+ 4))
+ goto err_no_mem;
+
+ /* IP address mask */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_mask) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
+ (char *) wpa_s->conf->ip_addr_mask,
+ 4))
+ goto err_no_mem;
+
+ /* IP address start */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_start) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrStart",
+ (char *)
+ wpa_s->conf->ip_addr_start,
+ 4))
+ goto err_no_mem;
+
+ /* IP address end */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_end) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrEnd",
+ (char *) wpa_s->conf->ip_addr_end,
+ 4))
+ goto err_no_mem;
+
/* Vendor Extensions */
for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
if (wpa_s->conf->wps_vendor_ext[i] == NULL)
@@ -916,9 +974,9 @@ err_no_mem:
}
-dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_p2p_device_config(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, iter_dict;
@@ -944,7 +1002,8 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
if (os_strcmp(entry.key, "DeviceName") == 0) {
char *devname;
- if (entry.type != DBUS_TYPE_STRING)
+ if (entry.type != DBUS_TYPE_STRING ||
+ os_strlen(entry.str_value) > WPS_DEV_NAME_MAX_LEN)
goto error;
devname = os_strdup(entry.str_value);
@@ -1049,6 +1108,26 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
wpa_s->conf->p2p_intra_bss = entry.bool_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_INTRA_BSS;
+ } else if (os_strcmp(entry.key, "IpAddrGo") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_go,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrMask") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_mask,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrStart") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_start,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrEnd") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_end,
+ entry.bytearray_value, 4);
} else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
entry.type == DBUS_TYPE_UINT32)
wpa_s->conf->p2p_group_idle = entry.uint32_value;
@@ -1087,8 +1166,9 @@ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peers(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct p2p_data *p2p = wpa_s->global->p2p;
@@ -1201,8 +1281,9 @@ static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
}
-dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_role(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char *str;
@@ -1224,8 +1305,9 @@ dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
}
-dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
@@ -1243,8 +1325,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
}
-dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peergo(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
@@ -1271,9 +1354,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
* Peer object properties accessor methods
*/
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1309,9 +1392,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1346,9 +1429,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1383,9 +1466,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1420,9 +1503,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1458,6 +1541,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
+ const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
@@ -1483,9 +1567,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1508,9 +1592,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_level(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1533,9 +1617,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1558,9 +1642,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1584,6 +1668,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
+ const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
@@ -1649,9 +1734,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
unsigned int i, num = 0;
@@ -1684,8 +1769,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_ies(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1709,9 +1795,9 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1774,9 +1860,9 @@ out_of_memory:
}
-dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_peer_groups(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1832,6 +1918,30 @@ out:
return success;
}
+dbus_bool_t wpas_dbus_getter_p2p_peer_vsie(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct peer_handler_args *peer_args = user_data;
+ const struct p2p_peer_info *info;
+
+ info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+ peer_args->p2p_device_addr, 0);
+ if (!info) {
+ dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
+ return FALSE;
+ }
+
+ if (!info->vendor_elems)
+ return wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_BYTE,
+ NULL, 0, error);
+
+ return wpas_dbus_simple_array_property_getter(
+ iter, DBUS_TYPE_BYTE, (char *) info->vendor_elems->buf,
+ info->vendor_elems->used, error);
+}
+
/**
* wpas_dbus_getter_persistent_groups - Get array of persistent group objects
@@ -1842,9 +1952,9 @@ out:
*
* Getter for "PersistentGroups" property.
*/
-dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_persistent_groups(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_ssid *ssid;
@@ -1904,16 +2014,16 @@ out:
*
* Getter for "Properties" property of a persistent group.
*/
-dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_persistent_group_properties(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
/* Leveraging the fact that persistent group object is still
* represented in same manner as network within.
*/
- return wpas_dbus_getter_network_properties(iter, error, net);
+ return wpas_dbus_getter_network_properties(property_desc, iter, error, net);
}
@@ -1927,9 +2037,9 @@ dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
*
* Setter for "Properties" property of a persistent group.
*/
-dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_persistent_group_properties(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct network_handler_args *net = user_data;
struct wpa_ssid *ssid = net->ssid;
@@ -2142,9 +2252,9 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
* Group object properties accessor methods
*/
-dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_members(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct wpa_ssid *ssid;
@@ -2211,8 +2321,9 @@ out_of_memory:
}
-dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_ssid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
@@ -2224,9 +2335,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_bssid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
u8 role = wpas_get_p2p_role(wpa_s);
@@ -2248,9 +2359,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_frequency(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
u16 op_freq;
@@ -2271,29 +2382,23 @@ dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- char *p_pass;
struct wpa_ssid *ssid = wpa_s->current_ssid;
if (ssid == NULL)
return FALSE;
- p_pass = ssid->passphrase;
- if (!p_pass)
- p_pass = "";
-
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &p_pass, error);
-
+ return wpas_dbus_string_property_getter(iter, ssid->passphrase, error);
}
-dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_psk(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
u8 *p_psk = NULL;
@@ -2313,9 +2418,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
struct hostapd_data *hapd;
@@ -2348,9 +2453,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, iter_dict, array_iter, sub;
@@ -2588,7 +2693,7 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service(
if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
goto error;
- if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
@@ -2600,26 +2705,27 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service(
bonjour = 1;
else
goto error_clear;
- wpa_dbus_dict_entry_clear(&entry);
- }
- }
- if (upnp == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
- if (os_strcmp(entry.key, "version") == 0 &&
- entry.type == DBUS_TYPE_INT32)
- version = entry.uint32_value;
- else if (os_strcmp(entry.key, "service") == 0 &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(service);
- service = os_strdup(entry.str_value);
- } else
+ } else if (os_strcmp(entry.key, "version") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
+ version = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "service") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(service);
+ service = os_strdup(entry.str_value);
+ } else if (os_strcmp(entry.key, "query") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
-
- wpa_dbus_dict_entry_clear(&entry);
+ wpabuf_free(query);
+ query = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ } else {
+ goto error_clear;
}
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+ if (upnp == 1) {
if (version <= 0 || service == NULL)
goto error;
@@ -2627,24 +2733,6 @@ DBusMessage * wpas_dbus_handler_p2p_delete_service(
if (ret != 0)
goto error;
} else if (bonjour == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
-
- if (os_strcmp(entry.key, "query") == 0) {
- if (entry.type != DBUS_TYPE_ARRAY ||
- entry.array_type != DBUS_TYPE_BYTE)
- goto error_clear;
- wpabuf_free(query);
- query = wpabuf_alloc_copy(
- entry.bytearray_value,
- entry.array_len);
- } else
- goto error_clear;
-
- wpa_dbus_dict_entry_clear(&entry);
- }
-
if (query == NULL)
goto error;
@@ -2876,8 +2964,9 @@ DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
#ifdef CONFIG_WIFI_DISPLAY
-dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_getter_global_wfd_ies(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
struct wpabuf *ie;
@@ -2898,8 +2987,9 @@ dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
}
-dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
- DBusError *error, void *user_data)
+dbus_bool_t wpas_dbus_setter_global_wfd_ies(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_global *global = user_data;
DBusMessageIter variant, array;
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index 2aecbbe..b3c45c1 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -89,139 +89,51 @@ DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
/*
* P2P Device property accessor methods.
*/
-dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_setter_p2p_device_config);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_device_config);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peers);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_role);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peergo);
/*
* P2P Peer properties.
*/
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
- DBusMessageIter *iter, DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
- DBusMessageIter *iter, DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_modelname);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_modelnumber);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_serialnumber);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_primary_device_type);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_config_method);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_level);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_capability);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_group_capability);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_secondary_device_types);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_vendor_extension);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_ies);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_address);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_groups);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_vsie);
/*
* P2P Group properties
*/
-
-dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_members);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_ssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_bssid);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_frequency);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_passphrase);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_psk);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_group_vendor_ext);
+DECLARE_ACCESSOR(wpas_dbus_setter_p2p_group_vendor_ext);
/*
* P2P Persistent Groups and properties
*/
-
-dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
- DBusError *error, void *user_data);
-
-dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+DECLARE_ACCESSOR(wpas_dbus_getter_persistent_groups);
+DECLARE_ACCESSOR(wpas_dbus_getter_persistent_group_properties);
+DECLARE_ACCESSOR(wpas_dbus_setter_persistent_group_properties);
DBusMessage * wpas_dbus_handler_add_persistent_group(
DBusMessage *message, struct wpa_supplicant *wpa_s);
@@ -233,15 +145,8 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
DBusMessage *message, struct wpa_supplicant *wpa_s);
#ifdef CONFIG_WIFI_DISPLAY
-
-dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
-dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
-
+DECLARE_ACCESSOR(wpas_dbus_getter_global_wfd_ies);
+DECLARE_ACCESSOR(wpas_dbus_setter_global_wfd_ies);
#endif /* CONFIG_WIFI_DISPLAY */
#endif /* DBUS_NEW_HANDLERS_P2P_H */
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index b2251ba..1594daf 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -286,10 +286,14 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
ret = wpas_wps_start_pin(wpa_s, params.bssid,
params.pin, 0,
DEV_PW_DEFAULT);
- if (ret > 0)
- os_snprintf(npin, sizeof(npin), "%08d", ret);
+ if (ret > 0) {
+ ret = os_snprintf(npin, sizeof(npin), "%08d", ret);
+ if (os_snprintf_error(sizeof(npin), ret))
+ return wpas_dbus_error_unknown_error(
+ message, "invalid PIN");
+ }
} else {
- ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
+ ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0, 0);
}
if (ret < 0) {
@@ -325,7 +329,7 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
* @wpa_s: %wpa_supplicant data structure
* Returns: NULL on success or DBus error on failure
*
- * Handler for "Cancel" method call. Returns NULL if WPS cancel successfull
+ * Handler for "Cancel" method call. Returns NULL if WPS cancel successful
* or DBus error on WPS cancel failure
*/
DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
@@ -349,9 +353,9 @@ DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
* true if wps_cred_processing configuration field is not equal to 1 or false
* if otherwise.
*/
-dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_process_credentials(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t process = wpa_s->conf->wps_cred_processing != 1;
@@ -371,9 +375,9 @@ dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
* Setter for "ProcessCredentials" property. Sets credentials_processed on 2
* if boolean argument is true or on 1 if otherwise.
*/
-dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_process_credentials(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t process_credentials, old_pc;
@@ -407,17 +411,15 @@ dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
* Getter for "ConfigMethods" property. Returned boolean will be true if
* providing the relevant string worked, or false otherwise.
*/
-dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_config_methods(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- char *methods = wpa_s->conf->config_methods;
- if (methods == NULL)
- methods = "";
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &methods, error);
+ return wpas_dbus_string_property_getter(iter,
+ wpa_s->conf->config_methods,
+ error);
}
@@ -431,9 +433,9 @@ dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
* Setter for "ConfigMethods" property. Sets the methods string, apply such
* change and returns true on success. Returns false otherwise.
*/
-dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_config_methods(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
char *methods, *new_methods;
@@ -454,3 +456,349 @@ dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter,
return TRUE;
}
+
+
+/**
+ * wpas_dbus_getter_wps_device_name - Get current WPS device name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "DeviceName" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->conf->device_name,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_name - Set current WPS device name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "DeviceName" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *devname;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_DEV_NAME_MAX_LEN)
+ return FALSE;
+
+ devname = os_strdup(methods);
+ if (!devname)
+ return FALSE;
+
+ os_free(wpa_s->conf->device_name);
+ wpa_s->conf->device_name = devname;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_NAME;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_manufacturer - Get current manufacturer name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Manufacturer" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_manufacturer(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->conf->manufacturer,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_manufacturer - Set current manufacturer name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "Manufacturer" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_manufacturer(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *manufacturer;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_MANUFACTURER_MAX_LEN)
+ return FALSE;
+
+ manufacturer = os_strdup(methods);
+ if (!manufacturer)
+ return FALSE;
+
+ os_free(wpa_s->conf->manufacturer);
+ wpa_s->conf->manufacturer = manufacturer;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_model_name - Get current device model name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "ModelName" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_model_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->conf->model_name,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_model_name - Set current device model name
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "ModelName" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_model_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *model_name;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_MODEL_NAME_MAX_LEN)
+ return FALSE;
+
+ model_name = os_strdup(methods);
+ if (!model_name)
+ return FALSE;
+ os_free(wpa_s->conf->model_name);
+ wpa_s->conf->model_name = model_name;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_model_number - Get current device model number
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "ModelNumber" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_model_number(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->conf->model_number,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_model_number - Set current device model number
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "ModelNumber" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_model_number(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *model_number;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_MODEL_NUMBER_MAX_LEN)
+ return FALSE;
+
+ model_number = os_strdup(methods);
+ if (!model_number)
+ return FALSE;
+
+ os_free(wpa_s->conf->model_number);
+ wpa_s->conf->model_number = model_number;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_serial_number - Get current device serial number
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "SerialNumber" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_serial_number(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter,
+ wpa_s->conf->serial_number,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_serial_number - Set current device serial number
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "SerialNumber" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_serial_number(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *serial_number;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_SERIAL_NUMBER_MAX_LEN)
+ return FALSE;
+
+ serial_number = os_strdup(methods);
+ if (!serial_number)
+ return FALSE;
+ os_free(wpa_s->conf->serial_number);
+ wpa_s->conf->serial_number = serial_number;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_device_type - Get current device type
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "DeviceType" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_device_type(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ (char *)
+ wpa_s->conf->device_type,
+ WPS_DEV_TYPE_LEN, error)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: error constructing reply", __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_device_type - Set current device type
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "DeviceType" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_device_type(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ u8 *dev_type;
+ int dev_len;
+ DBusMessageIter variant, array_iter;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ dbus_message_iter_recurse(iter, &variant);
+ if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ dbus_message_iter_recurse(&variant, &array_iter);
+ dbus_message_iter_get_fixed_array(&array_iter, &dev_type, &dev_len);
+
+ if (dev_len != WPS_DEV_TYPE_LEN)
+ return FALSE;
+
+ os_memcpy(wpa_s->conf->device_type, dev_type, WPS_DEV_TYPE_LEN);
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_TYPE;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c
index 45623f3..0115e32 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -46,7 +46,7 @@ static dbus_bool_t fill_dict_with_properties(
goto error;
/* An error getting a property fails the request entirely */
- if (!dsc->getter(&entry_iter, error, user_data)) {
+ if (!dsc->getter(dsc, &entry_iter, error, user_data)) {
wpa_printf(MSG_INFO,
"dbus: %s dbus_interface=%s dbus_property=%s getter failed",
__func__, dsc->dbus_interface,
@@ -176,7 +176,7 @@ static DBusMessage * properties_get(DBusMessage *message,
dbus_message_iter_init_append(reply, &iter);
dbus_error_init(&error);
- if (dsc->getter(&iter, &error, user_data) == FALSE) {
+ if (dsc->getter(dsc, &iter, &error, user_data) == FALSE) {
dbus_message_unref(reply);
reply = wpas_dbus_reply_new_from_error(
message, &error, DBUS_ERROR_FAILED,
@@ -213,7 +213,7 @@ static DBusMessage * properties_set(DBusMessage *message,
/* Iter will now point to the property's new value */
dbus_error_init(&error);
- if (dsc->setter(&iter, &error, user_data) == TRUE) {
+ if (dsc->setter(dsc, &iter, &error, user_data) == TRUE) {
/* Success */
reply = dbus_message_new_method_return(message);
} else {
@@ -627,7 +627,8 @@ static dbus_bool_t put_changed_properties(
return FALSE;
dbus_error_init(&error);
- if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) {
+ if (!dsc->getter(dsc, &entry_iter, &error, obj_dsc->user_data))
+ {
if (dbus_error_is_set(&error)) {
wpa_printf(MSG_ERROR,
"dbus: %s: Cannot get new value of property %s: (%s) %s",
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h
index 6e2c1f1..7b63b28 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -16,9 +16,13 @@ typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message,
void *user_data);
typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg);
-typedef dbus_bool_t (*WPADBusPropertyAccessor)(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+struct wpa_dbus_property_desc;
+typedef dbus_bool_t (*WPADBusPropertyAccessor)(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data);
+#define DECLARE_ACCESSOR(f) \
+dbus_bool_t f(const struct wpa_dbus_property_desc *property_desc, \
+ DBusMessageIter *iter, DBusError *error, void *user_data)
struct wpa_dbus_object_desc {
DBusConnection *connection;
@@ -89,6 +93,8 @@ struct wpa_dbus_property_desc {
WPADBusPropertyAccessor getter;
/* property setter function */
WPADBusPropertyAccessor setter;
+ /* other data */
+ const char *data;
};
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
index fba57e6..aee105b 100644
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -38,7 +38,7 @@ static struct interfaces * add_interface(struct dl_list *list,
if (!iface)
return NULL;
iface->dbus_interface = os_strdup(dbus_interface);
- iface->xml = wpabuf_alloc(6000);
+ iface->xml = wpabuf_alloc(15000);
if (iface->dbus_interface == NULL || iface->xml == NULL) {
os_free(iface->dbus_interface);
wpabuf_free(iface->xml);
@@ -257,7 +257,7 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
DBusMessage *reply;
struct wpabuf *xml;
- xml = wpabuf_alloc(15000);
+ xml = wpabuf_alloc(20000);
if (xml == NULL)
return NULL;
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old.c
deleted file mode 100644
index 88227af..0000000
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old.c
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "wps/wps.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../bss.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-#include "dbus_common_i.h"
-
-
-/**
- * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
- * @path: The dbus object path
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
- *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
- */
-char * wpas_dbus_decompose_object_path(const char *path, char **network,
- char **bssid)
-{
- const unsigned int dev_path_prefix_len =
- strlen(WPAS_DBUS_PATH_INTERFACES "/");
- char *obj_path_only;
- char *next_sep;
-
- /* Be a bit paranoid about path */
- if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
- dev_path_prefix_len))
- return NULL;
-
- /* Ensure there's something at the end of the path */
- if ((path + dev_path_prefix_len)[0] == '\0')
- return NULL;
-
- obj_path_only = os_strdup(path);
- if (obj_path_only == NULL)
- return NULL;
-
- next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
- if (next_sep != NULL) {
- const char *net_part = strstr(next_sep,
- WPAS_DBUS_NETWORKS_PART "/");
- const char *bssid_part = strstr(next_sep,
- WPAS_DBUS_BSSIDS_PART "/");
-
- if (network && net_part) {
- /* Deal with a request for a configured network */
- const char *net_name = net_part +
- strlen(WPAS_DBUS_NETWORKS_PART "/");
- *network = NULL;
- if (strlen(net_name))
- *network = os_strdup(net_name);
- } else if (bssid && bssid_part) {
- /* Deal with a request for a scanned BSSID */
- const char *bssid_name = bssid_part +
- strlen(WPAS_DBUS_BSSIDS_PART "/");
- if (strlen(bssid_name))
- *bssid = os_strdup(bssid_name);
- else
- *bssid = NULL;
- }
-
- /* Cut off interface object path before "/" */
- *next_sep = '\0';
- }
-
- return obj_path_only;
-}
-
-
-/**
- * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: A dbus error message
- *
- * Convenience function to create and return an invalid interface error
- */
-DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
-{
- return dbus_message_new_error(
- message, WPAS_ERROR_INVALID_IFACE,
- "wpa_supplicant knows nothing about this interface.");
-}
-
-
-/**
- * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid network error
- */
-DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
-{
- return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
- "The requested network does not exist.");
-}
-
-
-/**
- * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid bssid error
- */
-static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
-{
- return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
- "The BSSID requested was invalid.");
-}
-
-
-/**
- * wpas_dispatch_network_method - dispatch messages for configured networks
- * @message: the incoming dbus message
- * @wpa_s: a network interface's data
- * @network_id: id of the configured network we're interested in
- * Returns: a reply dbus message, or a dbus error message
- *
- * This function dispatches all incoming dbus messages for configured networks.
- */
-static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- int network_id)
-{
- DBusMessage *reply = NULL;
- const char *method = dbus_message_get_member(message);
- struct wpa_ssid *ssid;
-
- ssid = wpa_config_get_network(wpa_s->conf, network_id);
- if (ssid == NULL)
- return wpas_dbus_new_invalid_network_error(message);
-
- if (!strcmp(method, "set"))
- reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
- else if (!strcmp(method, "enable"))
- reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
- else if (!strcmp(method, "disable"))
- reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
-
- return reply;
-}
-
-
-/**
- * wpas_dispatch_bssid_method - dispatch messages for scanned networks
- * @message: the incoming dbus message
- * @wpa_s: a network interface's data
- * @bssid: bssid of the scanned network we're interested in
- * Returns: a reply dbus message, or a dbus error message
- *
- * This function dispatches all incoming dbus messages for scanned networks.
- */
-static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- const char *bssid_txt)
-{
- u8 bssid[ETH_ALEN];
- struct wpa_bss *bss;
-
- if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0)
- return wpas_dbus_new_invalid_bssid_error(message);
-
- bss = wpa_bss_get_bssid(wpa_s, bssid);
- if (bss == NULL)
- return wpas_dbus_new_invalid_bssid_error(message);
-
- /* Dispatch the method call against the scanned bssid */
- if (os_strcmp(dbus_message_get_member(message), "properties") == 0)
- return wpas_dbus_bssid_properties(message, wpa_s, bss);
-
- return NULL;
-}
-
-
-/**
- * wpas_iface_message_handler - Dispatch messages for interfaces or networks
- * @connection: Connection to the system message bus
- * @message: An incoming dbus message
- * @user_data: A pointer to a dbus control interface data structure
- * Returns: Whether or not the message was handled
- *
- * This function dispatches all incoming dbus messages for network interfaces,
- * or objects owned by them, such as scanned BSSIDs and configured networks.
- */
-static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- struct wpa_supplicant *wpa_s = user_data;
- const char *method = dbus_message_get_member(message);
- const char *path = dbus_message_get_path(message);
- const char *msg_interface = dbus_message_get_interface(message);
- char *iface_obj_path = NULL;
- char *network = NULL;
- char *bssid = NULL;
- DBusMessage *reply = NULL;
-
- /* Caller must specify a message interface */
- if (!msg_interface)
- goto out;
-
- wpa_printf(MSG_MSGDUMP, "dbus[old/iface]: %s.%s (%s) [%s]",
- msg_interface, method, path,
- dbus_message_get_signature(message));
-
- iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
- &bssid);
- if (iface_obj_path == NULL) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
-
- /* Make sure the message's object path actually refers to the
- * wpa_supplicant structure it's supposed to (which is wpa_s)
- */
- if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
- iface_obj_path) != wpa_s) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
-
- if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
- /* A method for one of this interface's configured networks */
- int nid = strtoul(network, NULL, 10);
-
- if (errno != EINVAL)
- reply = wpas_dispatch_network_method(message, wpa_s,
- nid);
- else
- reply = wpas_dbus_new_invalid_network_error(message);
- } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
- /* A method for one of this interface's scanned BSSIDs */
- reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
- } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
- /* A method for an interface only. */
- if (!strcmp(method, "scan"))
- reply = wpas_dbus_iface_scan(message, wpa_s);
- else if (!strcmp(method, "scanResults"))
- reply = wpas_dbus_iface_scan_results(message, wpa_s);
- else if (!strcmp(method, "addNetwork"))
- reply = wpas_dbus_iface_add_network(message, wpa_s);
- else if (!strcmp(method, "removeNetwork"))
- reply = wpas_dbus_iface_remove_network(message, wpa_s);
- else if (!strcmp(method, "selectNetwork"))
- reply = wpas_dbus_iface_select_network(message, wpa_s);
- else if (!strcmp(method, "capabilities"))
- reply = wpas_dbus_iface_capabilities(message, wpa_s);
- else if (!strcmp(method, "disconnect"))
- reply = wpas_dbus_iface_disconnect(message, wpa_s);
- else if (!strcmp(method, "setAPScan"))
- reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
- else if (!strcmp(method, "setSmartcardModules"))
- reply = wpas_dbus_iface_set_smartcard_modules(message,
- wpa_s);
- else if (!strcmp(method, "state"))
- reply = wpas_dbus_iface_get_state(message, wpa_s);
- else if (!strcmp(method, "scanning"))
- reply = wpas_dbus_iface_get_scanning(message, wpa_s);
-#ifndef CONFIG_NO_CONFIG_BLOBS
- else if (!strcmp(method, "setBlobs"))
- reply = wpas_dbus_iface_set_blobs(message, wpa_s);
- else if (!strcmp(method, "removeBlobs"))
- reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-#ifdef CONFIG_WPS
- else if (os_strcmp(method, "wpsPbc") == 0)
- reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
- else if (os_strcmp(method, "wpsPin") == 0)
- reply = wpas_dbus_iface_wps_pin(message, wpa_s);
- else if (os_strcmp(method, "wpsReg") == 0)
- reply = wpas_dbus_iface_wps_reg(message, wpa_s);
-#endif /* CONFIG_WPS */
- else if (os_strcmp(method, "flush") == 0)
- reply = wpas_dbus_iface_flush(message, wpa_s);
- }
-
- /* If the message was handled, send back the reply */
-out:
- if (reply) {
- if (!dbus_message_get_no_reply(message))
- dbus_connection_send(connection, reply, NULL);
- dbus_message_unref(reply);
- }
-
- os_free(iface_obj_path);
- os_free(network);
- os_free(bssid);
- return reply ? DBUS_HANDLER_RESULT_HANDLED :
- DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-
-/**
- * wpas_message_handler - dispatch incoming dbus messages
- * @connection: connection to the system message bus
- * @message: an incoming dbus message
- * @user_data: a pointer to a dbus control interface data structure
- * Returns: whether or not the message was handled
- *
- * This function dispatches all incoming dbus messages to the correct
- * handlers, depending on what the message's target object path is,
- * and what the method call is.
- */
-static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- struct wpas_dbus_priv *ctrl_iface = user_data;
- const char *method;
- const char *path;
- const char *msg_interface;
- DBusMessage *reply = NULL;
-
- method = dbus_message_get_member(message);
- path = dbus_message_get_path(message);
- msg_interface = dbus_message_get_interface(message);
- if (!method || !path || !ctrl_iface || !msg_interface)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- wpa_printf(MSG_MSGDUMP, "dbus[old]: %s.%s (%s) [%s]",
- msg_interface, method, path,
- dbus_message_get_signature(message));
-
- /* Validate the method interface */
- if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- if (!strcmp(path, WPAS_DBUS_PATH)) {
- /* dispatch methods against our global dbus interface here */
- if (!strcmp(method, "addInterface")) {
- reply = wpas_dbus_global_add_interface(
- message, ctrl_iface->global);
- } else if (!strcmp(method, "removeInterface")) {
- reply = wpas_dbus_global_remove_interface(
- message, ctrl_iface->global);
- } else if (!strcmp(method, "getInterface")) {
- reply = wpas_dbus_global_get_interface(
- message, ctrl_iface->global);
- } else if (!strcmp(method, "setDebugParams")) {
- reply = wpas_dbus_global_set_debugparams(
- message, ctrl_iface->global);
- }
- }
-
- /* If the message was handled, send back the reply */
- if (reply) {
- if (!dbus_message_get_no_reply(message))
- dbus_connection_send(connection, reply, NULL);
- dbus_message_unref(reply);
- }
-
- return reply ? DBUS_HANDLER_RESULT_HANDLED :
- DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
- * @wpa_s: %wpa_supplicant network interface data
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners that this interface has updated scan results.
- */
-void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
- struct wpas_dbus_priv *iface = wpa_s->global->dbus;
- DBusMessage *_signal;
-
- /* Do nothing if the control interface is not turned on */
- if (iface == NULL || !wpa_s->dbus_path)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "ScanResultsAvailable");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: Not enough memory to send scan results signal");
- return;
- }
- dbus_connection_send(iface->con, _signal, NULL);
- dbus_message_unref(_signal);
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_state_change - Send a state change signal
- * @wpa_s: %wpa_supplicant network interface data
- * @new_state: new state wpa_supplicant is entering
- * @old_state: old state wpa_supplicant is leaving
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners that wpa_supplicant has changed state
- */
-void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
- enum wpa_states new_state,
- enum wpa_states old_state)
-{
- struct wpas_dbus_priv *iface;
- DBusMessage *_signal = NULL;
- const char *new_state_str, *old_state_str;
-
- if (wpa_s->dbus_path == NULL)
- return; /* Skip signal since D-Bus setup is not yet ready */
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s->global == NULL)
- return;
- iface = wpa_s->global->dbus;
- if (iface == NULL)
- return;
-
- /* Only send signal if state really changed */
- if (new_state == old_state)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "StateChange");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: could not create dbus signal; likely out of memory",
- __func__);
- return;
- }
-
- new_state_str = wpa_supplicant_state_txt(new_state);
- old_state_str = wpa_supplicant_state_txt(old_state);
-
- if (!dbus_message_append_args(_signal,
- DBUS_TYPE_STRING, &new_state_str,
- DBUS_TYPE_STRING, &old_state_str,
- DBUS_TYPE_INVALID)) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Not enough memory to construct state change signal",
- __func__);
- goto out;
- }
-
- dbus_connection_send(iface->con, _signal, NULL);
-
-out:
- dbus_message_unref(_signal);
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_scanning - send scanning status
- * @wpa_s: %wpa_supplicant network interface data
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners of interface scanning state changes
- */
-void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
-{
- struct wpas_dbus_priv *iface = wpa_s->global->dbus;
- DBusMessage *_signal;
- dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-
- /* Do nothing if the control interface is not turned on */
- if (iface == NULL || !wpa_s->dbus_path)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "Scanning");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: Not enough memory to send scan results signal");
- return;
- }
-
- if (dbus_message_append_args(_signal,
- DBUS_TYPE_BOOLEAN, &scanning,
- DBUS_TYPE_INVALID)) {
- dbus_connection_send(iface->con, _signal, NULL);
- } else {
- wpa_printf(MSG_ERROR,
- "dbus: Not enough memory to construct signal");
- }
- dbus_message_unref(_signal);
-}
-
-
-#ifdef CONFIG_WPS
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
- const struct wps_credential *cred)
-{
- struct wpas_dbus_priv *iface;
- DBusMessage *_signal = NULL;
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s->global == NULL)
- return;
- iface = wpa_s->global->dbus;
- if (iface == NULL || !wpa_s->dbus_path)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "WpsCred");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Could not create dbus signal; likely out of memory",
- __func__);
- return;
- }
-
- if (!dbus_message_append_args(_signal,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &cred->cred_attr, cred->cred_attr_len,
- DBUS_TYPE_INVALID)) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Not enough memory to construct signal",
- __func__);
- goto out;
- }
-
- dbus_connection_send(iface->con, _signal, NULL);
-
-out:
- dbus_message_unref(_signal);
-}
-#else /* CONFIG_WPS */
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
- const struct wps_credential *cred)
-{
-}
-#endif /* CONFIG_WPS */
-
-void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
- int depth, const char *subject,
- const char *cert_hash,
- const struct wpabuf *cert)
-{
- struct wpas_dbus_priv *iface;
- DBusMessage *_signal = NULL;
- const char *hash;
- const char *cert_hex;
- int cert_hex_len;
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s->global == NULL)
- return;
- iface = wpa_s->global->dbus;
- if (iface == NULL || !wpa_s->dbus_path)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "Certification");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Could not create dbus signal; likely out of memory",
- __func__);
- return;
- }
-
- hash = cert_hash ? cert_hash : "";
- cert_hex = cert ? wpabuf_head(cert) : "";
- cert_hex_len = cert ? wpabuf_len(cert) : 0;
-
- if (!dbus_message_append_args(_signal,
- DBUS_TYPE_INT32, &depth,
- DBUS_TYPE_STRING, &subject,
- DBUS_TYPE_STRING, &hash,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &cert_hex, cert_hex_len,
- DBUS_TYPE_INVALID)) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Not enough memory to construct signal",
- __func__);
- goto out;
- }
-
- dbus_connection_send(iface->con, _signal, NULL);
-
-out:
- dbus_message_unref(_signal);
-
-}
-
-
-/**
- * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * Returns: 0 on success, -1 on failure
- *
- * Initialize the dbus control interface and start receiving commands from
- * external programs over the bus.
- */
-int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
-{
- DBusError error;
- int ret = -1;
- DBusObjectPathVTable wpas_vtable = {
- NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
- };
-
- /* Register the message handler for the global dbus interface */
- if (!dbus_connection_register_object_path(iface->con,
- WPAS_DBUS_PATH, &wpas_vtable,
- iface)) {
- wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
- return -1;
- }
-
- /* Register our service with the message bus */
- dbus_error_init(&error);
- switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
- 0, &error)) {
- case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
- ret = 0;
- break;
- case DBUS_REQUEST_NAME_REPLY_EXISTS:
- case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
- case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
- wpa_printf(MSG_ERROR,
- "dbus: Could not request service name: already registered");
- break;
- default:
- wpa_printf(MSG_ERROR,
- "dbus: Could not request service name: %s %s",
- error.name, error.message);
- break;
- }
- dbus_error_free(&error);
-
- if (ret != 0)
- return -1;
-
- wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
- "'.");
-
- return 0;
-}
-
-
-/**
- * wpas_dbus_register_new_iface - Register a new interface with dbus
- * @wpa_s: %wpa_supplicant interface description structure to register
- * Returns: 0 on success, -1 on error
- *
- * Registers a new interface with dbus and assigns it a dbus object path.
- */
-int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
-{
- struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
- DBusConnection * con;
- u32 next;
- DBusObjectPathVTable vtable = {
- NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
- };
-
- /* Do nothing if the control interface is not turned on */
- if (ctrl_iface == NULL)
- return 0;
-
- con = ctrl_iface->con;
- next = ctrl_iface->next_objid++;
-
- /* Create and set the interface's object path */
- wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
- if (wpa_s->dbus_path == NULL)
- return -1;
- os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX,
- WPAS_DBUS_PATH_INTERFACES "/%u",
- next);
-
- /* Register the message handler for the interface functions */
- if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
- wpa_s)) {
- wpa_printf(MSG_ERROR,
- "dbus: Could not set up message handler for interface %s",
- wpa_s->ifname);
- return -1;
- }
-
- return 0;
-}
-
-
-/**
- * wpas_dbus_unregister_iface - Unregister an interface from dbus
- * @wpa_s: wpa_supplicant interface structure
- * Returns: 0 on success, -1 on failure
- *
- * Unregisters the interface with dbus
- */
-int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
-{
- struct wpas_dbus_priv *ctrl_iface;
- DBusConnection *con;
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s == NULL || wpa_s->global == NULL)
- return 0;
- ctrl_iface = wpa_s->global->dbus;
- if (ctrl_iface == NULL || wpa_s->dbus_path == NULL)
- return 0;
-
- con = ctrl_iface->con;
- if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path))
- return -1;
-
- os_free(wpa_s->dbus_path);
- wpa_s->dbus_path = NULL;
-
- return 0;
-}
-
-
-/**
- * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * @path: Pointer to a dbus object path representing an interface
- * Returns: Pointer to the interface or %NULL if not found
- */
-struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
- struct wpa_global *global, const char *path)
-{
- struct wpa_supplicant *wpa_s;
-
- for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- if (wpa_s->dbus_path && strcmp(wpa_s->dbus_path, path) == 0)
- return wpa_s;
- }
- return NULL;
-}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old.h b/contrib/wpa/wpa_supplicant/dbus/dbus_old.h
deleted file mode 100644
index 451a9f8..0000000
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef CTRL_IFACE_DBUS_H
-#define CTRL_IFACE_DBUS_H
-
-struct wps_credential;
-
-#ifdef CONFIG_CTRL_IFACE_DBUS
-
-#define WPAS_DBUS_OBJECT_PATH_MAX 150
-
-#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant"
-#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant"
-#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant"
-
-#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces"
-#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface"
-
-#define WPAS_DBUS_NETWORKS_PART "Networks"
-#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
-
-#define WPAS_DBUS_BSSIDS_PART "BSSIDs"
-#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID"
-
-
-/* Errors */
-#define WPAS_ERROR_INVALID_NETWORK \
- WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork"
-#define WPAS_ERROR_INVALID_BSSID \
- WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID"
-
-#define WPAS_ERROR_INVALID_OPTS \
- WPAS_DBUS_INTERFACE ".InvalidOptions"
-#define WPAS_ERROR_INVALID_IFACE \
- WPAS_DBUS_INTERFACE ".InvalidInterface"
-
-#define WPAS_ERROR_ADD_ERROR \
- WPAS_DBUS_INTERFACE ".AddError"
-#define WPAS_ERROR_EXISTS_ERROR \
- WPAS_DBUS_INTERFACE ".ExistsError"
-#define WPAS_ERROR_REMOVE_ERROR \
- WPAS_DBUS_INTERFACE ".RemoveError"
-
-#define WPAS_ERROR_SCAN_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".ScanError"
-#define WPAS_ERROR_ADD_NETWORK_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError"
-#define WPAS_ERROR_INTERNAL_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".InternalError"
-#define WPAS_ERROR_REMOVE_NETWORK_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError"
-
-#define WPAS_ERROR_WPS_PBC_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".WpsPbcError"
-#define WPAS_ERROR_WPS_PIN_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".WpsPinError"
-#define WPAS_ERROR_WPS_REG_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".WpsRegError"
-
-#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x"
-
-struct wpa_global;
-struct wpa_supplicant;
-
-int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface);
-void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
- enum wpa_states new_state,
- enum wpa_states old_state);
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
- const struct wps_credential *cred);
-void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
- int depth, const char *subject,
- const char *cert_hash,
- const struct wpabuf *cert);
-
-char * wpas_dbus_decompose_object_path(const char *path, char **network,
- char **bssid);
-
-int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
-int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
-
-
-/* Methods internal to the dbus control interface */
-struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
- struct wpa_global *global, const char *path);
-
-#else /* CONFIG_CTRL_IFACE_DBUS */
-
-static inline void
-wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
- enum wpa_states new_state,
- enum wpa_states old_state)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
- const struct wps_credential *cred)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
- int depth, const char *subject,
- const char *cert_hash,
- const struct wpabuf *cert)
-{
-}
-
-static inline int
-wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-
-static inline int
-wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-
-#endif /* CONFIG_CTRL_IFACE_DBUS */
-
-#endif /* CTRL_IFACE_DBUS_H */
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c
deleted file mode 100644
index e8f62ef..0000000
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.c
+++ /dev/null
@@ -1,1404 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "eap_peer/eap_methods.h"
-#include "common/ieee802_11_defs.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "rsn_supp/wpa.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../driver_i.h"
-#include "../notify.h"
-#include "../wpas_glue.h"
-#include "../bss.h"
-#include "../scan.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-#include "dbus_dict_helpers.h"
-
-/**
- * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid options error
- */
-DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
- const char *arg)
-{
- DBusMessage *reply;
-
- reply = dbus_message_new_error(
- message, WPAS_ERROR_INVALID_OPTS,
- "Did not receive correct message arguments.");
- if (arg != NULL)
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-
-/**
- * wpas_dbus_new_success_reply - Return a new success reply message
- * @message: Pointer to incoming dbus message this reply refers to
- * Returns: a dbus message containing a single UINT32 that indicates
- * success (ie, a value of 1)
- *
- * Convenience function to create and return a success reply message
- */
-DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
-{
- DBusMessage *reply;
- unsigned int success = 1;
-
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
- DBUS_TYPE_INVALID);
- return reply;
-}
-
-
-/**
- * wpas_dbus_global_add_interface - Request registration of a network interface
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object path of the new interface object,
- * or a dbus error message with more information
- *
- * Handler function for "addInterface" method call. Handles requests
- * by dbus clients to register a network interface that wpa_supplicant
- * will manage.
- */
-DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
- struct wpa_global *global)
-{
- char *ifname = NULL;
- char *driver = NULL;
- char *driver_param = NULL;
- char *confname = NULL;
- char *bridge_ifname = NULL;
- DBusMessage *reply = NULL;
- DBusMessageIter iter;
-
- dbus_message_iter_init(message, &iter);
-
- /* First argument: interface name (DBUS_TYPE_STRING)
- * Required; must be non-zero length
- */
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- goto error;
- dbus_message_iter_get_basic(&iter, &ifname);
- if (!os_strlen(ifname))
- goto error;
-
- /* Second argument: dict of options */
- if (dbus_message_iter_next(&iter)) {
- DBusMessageIter iter_dict;
- struct wpa_dbus_dict_entry entry;
-
- if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
- goto error;
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
- if (!strcmp(entry.key, "driver") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(driver);
- driver = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (driver == NULL)
- goto error;
- } else if (!strcmp(entry.key, "driver-params") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(driver_param);
- driver_param = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (driver_param == NULL)
- goto error;
- } else if (!strcmp(entry.key, "config-file") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(confname);
- confname = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (confname == NULL)
- goto error;
- } else if (!strcmp(entry.key, "bridge-ifname") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(bridge_ifname);
- bridge_ifname = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (bridge_ifname == NULL)
- goto error;
- } else {
- wpa_dbus_dict_entry_clear(&entry);
- goto error;
- }
- }
- }
-
- /*
- * Try to get the wpa_supplicant record for this iface, return
- * an error if we already control it.
- */
- if (wpa_supplicant_get_iface(global, ifname) != NULL) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_EXISTS_ERROR,
- "wpa_supplicant already controls this interface.");
- } else {
- struct wpa_supplicant *wpa_s;
- struct wpa_interface iface;
-
- os_memset(&iface, 0, sizeof(iface));
- iface.ifname = ifname;
- iface.driver = driver;
- iface.driver_param = driver_param;
- iface.confname = confname;
- iface.bridge_ifname = bridge_ifname;
- /* Otherwise, have wpa_supplicant attach to it. */
- wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
- if (wpa_s && wpa_s->dbus_path) {
- const char *path = wpa_s->dbus_path;
-
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
- &path, DBUS_TYPE_INVALID);
- } else {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_ERROR,
- "wpa_supplicant couldn't grab this interface.");
- }
- }
-
-out:
- os_free(driver);
- os_free(driver_param);
- os_free(confname);
- os_free(bridge_ifname);
- return reply;
-
-error:
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
-}
-
-
-/**
- * wpas_dbus_global_remove_interface - Request deregistration of an interface
- * @message: Pointer to incoming dbus message
- * @global: wpa_supplicant global data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0), or returns a dbus error message with more information
- *
- * Handler function for "removeInterface" method call. Handles requests
- * by dbus clients to deregister a network interface that wpa_supplicant
- * currently manages.
- */
-DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
- struct wpa_global *global)
-{
- struct wpa_supplicant *wpa_s;
- char *path;
- DBusMessage *reply = NULL;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
- if (wpa_s == NULL) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
-
- if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
- reply = wpas_dbus_new_success_reply(message);
- } else {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_REMOVE_ERROR,
- "wpa_supplicant couldn't remove this interface.");
- }
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_global_get_interface - Get the object path for an interface name
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object path of the interface object,
- * or a dbus error message with more information
- *
- * Handler function for "getInterface" method call. Handles requests
- * by dbus clients for the object path of an specific network interface.
- */
-DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
- struct wpa_global *global)
-{
- DBusMessage *reply = NULL;
- const char *ifname;
- const char *path;
- struct wpa_supplicant *wpa_s;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &ifname,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- wpa_s = wpa_supplicant_get_iface(global, ifname);
- if (wpa_s == NULL || !wpa_s->dbus_path) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
-
- path = wpa_s->dbus_path;
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_global_set_debugparams- Set the debug params
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0), or returns a dbus error message with more information
- *
- * Handler function for "setDebugParams" method call. Handles requests
- * by dbus clients for the object path of an specific network interface.
- */
-DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
- struct wpa_global *global)
-{
- DBusMessage *reply = NULL;
- int debug_level;
- dbus_bool_t debug_timestamp;
- dbus_bool_t debug_show_keys;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_INT32, &debug_level,
- DBUS_TYPE_BOOLEAN, &debug_timestamp,
- DBUS_TYPE_BOOLEAN, &debug_show_keys,
- DBUS_TYPE_INVALID)) {
- return wpas_dbus_new_invalid_opts_error(message, NULL);
- }
-
- if (wpa_supplicant_set_debug_params(global, debug_level,
- debug_timestamp ? 1 : 0,
- debug_show_keys ? 1 : 0)) {
- return wpas_dbus_new_invalid_opts_error(message, NULL);
- }
-
- reply = wpas_dbus_new_success_reply(message);
-
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_scan - Request a wireless scan on an interface
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "scan" method call of a network device. Requests
- * that wpa_supplicant perform a wireless scan as soon as possible
- * on a particular wireless interface.
- */
-DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_scan_results - Get the results of a recent scan request
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a dbus array of objects paths, or returns
- * a dbus error message if not scan results could be found
- *
- * Handler function for "scanResults" method call of a network device. Returns
- * a dbus message containing the object paths of wireless networks found.
- */
-DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply;
- DBusMessageIter iter;
- DBusMessageIter sub_iter;
- struct wpa_bss *bss;
-
- if (!wpa_s->dbus_path)
- return dbus_message_new_error(message,
- WPAS_ERROR_INTERNAL_ERROR,
- "no D-Bus interface available");
-
- /* Create and initialize the return message */
- reply = dbus_message_new_method_return(message);
- dbus_message_iter_init_append(reply, &iter);
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING,
- &sub_iter))
- goto error;
-
- /* Loop through scan results and append each result's object path */
- dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
- char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
- char *path = path_buf;
-
- /* Construct the object path for this network. Note that ':'
- * is not a valid character in dbus object paths.
- */
- os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_BSSIDS_PART "/"
- WPAS_DBUS_BSSID_FORMAT,
- wpa_s->dbus_path, MAC2STR(bss->bssid));
- if (!dbus_message_iter_append_basic(&sub_iter,
- DBUS_TYPE_OBJECT_PATH,
- &path))
- goto error;
- }
-
- if (!dbus_message_iter_close_container(&iter, &sub_iter))
- goto error;
-
- return reply;
-
-error:
- dbus_message_unref(reply);
- return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning scan results");
-}
-
-
-/**
- * wpas_dbus_bssid_properties - Return the properties of a scanned network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @res: wpa_supplicant scan result for which to get properties
- * Returns: a dbus message containing the properties for the requested network
- *
- * Handler function for "properties" method call of a scanned network.
- * Returns a dbus message containing the the properties.
- */
-DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss)
-{
- DBusMessage *reply;
- DBusMessageIter iter, iter_dict;
- const u8 *wpa_ie, *rsn_ie, *wps_ie;
-
- /* Dump the properties into a dbus message */
- reply = dbus_message_new_method_return(message);
-
- wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
- rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- wps_ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
-
- dbus_message_iter_init_append(reply, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &iter_dict) ||
- !wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
- (const char *) bss->bssid,
- ETH_ALEN) ||
- !wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
- (const char *) bss->ssid,
- bss->ssid_len) ||
- (wpa_ie &&
- !wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
- (const char *) wpa_ie,
- wpa_ie[1] + 2)) ||
- (rsn_ie &&
- !wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
- (const char *) rsn_ie,
- rsn_ie[1] + 2)) ||
- (wps_ie &&
- !wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
- (const char *) wps_ie,
- wps_ie[1] + 2)) ||
- (bss->freq &&
- !wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) ||
- !wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
- bss->caps) ||
- (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) ||
- (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) ||
- (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) ||
- !wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
- wpa_bss_get_max_rate(bss) * 500000) ||
- !wpa_dbus_dict_close_write(&iter, &iter_dict)) {
- if (reply)
- dbus_message_unref(reply);
- reply = dbus_message_new_error(
- message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning BSSID properties.");
- }
-
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_capabilities - Return interface capabilities
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a dict of strings
- *
- * Handler function for "capabilities" method call of an interface.
- */
-DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- struct wpa_driver_capa capa;
- int res;
- DBusMessageIter iter, iter_dict;
- char **eap_methods;
- size_t num_items;
- dbus_bool_t strict = FALSE;
- DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_BOOLEAN, &strict,
- DBUS_TYPE_INVALID))
- strict = FALSE;
-
- reply = dbus_message_new_method_return(message);
-
- dbus_message_iter_init_append(reply, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
- goto error;
-
- /* EAP methods */
- eap_methods = eap_get_names_as_string_array(&num_items);
- if (eap_methods) {
- dbus_bool_t success;
- size_t i = 0;
-
- success = wpa_dbus_dict_append_string_array(
- &iter_dict, "eap", (const char **) eap_methods,
- num_items);
-
- /* free returned method array */
- while (eap_methods[i])
- os_free(eap_methods[i++]);
- os_free(eap_methods);
-
- if (!success)
- goto error;
- }
-
- res = wpa_drv_get_capa(wpa_s, &capa);
-
- /***** pairwise cipher */
- if (res < 0) {
- if (!strict) {
- const char *args[] = {"CCMP", "TKIP", "NONE"};
-
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "pairwise", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "CCMP")) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "TKIP")) ||
- ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "NONE")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- /***** group cipher */
- if (res < 0) {
- if (!strict) {
- const char *args[] = {
- "CCMP", "TKIP", "WEP104", "WEP40"
- };
-
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "group", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
-
- if (((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "CCMP")) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "TKIP")) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WEP104")) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WEP40")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- /***** key management */
- if (res < 0) {
- if (!strict) {
- const char *args[] = {
- "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
- "NONE"
- };
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "key_mgmt", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array) ||
- !wpa_dbus_dict_string_array_add_element(&iter_array,
- "NONE") ||
- !wpa_dbus_dict_string_array_add_element(&iter_array,
- "IEEE8021X") ||
- ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-EAP")) ||
- ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-PSK")) ||
- ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-NONE")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- /***** WPA protocol */
- if (res < 0) {
- if (!strict) {
- const char *args[] = { "RSN", "WPA" };
-
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "proto", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array) ||
- ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "RSN")) ||
- ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- /***** auth alg */
- if (res < 0) {
- if (!strict) {
- const char *args[] = { "OPEN", "SHARED", "LEAP" };
-
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "auth_alg", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array) ||
- ((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "OPEN")) ||
- ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "SHARED")) ||
- ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "LEAP")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
- goto error;
-
- return reply;
-
-error:
- if (reply)
- dbus_message_unref(reply);
- return dbus_message_new_error(
- message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning interface capabilities.");
-}
-
-
-/**
- * wpas_dbus_iface_add_network - Add a new configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing the object path of the new network
- *
- * Handler function for "addNetwork" method call of a network interface.
- */
-DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- struct wpa_ssid *ssid = NULL;
- char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
-
- if (wpa_s->dbus_path)
- ssid = wpa_config_add_network(wpa_s->conf);
- if (ssid == NULL) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_NETWORK_ERROR,
- "wpa_supplicant could not add a network on this interface.");
- goto out;
- }
- wpas_notify_network_added(wpa_s, ssid);
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
-
- /* Construct the object path for this network. */
- os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
- wpa_s->dbus_path, ssid->id);
-
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
- &path, DBUS_TYPE_INVALID);
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_remove_network - Remove a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "removeNetwork" method call of a network interface.
- */
-DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- const char *op;
- char *iface = NULL, *net_id = NULL;
- int id;
- struct wpa_ssid *ssid;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &op,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- /* Extract the network ID */
- iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
- if (iface == NULL || net_id == NULL) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- /* Ensure the network is actually a child of this interface */
- if (!wpa_s->dbus_path || os_strcmp(iface, wpa_s->dbus_path) != 0) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- id = strtoul(net_id, NULL, 10);
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
- "error removing the specified on this interface.");
- goto out;
- }
-
- reply = wpas_dbus_new_success_reply(message);
-
-out:
- os_free(iface);
- os_free(net_id);
- return reply;
-}
-
-
-static const char * const dont_quote[] = {
- "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
- "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
- "bssid", "scan_freq", "freq_list", NULL
-};
-
-
-static dbus_bool_t should_quote_opt(const char *key)
-{
- int i = 0;
-
- while (dont_quote[i] != NULL) {
- if (os_strcmp(key, dont_quote[i]) == 0)
- return FALSE;
- i++;
- }
- return TRUE;
-}
-
-
-/**
- * wpas_dbus_iface_set_network - Set options for a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "set" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- DBusMessage *reply = NULL;
- struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
- DBusMessageIter iter, iter_dict;
-
- dbus_message_iter_init(message, &iter);
-
- if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- char *value = NULL;
- size_t size = 50;
- int ret;
-
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
- reply = wpas_dbus_new_invalid_opts_error(message,
- NULL);
- goto out;
- }
-
- /* Type conversions, since wpa_supplicant wants strings */
- if (entry.type == DBUS_TYPE_ARRAY &&
- entry.array_type == DBUS_TYPE_BYTE) {
- if (entry.array_len <= 0)
- goto error;
-
- size = entry.array_len * 2 + 1;
- value = os_zalloc(size);
- if (value == NULL)
- goto error;
- ret = wpa_snprintf_hex(value, size,
- (u8 *) entry.bytearray_value,
- entry.array_len);
- if (ret <= 0)
- goto error;
- } else if (entry.type == DBUS_TYPE_STRING) {
- if (should_quote_opt(entry.key)) {
- size = os_strlen(entry.str_value);
- /* Zero-length option check */
- if (size == 0)
- goto error;
- size += 3; /* For quotes and terminator */
- value = os_zalloc(size);
- if (value == NULL)
- goto error;
- ret = os_snprintf(value, size, "\"%s\"",
- entry.str_value);
- if (os_snprintf_error(size, ret))
- goto error;
- } else {
- value = os_strdup(entry.str_value);
- if (value == NULL)
- goto error;
- }
- } else if (entry.type == DBUS_TYPE_UINT32) {
- value = os_zalloc(size);
- if (value == NULL)
- goto error;
- ret = os_snprintf(value, size, "%u",
- entry.uint32_value);
- if (os_snprintf_error(size, ret))
- goto error;
- } else if (entry.type == DBUS_TYPE_INT32) {
- value = os_zalloc(size);
- if (value == NULL)
- goto error;
- ret = os_snprintf(value, size, "%d",
- entry.int32_value);
- if (os_snprintf_error(size, ret))
- goto error;
- } else
- goto error;
-
- if (wpa_config_set(ssid, entry.key, value, 0) < 0)
- goto error;
-
- if ((os_strcmp(entry.key, "psk") == 0 &&
- value[0] == '"' && ssid->ssid_len) ||
- (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
- wpa_config_update_psk(ssid);
- else if (os_strcmp(entry.key, "priority") == 0)
- wpa_config_update_prio_list(wpa_s->conf);
-
- os_free(value);
- wpa_dbus_dict_entry_clear(&entry);
- continue;
-
- error:
- os_free(value);
- reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
- wpa_dbus_dict_entry_clear(&entry);
- break;
- }
-
- if (!reply)
- reply = wpas_dbus_new_success_reply(message);
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_enable_network - Mark a configured network as enabled
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "enable" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- wpa_supplicant_enable_network(wpa_s, ssid);
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_disable_network - Mark a configured network as disabled
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "disable" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- wpa_supplicant_disable_network(wpa_s, ssid);
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_select_network - Attempt association with a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "selectNetwork" method call of network interface.
- */
-DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- const char *op;
- struct wpa_ssid *ssid;
- char *iface_obj_path = NULL;
- char *network = NULL;
-
- if (os_strlen(dbus_message_get_signature(message)) == 0) {
- /* Any network */
- ssid = NULL;
- } else {
- int nid;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &op,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message,
- NULL);
- goto out;
- }
-
- /* Extract the network number */
- iface_obj_path = wpas_dbus_decompose_object_path(op,
- &network,
- NULL);
- if (iface_obj_path == NULL) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
- /* Ensure the object path really points to this interface */
- if (network == NULL || !wpa_s->dbus_path ||
- os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- nid = strtoul(network, NULL, 10);
- if (errno == EINVAL) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- ssid = wpa_config_get_network(wpa_s->conf, nid);
- if (ssid == NULL) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
- }
-
- /* Finally, associate with the network */
- wpa_supplicant_select_network(wpa_s, ssid);
-
- reply = wpas_dbus_new_success_reply(message);
-
-out:
- os_free(iface_obj_path);
- os_free(network);
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_disconnect - Terminate the current connection
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "disconnect" method call of network interface.
- */
-DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_set_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "setAPScan" method call.
- */
-DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- dbus_uint32_t ap_scan = 1;
-
- if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- reply = wpas_dbus_new_success_reply(message);
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "setSmartcardModules" method call.
- */
-DBusMessage * wpas_dbus_iface_set_smartcard_modules(
- DBusMessage *message, struct wpa_supplicant *wpa_s)
-{
- DBusMessageIter iter, iter_dict;
- char *opensc_engine_path = NULL;
- char *pkcs11_engine_path = NULL;
- char *pkcs11_module_path = NULL;
- struct wpa_dbus_dict_entry entry;
-
- if (!dbus_message_iter_init(message, &iter))
- goto error;
-
- if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
- goto error;
-
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
- if (!strcmp(entry.key, "opensc_engine_path") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(opensc_engine_path);
- opensc_engine_path = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (opensc_engine_path == NULL)
- goto error;
- } else if (!strcmp(entry.key, "pkcs11_engine_path") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(pkcs11_engine_path);
- pkcs11_engine_path = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (pkcs11_engine_path == NULL)
- goto error;
- } else if (!strcmp(entry.key, "pkcs11_module_path") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(pkcs11_module_path);
- pkcs11_module_path = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (pkcs11_module_path == NULL)
- goto error;
- } else {
- wpa_dbus_dict_entry_clear(&entry);
- goto error;
- }
- }
-
- os_free(wpa_s->conf->opensc_engine_path);
- wpa_s->conf->opensc_engine_path = opensc_engine_path;
- os_free(wpa_s->conf->pkcs11_engine_path);
- wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
- os_free(wpa_s->conf->pkcs11_module_path);
- wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
-
- wpa_sm_set_eapol(wpa_s->wpa, NULL);
- eapol_sm_deinit(wpa_s->eapol);
- wpa_s->eapol = NULL;
- wpa_supplicant_init_eapol(wpa_s);
- wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
-
- return wpas_dbus_new_success_reply(message);
-
-error:
- os_free(opensc_engine_path);
- os_free(pkcs11_engine_path);
- os_free(pkcs11_module_path);
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-}
-
-
-/**
- * wpas_dbus_iface_get_state - Get interface state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a STRING representing the current
- * interface state
- *
- * Handler function for "state" method call.
- */
-DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- const char *str_state;
-
- reply = dbus_message_new_method_return(message);
- if (reply != NULL) {
- str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
- DBUS_TYPE_INVALID);
- }
-
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_get_scanning - Get interface scanning state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing whether the interface is scanning
- *
- * Handler function for "scanning" method call.
- */
-DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-
- reply = dbus_message_new_method_return(message);
- if (reply != NULL) {
- dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
- DBUS_TYPE_INVALID);
- } else {
- wpa_printf(MSG_ERROR,
- "dbus: Not enough memory to return scanning state");
- }
-
- return reply;
-}
-
-
-#ifndef CONFIG_NO_CONFIG_BLOBS
-
-/**
- * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Asks wpa_supplicant to internally store a one or more binary blobs.
- */
-DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
- DBusMessageIter iter, iter_dict;
-
- dbus_message_iter_init(message, &iter);
-
- if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- struct wpa_config_blob *blob;
-
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
- reply = wpas_dbus_new_invalid_opts_error(message,
- NULL);
- break;
- }
-
- if (entry.type != DBUS_TYPE_ARRAY ||
- entry.array_type != DBUS_TYPE_BYTE) {
- reply = wpas_dbus_new_invalid_opts_error(
- message, "Byte array expected.");
- break;
- }
-
- if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
- !strlen(entry.key)) {
- reply = wpas_dbus_new_invalid_opts_error(
- message, "Invalid array size.");
- break;
- }
-
- blob = os_zalloc(sizeof(*blob));
- if (blob == NULL) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_ERROR,
- "Not enough memory to add blob.");
- break;
- }
- blob->data = os_zalloc(entry.array_len);
- if (blob->data == NULL) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_ERROR,
- "Not enough memory to add blob data.");
- os_free(blob);
- break;
- }
-
- blob->name = os_strdup(entry.key);
- blob->len = entry.array_len;
- os_memcpy(blob->data, (u8 *) entry.bytearray_value,
- entry.array_len);
- if (blob->name == NULL) {
- wpa_config_free_blob(blob);
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_ERROR,
- "Error adding blob.");
- break;
- }
-
- /* Success */
- if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
- wpas_notify_blob_removed(wpa_s, blob->name);
- wpa_config_set_blob(wpa_s->conf, blob);
- wpas_notify_blob_added(wpa_s, blob->name);
-
- wpa_dbus_dict_entry_clear(&entry);
- }
- wpa_dbus_dict_entry_clear(&entry);
-
- return reply ? reply : wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_remove_blob - Remove named binary blobs
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Asks wpa_supplicant to remove one or more previously stored binary blobs.
- */
-DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessageIter iter, array;
- char *err_msg = NULL;
-
- dbus_message_iter_init(message, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- dbus_message_iter_recurse(&iter, &array);
- while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
- const char *name;
-
- dbus_message_iter_get_basic(&array, &name);
- if (!os_strlen(name))
- err_msg = "Invalid blob name.";
- else if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
- err_msg = "Error removing blob.";
- else
- wpas_notify_blob_removed(wpa_s, name);
- dbus_message_iter_next(&array);
- }
-
- if (err_msg)
- return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
- err_msg);
-
- return wpas_dbus_new_success_reply(message);
-}
-
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-
-
-/**
- * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0), or returns a dbus error message with more information
- *
- * Handler function for "flush" method call. Handles requests for an
- * interface with an optional "age" parameter that specifies the minimum
- * age of a BSS to be flushed.
- */
-DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- int flush_age = 0;
-
- if (os_strlen(dbus_message_get_signature(message)) != 0 &&
- !dbus_message_get_args(message, NULL,
- DBUS_TYPE_INT32, &flush_age,
- DBUS_TYPE_INVALID)) {
- return wpas_dbus_new_invalid_opts_error(message, NULL);
- }
-
- if (flush_age == 0)
- wpa_bss_flush(wpa_s);
- else
- wpa_bss_flush_by_age(wpa_s, flush_age);
-
- return wpas_dbus_new_success_reply(message);
-}
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h
deleted file mode 100644
index e60ad06..0000000
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef CTRL_IFACE_DBUS_HANDLERS_H
-#define CTRL_IFACE_DBUS_HANDLERS_H
-
-struct wpa_bss;
-
-DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message);
-DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message);
-
-DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
- struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
- struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
- struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
- struct wpa_global *global);
-
-DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss);
-
-DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_smartcard_modules(
- DBusMessage *message, struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message);
-DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
- const char *arg);
-
-#endif /* CTRL_IFACE_DBUS_HANDLERS_H */
-
diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c
deleted file mode 100644
index 5309a53..0000000
--- a/contrib/wpa/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface (WPS)
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../wps_supplicant.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-
-/**
- * wpas_dbus_iface_wps_pbc - Request credentials using WPS PBC method
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "wpsPbc" method call
- */
-DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- char *arg_bssid = NULL;
- u8 bssid[ETH_ALEN];
- int ret = 0;
-
- if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
- DBUS_TYPE_INVALID))
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- if (os_strcmp(arg_bssid, "any") == 0)
- ret = wpas_wps_start_pbc(wpa_s, NULL, 0);
- else if (!hwaddr_aton(arg_bssid, bssid))
- ret = wpas_wps_start_pbc(wpa_s, bssid, 0);
- else {
- return wpas_dbus_new_invalid_opts_error(message,
- "Invalid BSSID");
- }
-
- if (ret < 0) {
- return dbus_message_new_error(
- message, WPAS_ERROR_WPS_PBC_ERROR,
- "Could not start PBC negotiation");
- }
-
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_wps_pin - Establish the PIN number of the enrollee
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "wpsPin" method call
- */
-DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- char *arg_bssid;
- char *pin = NULL;
- u8 bssid[ETH_ALEN], *_bssid = NULL;
- int ret = 0;
- char npin[9];
-
- if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
- DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- if (os_strcmp(arg_bssid, "any") == 0)
- _bssid = NULL;
- else if (!hwaddr_aton(arg_bssid, bssid))
- _bssid = bssid;
- else {
- return wpas_dbus_new_invalid_opts_error(message,
- "Invalid BSSID");
- }
-
- if (os_strlen(pin) > 0)
- ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
- DEV_PW_DEFAULT);
- else
- ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0,
- DEV_PW_DEFAULT);
-
- if (ret < 0) {
- return dbus_message_new_error(message,
- WPAS_ERROR_WPS_PIN_ERROR,
- "Could not init PIN");
- }
-
- reply = dbus_message_new_method_return(message);
- if (reply == NULL)
- return NULL;
-
- if (ret > 0) {
- os_snprintf(npin, sizeof(npin), "%08d", ret);
- pin = npin;
- }
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
- DBUS_TYPE_INVALID);
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_wps_reg - Request credentials using the PIN of the AP
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "wpsReg" method call
- */
-DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- char *arg_bssid;
- char *pin = NULL;
- u8 bssid[ETH_ALEN];
- int ret = 0;
-
- if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
- DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- if (!hwaddr_aton(arg_bssid, bssid))
- ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
- else {
- return wpas_dbus_new_invalid_opts_error(message,
- "Invalid BSSID");
- }
-
- if (ret < 0) {
- return dbus_message_new_error(message,
- WPAS_ERROR_WPS_REG_ERROR,
- "Could not request credentials");
- }
-
- return wpas_dbus_new_success_reply(message);
-}
diff --git a/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in b/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in
deleted file mode 100644
index a75918f..0000000
--- a/contrib/wpa/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in
+++ /dev/null
@@ -1,5 +0,0 @@
-[D-BUS Service]
-Name=fi.epitest.hostap.WPASupplicant
-Exec=@BINDIR@/wpa_supplicant -u
-User=root
-SystemdService=wpa_supplicant.service
diff --git a/contrib/wpa/wpa_supplicant/defconfig b/contrib/wpa/wpa_supplicant/defconfig
index 01a8c2c..88cd790 100644
--- a/contrib/wpa/wpa_supplicant/defconfig
+++ b/contrib/wpa/wpa_supplicant/defconfig
@@ -1,9 +1,9 @@
# Example wpa_supplicant 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.
+# wpa_supplicant 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 cases, these lines should use += in order not
@@ -31,6 +31,9 @@ CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
+# QCA vendor extensions to nl80211
+#CONFIG_DRIVER_NL80211_QCA=y
+
# driver_nl80211.c requires libnl. If you are compiling it yourself
# you may need to point hostapd to your version of libnl.
#
@@ -41,7 +44,7 @@ CONFIG_DRIVER_NL80211=y
#CONFIG_LIBNL20=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
-#CONFIG_LIBNL32=y
+CONFIG_LIBNL32=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
@@ -70,6 +73,12 @@ CONFIG_DRIVER_NL80211=y
# Driver interface for wired Ethernet drivers
CONFIG_DRIVER_WIRED=y
+# Driver interface for MACsec capable Qualcomm Atheros drivers
+#CONFIG_DRIVER_MACSEC_QCA=y
+
+# Driver interface for Linux MACsec drivers
+#CONFIG_DRIVER_MACSEC_LINUX=y
+
# Driver interface for the Broadcom RoboSwitch family
#CONFIG_DRIVER_ROBOSWITCH=y
@@ -80,8 +89,8 @@ CONFIG_DRIVER_WIRED=y
#LIBS += -lsocket -ldlpi -lnsl
#LIBS_c += -lsocket
-# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
-# included)
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method or
+# MACsec is included)
CONFIG_IEEE8021X_EAPOL=y
# EAP-MD5
@@ -100,10 +109,7 @@ CONFIG_EAP_PEAP=y
CONFIG_EAP_TTLS=y
# EAP-FAST
-# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
-# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
-# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
-#CONFIG_EAP_FAST=y
+CONFIG_EAP_FAST=y
# EAP-GTC
CONFIG_EAP_GTC=y
@@ -118,10 +124,10 @@ CONFIG_EAP_OTP=y
#CONFIG_EAP_PSK=y
# EAP-pwd (secure authentication using only a password)
-#CONFIG_EAP_PWD=y
+CONFIG_EAP_PWD=y
# EAP-PAX
-#CONFIG_EAP_PAX=y
+CONFIG_EAP_PAX=y
# LEAP
CONFIG_EAP_LEAP=y
@@ -137,18 +143,18 @@ CONFIG_EAP_LEAP=y
#CONFIG_USIM_SIMULATOR=y
# EAP-SAKE
-#CONFIG_EAP_SAKE=y
+CONFIG_EAP_SAKE=y
# EAP-GPSK
-#CONFIG_EAP_GPSK=y
+CONFIG_EAP_GPSK=y
# Include support for optional SHA256 cipher suite in EAP-GPSK
-#CONFIG_EAP_GPSK_SHA256=y
+CONFIG_EAP_GPSK_SHA256=y
# EAP-TNC and related Trusted Network Connect support (experimental)
-#CONFIG_EAP_TNC=y
+CONFIG_EAP_TNC=y
# Wi-Fi Protected Setup (WPS)
-#CONFIG_WPS=y
+CONFIG_WPS=y
# Enable WPS external registrar functionality
#CONFIG_WPS_ER=y
# Disable credentials for an open network by default when acting as a WPS
@@ -158,11 +164,14 @@ CONFIG_EAP_LEAP=y
#CONFIG_WPS_NFC=y
# EAP-IKEv2
-#CONFIG_EAP_IKEV2=y
+CONFIG_EAP_IKEV2=y
# EAP-EKE
#CONFIG_EAP_EKE=y
+# MACsec
+#CONFIG_MACSEC=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
@@ -223,6 +232,9 @@ CONFIG_CTRL_IFACE=y
# wpa_passphrase). This saves about 0.5 kB in code size.
#CONFIG_NO_WPA_PASSPHRASE=y
+# Simultaneous Authentication of Equals (SAE), WPA3-Personal
+CONFIG_SAE=y
+
# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
# This can be used if ap_scan=1 mode is never enabled.
#CONFIG_NO_SCAN_PROCESSING=y
@@ -267,6 +279,9 @@ CONFIG_BACKEND=file
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
+# Should we use kqueue instead of select? Select is used by default.
+#CONFIG_ELOOP_KQUEUE=y
+
# Select layer 2 packet implementation
# linux = Linux packet socket (default)
# pcap = libpcap/libdnet/WinPcap
@@ -276,17 +291,24 @@ CONFIG_BACKEND=file
# none = Empty template
#CONFIG_L2_PACKET=linux
-# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
-CONFIG_PEERKEY=y
+# Disable Linux packet socket workaround applicable for station interface
+# in a bridge for EAPOL frames. This should be uncommented only if the kernel
+# is known to not have the regression issue in packet socket behavior with
+# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
+#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
# IEEE 802.11w (management frame protection), also known as PMF
# Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
+CONFIG_IEEE80211W=y
+
+# Support Operating Channel Validation
+#CONFIG_OCV=y
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
# internal = Internal TLSv1 implementation (experimental)
+# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental)
# none = Empty template
#CONFIG_TLS=openssl
@@ -304,6 +326,10 @@ CONFIG_PEERKEY=y
# will be used)
#CONFIG_TLSV12=y
+# Select which ciphers to use by default with OpenSSL if the user does not
+# specify them.
+#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW"
+
# If CONFIG_TLS=internal is used, additional library and include paths are
# needed for LibTomMath. Alternatively, an integrated, minimal version of
# LibTomMath can be used. See beginning of libtommath.c for details on benefits
@@ -326,16 +352,12 @@ CONFIG_PEERKEY=y
#CONFIG_NDIS_EVENTS_INTEGRATED=y
#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
-# Add support for old DBus control interface
-# (fi.epitest.hostap.WPASupplicant)
-#CONFIG_CTRL_IFACE_DBUS=y
-
# Add support for new DBus control interface
# (fi.w1.hostap.wpa_supplicant1)
-#CONFIG_CTRL_IFACE_DBUS_NEW=y
+CONFIG_CTRL_IFACE_DBUS_NEW=y
# Add introspection support for new DBus control interface
-#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+CONFIG_CTRL_IFACE_DBUS_INTRO=y
# Add support for loading EAP methods dynamically as shared libraries.
# When this option is enabled, each EAP method can be either included
@@ -358,14 +380,14 @@ CONFIG_PEERKEY=y
# amount of memory/flash.
#CONFIG_DYNAMIC_EAP_METHODS=y
-# IEEE Std 802.11r-2008 (Fast BSS Transition)
-#CONFIG_IEEE80211R=y
+# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode
+CONFIG_IEEE80211R=y
# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
-#CONFIG_DEBUG_FILE=y
+CONFIG_DEBUG_FILE=y
# Send debug messages to syslog instead of stdout
-#CONFIG_DEBUG_SYSLOG=y
+CONFIG_DEBUG_SYSLOG=y
# Set syslog facility for debug messages
#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
@@ -435,12 +457,17 @@ CONFIG_PEERKEY=y
# that meet the requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-#CONFIG_IEEE80211N=y
+CONFIG_IEEE80211N=y
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
# (depends on CONFIG_IEEE80211N)
-#CONFIG_IEEE80211AC=y
+CONFIG_IEEE80211AC=y
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
@@ -450,10 +477,13 @@ CONFIG_PEERKEY=y
# This can be used to enable functionality to improve interworking with
# external networks (GAS/ANQP to learn more about the networks and network
# selection based on available credentials).
-#CONFIG_INTERWORKING=y
+CONFIG_INTERWORKING=y
# Hotspot 2.0
-#CONFIG_HS20=y
+CONFIG_HS20=y
+
+# Enable interface matching in wpa_supplicant
+#CONFIG_MATCH_IFACE=y
# Disable roaming in wpa_supplicant
#CONFIG_NO_ROAMING=y
@@ -463,20 +493,20 @@ CONFIG_PEERKEY=y
# should be noted that this is mainly aimed at simple cases like
# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
# external RADIUS server can be supported with hostapd.
-#CONFIG_AP=y
+CONFIG_AP=y
# P2P (Wi-Fi Direct)
# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
# more information on P2P operations.
-#CONFIG_P2P=y
+CONFIG_P2P=y
# Enable TDLS support
#CONFIG_TDLS=y
-# Wi-Fi Direct
-# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# Wi-Fi Display
+# This can be used to enable Wi-Fi Display extensions for P2P using an external
# program to control the additional information exchanges in the messages.
-#CONFIG_WIFI_DISPLAY=y
+CONFIG_WIFI_DISPLAY=y
# Autoscan
# This can be used to enable automatic scan support in wpa_supplicant.
@@ -504,3 +534,69 @@ CONFIG_PEERKEY=y
# OS X builds. This is only for building eapol_test.
#CONFIG_OSX=y
+
+# Automatic Channel Selection
+# This will allow wpa_supplicant to pick the channel automatically when channel
+# is set to "0".
+#
+# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative
+# to "channel=0". This would enable us to eventually add other ACS algorithms in
+# similar way.
+#
+# Automatic selection is currently only done through initialization, later on
+# we hope to do background checks to keep us moving to more ideal channels as
+# time goes by. ACS is currently only supported through the nl80211 driver and
+# your driver must have survey dump capability that is filled by the driver
+# during scanning.
+#
+# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with
+# a newly to create wpa_supplicant.conf variable acs_num_scans.
+#
+# Supported ACS drivers:
+# * ath9k
+# * ath5k
+# * ath10k
+#
+# For more details refer to:
+# http://wireless.kernel.org/en/users/Documentation/acs
+#CONFIG_ACS=y
+
+# Support Multi Band Operation
+#CONFIG_MBO=y
+
+# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
+#CONFIG_FILS=y
+# FILS shared key authentication with PFS
+#CONFIG_FILS_SK_PFS=y
+
+# Support RSN on IBSS networks
+# This is needed to be able to use mode=1 network profile with proto=RSN and
+# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None).
+CONFIG_IBSS_RSN=y
+
+# External PMKSA cache control
+# This can be used to enable control interface commands that allow the current
+# PMKSA cache entries to be fetched and new entries to be added.
+#CONFIG_PMKSA_CACHE_EXTERNAL=y
+
+# Mesh Networking (IEEE 802.11s)
+#CONFIG_MESH=y
+
+# Background scanning modules
+# These can be used to request wpa_supplicant to perform background scanning
+# operations for roaming within an ESS (same SSID). See the bgscan parameter in
+# the wpa_supplicant.conf file for more details.
+# Periodic background scans based on signal strength
+CONFIG_BGSCAN_SIMPLE=y
+# Learn channels used by the network and try to avoid bgscans on other
+# channels (experimental)
+#CONFIG_BGSCAN_LEARN=y
+
+# Opportunistic Wireless Encryption (OWE)
+# Experimental implementation of draft-harkins-owe-07.txt
+#CONFIG_OWE=y
+
+# Device Provisioning Protocol (DPP)
+# This requires CONFIG_IEEE80211W=y to be enabled, too. (see
+# wpa_supplicant/README-DPP for details)
+CONFIG_DPP=y
diff --git a/contrib/wpa/wpa_supplicant/dpp_supplicant.c b/contrib/wpa/wpa_supplicant/dpp_supplicant.c
new file mode 100644
index 0000000..e003a85
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/dpp_supplicant.c
@@ -0,0 +1,2246 @@
+/*
+ * wpa_supplicant - DPP
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/dpp.h"
+#include "common/gas.h"
+#include "common/gas_server.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "driver_i.h"
+#include "offchannel.h"
+#include "gas_query.h"
+#include "bss.h"
+#include "scan.h"
+#include "notify.h"
+#include "dpp_supplicant.h"
+
+
+static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
+ unsigned int freq);
+static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator);
+static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result);
+static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s);
+static void
+wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result);
+
+static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+/* Use a hardcoded Transaction ID 1 in Peer Discovery frames since there is only
+ * a single transaction in progress at any point in time. */
+static const u8 TRANSACTION_ID = 1;
+
+
+/**
+ * wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @cmd: DPP URI read from a QR Code
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct dpp_bootstrap_info *bi;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ bi = dpp_add_qr_code(wpa_s->dpp, cmd);
+ if (!bi)
+ return -1;
+
+ if (auth && auth->response_pending &&
+ dpp_notify_new_qr_code(auth, bi) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Sending out pending authentication response");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ auth->peer_mac_addr, wpa_s->own_addr,
+ broadcast,
+ wpabuf_head(auth->resp_msg),
+ wpabuf_len(auth->resp_msg),
+ 500, wpas_dpp_tx_status, 0);
+ }
+
+ return bi->id;
+}
+
+
+static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->resp_msg)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Retry Authentication Response after timeout");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->resp_msg),
+ wpabuf_len(auth->resp_msg),
+ 500, wpas_dpp_tx_status, 0);
+}
+
+
+static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ unsigned int wait_time, max_tries;
+
+ if (!auth || !auth->resp_msg)
+ return;
+
+ if (wpa_s->dpp_resp_max_tries)
+ max_tries = wpa_s->dpp_resp_max_tries;
+ else
+ max_tries = 5;
+ auth->auth_resp_tries++;
+ if (auth->auth_resp_tries >= max_tries) {
+ wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
+ offchannel_send_action_done(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ if (wpa_s->dpp_resp_retry_time)
+ wait_time = wpa_s->dpp_resp_retry_time;
+ else
+ wait_time = 1000;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Schedule retransmission of Authentication Response frame in %u ms",
+ wait_time);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+ eloop_register_timeout(wait_time / 1000,
+ (wait_time % 1000) * 1000,
+ wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+}
+
+
+static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_s->scan_runs = 0;
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ const char *res_txt;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED");
+ wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
+ " result=%s", freq, MAC2STR(dst), res_txt);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
+
+ if (!wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore TX status since there is no ongoing authentication exchange");
+ return;
+ }
+
+#ifdef CONFIG_DPP2
+ if (auth->connect_on_tx_status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Try to connect after completed configuration result");
+ wpas_dpp_try_to_connect(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
+ if (wpa_s->dpp_auth->remove_on_tx_status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate authentication exchange due to an earlier error");
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
+ NULL);
+ offchannel_send_action_done(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ if (wpa_s->dpp_auth_ok_on_ack)
+ wpas_dpp_auth_success(wpa_s, 1);
+
+ if (!is_broadcast_ether_addr(dst) &&
+ result != OFFCHANNEL_SEND_ACTION_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unicast DPP Action frame was not ACKed");
+ if (auth->waiting_auth_resp) {
+ /* In case of DPP Authentication Request frame, move to
+ * the next channel immediately. */
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_auth_init_next(wpa_s);
+ return;
+ }
+ if (auth->waiting_auth_conf) {
+ wpas_dpp_auth_resp_retry(wpa_s);
+ return;
+ }
+ }
+
+ if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+ /* Allow timeout handling to stop iteration if no response is
+ * received from a peer that has ACKed a request. */
+ auth->auth_req_ack = 1;
+ }
+
+ if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
+ wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
+ wpa_s->dpp_auth->curr_freq,
+ wpa_s->dpp_auth->neg_freq);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq);
+ }
+
+ if (wpa_s->dpp_auth_ok_on_ack)
+ wpa_s->dpp_auth_ok_on_ack = 0;
+}
+
+
+static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ unsigned int freq;
+ struct os_reltime now, diff;
+ unsigned int wait_time, diff_ms;
+
+ if (!auth || !auth->waiting_auth_resp)
+ return;
+
+ wait_time = wpa_s->dpp_resp_wait_time ?
+ wpa_s->dpp_resp_wait_time : 2000;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff);
+ diff_ms = diff.sec * 1000 + diff.usec / 1000;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
+ wait_time, diff_ms);
+
+ if (auth->auth_req_ack && diff_ms >= wait_time) {
+ /* Peer ACK'ed Authentication Request frame, but did not reply
+ * with Authentication Response frame within two seconds. */
+ wpa_printf(MSG_INFO,
+ "DPP: No response received from responder - stopping initiation attempt");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ if (diff_ms >= wait_time) {
+ /* Authentication Request frame was not ACK'ed and no reply
+ * was receiving within two seconds. */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue Initiator channel iteration");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ wpas_dpp_auth_init_next(wpa_s);
+ return;
+ }
+
+ /* Driver did not support 2000 ms long wait_time with TX command, so
+ * schedule listen operation to continue waiting for the response.
+ *
+ * DPP listen operations continue until stopped, so simply schedule a
+ * new call to this function at the point when the two second reply
+ * wait has expired. */
+ wait_time -= diff_ms;
+
+ freq = auth->curr_freq;
+ if (auth->neg_freq > 0)
+ freq = auth->neg_freq;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue reply wait on channel %u MHz for %u ms",
+ freq, wait_time);
+ wpa_s->dpp_in_response_listen = 1;
+ wpas_dpp_listen_start(wpa_s, freq);
+
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+}
+
+
+static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->dpp_config_obj_override)
+ auth->config_obj_override =
+ os_strdup(wpa_s->dpp_config_obj_override);
+ if (wpa_s->dpp_discovery_override)
+ auth->discovery_override =
+ os_strdup(wpa_s->dpp_discovery_override);
+ if (wpa_s->dpp_groups_override)
+ auth->groups_override =
+ os_strdup(wpa_s->dpp_groups_override);
+ auth->ignore_netaccesskey_mismatch =
+ wpa_s->dpp_ignore_netaccesskey_mismatch;
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
+static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (!wpa_s->dpp_auth)
+ return;
+ wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
+ wpas_dpp_auth_init_next(wpa_s);
+}
+
+
+static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ const u8 *dst;
+ unsigned int wait_time, max_wait_time, freq, max_tries, used;
+ struct os_reltime now, diff;
+
+ wpa_s->dpp_in_response_listen = 0;
+ if (!auth)
+ return -1;
+
+ if (auth->freq_idx == 0)
+ os_get_reltime(&wpa_s->dpp_init_iter_start);
+
+ if (auth->freq_idx >= auth->num_freq) {
+ auth->num_freq_iters++;
+ if (wpa_s->dpp_init_max_tries)
+ max_tries = wpa_s->dpp_init_max_tries;
+ else
+ max_tries = 5;
+ if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
+ wpa_printf(MSG_INFO,
+ "DPP: No response received from responder - stopping initiation attempt");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return -1;
+ }
+ auth->freq_idx = 0;
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
+ if (wpa_s->dpp_init_retry_time)
+ wait_time = wpa_s->dpp_init_retry_time;
+ else
+ wait_time = 10000;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff);
+ used = diff.sec * 1000 + diff.usec / 1000;
+ if (used > wait_time)
+ wait_time = 0;
+ else
+ wait_time -= used;
+ wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
+ wait_time);
+ eloop_register_timeout(wait_time / 1000,
+ (wait_time % 1000) * 1000,
+ wpas_dpp_init_timeout, wpa_s,
+ NULL);
+ return 0;
+ }
+ freq = auth->freq[auth->freq_idx++];
+ auth->curr_freq = freq;
+
+ if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ dst = broadcast;
+ else
+ dst = auth->peer_bi->mac_addr;
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ wait_time = wpa_s->max_remain_on_chan;
+ max_wait_time = wpa_s->dpp_resp_wait_time ?
+ wpa_s->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wait_time += 10; /* give the driver some extra time to complete */
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ wpas_dpp_reply_wait_timeout,
+ wpa_s, NULL);
+ wait_time -= 10;
+ if (auth->neg_freq > 0 && freq != auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
+ freq, auth->neg_freq);
+ }
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
+ auth->auth_req_ack = 0;
+ os_get_reltime(&wpa_s->dpp_last_init);
+ return offchannel_send_action(wpa_s, freq, dst,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->req_msg),
+ wpabuf_len(auth->req_msg),
+ wait_time, wpas_dpp_tx_status, 0);
+}
+
+
+int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
+ u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ unsigned int neg_freq = 0;
+
+ wpa_s->dpp_gas_client = 0;
+
+ pos = os_strstr(cmd, " peer=");
+ if (!pos)
+ return -1;
+ pos += 6;
+ peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Could not find bootstrapping info for the identified peer");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " own=");
+ if (pos) {
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Could not find bootstrapping info for the identified local entry");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
+ peer_bi->curve->name, own_bi->curve->name);
+ return -1;
+ }
+ }
+
+ pos = os_strstr(cmd, " role=");
+ if (pos) {
+ pos += 6;
+ if (os_strncmp(pos, "configurator", 12) == 0)
+ allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strncmp(pos, "enrollee", 8) == 0)
+ allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ else
+ goto fail;
+ }
+
+ pos = os_strstr(cmd, " netrole=");
+ if (pos) {
+ pos += 9;
+ wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
+ }
+
+ pos = os_strstr(cmd, " neg_freq=");
+ if (pos)
+ neg_freq = atoi(pos + 10);
+
+ if (wpa_s->dpp_auth) {
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
+ NULL);
+ offchannel_send_action_done(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ }
+ wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles,
+ neg_freq,
+ wpa_s->hw.modes, wpa_s->hw.num_modes);
+ if (!wpa_s->dpp_auth)
+ goto fail;
+ wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
+ if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth, cmd) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ goto fail;
+ }
+
+ wpa_s->dpp_auth->neg_freq = neg_freq;
+
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
+ os_memcpy(wpa_s->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
+ ETH_ALEN);
+
+ return wpas_dpp_auth_init_next(wpa_s);
+fail:
+ return -1;
+}
+
+
+struct wpas_dpp_listen_work {
+ unsigned int freq;
+ unsigned int duration;
+ struct wpabuf *probe_resp_ie;
+};
+
+
+static void wpas_dpp_listen_work_free(struct wpas_dpp_listen_work *lwork)
+{
+ if (!lwork)
+ return;
+ os_free(lwork);
+}
+
+
+static void wpas_dpp_listen_work_done(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_dpp_listen_work *lwork;
+
+ if (!wpa_s->dpp_listen_work)
+ return;
+
+ lwork = wpa_s->dpp_listen_work->ctx;
+ wpas_dpp_listen_work_free(lwork);
+ radio_work_done(wpa_s->dpp_listen_work);
+ wpa_s->dpp_listen_work = NULL;
+}
+
+
+static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpas_dpp_listen_work *lwork = work->ctx;
+
+ if (deinit) {
+ if (work->started) {
+ wpa_s->dpp_listen_work = NULL;
+ wpas_dpp_listen_stop(wpa_s);
+ }
+ wpas_dpp_listen_work_free(lwork);
+ return;
+ }
+
+ wpa_s->dpp_listen_work = work;
+
+ wpa_s->dpp_pending_listen_freq = lwork->freq;
+
+ if (wpa_drv_remain_on_channel(wpa_s, lwork->freq,
+ wpa_s->max_remain_on_chan) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
+ lwork->freq);
+ wpa_s->dpp_listen_freq = 0;
+ wpas_dpp_listen_work_done(wpa_s);
+ wpa_s->dpp_pending_listen_freq = 0;
+ return;
+ }
+ wpa_s->off_channel_freq = 0;
+ wpa_s->roc_waiting_drv_freq = lwork->freq;
+}
+
+
+static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
+ unsigned int freq)
+{
+ struct wpas_dpp_listen_work *lwork;
+
+ if (wpa_s->dpp_listen_work) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Reject start_listen since dpp_listen_work already exists");
+ return -1;
+ }
+
+ if (wpa_s->dpp_listen_freq)
+ wpas_dpp_listen_stop(wpa_s);
+ wpa_s->dpp_listen_freq = freq;
+
+ lwork = os_zalloc(sizeof(*lwork));
+ if (!lwork)
+ return -1;
+ lwork->freq = freq;
+
+ if (radio_add_work(wpa_s, freq, "dpp-listen", 0, dpp_start_listen_cb,
+ lwork) < 0) {
+ wpas_dpp_listen_work_free(lwork);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int freq;
+
+ freq = atoi(cmd);
+ if (freq <= 0)
+ return -1;
+
+ if (os_strstr(cmd, " role=configurator"))
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strstr(cmd, " role=enrollee"))
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ else
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
+ wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL;
+ if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
+ wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
+ freq);
+ return 0;
+ }
+
+ return wpas_dpp_listen_start(wpa_s, freq);
+}
+
+
+void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->dpp_in_response_listen = 0;
+ if (!wpa_s->dpp_listen_freq)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz",
+ wpa_s->dpp_listen_freq);
+ wpa_drv_cancel_remain_on_channel(wpa_s);
+ wpa_s->dpp_listen_freq = 0;
+ wpas_dpp_listen_work_done(wpa_s);
+}
+
+
+void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq)
+{
+ wpas_dpp_listen_work_done(wpa_s);
+
+ if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
+ unsigned int new_freq;
+
+ /* Continue listen with a new remain-on-channel */
+ if (wpa_s->dpp_auth->neg_freq > 0)
+ new_freq = wpa_s->dpp_auth->neg_freq;
+ else
+ new_freq = wpa_s->dpp_auth->curr_freq;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue wait on %u MHz for the ongoing DPP provisioning session",
+ new_freq);
+ wpas_dpp_listen_start(wpa_s, new_freq);
+ return;
+ }
+
+ if (wpa_s->dpp_listen_freq) {
+ /* Continue listen with a new remain-on-channel */
+ wpas_dpp_listen_start(wpa_s, wpa_s->dpp_listen_freq);
+ }
+}
+
+
+static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap, *i_bootstrap;
+ u16 r_bootstrap_len, i_bootstrap_len;
+ struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
+
+ if (!wpa_s->dpp)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+
+ i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
+ i_bootstrap, i_bootstrap_len);
+
+ /* Try to find own and peer bootstrapping key matches based on the
+ * received hash values */
+ dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap,
+ &own_bi, &peer_bi);
+ if (!own_bi) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "No matching own bootstrapping key found - ignore message");
+ return;
+ }
+
+ if (wpa_s->dpp_auth) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Already in DPP authentication exchange - ignore new one");
+ return;
+ }
+
+ wpa_s->dpp_gas_client = 0;
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles,
+ wpa_s->dpp_qr_mutual,
+ peer_bi, own_bi, freq, hdr, buf, len);
+ if (!wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG, "DPP: No response generated");
+ return;
+ }
+ wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
+ if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth,
+ wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+ os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
+
+ if (wpa_s->dpp_listen_freq &&
+ wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Stop listen on %u MHz to allow response on the request %u MHz",
+ wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
+ wpas_dpp_listen_stop(wpa_s);
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), wpa_s->dpp_auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
+ src, wpa_s->own_addr, broadcast,
+ wpabuf_head(wpa_s->dpp_auth->resp_msg),
+ wpabuf_len(wpa_s->dpp_auth->resp_msg),
+ 500, wpas_dpp_tx_status, 0);
+}
+
+
+static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
+{
+ /* TODO: stop wait and start ROC */
+}
+
+
+static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
+ struct wpa_ssid *ssid;
+
+#ifdef CONFIG_DPP2
+ if (auth->akm == DPP_AKM_SAE) {
+#ifdef CONFIG_SAE
+ struct wpa_driver_capa capa;
+ int res;
+
+ res = wpa_drv_get_capa(wpa_s, &capa);
+ if (res == 0 &&
+ !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: SAE not supported by the driver");
+ return NULL;
+ }
+#else /* CONFIG_SAE */
+ wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build");
+ return NULL;
+#endif /* CONFIG_SAE */
+ }
+#endif /* CONFIG_DPP2 */
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (!ssid)
+ return NULL;
+ wpas_notify_network_added(wpa_s, ssid);
+ wpa_config_set_network_defaults(ssid);
+ ssid->disabled = 1;
+
+ ssid->ssid = os_malloc(auth->ssid_len);
+ if (!ssid->ssid)
+ goto fail;
+ os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
+ ssid->ssid_len = auth->ssid_len;
+
+ if (auth->connector) {
+ ssid->key_mgmt = WPA_KEY_MGMT_DPP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ ssid->dpp_connector = os_strdup(auth->connector);
+ if (!ssid->dpp_connector)
+ goto fail;
+ }
+
+ if (auth->c_sign_key) {
+ ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
+ if (!ssid->dpp_csign)
+ goto fail;
+ os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
+ wpabuf_len(auth->c_sign_key));
+ ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
+ }
+
+ if (auth->net_access_key) {
+ ssid->dpp_netaccesskey =
+ os_malloc(wpabuf_len(auth->net_access_key));
+ if (!ssid->dpp_netaccesskey)
+ goto fail;
+ os_memcpy(ssid->dpp_netaccesskey,
+ wpabuf_head(auth->net_access_key),
+ wpabuf_len(auth->net_access_key));
+ ssid->dpp_netaccesskey_len = wpabuf_len(auth->net_access_key);
+ ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
+ }
+
+ if (!auth->connector || dpp_akm_psk(auth->akm) ||
+ dpp_akm_sae(auth->akm)) {
+ if (!auth->connector)
+ ssid->key_mgmt = 0;
+ if (dpp_akm_psk(auth->akm))
+ ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
+ if (dpp_akm_sae(auth->akm))
+ ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_FT_SAE;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+ if (auth->passphrase[0]) {
+ if (wpa_config_set_quoted(ssid, "psk",
+ auth->passphrase) < 0)
+ goto fail;
+ wpa_config_update_psk(ssid);
+ ssid->export_keys = 1;
+ } else {
+ ssid->psk_set = auth->psk_set;
+ os_memcpy(ssid->psk, auth->psk, PMK_LEN);
+ }
+ }
+
+ return ssid;
+fail:
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return NULL;
+}
+
+
+static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
+ struct wpa_ssid *ssid;
+
+ if (wpa_s->conf->dpp_config_processing < 1)
+ return 0;
+
+ ssid = wpas_dpp_add_network(wpa_s, auth);
+ if (!ssid)
+ return -1;
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
+ if (wpa_s->conf->dpp_config_processing == 2)
+ ssid->disabled = 0;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+ if (wpa_s->conf->dpp_config_processing < 2)
+ return 0;
+
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
+ auth->connect_on_tx_status = 1;
+ return 0;
+ }
+#endif /* CONFIG_DPP2 */
+
+ wpas_dpp_try_to_connect(wpa_s);
+ return 0;
+}
+
+
+static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+ if (auth->ssid_len)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
+ wpa_ssid_txt(auth->ssid, auth->ssid_len));
+ if (auth->connector) {
+ /* TODO: Save the Connector and consider using a command
+ * to fetch the value instead of sending an event with
+ * it. The Connector could end up being larger than what
+ * most clients are ready to receive as an event
+ * message. */
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
+ auth->connector);
+ }
+ if (auth->c_sign_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hex = os_malloc(hexlen);
+ if (hex) {
+ wpa_snprintf_hex(hex, hexlen,
+ wpabuf_head(auth->c_sign_key),
+ wpabuf_len(auth->c_sign_key));
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
+ hex);
+ os_free(hex);
+ }
+ }
+ if (auth->net_access_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
+ hex = os_malloc(hexlen);
+ if (hex) {
+ wpa_snprintf_hex(hex, hexlen,
+ wpabuf_head(auth->net_access_key),
+ wpabuf_len(auth->net_access_key));
+ if (auth->net_access_key_expiry)
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
+ (long unsigned)
+ auth->net_access_key_expiry);
+ else
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_NET_ACCESS_KEY "%s", hex);
+ os_free(hex);
+ }
+ }
+
+ return wpas_dpp_process_config(wpa_s, auth);
+}
+
+
+static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
+ enum gas_query_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const u8 *pos;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ int res;
+ enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+
+ wpa_s->dpp_gas_dialog_token = -1;
+
+ if (!auth || !auth->auth_success) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return;
+ }
+ if (result != GAS_QUERY_SUCCESS ||
+ !resp || status_code != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
+ goto fail;
+ }
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
+ adv_proto);
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
+ resp);
+
+ if (wpabuf_len(adv_proto) != 10 ||
+ !(pos = wpabuf_head(adv_proto)) ||
+ pos[0] != WLAN_EID_ADV_PROTO ||
+ pos[1] != 8 ||
+ pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[4] != 5 ||
+ WPA_GET_BE24(&pos[5]) != OUI_WFA ||
+ pos[8] != 0x1a ||
+ pos[9] != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not a DPP Advertisement Protocol ID");
+ goto fail;
+ }
+
+ if (dpp_conf_resp_rx(auth, resp) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
+ goto fail;
+ }
+
+ res = wpas_dpp_handle_config_obj(wpa_s, auth);
+ if (res < 0)
+ goto fail;
+
+ status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_REJECT_CONFIG) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
+ status = DPP_STATUS_CONFIG_REJECTED;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+fail:
+ if (status != DPP_STATUS_OK)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
+ msg = dpp_build_conf_result(auth, status);
+ if (!msg)
+ goto fail2;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(addr), auth->curr_freq,
+ DPP_PA_CONFIGURATION_RESULT);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ addr, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg),
+ wpabuf_len(msg),
+ 500, wpas_dpp_tx_status, 0);
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+ return;
+ }
+fail2:
+#endif /* CONFIG_DPP2 */
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
+static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ struct wpabuf *buf;
+ char json[100];
+ int res;
+
+ wpa_s->dpp_gas_client = 1;
+ os_snprintf(json, sizeof(json),
+ "{\"name\":\"Test\","
+ "\"wi-fi_tech\":\"infra\","
+ "\"netRole\":\"%s\"}",
+ wpa_s->dpp_netrole_ap ? "ap" : "sta");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
+ json[29] = 'k'; /* replace "infra" with "knfra" */
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
+
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+
+ buf = dpp_build_conf_req(auth, json);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration request data available");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq);
+
+ res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
+ 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
+ if (res < 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
+ wpabuf_free(buf);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: GAS query started with dialog token %u", res);
+ wpa_s->dpp_gas_dialog_token = res;
+ }
+}
+
+
+static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator)
+{
+ wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Confirm");
+ if (wpa_s->dpp_auth->configurator) {
+ /* Prevent GAS response */
+ wpa_s->dpp_auth->auth_success = 0;
+ }
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wpa_s->dpp_auth->configurator)
+ wpas_dpp_start_gas_server(wpa_s);
+ else
+ wpas_dpp_start_gas_client(wpa_s);
+}
+
+
+static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR
+ " (freq %u MHz)", MAC2STR(src), freq);
+
+ if (!auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Authentication in progress - drop");
+ return;
+ }
+
+ if (!is_zero_ether_addr(auth->peer_mac_addr) &&
+ os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+
+ if (auth->curr_freq != freq && auth->neg_freq == freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder accepted request for different negotiation channel");
+ auth->curr_freq = freq;
+ }
+
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
+ msg = dpp_auth_resp_rx(auth, hdr, buf, len);
+ if (!msg) {
+ if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start wait for full response");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_start(wpa_s, auth->curr_freq);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
+ return;
+ }
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ src, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 500, wpas_dpp_tx_status, 0);
+ wpabuf_free(msg);
+ wpa_s->dpp_auth_ok_on_ack = 1;
+}
+
+
+static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Authentication in progress - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+ return;
+ }
+
+ wpas_dpp_auth_success(wpa_s, 0);
+}
+
+
+#ifdef CONFIG_DPP2
+
+static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Configuration Result");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
+static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error status;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth || !auth->waiting_conf_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ status = dpp_conf_result_rx(auth, hdr, buf, len);
+
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ if (status == DPP_STATUS_OK)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *buf, size_t len)
+{
+ struct wpa_ssid *ssid;
+ const u8 *connector, *trans_id, *status;
+ u16 connector_len, trans_id_len, status_len;
+ struct dpp_introduction intro;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_time now;
+ struct os_reltime rnow;
+ os_time_t expiry;
+ unsigned int seconds;
+ enum dpp_status_error res;
+
+ wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR,
+ MAC2STR(src));
+ if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) ||
+ os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from "
+ MACSTR " - drop", MAC2STR(src));
+ return;
+ }
+ offchannel_send_action_done(wpa_s);
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == wpa_s->dpp_intro_network)
+ break;
+ }
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Profile not found for network introduction");
+ return;
+ }
+
+ trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Transaction ID");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_transaction_id", MAC2STR(src));
+ goto fail;
+ }
+ if (trans_id[0] != TRANSACTION_ID) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore frame with unexpected Transaction ID %u",
+ trans_id[0]);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=transaction_id_mismatch", MAC2STR(src));
+ goto fail;
+ }
+
+ status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len);
+ if (!status || status_len != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_status", MAC2STR(src));
+ goto fail;
+ }
+ if (status[0] != DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer rejected network introduction: Status %u",
+ status[0]);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " status=%u", MAC2STR(src), status[0]);
+ goto fail;
+ }
+
+ connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
+ if (!connector) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include its Connector");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_connector", MAC2STR(src));
+ goto fail;
+ }
+
+ res = dpp_peer_intro(&intro, ssid->dpp_connector,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ ssid->dpp_csign,
+ ssid->dpp_csign_len,
+ connector, connector_len, &expiry);
+ if (res != DPP_STATUS_OK) {
+ wpa_printf(MSG_INFO,
+ "DPP: Network Introduction protocol resulted in failure");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=peer_connector_validation_failed", MAC2STR(src));
+ goto fail;
+ }
+
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ goto fail;
+ os_memcpy(entry->aa, src, ETH_ALEN);
+ os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
+ os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
+ entry->pmk_len = intro.pmk_len;
+ entry->akmp = WPA_KEY_MGMT_DPP;
+ if (expiry) {
+ os_get_time(&now);
+ seconds = expiry - now.sec;
+ } else {
+ seconds = 86400 * 7;
+ }
+ os_get_reltime(&rnow);
+ entry->expiration = rnow.sec + seconds;
+ entry->reauth_time = rnow.sec + seconds;
+ entry->network_ctx = ssid;
+ wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " status=%u", MAC2STR(src), status[0]);
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Try connection again after successful network introduction");
+ if (wpa_supplicant_fast_associate(wpa_s) != 1) {
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+fail:
+ os_memset(&intro, 0, sizeof(intro));
+}
+
+
+static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq)
+{
+ int i, j;
+
+ if (!wpa_s->hw.modes)
+ return -1;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan = &mode->channels[j];
+
+ if (chan->freq != (int) freq)
+ continue;
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
+ freq);
+
+ return 0;
+}
+
+
+static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
+ struct dpp_pkex *pkex)
+{
+ if (pkex->freq == 2437)
+ pkex->freq = 5745;
+ else if (pkex->freq == 5745)
+ pkex->freq = 5220;
+ else if (pkex->freq == 5220)
+ pkex->freq = 60480;
+ else
+ return -1; /* no more channels to try */
+
+ if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
+ pkex->freq);
+ return 0;
+ }
+
+ /* Could not use this channel - try the next one */
+ return wpas_dpp_pkex_next_channel(wpa_s, pkex);
+}
+
+
+static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+
+ if (!pkex || !pkex->exchange_req)
+ return;
+ if (pkex->exch_req_tries >= 5) {
+ if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "No response from PKEX peer");
+ dpp_pkex_free(pkex);
+ wpa_s->dpp_pkex = NULL;
+ return;
+ }
+ pkex->exch_req_tries = 0;
+ }
+
+ pkex->exch_req_tries++;
+ wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
+ pkex->exch_req_tries);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ);
+ offchannel_send_action(wpa_s, pkex->freq, broadcast,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(pkex->exchange_req),
+ wpabuf_len(pkex->exchange_req),
+ pkex->exch_req_wait_time,
+ wpas_dpp_tx_pkex_status, 0);
+}
+
+
+static void
+wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ const char *res_txt;
+ struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+
+ res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED");
+ wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
+ " result=%s (PKEX)",
+ freq, MAC2STR(dst), res_txt);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
+
+ if (!pkex) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore TX status since there is no ongoing PKEX exchange");
+ return;
+ }
+
+ if (pkex->failed) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate PKEX exchange due to an earlier error");
+ if (pkex->t > pkex->own_bi->pkex_t)
+ pkex->own_bi->pkex_t = pkex->t;
+ dpp_pkex_free(pkex);
+ wpa_s->dpp_pkex = NULL;
+ return;
+ }
+
+ if (pkex->exch_req_wait_time && pkex->exchange_req) {
+ /* Wait for PKEX Exchange Response frame and retry request if
+ * no response is seen. */
+ eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
+ eloop_register_timeout(pkex->exch_req_wait_time / 1000,
+ (pkex->exch_req_wait_time % 1000) * 1000,
+ wpas_dpp_pkex_retry_timeout, wpa_s,
+ NULL);
+ }
+}
+
+
+static void
+wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *buf, size_t len, unsigned int freq)
+{
+ struct wpabuf *msg;
+ unsigned int wait_time;
+
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
+ MAC2STR(src));
+
+ /* TODO: Support multiple PKEX codes by iterating over all the enabled
+ * values here */
+
+ if (!wpa_s->dpp_pkex_code || !wpa_s->dpp_pkex_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No PKEX code configured - ignore request");
+ return;
+ }
+
+ if (wpa_s->dpp_pkex) {
+ /* TODO: Support parallel operations */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Already in PKEX session - ignore new request");
+ return;
+ }
+
+ wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi,
+ wpa_s->own_addr, src,
+ wpa_s->dpp_pkex_identifier,
+ wpa_s->dpp_pkex_code,
+ buf, len);
+ if (!wpa_s->dpp_pkex) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to process the request - ignore it");
+ return;
+ }
+
+ msg = wpa_s->dpp_pkex->exchange_resp;
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP);
+ offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
+ broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_pkex_status, 0);
+}
+
+
+static void
+wpas_dpp_rx_pkex_exchange_resp(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *buf, size_t len, unsigned int freq)
+{
+ struct wpabuf *msg;
+ unsigned int wait_time;
+
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR,
+ MAC2STR(src));
+
+ /* TODO: Support multiple PKEX codes by iterating over all the enabled
+ * values here */
+
+ if (!wpa_s->dpp_pkex || !wpa_s->dpp_pkex->initiator ||
+ wpa_s->dpp_pkex->exchange_done) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+ return;
+ }
+
+ eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
+ wpa_s->dpp_pkex->exch_req_wait_time = 0;
+
+ msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len);
+ if (!msg) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
+ MAC2STR(src));
+
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ);
+ offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
+ broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_pkex_status, 0);
+ wpabuf_free(msg);
+}
+
+
+static struct dpp_bootstrap_info *
+wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
+ unsigned int freq)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
+ if (!bi)
+ return NULL;
+ wpa_s->dpp_pkex = NULL;
+ return bi;
+}
+
+
+static void
+wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct wpabuf *msg;
+ unsigned int wait_time;
+ struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
+ MAC2STR(src));
+
+ if (!pkex || pkex->initiator || !pkex->exchange_done) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+ return;
+ }
+
+ msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
+ if (!msg) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
+ if (pkex->failed) {
+ wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
+ if (pkex->t > pkex->own_bi->pkex_t)
+ pkex->own_bi->pkex_t = pkex->t;
+ dpp_pkex_free(wpa_s->dpp_pkex);
+ wpa_s->dpp_pkex = NULL;
+ }
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
+ MACSTR, MAC2STR(src));
+
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP);
+ offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
+ broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_pkex_status, 0);
+ wpabuf_free(msg);
+
+ wpas_dpp_pkex_finish(wpa_s, src, freq);
+}
+
+
+static void
+wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ int res;
+ struct dpp_bootstrap_info *bi;
+ struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+ char cmd[500];
+
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR,
+ MAC2STR(src));
+
+ if (!pkex || !pkex->initiator || !pkex->exchange_done) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+ return;
+ }
+
+ res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
+ return;
+ }
+
+ bi = wpas_dpp_pkex_finish(wpa_s, src, freq);
+ if (!bi)
+ return;
+
+ os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
+ bi->id,
+ wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : "");
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start authentication after PKEX with parameters: %s",
+ cmd);
+ if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Authentication initialization failed");
+ return;
+ }
+}
+
+
+void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *buf, size_t len, unsigned int freq)
+{
+ u8 crypto_suite;
+ enum dpp_public_action_frame_type type;
+ const u8 *hdr;
+ unsigned int pkex_t;
+
+ if (len < DPP_HDR_LEN)
+ return;
+ if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
+ return;
+ hdr = buf;
+ buf += 4;
+ len -= 4;
+ crypto_suite = *buf++;
+ type = *buf++;
+ len -= 2;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Public Action frame crypto suite %u type %d from "
+ MACSTR " freq=%u",
+ crypto_suite, type, MAC2STR(src), freq);
+ if (crypto_suite != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
+ crypto_suite);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d ignore=unsupported-crypto-suite",
+ MAC2STR(src), freq, type);
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
+ if (dpp_check_attrs(buf, len) < 0) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d ignore=invalid-attributes",
+ MAC2STR(src), freq, type);
+ return;
+ }
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, type);
+
+ switch (type) {
+ case DPP_PA_AUTHENTICATION_REQ:
+ wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq);
+ break;
+ case DPP_PA_AUTHENTICATION_RESP:
+ wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq);
+ break;
+ case DPP_PA_AUTHENTICATION_CONF:
+ wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len);
+ break;
+ case DPP_PA_PEER_DISCOVERY_RESP:
+ wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len);
+ break;
+ case DPP_PA_PKEX_EXCHANGE_REQ:
+ wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq);
+ break;
+ case DPP_PA_PKEX_EXCHANGE_RESP:
+ wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq);
+ break;
+ case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
+ wpas_dpp_rx_pkex_commit_reveal_req(wpa_s, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
+ wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len,
+ freq);
+ break;
+#ifdef CONFIG_DPP2
+ case DPP_PA_CONFIGURATION_RESULT:
+ wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
+ break;
+#endif /* CONFIG_DPP2 */
+ default:
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignored unsupported frame subtype %d", type);
+ break;
+ }
+
+ if (wpa_s->dpp_pkex)
+ pkex_t = wpa_s->dpp_pkex->t;
+ else if (wpa_s->dpp_pkex_bi)
+ pkex_t = wpa_s->dpp_pkex_bi->pkex_t;
+ else
+ pkex_t = 0;
+ if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
+ wpas_dpp_pkex_remove(wpa_s, "*");
+ }
+}
+
+
+static struct wpabuf *
+wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
+ size_t query_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ struct wpabuf *resp;
+
+ wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
+ MAC2STR(sa));
+ if (!auth || !auth->auth_success ||
+ os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Received Configuration Request (GAS Query Request)",
+ query, query_len);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
+ MAC2STR(sa));
+ resp = dpp_conf_req_rx(auth, query, query_len);
+ if (!resp)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ auth->conf_resp = resp;
+ return resp;
+}
+
+
+static void
+wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth) {
+ wpabuf_free(resp);
+ return;
+ }
+ if (auth->conf_resp != resp) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore GAS status report (ok=%d) for unknown response",
+ ok);
+ wpabuf_free(resp);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
+ ok);
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+#ifdef CONFIG_DPP2
+ if (ok && auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
+ auth->waiting_conf_result = 1;
+ auth->conf_resp = NULL;
+ wpabuf_free(resp);
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(2, 0,
+ wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ if (ok)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ wpabuf_free(resp);
+}
+
+
+int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct dpp_authentication *auth;
+ int ret = -1;
+ char *curve = NULL;
+
+ auth = os_zalloc(sizeof(*auth));
+ if (!auth)
+ return -1;
+
+ curve = get_param(cmd, " curve=");
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
+ dpp_configurator_own_config(auth, curve, 0) == 0)
+ ret = wpas_dpp_handle_config_obj(wpa_s, auth);
+
+ dpp_auth_deinit(auth);
+ os_free(curve);
+
+ return ret;
+}
+
+
+static void
+wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ const char *res_txt;
+
+ res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED");
+ wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
+ " result=%s (DPP Peer Discovery Request)",
+ freq, MAC2STR(dst), res_txt);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
+ /* TODO: Time out wait for response more quickly in error cases? */
+}
+
+
+int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_bss *bss)
+{
+ struct os_time now;
+ struct wpabuf *msg;
+ unsigned int wait_time;
+ const u8 *rsn;
+ struct wpa_ie_data ied;
+
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
+ return 0; /* Not using DPP AKM - continue */
+ rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
+ !(ied.key_mgmt & WPA_KEY_MGMT_DPP))
+ return 0; /* AP does not support DPP AKM - continue */
+ if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid))
+ return 0; /* PMKSA exists for DPP AKM - continue */
+
+ if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
+ "missing %s",
+ !ssid->dpp_connector ? "Connector" :
+ (!ssid->dpp_netaccesskey ? "netAccessKey" :
+ "C-sign-key"));
+ return -1;
+ }
+
+ os_get_time(&now);
+
+ if (ssid->dpp_netaccesskey_expiry &&
+ (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
+ "netAccessKey expired");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Starting network introduction protocol to derive PMKSA for "
+ MACSTR, MAC2STR(bss->bssid));
+
+ msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_REQ,
+ 5 + 4 + os_strlen(ssid->dpp_connector));
+ if (!msg)
+ return -1;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
+ goto skip_trans_id;
+ }
+ if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 0);
+ goto skip_trans_id;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, TRANSACTION_ID);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_trans_id:
+ if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
+ goto skip_connector;
+ }
+ if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) {
+ char *connector;
+
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
+ connector = dpp_corrupt_connector_signature(
+ ssid->dpp_connector);
+ if (!connector) {
+ wpabuf_free(msg);
+ return -1;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(connector));
+ wpabuf_put_str(msg, connector);
+ os_free(connector);
+ goto skip_connector;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Connector */
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector));
+ wpabuf_put_str(msg, ssid->dpp_connector);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_connector:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* TODO: Timeout on AP response */
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ);
+ offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
+ broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_introduction_status, 0);
+ wpabuf_free(msg);
+
+ /* Request this connection attempt to terminate - new one will be
+ * started when network introduction protocol completes */
+ os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN);
+ wpa_s->dpp_intro_network = ssid;
+ return 1;
+}
+
+
+int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct dpp_bootstrap_info *own_bi;
+ const char *pos, *end;
+ unsigned int wait_time;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not found");
+ return -1;
+ }
+ if (own_bi->type != DPP_BOOTSTRAP_PKEX) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not for PKEX");
+ return -1;
+ }
+ wpa_s->dpp_pkex_bi = own_bi;
+ own_bi->pkex_t = 0; /* clear pending errors on new code */
+
+ os_free(wpa_s->dpp_pkex_identifier);
+ wpa_s->dpp_pkex_identifier = NULL;
+ pos = os_strstr(cmd, " identifier=");
+ if (pos) {
+ pos += 12;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ return -1;
+ wpa_s->dpp_pkex_identifier = os_malloc(end - pos + 1);
+ if (!wpa_s->dpp_pkex_identifier)
+ return -1;
+ os_memcpy(wpa_s->dpp_pkex_identifier, pos, end - pos);
+ wpa_s->dpp_pkex_identifier[end - pos] = '\0';
+ }
+
+ pos = os_strstr(cmd, " code=");
+ if (!pos)
+ return -1;
+ os_free(wpa_s->dpp_pkex_code);
+ wpa_s->dpp_pkex_code = os_strdup(pos + 6);
+ if (!wpa_s->dpp_pkex_code)
+ return -1;
+
+ if (os_strstr(cmd, " init=1")) {
+ struct dpp_pkex *pkex;
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
+ dpp_pkex_free(wpa_s->dpp_pkex);
+ wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
+ wpa_s->dpp_pkex_identifier,
+ wpa_s->dpp_pkex_code);
+ pkex = wpa_s->dpp_pkex;
+ if (!pkex)
+ return -1;
+
+ msg = pkex->exchange_req;
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ pkex->freq = 2437;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(broadcast), pkex->freq,
+ DPP_PA_PKEX_EXCHANGE_REQ);
+ offchannel_send_action(wpa_s, pkex->freq, broadcast,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_pkex_status, 0);
+ if (wait_time == 0)
+ wait_time = 2000;
+ pkex->exch_req_wait_time = wait_time;
+ pkex->exch_req_tries = 1;
+ }
+
+ /* TODO: Support multiple PKEX info entries */
+
+ os_free(wpa_s->dpp_pkex_auth_cmd);
+ wpa_s->dpp_pkex_auth_cmd = os_strdup(cmd);
+
+ return 1;
+}
+
+
+int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id)
+{
+ unsigned int id_val;
+
+ if (os_strcmp(id, "*") == 0) {
+ id_val = 0;
+ } else {
+ id_val = atoi(id);
+ if (id_val == 0)
+ return -1;
+ }
+
+ if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code)
+ return -1;
+
+ /* TODO: Support multiple PKEX entries */
+ os_free(wpa_s->dpp_pkex_code);
+ wpa_s->dpp_pkex_code = NULL;
+ os_free(wpa_s->dpp_pkex_identifier);
+ wpa_s->dpp_pkex_identifier = NULL;
+ os_free(wpa_s->dpp_pkex_auth_cmd);
+ wpa_s->dpp_pkex_auth_cmd = NULL;
+ wpa_s->dpp_pkex_bi = NULL;
+ /* TODO: Remove dpp_pkex only if it is for the identified PKEX code */
+ dpp_pkex_free(wpa_s->dpp_pkex);
+ wpa_s->dpp_pkex = NULL;
+ return 0;
+}
+
+
+void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
+{
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ dpp_pkex_free(wpa_s->dpp_pkex);
+ wpa_s->dpp_pkex = NULL;
+ if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
+ gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
+}
+
+
+int wpas_dpp_init(struct wpa_supplicant *wpa_s)
+{
+ u8 adv_proto_id[7];
+
+ adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC;
+ adv_proto_id[1] = 5;
+ WPA_PUT_BE24(&adv_proto_id[2], OUI_WFA);
+ adv_proto_id[5] = DPP_OUI_TYPE;
+ adv_proto_id[6] = 0x01;
+
+ if (gas_server_register(wpa_s->gas_server, adv_proto_id,
+ sizeof(adv_proto_id), wpas_dpp_gas_req_handler,
+ wpas_dpp_gas_status_handler, wpa_s) < 0)
+ return -1;
+ wpa_s->dpp = dpp_global_init();
+ return wpa_s->dpp ? 0 : -1;
+}
+
+
+void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(wpa_s->dpp_config_obj_override);
+ wpa_s->dpp_config_obj_override = NULL;
+ os_free(wpa_s->dpp_discovery_override);
+ wpa_s->dpp_discovery_override = NULL;
+ os_free(wpa_s->dpp_groups_override);
+ wpa_s->dpp_groups_override = NULL;
+ wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!wpa_s->dpp)
+ return;
+ dpp_global_clear(wpa_s->dpp);
+ eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+ dpp_pfs_free(wpa_s->dpp_pfs);
+ wpa_s->dpp_pfs = NULL;
+#endif /* CONFIG_DPP2 */
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ wpas_dpp_stop(wpa_s);
+ wpas_dpp_pkex_remove(wpa_s, "*");
+ os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
+ os_free(wpa_s->dpp_configurator_params);
+ wpa_s->dpp_configurator_params = NULL;
+}
diff --git a/contrib/wpa/wpa_supplicant/dpp_supplicant.h b/contrib/wpa/wpa_supplicant/dpp_supplicant.h
new file mode 100644
index 0000000..ecb7a7d
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/dpp_supplicant.h
@@ -0,0 +1,29 @@
+/*
+ * wpa_supplicant - DPP
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DPP_SUPPLICANT_H
+#define DPP_SUPPLICANT_H
+
+int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s);
+void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq);
+void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *buf, size_t len, unsigned int freq);
+int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id);
+void wpas_dpp_stop(struct wpa_supplicant *wpa_s);
+int wpas_dpp_init(struct wpa_supplicant *wpa_s);
+void wpas_dpp_deinit(struct wpa_supplicant *wpa_s);
+int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_bss *bss);
+
+#endif /* DPP_SUPPLICANT_H */
diff --git a/contrib/wpa/wpa_supplicant/driver_i.h b/contrib/wpa/wpa_supplicant/driver_i.h
index 73768c7..4a9f472 100644
--- a/contrib/wpa/wpa_supplicant/driver_i.h
+++ b/contrib/wpa/wpa_supplicant/driver_i.h
@@ -100,12 +100,10 @@ static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- u32 interval)
+ struct wpa_driver_scan_params *params)
{
if (wpa_s->driver->sched_scan)
- return wpa_s->driver->sched_scan(wpa_s->drv_priv,
- params, interval);
+ return wpa_s->driver->sched_scan(wpa_s->drv_priv, params);
return -1;
}
@@ -160,6 +158,15 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_get_seqnum(struct wpa_supplicant *wpa_s,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (wpa_s->driver->get_seqnum)
+ return wpa_s->driver->get_seqnum(wpa_s->ifname, wpa_s->drv_priv,
+ addr, idx, seq);
+ return -1;
+}
+
static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
const u8 *addr, int reason_code)
{
@@ -182,20 +189,19 @@ static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s,
- const u8 *bssid, const u8 *pmkid)
+ struct wpa_pmkid_params *params)
{
if (wpa_s->driver->add_pmkid) {
- return wpa_s->driver->add_pmkid(wpa_s->drv_priv, bssid, pmkid);
+ return wpa_s->driver->add_pmkid(wpa_s->drv_priv, params);
}
return -1;
}
static inline int wpa_drv_remove_pmkid(struct wpa_supplicant *wpa_s,
- const u8 *bssid, const u8 *pmkid)
+ struct wpa_pmkid_params *params)
{
if (wpa_s->driver->remove_pmkid) {
- return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, bssid,
- pmkid);
+ return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, params);
}
return -1;
}
@@ -269,11 +275,12 @@ static inline int wpa_drv_mlme_setprotection(struct wpa_supplicant *wpa_s,
static inline struct hostapd_hw_modes *
wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes,
- u16 *flags)
+ u16 *flags, u8 *dfs_domain)
{
if (wpa_s->driver->get_hw_feature_data)
return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv,
- num_modes, flags);
+ num_modes, flags,
+ dfs_domain);
return NULL;
}
@@ -292,7 +299,7 @@ static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
if (wpa_s->driver->send_mlme)
return wpa_s->driver->send_mlme(wpa_s->drv_priv,
data, data_len, noack,
- freq);
+ freq, NULL, 0);
return -1;
}
@@ -401,7 +408,7 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
if (wpa_s->driver->if_add)
return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
addr, bss_ctx, NULL, force_ifname,
- if_addr, bridge, 0);
+ if_addr, bridge, 0, 0);
return -1;
}
@@ -485,6 +492,14 @@ static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
+ struct wpa_channel_info *ci)
+{
+ if (wpa_s->driver->channel_info)
+ return wpa_s->driver->channel_info(wpa_s->drv_priv, ci);
+ return -1;
+}
+
static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s,
struct hostap_sta_driver_data *sta)
{
@@ -682,6 +697,14 @@ static inline int wpa_drv_roaming(struct wpa_supplicant *wpa_s, int allowed,
return wpa_s->driver->roaming(wpa_s->drv_priv, allowed, bssid);
}
+static inline int wpa_drv_disable_fils(struct wpa_supplicant *wpa_s,
+ int disable)
+{
+ if (!wpa_s->driver->disable_fils)
+ return -1;
+ return wpa_s->driver->disable_fils(wpa_s->drv_priv, disable);
+}
+
static inline int wpa_drv_set_mac_addr(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
@@ -708,6 +731,14 @@ static inline int wpa_drv_macsec_deinit(struct wpa_supplicant *wpa_s)
return wpa_s->driver->macsec_deinit(wpa_s->drv_priv);
}
+static inline int wpa_drv_macsec_get_capability(struct wpa_supplicant *wpa_s,
+ enum macsec_cap *cap)
+{
+ if (!wpa_s->driver->macsec_get_capability)
+ return -1;
+ return wpa_s->driver->macsec_get_capability(wpa_s->drv_priv, cap);
+}
+
static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
Boolean enabled)
{
@@ -716,6 +747,14 @@ static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
return wpa_s->driver->enable_protect_frames(wpa_s->drv_priv, enabled);
}
+static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
+ Boolean enabled)
+{
+ if (!wpa_s->driver->enable_encrypt)
+ return -1;
+ return wpa_s->driver->enable_encrypt(wpa_s->drv_priv, enabled);
+}
+
static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
Boolean enabled, u32 window)
{
@@ -726,12 +765,11 @@ static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s,
- const u8 *cs, size_t cs_len)
+ u64 cs)
{
if (!wpa_s->driver->set_current_cipher_suite)
return -1;
- return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs,
- cs_len);
+ return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs);
}
static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
@@ -743,145 +781,135 @@ static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_get_receive_lowest_pn(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 *lowest_pn)
+ struct receive_sa *sa)
{
if (!wpa_s->driver->get_receive_lowest_pn)
return -1;
- return wpa_s->driver->get_receive_lowest_pn(wpa_s->drv_priv, channel,
- an, lowest_pn);
+ return wpa_s->driver->get_receive_lowest_pn(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_get_transmit_next_pn(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 *next_pn)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->get_transmit_next_pn)
return -1;
- return wpa_s->driver->get_transmit_next_pn(wpa_s->drv_priv, channel,
- an, next_pn);
+ return wpa_s->driver->get_transmit_next_pn(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_set_transmit_next_pn(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 next_pn)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->set_transmit_next_pn)
return -1;
- return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, channel,
- an, next_pn);
+ return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, sa);
}
-static inline int wpa_drv_get_available_receive_sc(struct wpa_supplicant *wpa_s,
- u32 *channel)
+static inline int wpa_drv_set_receive_lowest_pn(struct wpa_supplicant *wpa_s,
+ struct receive_sa *sa)
{
- if (!wpa_s->driver->get_available_receive_sc)
+ if (!wpa_s->driver->set_receive_lowest_pn)
return -1;
- return wpa_s->driver->get_available_receive_sc(wpa_s->drv_priv,
- channel);
+ return wpa_s->driver->set_receive_lowest_pn(wpa_s->drv_priv, sa);
}
static inline int
-wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, u32 channel,
- const u8 *sci_addr, u16 sci_port,
+wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, struct receive_sc *sc,
unsigned int conf_offset, int validation)
{
if (!wpa_s->driver->create_receive_sc)
return -1;
- return wpa_s->driver->create_receive_sc(wpa_s->drv_priv, channel,
- sci_addr, sci_port, conf_offset,
- validation);
+ return wpa_s->driver->create_receive_sc(wpa_s->drv_priv, sc,
+ conf_offset, validation);
}
static inline int wpa_drv_delete_receive_sc(struct wpa_supplicant *wpa_s,
- u32 channel)
+ struct receive_sc *sc)
{
if (!wpa_s->driver->delete_receive_sc)
return -1;
- return wpa_s->driver->delete_receive_sc(wpa_s->drv_priv, channel);
+ return wpa_s->driver->delete_receive_sc(wpa_s->drv_priv, sc);
}
static inline int wpa_drv_create_receive_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 lowest_pn, const u8 *sak)
+ struct receive_sa *sa)
{
if (!wpa_s->driver->create_receive_sa)
return -1;
- return wpa_s->driver->create_receive_sa(wpa_s->drv_priv, channel, an,
- lowest_pn, sak);
+ return wpa_s->driver->create_receive_sa(wpa_s->drv_priv, sa);
}
-static inline int wpa_drv_enable_receive_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an)
+static inline int wpa_drv_delete_receive_sa(struct wpa_supplicant *wpa_s,
+ struct receive_sa *sa)
{
- if (!wpa_s->driver->enable_receive_sa)
+ if (!wpa_s->driver->delete_receive_sa)
return -1;
- return wpa_s->driver->enable_receive_sa(wpa_s->drv_priv, channel, an);
+ return wpa_s->driver->delete_receive_sa(wpa_s->drv_priv, sa);
}
-static inline int wpa_drv_disable_receive_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an)
+static inline int wpa_drv_enable_receive_sa(struct wpa_supplicant *wpa_s,
+ struct receive_sa *sa)
{
- if (!wpa_s->driver->disable_receive_sa)
+ if (!wpa_s->driver->enable_receive_sa)
return -1;
- return wpa_s->driver->disable_receive_sa(wpa_s->drv_priv, channel, an);
+ return wpa_s->driver->enable_receive_sa(wpa_s->drv_priv, sa);
}
-static inline int
-wpa_drv_get_available_transmit_sc(struct wpa_supplicant *wpa_s, u32 *channel)
+static inline int wpa_drv_disable_receive_sa(struct wpa_supplicant *wpa_s,
+ struct receive_sa *sa)
{
- if (!wpa_s->driver->get_available_transmit_sc)
+ if (!wpa_s->driver->disable_receive_sa)
return -1;
- return wpa_s->driver->get_available_transmit_sc(wpa_s->drv_priv,
- channel);
+ return wpa_s->driver->disable_receive_sa(wpa_s->drv_priv, sa);
}
static inline int
-wpa_drv_create_transmit_sc(struct wpa_supplicant *wpa_s, u32 channel,
- const u8 *sci_addr, u16 sci_port,
+wpa_drv_create_transmit_sc(struct wpa_supplicant *wpa_s, struct transmit_sc *sc,
unsigned int conf_offset)
{
if (!wpa_s->driver->create_transmit_sc)
return -1;
- return wpa_s->driver->create_transmit_sc(wpa_s->drv_priv, channel,
- sci_addr, sci_port,
+ return wpa_s->driver->create_transmit_sc(wpa_s->drv_priv, sc,
conf_offset);
}
static inline int wpa_drv_delete_transmit_sc(struct wpa_supplicant *wpa_s,
- u32 channel)
+ struct transmit_sc *sc)
{
if (!wpa_s->driver->delete_transmit_sc)
return -1;
- return wpa_s->driver->delete_transmit_sc(wpa_s->drv_priv, channel);
+ return wpa_s->driver->delete_transmit_sc(wpa_s->drv_priv, sc);
}
static inline int wpa_drv_create_transmit_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 next_pn,
- Boolean confidentiality,
- const u8 *sak)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->create_transmit_sa)
return -1;
- return wpa_s->driver->create_transmit_sa(wpa_s->drv_priv, channel, an,
- next_pn, confidentiality, sak);
+ return wpa_s->driver->create_transmit_sa(wpa_s->drv_priv, sa);
+}
+
+static inline int wpa_drv_delete_transmit_sa(struct wpa_supplicant *wpa_s,
+ struct transmit_sa *sa)
+{
+ if (!wpa_s->driver->delete_transmit_sa)
+ return -1;
+ return wpa_s->driver->delete_transmit_sa(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_enable_transmit_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->enable_transmit_sa)
return -1;
- return wpa_s->driver->enable_transmit_sa(wpa_s->drv_priv, channel, an);
+ return wpa_s->driver->enable_transmit_sa(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_disable_transmit_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->disable_transmit_sa)
return -1;
- return wpa_s->driver->disable_transmit_sa(wpa_s->drv_priv, channel, an);
+ return wpa_s->driver->disable_transmit_sa(wpa_s->drv_priv, sa);
}
#endif /* CONFIG_MACSEC */
@@ -898,6 +926,11 @@ static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s,
unsigned int *num,
unsigned int *freq_list)
{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->get_pref_freq_list_override)
+ return wpas_ctrl_iface_get_pref_freq_list_override(
+ wpa_s, if_type, num, freq_list);
+#endif /* CONFIG_TESTING_OPTIONS */
if (!wpa_s->driver->get_pref_freq_list)
return -1;
return wpa_s->driver->get_pref_freq_list(wpa_s->drv_priv, if_type,
@@ -912,4 +945,129 @@ static inline int wpa_drv_set_prob_oper_freq(struct wpa_supplicant *wpa_s,
return wpa_s->driver->set_prob_oper_freq(wpa_s->drv_priv, freq);
}
+static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s,
+ u64 scan_cookie)
+{
+ if (!wpa_s->driver->abort_scan)
+ return -1;
+ return wpa_s->driver->abort_scan(wpa_s->drv_priv, scan_cookie);
+}
+
+static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s,
+ u32 filters)
+{
+ if (!wpa_s->driver->configure_data_frame_filters)
+ return -1;
+ return wpa_s->driver->configure_data_frame_filters(wpa_s->drv_priv,
+ filters);
+}
+
+static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type type)
+{
+ if (!wpa_s->driver->get_ext_capab)
+ return -1;
+ return wpa_s->driver->get_ext_capab(wpa_s->drv_priv, type,
+ &wpa_s->extended_capa,
+ &wpa_s->extended_capa_mask,
+ &wpa_s->extended_capa_len);
+}
+
+static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s,
+ unsigned int channel,
+ unsigned int period,
+ unsigned int interval,
+ unsigned int count,
+ const u8 *device_types,
+ size_t dev_types_len,
+ const u8 *ies, size_t ies_len)
+{
+ if (!wpa_s->driver->p2p_lo_start)
+ return -1;
+ return wpa_s->driver->p2p_lo_start(wpa_s->drv_priv, channel, period,
+ interval, count, device_types,
+ dev_types_len, ies, ies_len);
+}
+
+static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->p2p_lo_stop)
+ return -1;
+ return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t len)
+{
+ if (!wpa_s->driver->set_default_scan_ies)
+ return -1;
+ return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len);
+}
+
+static inline int wpa_drv_set_tdls_mode(struct wpa_supplicant *wpa_s,
+ int tdls_external_control)
+{
+ if (!wpa_s->driver->set_tdls_mode)
+ return -1;
+ return wpa_s->driver->set_tdls_mode(wpa_s->drv_priv,
+ tdls_external_control);
+}
+
+static inline struct wpa_bss_candidate_info *
+wpa_drv_get_bss_trans_status(struct wpa_supplicant *wpa_s,
+ struct wpa_bss_trans_info *params)
+{
+ if (!wpa_s->driver->get_bss_transition_status)
+ return NULL;
+ return wpa_s->driver->get_bss_transition_status(wpa_s->drv_priv,
+ params);
+}
+
+static inline int wpa_drv_ignore_assoc_disallow(struct wpa_supplicant *wpa_s,
+ int val)
+{
+ if (!wpa_s->driver->ignore_assoc_disallow)
+ return -1;
+ return wpa_s->driver->ignore_assoc_disallow(wpa_s->drv_priv, val);
+}
+
+static inline int wpa_drv_set_bssid_blacklist(struct wpa_supplicant *wpa_s,
+ unsigned int num_bssid,
+ const u8 *bssids)
+{
+ if (!wpa_s->driver->set_bssid_blacklist)
+ return -1;
+ return wpa_s->driver->set_bssid_blacklist(wpa_s->drv_priv, num_bssid,
+ bssids);
+}
+
+static inline int wpa_drv_update_connect_params(
+ struct wpa_supplicant *wpa_s,
+ struct wpa_driver_associate_params *params,
+ enum wpa_drv_update_connect_params_mask mask)
+{
+ if (!wpa_s->driver->update_connect_params)
+ return -1;
+ return wpa_s->driver->update_connect_params(wpa_s->drv_priv, params,
+ mask);
+}
+
+static inline int
+wpa_drv_send_external_auth_status(struct wpa_supplicant *wpa_s,
+ struct external_auth *params)
+{
+ if (!wpa_s->driver->send_external_auth_status)
+ return -1;
+ return wpa_s->driver->send_external_auth_status(wpa_s->drv_priv,
+ params);
+}
+
+static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val)
+{
+ if (!wpa_s->driver->set_4addr_mode)
+ return -1;
+ return wpa_s->driver->set_4addr_mode(wpa_s->drv_priv,
+ wpa_s->bridge_ifname, val);
+}
+
#endif /* DRIVER_I_H */
diff --git a/contrib/wpa/wpa_supplicant/eapol_test.c b/contrib/wpa/wpa_supplicant/eapol_test.c
index dce7d1f..3fd4ce6 100644
--- a/contrib/wpa/wpa_supplicant/eapol_test.c
+++ b/contrib/wpa/wpa_supplicant/eapol_test.c
@@ -14,6 +14,7 @@
#include "common.h"
#include "utils/ext_password.h"
+#include "common/version.h"
#include "config.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
@@ -192,7 +193,7 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
return;
}
- radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e));
+ radius_msg_make_authenticator(msg);
hdr = (const struct eap_hdr *) eap;
pos = (const u8 *) (hdr + 1);
@@ -257,6 +258,13 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
goto fail;
}
+ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_SERVICE_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
+ RADIUS_SERVICE_TYPE_FRAMED)) {
+ printf("Could not add Service-Type\n");
+ goto fail;
+ }
+
os_snprintf(buf, sizeof(buf), "%s", e->connect_info);
if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
@@ -703,7 +711,8 @@ static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx)
eap = (struct eap_hdr *) (hdr + 1);
eap->code = EAP_CODE_REQUEST;
- eap->identifier = 0;
+ if (os_get_random((u8 *) &eap->identifier, sizeof(eap->identifier)) < 0)
+ eap->identifier = os_random() & 0xff;
eap->length = htons(5);
pos = (u8 *) (eap + 1);
*pos = EAP_TYPE_IDENTITY;
@@ -1239,7 +1248,7 @@ static void eapol_test_terminate(int sig, void *signal_ctx)
static void usage(void)
{
printf("usage:\n"
- "eapol_test [-enWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
+ "eapol_test [-enWSv] -c<conf> [-a<AS IP>] [-p<AS port>] "
"[-s<AS secret>]\\\n"
" [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
" [-M<client MAC address>] [-o<server cert file] \\\n"
@@ -1264,6 +1273,7 @@ static void usage(void)
" -W = wait for a control interface monitor before starting\n"
" -S = save configuration after authentication\n"
" -n = no MPPE keys expected\n"
+ " -v = show version\n"
" -t<timeout> = sets timeout in seconds (default: 30 s)\n"
" -C<Connect-Info> = RADIUS Connect-Info (default: "
"CONNECT 11Mbps 802.11b)\n"
@@ -1317,7 +1327,7 @@ int main(int argc, char *argv[])
wpa_debug_show_keys = 1;
for (;;) {
- c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:W");
+ c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:vW");
if (c < 0)
break;
switch (c) {
@@ -1383,6 +1393,9 @@ int main(int argc, char *argv[])
ctrl_iface = optarg;
eapol_test.ctrl_iface = 1;
break;
+ case 'v':
+ printf("eapol_test v" VERSION_STR "\n");
+ return 0;
case 'W':
wait_for_monitor++;
break;
diff --git a/contrib/wpa/wpa_supplicant/eapol_test.py b/contrib/wpa/wpa_supplicant/eapol_test.py
index 80e7dfc..734428d 100755
--- a/contrib/wpa/wpa_supplicant/eapol_test.py
+++ b/contrib/wpa/wpa_supplicant/eapol_test.py
@@ -136,7 +136,7 @@ def main():
results = res[i].get(False)
except:
results = "N/A"
- print "%d: %s" % (i, results)
+ print("%d: %s" % (i, results))
if __name__ == "__main__":
main()
diff --git a/contrib/wpa/wpa_supplicant/events.c b/contrib/wpa/wpa_supplicant/events.c
index e2105ec..f6ec111 100644
--- a/contrib/wpa/wpa_supplicant/events.c
+++ b/contrib/wpa/wpa_supplicant/events.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -28,6 +28,8 @@
#include "notify.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/gas_server.h"
+#include "common/dpp.h"
#include "crypto/random.h"
#include "blacklist.h"
#include "wpas_glue.h"
@@ -46,6 +48,10 @@
#include "mesh.h"
#include "mesh_mpm.h"
#include "wmm_ac.h"
+#include "dpp_supplicant.h"
+
+
+#define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5
#ifndef CONFIG_NO_SCAN_PROCESSING
@@ -54,8 +60,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_SCAN_PROCESSING */
-static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
struct os_reltime now;
@@ -72,6 +77,7 @@ static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
}
+#ifndef CONFIG_NO_SCAN_PROCESSING
/**
* wpas_reenabled_network_time - Time until first network is re-enabled
* @wpa_s: Pointer to wpa_supplicant data
@@ -107,6 +113,7 @@ static int wpas_reenabled_network_time(struct wpa_supplicant *wpa_s)
return res;
}
+#endif /* CONFIG_NO_SCAN_PROCESSING */
void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx)
@@ -279,9 +286,21 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
wpa_supplicant_ap_deinit(wpa_s);
#endif /* CONFIG_AP */
+#ifdef CONFIG_HS20
+ /* Clear possibly configured frame filters */
+ wpa_drv_configure_frame_filters(wpa_s, 0);
+#endif /* CONFIG_HS20 */
+
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
return;
+ if (os_reltime_initialized(&wpa_s->session_start)) {
+ os_reltime_age(&wpa_s->session_start, &wpa_s->session_length);
+ wpa_s->session_start.sec = 0;
+ wpa_s->session_start.usec = 0;
+ wpas_notify_session_length(wpa_s);
+ }
+
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
os_memset(wpa_s->bssid, 0, ETH_ALEN);
@@ -295,7 +314,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
- if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+ if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
wpa_s->ap_ies_from_associnfo = 0;
wpa_s->current_ssid = NULL;
@@ -304,6 +325,16 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
wpas_rrm_reset(wpa_s);
wpa_s->wnmsleep_used = 0;
+ wnm_clear_coloc_intf_reporting(wpa_s);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ wpa_s->last_tk_alg = WPA_ALG_NONE;
+ os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_s->ieee80211ac = 0;
+
+ if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+ wpa_s->enabled_4addr_mode = 0;
}
@@ -320,7 +351,7 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
for (i = 0; i < ie.num_pmkid; i++) {
pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
ie.pmkid + i * PMKID_LEN,
- NULL, NULL, 0);
+ NULL, NULL, 0, NULL, 0);
if (pmksa_set == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
break;
@@ -472,6 +503,11 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
return 1;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_OWE
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only)
+ return 1;
+#endif /* CONFIG_OWE */
+
if (has_wep_key(ssid))
privacy = 1;
@@ -496,7 +532,7 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_bss *bss)
+ struct wpa_bss *bss, int debug_print)
{
struct wpa_ie_data ie;
int proto_match = 0;
@@ -515,44 +551,63 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
+ while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
proto_match++;
if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - parse "
- "failed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - parse failed");
break;
}
+ if (!ie.has_pairwise)
+ ie.pairwise_cipher = wpa_default_rsn_cipher(bss->freq);
+ if (!ie.has_group)
+ ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
- "in RSN IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on TSN in RSN IE");
return 1;
}
- if (!(ie.proto & ssid->proto)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - proto "
- "mismatch");
+ if (!(ie.proto & ssid->proto) &&
+ !(ssid->proto & WPA_PROTO_OSEN)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - proto mismatch");
break;
}
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - PTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - PTK cipher mismatch");
break;
}
if (!(ie.group_cipher & ssid->group_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - GTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - GTK cipher mismatch");
+ break;
+ }
+
+ if (ssid->group_mgmt_cipher &&
+ !(ie.mgmt_group_cipher & ssid->group_mgmt_cipher)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - group mgmt cipher mismatch");
break;
}
if (!(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - key mgmt "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - key mgmt mismatch");
break;
}
@@ -560,87 +615,157 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
- "frame protection");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection");
break;
}
#endif /* CONFIG_IEEE80211W */
+ if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) ==
+ NO_MGMT_FRAME_PROTECTION) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection enabled but AP requires it");
+ break;
+ }
+#ifdef CONFIG_MBO
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) !=
+ NO_MGMT_FRAME_PROTECTION) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection enabled on MBO AP");
+ break;
+ }
+#endif /* CONFIG_MBO */
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on RSN IE");
return 1;
}
+#ifdef CONFIG_IEEE80211W
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED &&
+ (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MFP Required but network not MFP Capable");
+ return 0;
+ }
+#endif /* CONFIG_IEEE80211W */
+
wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
proto_match++;
if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - parse "
- "failed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - parse failed");
break;
}
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
- "in WPA IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on TSN in WPA IE");
return 1;
}
if (!(ie.proto & ssid->proto)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - proto "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - proto mismatch");
break;
}
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - PTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - PTK cipher mismatch");
break;
}
if (!(ie.group_cipher & ssid->group_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - GTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - GTK cipher mismatch");
break;
}
if (!(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - key mgmt "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - key mgmt mismatch");
break;
}
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on WPA IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on WPA IE");
return 1;
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
!rsn_ie) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " allow for non-WPA IEEE 802.1X");
+ return 1;
+ }
+
+#ifdef CONFIG_OWE
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only &&
+ !wpa_ie && !rsn_ie) {
+ if (wpa_s->owe_transition_select &&
+ wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE) &&
+ ssid->owe_transition_bss_select_count + 1 <=
+ MAX_OWE_TRANSITION_BSS_SELECT_COUNT) {
+ ssid->owe_transition_bss_select_count++;
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip OWE transition BSS (selection count %d does not exceed %d)",
+ ssid->owe_transition_bss_select_count,
+ MAX_OWE_TRANSITION_BSS_SELECT_COUNT);
+ wpa_s->owe_transition_search = 1;
+ return 0;
+ }
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " allow in OWE transition mode");
return 1;
}
+#endif /* CONFIG_OWE */
if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no WPA/RSN proto match");
return 0;
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) &&
wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN");
return 1;
}
if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
return 1;
}
- wpa_dbg(wpa_s, MSG_DEBUG, " reject due to mismatch with "
- "WPA/WPA2");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " reject due to mismatch with WPA/WPA2");
return 0;
}
@@ -660,7 +785,8 @@ static int freq_allowed(int *freqs, int freq)
}
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ int debug_print)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -717,9 +843,9 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
if (!ht_supported(mode)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support "
- "HT PHY");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support HT PHY");
return 0;
}
continue;
@@ -729,9 +855,9 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) {
if (!vht_supported(mode)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support "
- "VHT PHY");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support VHT PHY");
return 0;
}
continue;
@@ -751,10 +877,11 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
* order to join a BSS all required rates
* have to be supported by the hardware.
*/
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
- r / 10, r % 10,
- bss->freq, mode->mode, mode->num_rates);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
+ r / 10, r % 10,
+ bss->freq, mode->mode, mode->num_rates);
return 0;
}
}
@@ -807,36 +934,124 @@ static int addr_in_list(const u8 *addr, const u8 *list, size_t num)
}
-static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
- int i, struct wpa_bss *bss,
- struct wpa_ssid *group,
- int only_first_ssid)
+static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const u8 **ret_ssid, size_t *ret_ssid_len)
+{
+#ifdef CONFIG_OWE
+ const u8 *owe, *pos, *end, *bssid;
+ u8 ssid_len;
+ struct wpa_bss *open_bss;
+
+ owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+ if (!owe || !wpa_bss_get_ie(bss, WLAN_EID_RSN))
+ return;
+
+ pos = owe + 6;
+ end = owe + 2 + owe[1];
+
+ if (end - pos < ETH_ALEN + 1)
+ return;
+ bssid = pos;
+ pos += ETH_ALEN;
+ ssid_len = *pos++;
+ if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
+ return;
+
+ /* Match the profile SSID against the OWE transition mode SSID on the
+ * open network. */
+ wpa_dbg(wpa_s, MSG_DEBUG, "OWE: transition mode BSSID: " MACSTR
+ " SSID: %s", MAC2STR(bssid), wpa_ssid_txt(pos, ssid_len));
+ *ret_ssid = pos;
+ *ret_ssid_len = ssid_len;
+
+ if (bss->ssid_len > 0)
+ return;
+
+ open_bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (!open_bss)
+ return;
+ if (ssid_len != open_bss->ssid_len ||
+ os_memcmp(pos, open_bss->ssid, ssid_len) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "OWE: transition mode SSID mismatch: %s",
+ wpa_ssid_txt(open_bss->ssid, open_bss->ssid_len));
+ return;
+ }
+
+ owe = wpa_bss_get_vendor_ie(open_bss, OWE_IE_VENDOR_TYPE);
+ if (!owe || wpa_bss_get_ie(open_bss, WLAN_EID_RSN)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "OWE: transition mode open BSS unexpected info");
+ return;
+ }
+
+ pos = owe + 6;
+ end = owe + 2 + owe[1];
+
+ if (end - pos < ETH_ALEN + 1)
+ return;
+ if (os_memcmp(pos, bss->bssid, ETH_ALEN) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "OWE: transition mode BSSID mismatch: " MACSTR,
+ MAC2STR(pos));
+ return;
+ }
+ pos += ETH_ALEN;
+ ssid_len = *pos++;
+ if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
+ return;
+ wpa_dbg(wpa_s, MSG_DEBUG, "OWE: learned transition mode OWE SSID: %s",
+ wpa_ssid_txt(pos, ssid_len));
+ os_memcpy(bss->ssid, pos, ssid_len);
+ bss->ssid_len = ssid_len;
+#endif /* CONFIG_OWE */
+}
+
+
+struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
+ int i, struct wpa_bss *bss,
+ struct wpa_ssid *group,
+ int only_first_ssid, int debug_print)
{
u8 wpa_ie_len, rsn_ie_len;
int wpa;
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
- int osen;
+ int osen, rsn_osen = 0;
+#ifdef CONFIG_MBO
+ const u8 *assoc_disallow;
+#endif /* CONFIG_MBO */
+ const u8 *match_ssid;
+ size_t match_ssid_len;
+ struct wpa_ie_data data;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
rsn_ie_len = ie ? ie[1] : 0;
+ if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+ (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+ rsn_osen = 1;
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
- wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
- "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
- i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
- wpa_ie_len, rsn_ie_len, bss->caps, bss->level, bss->freq,
- wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "",
- (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
- wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ?
- " p2p" : "",
- osen ? " osen=1" : "");
+ if (debug_print) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR
+ " ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
+ i, MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len),
+ wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
+ bss->freq,
+ wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ?
+ " wps" : "",
+ (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+ wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE))
+ ? " p2p" : "",
+ osen ? " osen=1" : "");
+ }
e = wpa_blacklist_get(wpa_s, bss->bssid);
if (e) {
@@ -853,24 +1068,34 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
limit = 0;
}
if (e->count > limit) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
- "(count=%d limit=%d)", e->count, limit);
+ if (debug_print) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (count=%d limit=%d)",
+ e->count, limit);
+ }
return NULL;
}
}
- if (bss->ssid_len == 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known");
+ match_ssid = bss->ssid;
+ match_ssid_len = bss->ssid_len;
+ owe_trans_ssid(wpa_s, bss, &match_ssid, &match_ssid_len);
+
+ if (match_ssid_len == 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known");
return NULL;
}
if (disallowed_bssid(wpa_s, bss->bssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed");
return NULL;
}
- if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed");
+ if (disallowed_ssid(wpa_s, match_ssid, match_ssid_len)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed");
return NULL;
}
@@ -881,21 +1106,25 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int res;
if (wpas_network_disabled(wpa_s, ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
continue;
}
res = wpas_temp_disabled(wpa_s, ssid);
if (res > 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled "
- "temporarily for %d second(s)", res);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - disabled temporarily for %d second(s)",
+ res);
continue;
}
#ifdef CONFIG_WPS
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
- "(WPS)");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (WPS)");
continue;
}
@@ -919,15 +1148,19 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
check_ssid = 0;
if (check_ssid &&
- (bss->ssid_len != ssid->ssid_len ||
- os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
+ (match_ssid_len != ssid->ssid_len ||
+ os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SSID mismatch");
continue;
}
if (ssid->bssid_set &&
os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID mismatch");
continue;
}
@@ -935,8 +1168,9 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
if (ssid->num_bssid_blacklist &&
addr_in_list(bss->bssid, ssid->bssid_blacklist,
ssid->num_bssid_blacklist)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID blacklisted");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID blacklisted");
continue;
}
@@ -944,63 +1178,108 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
if (ssid->num_bssid_whitelist &&
!addr_in_list(bss->bssid, ssid->bssid_whitelist,
ssid->num_bssid_whitelist)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID not in whitelist");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in whitelist");
continue;
}
- if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
+ if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
+ debug_print))
continue;
if (!osen && !wpa &&
!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-WPA network "
- "not allowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-WPA network not allowed");
continue;
}
if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
has_wep_key(ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - ignore WPA/WPA2 AP for WEP network block");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - ignore WPA/WPA2 AP for WEP network block");
continue;
}
- if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-OSEN network "
- "not allowed");
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
+ !rsn_osen) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-OSEN network not allowed");
continue;
}
if (!wpa_supplicant_match_privacy(bss, ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - privacy mismatch");
continue;
}
- if (!bss_is_ess(bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network");
+ if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
+ !bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
+ continue;
+ }
+
+ if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - PBSS mismatch (ssid %d bss %d)",
+ ssid->pbss, bss_is_pbss(bss));
continue;
}
if (!freq_allowed(ssid->freq_list, bss->freq)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not "
- "allowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed");
continue;
}
- if (!rate_match(wpa_s, bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do "
- "not match");
+#ifdef CONFIG_MESH
+ if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
+ ssid->frequency != bss->freq) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed (mesh)");
continue;
}
+#endif /* CONFIG_MESH */
+
+ if (!rate_match(wpa_s, bss, debug_print)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - rate sets do not match");
+ continue;
+ }
+
+#ifndef CONFIG_IBSS_RSN
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
+ WPA_KEY_MGMT_WPA_NONE))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - IBSS RSN not supported in the build");
+ continue;
+ }
+#endif /* !CONFIG_IBSS_RSN */
#ifdef CONFIG_P2P
if (ssid->p2p_group &&
!wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
!wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P IE seen");
continue;
}
@@ -1010,20 +1289,26 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
if (ie == NULL) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P element");
continue;
}
p2p_ie = wpa_bss_get_vendor_ie_multi(
bss, P2P_IE_VENDOR_TYPE);
if (p2p_ie == NULL) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - could not fetch P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - could not fetch P2P element");
continue;
}
if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
|| os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
ETH_ALEN) != 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no matching GO P2P Device Address in P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no matching GO P2P Device Address in P2P element");
wpabuf_free(p2p_ie);
continue;
}
@@ -1043,12 +1328,51 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
os_reltime_sub(&wpa_s->scan_min_time,
&bss->last_update, &diff);
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - scan result not recent enough (%u.%06u seconds too old)",
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - scan result not recent enough (%u.%06u seconds too old)",
(unsigned int) diff.sec,
(unsigned int) diff.usec);
continue;
}
+#ifdef CONFIG_MBO
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_assoc_disallow)
+ goto skip_assoc_disallow;
+#endif /* CONFIG_TESTING_OPTIONS */
+ assoc_disallow = wpas_mbo_get_bss_attr(
+ bss, MBO_ATTR_ID_ASSOC_DISALLOW);
+ if (assoc_disallow && assoc_disallow[1] >= 1) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO association disallowed (reason %u)",
+ assoc_disallow[2]);
+ continue;
+ }
+
+ if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - AP temporarily disallowed");
+ continue;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
+ (!ssid->dpp_connector ||
+ !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no PMKSA entry for DPP");
+ continue;
+ }
+#endif /* CONFIG_DPP */
/* Matching configuration found */
return ssid;
@@ -1067,6 +1391,25 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
{
unsigned int i;
+ if (wpa_s->current_ssid) {
+ struct wpa_ssid *ssid;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Scan results matching the currently selected network");
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+ ssid = wpa_scan_res_match(wpa_s, i, bss, group,
+ only_first_ssid, 0);
+ if (ssid != wpa_s->current_ssid)
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG, "%u: " MACSTR
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ i, MAC2STR(bss->bssid), bss->freq, bss->level,
+ bss->snr, bss->est_throughput);
+ }
+ }
+
if (only_first_ssid)
wpa_dbg(wpa_s, MSG_DEBUG, "Try to find BSS matching pre-selected network id=%d",
group->id);
@@ -1076,8 +1419,11 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
for (i = 0; i < wpa_s->last_scan_res_used; i++) {
struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+ wpa_s->owe_transition_select = 1;
*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
- only_first_ssid);
+ only_first_ssid, 1);
+ wpa_s->owe_transition_select = 0;
if (!*selected_ssid)
continue;
wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
@@ -1258,6 +1604,17 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
{
if (wpas_network_disabled(wpa_s, ssid))
continue;
+#ifndef CONFIG_IBSS_RSN
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
+ WPA_KEY_MGMT_WPA_NONE))) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "IBSS RSN not supported in the build - cannot use the profile for SSID '%s'",
+ wpa_ssid_txt(ssid->ssid,
+ ssid->ssid_len));
+ continue;
+ }
+#endif /* !CONFIG_IBSS_RSN */
if (ssid->mode == IEEE80211_MODE_IBSS ||
ssid->mode == IEEE80211_MODE_AP ||
ssid->mode == IEEE80211_MODE_MESH)
@@ -1301,7 +1658,9 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
{
struct wpa_bss *current_bss = NULL;
#ifndef CONFIG_NO_ROAMING
- int min_diff;
+ int min_diff, diff;
+ int to_5ghz;
+ int cur_est, sel_est;
#endif /* CONFIG_NO_ROAMING */
if (wpa_s->reassociate)
@@ -1335,12 +1694,13 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
#ifndef CONFIG_NO_ROAMING
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
- " level=%d snr=%d est_throughput=%u",
- MAC2STR(current_bss->bssid), current_bss->level,
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ MAC2STR(current_bss->bssid),
+ current_bss->freq, current_bss->level,
current_bss->snr, current_bss->est_throughput);
wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR
- " level=%d snr=%d est_throughput=%u",
- MAC2STR(selected->bssid), selected->level,
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ MAC2STR(selected->bssid), selected->freq, selected->level,
selected->snr, selected->est_throughput);
if (wpa_s->current_ssid->bssid_set &&
@@ -1357,12 +1717,23 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
return 1;
}
- if (current_bss->level < 0 && current_bss->level > selected->level) {
+ to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
+
+ if (current_bss->level < 0 &&
+ current_bss->level > selected->level + to_5ghz * 2) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
"signal level");
return 0;
}
+ if (current_bss->est_throughput > selected->est_throughput + 5000) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - Current BSS has better estimated throughput");
+ return 0;
+ }
+
+ cur_est = current_bss->est_throughput;
+ sel_est = selected->est_throughput;
min_diff = 2;
if (current_bss->level < 0) {
if (current_bss->level < -85)
@@ -1375,13 +1746,42 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
min_diff = 4;
else
min_diff = 5;
+ if (cur_est > sel_est * 1.5)
+ min_diff += 10;
+ else if (cur_est > sel_est * 1.2)
+ min_diff += 5;
+ else if (cur_est > sel_est * 1.1)
+ min_diff += 2;
+ else if (cur_est > sel_est)
+ min_diff++;
+ }
+ if (to_5ghz) {
+ int reduce = 2;
+
+ /* Make it easier to move to 5 GHz band */
+ if (sel_est > cur_est * 1.5)
+ reduce = 5;
+ else if (sel_est > cur_est * 1.2)
+ reduce = 4;
+ else if (sel_est > cur_est * 1.1)
+ reduce = 3;
+
+ if (min_diff > reduce)
+ min_diff -= reduce;
+ else
+ min_diff = 0;
}
- if (abs(current_bss->level - selected->level) < min_diff) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
- "in signal level");
+ diff = abs(current_bss->level - selected->level);
+ if (diff < min_diff) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - too small difference in signal level (%d < %d)",
+ diff, min_diff);
return 0;
}
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Allow reassociation due to difference in signal level (%d >= %d)",
+ diff, min_diff);
return 1;
#else /* CONFIG_NO_ROAMING */
return 0;
@@ -1389,11 +1789,18 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
}
-/* Return != 0 if no scan results could be fetched or if scan results should not
- * be shared with other virtual interfaces. */
+/*
+ * Return a negative value if no scan results could be fetched or if scan
+ * results should not be shared with other virtual interfaces.
+ * Return 0 if scan results were fetched and may be shared with other
+ * interfaces.
+ * Return 1 if scan results may be shared with other virtual interfaces but may
+ * not trigger any operations.
+ * Return 2 if the interface was removed and cannot be used.
+ */
static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
union wpa_event_data *data,
- int own_request)
+ int own_request, int update_only)
{
struct wpa_scan_results *scan_res = NULL;
int ret = 0;
@@ -1418,6 +1825,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return -1;
if (!own_request)
return -1;
+ if (data && data->scan_info.external_scan)
+ return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
"scanning again");
wpa_supplicant_req_new_scan(wpa_s, 1, 0);
@@ -1441,15 +1850,20 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_NO_RANDOM_POOL */
+ if (update_only) {
+ ret = 1;
+ goto scan_work_done;
+ }
+
if (own_request && wpa_s->scan_res_handler &&
- (wpa_s->own_scan_running || !wpa_s->radio->external_scan_running)) {
+ !(data && data->scan_info.external_scan)) {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
scan_res_handler = wpa_s->scan_res_handler;
wpa_s->scan_res_handler = NULL;
scan_res_handler(wpa_s, scan_res);
- ret = -2;
+ ret = 1;
goto scan_work_done;
}
@@ -1463,9 +1877,11 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
}
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
- wpa_s->own_scan_running, wpa_s->radio->external_scan_running);
+ wpa_s->own_scan_running,
+ data ? data->scan_info.external_scan : 0);
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
- wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
+ wpa_s->manual_scan_use_id && wpa_s->own_scan_running &&
+ own_request && !(data && data->scan_info.external_scan)) {
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
wpa_s->manual_scan_id);
wpa_s->manual_scan_use_id = 0;
@@ -1476,7 +1892,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpas_notify_scan_done(wpa_s, 1);
- if (!wpa_s->own_scan_running && wpa_s->radio->external_scan_running) {
+ if (data && data->scan_info.external_scan) {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
wpa_scan_results_free(scan_res);
return 0;
@@ -1488,6 +1904,10 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
if (sme_proc_obss_scan(wpa_s) > 0)
goto scan_work_done;
+ if (own_request && data &&
+ wpas_beacon_rep_scan_process(wpa_s, scan_res, &data->scan_info) > 0)
+ goto scan_work_done;
+
if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)))
goto scan_work_done;
@@ -1505,9 +1925,13 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpas_wps_update_ap_info(wpa_s, scan_res);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+ wpa_s->wpa_state < WPA_COMPLETED)
+ goto scan_work_done;
+
wpa_scan_results_free(scan_res);
- if (wpa_s->scan_work) {
+ if (own_request && wpa_s->scan_work) {
struct wpa_radio_work *work = wpa_s->scan_work;
wpa_s->scan_work = NULL;
radio_work_done(work);
@@ -1517,7 +1941,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
scan_work_done:
wpa_scan_results_free(scan_res);
- if (wpa_s->scan_work) {
+ if (own_request && wpa_s->scan_work) {
struct wpa_radio_work *work = wpa_s->scan_work;
wpa_s->scan_work = NULL;
radio_work_done(work);
@@ -1546,8 +1970,17 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
if (wpa_s->p2p_mgmt)
return 0; /* no normal connection on p2p_mgmt interface */
+ wpa_s->owe_transition_search = 0;
selected = wpa_supplicant_pick_network(wpa_s, &ssid);
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Avoiding join because we already joined a mesh group");
+ return 0;
+ }
+#endif /* CONFIG_MESH */
+
if (selected) {
int skip;
skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
@@ -1557,6 +1990,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
return 0;
}
+ if (ssid != wpa_s->current_ssid &&
+ wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+
if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
return -1;
@@ -1564,18 +2004,12 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
if (new_scan)
wpa_supplicant_rsn_preauth_scan_results(wpa_s);
/*
- * Do not notify other virtual radios of scan results since we do not
- * want them to start other associations at the same time.
+ * Do not allow other virtual radios to trigger operations based
+ * on these scan results since we do not want them to start
+ * other associations at the same time.
*/
return 1;
} else {
-#ifdef CONFIG_MESH
- if (wpa_s->ifmsh) {
- wpa_msg(wpa_s, MSG_INFO,
- "Avoiding join because we already joined a mesh group");
- return 0;
- }
-#endif /* CONFIG_MESH */
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -1638,6 +2072,17 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
return 0;
}
#endif /* CONFIG_WPS */
+#ifdef CONFIG_OWE
+ if (wpa_s->owe_transition_search) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "OWE: Use shorter wait during transition mode search");
+ timeout_sec = 0;
+ timeout_usec = 500000;
+ wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+ timeout_usec);
+ return 0;
+ }
+#endif /* CONFIG_OWE */
if (wpa_supplicant_req_sched_scan(wpa_s))
wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
timeout_usec);
@@ -1656,7 +2101,7 @@ static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
struct wpa_supplicant *ifs;
int res;
- res = _wpa_supplicant_event_scan_results(wpa_s, data, 1);
+ res = _wpa_supplicant_event_scan_results(wpa_s, data, 1, 0);
if (res == 2) {
/*
* Interface may have been removed, so must not dereference
@@ -1664,7 +2109,8 @@ static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
*/
return 1;
}
- if (res != 0) {
+
+ if (res < 0) {
/*
* If no scan results could be fetched, then no need to
* notify those interfaces that did not actually request
@@ -1684,7 +2130,10 @@ static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
if (ifs != wpa_s) {
wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
"sibling", ifs->ifname);
- _wpa_supplicant_event_scan_results(ifs, data, 0);
+ res = _wpa_supplicant_event_scan_results(ifs, data, 0,
+ res > 0);
+ if (res < 0)
+ return 0;
}
}
@@ -1701,6 +2150,8 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
#else /* CONFIG_NO_SCAN_PROCESSING */
struct os_reltime now;
+ wpa_s->ignore_post_flush_scan_res = 0;
+
if (wpa_s->last_scan_res_used == 0)
return -1;
@@ -1831,14 +2282,109 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_INTERWORKING */
+static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+ const u8 *map_sub_elem, *pos;
+ size_t len;
+
+ if (!wpa_s->current_ssid ||
+ !wpa_s->current_ssid->multi_ap_backhaul_sta ||
+ !ies ||
+ ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+ if (!elems.multi_ap || elems.multi_ap_len < 7) {
+ wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
+ goto fail;
+ }
+
+ pos = elems.multi_ap + 4;
+ len = elems.multi_ap_len - 4;
+
+ map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
+ if (!map_sub_elem || map_sub_elem[1] < 1) {
+ wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
+ goto fail;
+ }
+
+ if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
+ if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) &&
+ wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+ wpa_printf(MSG_INFO,
+ "WPS active, accepting fronthaul-only BSS");
+ /* Don't set 4addr mode in this case, so just return */
+ return;
+ }
+ wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS");
+ goto fail;
+ }
+
+ if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to set 4addr mode");
+ goto fail;
+ }
+ wpa_s->enabled_4addr_mode = 1;
+ return;
+
+fail:
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+}
+
+
+#ifdef CONFIG_FST
+static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
+ const u8 *ie, size_t ie_len)
+{
+ struct mb_ies_info mb_ies;
+
+ if (!ie || !ie_len || !wpa_s->fst)
+ return -ENOENT;
+
+ os_memset(&mb_ies, 0, sizeof(mb_ies));
+
+ while (ie_len >= 2 && mb_ies.nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
+ size_t len;
+
+ len = 2 + ie[1];
+ if (len > ie_len) {
+ wpa_hexdump(MSG_DEBUG, "FST: Truncated IE found",
+ ie, ie_len);
+ break;
+ }
+
+ if (ie[0] == WLAN_EID_MULTI_BAND) {
+ wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
+ (unsigned int) len);
+ mb_ies.ies[mb_ies.nof_ies].ie = ie + 2;
+ mb_ies.ies[mb_ies.nof_ies].ie_len = len - 2;
+ mb_ies.nof_ies++;
+ }
+
+ ie_len -= len;
+ ie += len;
+ }
+
+ if (mb_ies.nof_ies > 0) {
+ wpabuf_free(wpa_s->received_mb_ies);
+ wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+#endif /* CONFIG_FST */
+
+
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
int l, len, found = 0, wpa_found, rsn_found;
const u8 *p;
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
if (data->assoc_info.req_ies)
@@ -1859,6 +2405,13 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_INTERWORKING */
+ if (wpa_s->hw_capab == CAPAB_VHT &&
+ get_ie(data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
+ wpa_s->ieee80211ac = 1;
+
+ multi_ap_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
}
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -1868,6 +2421,26 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz",
data->assoc_info.freq);
+ wpa_s->connection_set = 0;
+ if (data->assoc_info.req_ies && data->assoc_info.resp_ies) {
+ struct ieee802_11_elems req_elems, resp_elems;
+
+ if (ieee802_11_parse_elems(data->assoc_info.req_ies,
+ data->assoc_info.req_ies_len,
+ &req_elems, 0) != ParseFailed &&
+ ieee802_11_parse_elems(data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ &resp_elems, 0) != ParseFailed) {
+ wpa_s->connection_set = 1;
+ wpa_s->connection_ht = req_elems.ht_capabilities &&
+ resp_elems.ht_capabilities;
+ wpa_s->connection_vht = req_elems.vht_capabilities &&
+ resp_elems.vht_capabilities;
+ wpa_s->connection_he = req_elems.he_capabilities &&
+ resp_elems.he_capabilities;
+ }
+ }
+
p = data->assoc_info.req_ies;
l = data->assoc_info.req_ies_len;
@@ -1881,6 +2454,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
}
if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
(os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
(p[0] == WLAN_EID_RSN && p[1] >= 2)) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
@@ -1894,6 +2469,58 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+#ifdef CONFIG_FILS
+#ifdef CONFIG_SME
+ if ((wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
+ wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS) &&
+ (!data->assoc_info.resp_frame ||
+ fils_process_assoc_resp(wpa_s->wpa,
+ data->assoc_info.resp_frame,
+ data->assoc_info.resp_frame_len) < 0)) {
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+ return -1;
+ }
+#endif /* CONFIG_SME */
+
+ /* Additional processing for FILS when SME is in driver */
+ if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+ wpa_sm_set_reset_fils_completed(wpa_s->wpa, 1);
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+ (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ owe_process_assoc_resp(wpa_s->wpa, bssid,
+ data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len) < 0)) {
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+ return -1;
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ wpa_sm_set_dpp_z(wpa_s->wpa, NULL);
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->dpp_pfs) {
+ struct ieee802_11_elems elems;
+
+ if (ieee802_11_parse_elems(data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ &elems, 0) == ParseFailed ||
+ !elems.owe_dh)
+ goto no_pfs;
+ if (dpp_pfs_process(wpa_s->dpp_pfs, elems.owe_dh,
+ elems.owe_dh_len) < 0) {
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_UNSPECIFIED);
+ return -1;
+ }
+
+ wpa_sm_set_dpp_z(wpa_s->wpa, wpa_s->dpp_pfs->secret);
+ }
+no_pfs:
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
@@ -2013,19 +2640,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
-#ifdef CONFIG_FST
- wpabuf_free(wpa_s->received_mb_ies);
- wpa_s->received_mb_ies = NULL;
- if (wpa_s->fst) {
- struct mb_ies_info mb_ies;
-
- wpa_printf(MSG_DEBUG, "Looking for MB IE");
- if (!mb_ies_info_by_ies(&mb_ies, data->assoc_info.resp_ies,
- data->assoc_info.resp_ies_len))
- wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies);
- }
-#endif /* CONFIG_FST */
-
if (wpa_s->assoc_freq && data->assoc_info.freq &&
wpa_s->assoc_freq != data->assoc_info.freq) {
wpa_printf(MSG_DEBUG, "Operating frequency changed from "
@@ -2064,11 +2678,50 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
}
+static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+#ifdef CONFIG_FST
+ struct assoc_info *ai = data ? &data->assoc_info : NULL;
+ struct wpa_bss *bss = wpa_s->current_bss;
+ const u8 *ieprb, *iebcn;
+
+ wpabuf_free(wpa_s->received_mb_ies);
+ wpa_s->received_mb_ies = NULL;
+
+ if (ai &&
+ !wpas_fst_update_mbie(wpa_s, ai->resp_ies, ai->resp_ies_len)) {
+ wpa_printf(MSG_DEBUG,
+ "FST: MB IEs updated from Association Response frame");
+ return;
+ }
+
+ if (ai &&
+ !wpas_fst_update_mbie(wpa_s, ai->beacon_ies, ai->beacon_ies_len)) {
+ wpa_printf(MSG_DEBUG,
+ "FST: MB IEs updated from association event Beacon IEs");
+ return;
+ }
+
+ if (!bss)
+ return;
+
+ ieprb = (const u8 *) (bss + 1);
+ iebcn = ieprb + bss->ie_len;
+
+ if (!wpas_fst_update_mbie(wpa_s, ieprb, bss->ie_len))
+ wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss IE");
+ else if (!wpas_fst_update_mbie(wpa_s, iebcn, bss->beacon_ie_len))
+ wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss beacon IE");
+#endif /* CONFIG_FST */
+}
+
+
static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
u8 bssid[ETH_ALEN];
- int ft_completed;
+ int ft_completed, already_authorized;
int new_bss = 0;
#ifdef CONFIG_AP
@@ -2089,6 +2742,13 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
ft_completed = wpa_ft_is_completed(wpa_s->wpa);
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
return;
+ /*
+ * FILS authentication can share the same mechanism to mark the
+ * connection fully authenticated, so set ft_completed also based on
+ * FILS result.
+ */
+ if (!ft_completed)
+ ft_completed = wpa_fils_is_completed(wpa_s->wpa);
if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
@@ -2099,6 +2759,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ if (os_reltime_initialized(&wpa_s->session_start)) {
+ os_reltime_age(&wpa_s->session_start,
+ &wpa_s->session_length);
+ wpa_s->session_start.sec = 0;
+ wpa_s->session_start.usec = 0;
+ wpas_notify_session_length(wpa_s);
+ } else {
+ wpas_notify_auth_changed(wpa_s);
+ os_get_reltime(&wpa_s->session_start);
+ }
wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
MACSTR, MAC2STR(bssid));
new_bss = 1;
@@ -2124,6 +2794,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
"WPA/RSN IEs not updated");
}
+ wpas_fst_update_mb_assoc(wpa_s, data);
+
#ifdef CONFIG_SME
os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
wpa_s->sme.prev_bssid_set = 1;
@@ -2142,6 +2814,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
if (wpa_s->l2)
l2_packet_notify_auth_start(wpa_s->l2);
+ already_authorized = data && data->assoc_info.authorized;
+
/*
* Set portEnabled first to FALSE in order to get EAP state machine out
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
@@ -2150,11 +2824,14 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
* AUTHENTICATED without ever giving chance to EAP state machine to
* reset the state.
*/
- if (!ft_completed) {
+ if (!ft_completed && !already_authorized) {
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
}
- if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed)
+ if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE || ft_completed ||
+ already_authorized)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
/* 802.1X::portControl = Auto */
eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -2182,8 +2859,17 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
}
wpa_supplicant_cancel_scan(wpa_s);
- if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
- wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+ if (ft_completed) {
+ /*
+ * FT protocol completed - make sure EAPOL state machine ends
+ * up in authenticated.
+ */
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
+ wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
/*
* We are done; the driver will take care of RSN 4-way
* handshake.
@@ -2192,7 +2878,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
- } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
* The driver will take care of RSN 4-way handshake, so we need
@@ -2200,15 +2886,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
* waiting for WPA supplicant.
*/
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- } else if (ft_completed) {
- /*
- * FT protocol completed - make sure EAPOL state machine ends
- * up in authenticated.
- */
- wpa_supplicant_cancel_auth_timeout(wpa_s);
- wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
}
wpa_s->last_eapol_matches_bssid = 0;
@@ -2217,7 +2894,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
struct os_reltime now, age;
os_get_reltime(&now);
os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
- if (age.sec == 0 && age.usec < 100000 &&
+ if (age.sec == 0 && age.usec < 200000 &&
os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
@@ -2246,7 +2923,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE &&
wpa_s->ibss_rsn == NULL) {
- wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
+ wpa_s->ibss_rsn = ibss_rsn_init(wpa_s, wpa_s->current_ssid);
if (!wpa_s->ibss_rsn) {
wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
wpa_supplicant_deauthenticate(
@@ -2268,6 +2945,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
if (wpa_s->reassoc_same_bss)
wmm_ac_restore_tspecs(wpa_s);
}
+
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) {
+ struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
+ const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
+
+ if (fils_cache_id)
+ wpa_sm_set_fils_cache_id(wpa_s->wpa, fils_cache_id);
+ }
+#endif /* CONFIG_FILS */
}
@@ -2340,6 +3027,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
struct wpa_bss *fast_reconnect = NULL;
struct wpa_ssid *fast_reconnect_ssid = NULL;
struct wpa_ssid *last_ssid;
+ struct wpa_bss *curr = NULL;
authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@@ -2355,6 +3043,19 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
return;
}
+ if (!wpa_s->disconnected && wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+ reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY &&
+ locally_generated)
+ /*
+ * Remove the inactive AP (which is probably out of range) from
+ * the BSS list after marking disassociation. In particular
+ * mac80211-based drivers use the
+ * WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY reason code in
+ * locally generated disconnection events for cases where the
+ * AP does not reply anymore.
+ */
+ curr = wpa_s->current_bss;
+
if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
"pre-shared key may be incorrect");
@@ -2365,7 +3066,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS ||
- wpas_wps_searching(wpa_s))) {
+ wpas_wps_searching(wpa_s) ||
+ wpas_wps_reenable_networks_pending(wpa_s))) {
wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
"reconnect (wps=%d/%d wpa_state=%d)",
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
@@ -2415,6 +3117,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
last_ssid = wpa_s->current_ssid;
wpa_supplicant_mark_disassoc(wpa_s);
+ if (curr)
+ wpa_bss_remove(wpa_s, curr, "Connection to AP lost");
+
if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
wpa_s->current_ssid = last_ssid;
@@ -2425,7 +3130,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
!disallowed_bssid(wpa_s, fast_reconnect->bssid) &&
!disallowed_ssid(wpa_s, fast_reconnect->ssid,
fast_reconnect->ssid_len) &&
- !wpas_temp_disabled(wpa_s, fast_reconnect_ssid)) {
+ !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
+ !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) {
#ifndef CONFIG_NO_SCAN_PROCESSING
wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
if (wpa_supplicant_connect(wpa_s, fast_reconnect,
@@ -2623,6 +3329,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_s->matched) {
+ wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+ break;
+ }
+#endif /* CONFIG_MATCH_IFACE */
+
#ifdef CONFIG_TERMINATE_ONLASTIF
/* check if last interface */
if (!any_interfaces(wpa_s->global->ifaces))
@@ -2633,18 +3346,6 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
}
-#ifdef CONFIG_PEERKEY
-static void
-wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
-{
- if (data == NULL)
- return;
- wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
-}
-#endif /* CONFIG_PEERKEY */
-
-
#ifdef CONFIG_TDLS
static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
@@ -3003,15 +3704,28 @@ static const char * reg_type_str(enum reg_type type)
}
-static void wpa_supplicant_update_channel_list(
- struct wpa_supplicant *wpa_s, struct channel_list_changed *info)
+void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
+ struct channel_list_changed *info)
{
struct wpa_supplicant *ifs;
+ u8 dfs_domain;
+
+ /*
+ * To allow backwards compatibility with higher level layers that
+ * assumed the REGDOM_CHANGE event is sent over the initially added
+ * interface. Find the highest parent of this interface and use it to
+ * send the event.
+ */
+ for (ifs = wpa_s; ifs->parent && ifs != ifs->parent; ifs = ifs->parent)
+ ;
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
- reg_init_str(info->initiator), reg_type_str(info->type),
- info->alpha2[0] ? " alpha2=" : "",
- info->alpha2[0] ? info->alpha2 : "");
+ if (info) {
+ wpa_msg(ifs, MSG_INFO,
+ WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
+ reg_init_str(info->initiator), reg_type_str(info->type),
+ info->alpha2[0] ? " alpha2=" : "",
+ info->alpha2[0] ? info->alpha2 : "");
+ }
if (wpa_s->drv_priv == NULL)
return; /* Ignore event during drv initialization */
@@ -3022,15 +3736,17 @@ static void wpa_supplicant_update_channel_list(
ifs->ifname);
free_hw_features(ifs);
ifs->hw.modes = wpa_drv_get_hw_feature_data(
- ifs, &ifs->hw.num_modes, &ifs->hw.flags);
- }
-
- /* Restart sched_scan with updated channel list */
- if (wpa_s->sched_scanning) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Channel list changed restart sched scan.");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ ifs, &ifs->hw.num_modes, &ifs->hw.flags, &dfs_domain);
+
+ /* Restart PNO/sched_scan with updated channel list */
+ if (ifs->pno) {
+ wpas_stop_pno(ifs);
+ wpas_start_pno(ifs);
+ } else if (ifs->sched_scanning && !ifs->pno_sched_pending) {
+ wpa_dbg(ifs, MSG_DEBUG,
+ "Channel list changed - restart sched_scan");
+ wpas_scan_restart_sched_scan(ifs);
+ }
}
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DRIVER);
@@ -3095,6 +3811,15 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
return;
#endif /* CONFIG_GAS */
+#ifdef CONFIG_GAS_SERVER
+ if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC ||
+ mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) &&
+ gas_server_rx(wpa_s->gas_server, mgmt->da, mgmt->sa, mgmt->bssid,
+ mgmt->u.action.category,
+ payload, plen, freq) == 0)
+ return;
+#endif /* CONFIG_GAS_SERVER */
+
#ifdef CONFIG_TDLS
if (category == WLAN_ACTION_PUBLIC && plen >= 4 &&
payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
@@ -3121,6 +3846,15 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_INTERWORKING */
if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+ payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) {
+ wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa,
+ mgmt->da,
+ payload + 1,
+ plen - 1);
+ return;
+ }
+
+ if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1);
return;
@@ -3141,6 +3875,18 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_FST */
+#ifdef CONFIG_DPP
+ if (category == WLAN_ACTION_PUBLIC && plen >= 5 &&
+ payload[0] == WLAN_PA_VENDOR_SPECIFIC &&
+ WPA_GET_BE24(&payload[1]) == OUI_WFA &&
+ payload[4] == DPP_OUI_TYPE) {
+ payload++;
+ plen--;
+ wpas_dpp_rx_action(wpa_s, mgmt->sa, payload, plen, freq);
+ return;
+ }
+#endif /* CONFIG_DPP */
+
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
category, payload, plen, freq);
if (wpa_s->ifmsh)
@@ -3181,23 +3927,252 @@ static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s,
}
-static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s)
{
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Connection authorized by device, previous state %d",
- wpa_s->wpa_state);
if (wpa_s->wpa_state == WPA_ASSOCIATED) {
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
}
+}
+
+
+static unsigned int wpas_event_cac_ms(const struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ size_t i;
+ int j;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ const struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+
+ for (j = 0; j < mode->num_channels; j++) {
+ const struct hostapd_channel_data *chan;
+
+ chan = &mode->channels[j];
+ if (chan->freq == freq)
+ return chan->dfs_cac_ms;
+ }
+ }
+
+ return 0;
+}
+
+
+static void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
+ wpas_ap_event_dfs_cac_started(wpa_s, radar);
+ } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+ {
+ unsigned int cac_time = wpas_event_cac_ms(wpa_s, radar->freq);
+
+ cac_time /= 1000; /* convert from ms to sec */
+ if (!cac_time)
+ cac_time = 10 * 60; /* max timeout: 10 minutes */
+
+ /* Restart auth timeout: CAC time added to initial timeout */
+ wpas_auth_timeout_restart(wpa_s, cac_time);
+ }
+}
+
+
+static void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
+ wpas_ap_event_dfs_cac_finished(wpa_s, radar);
+ } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+ {
+ /* Restart auth timeout with original value after CAC is
+ * finished */
+ wpas_auth_timeout_restart(wpa_s, 0);
+ }
+}
+
+
+static void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
+ wpas_ap_event_dfs_cac_aborted(wpa_s, radar);
+ } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+ {
+ /* Restart auth timeout with original value after CAC is
+ * aborted */
+ wpas_auth_timeout_restart(wpa_s, 0);
+ }
+}
+
+
+static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Connection authorized by device, previous state %d",
+ wpa_s->wpa_state);
+
+ wpa_supplicant_event_port_authorized(wpa_s);
+
wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr);
wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck,
data->assoc_info.ptk_kck_len,
data->assoc_info.ptk_kek,
data->assoc_info.ptk_kek_len);
+#ifdef CONFIG_FILS
+ if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) {
+ struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+ const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
+
+ /* Update ERP next sequence number */
+ eapol_sm_update_erp_next_seq_num(
+ wpa_s->eapol, data->assoc_info.fils_erp_next_seq_num);
+
+ if (data->assoc_info.fils_pmk && data->assoc_info.fils_pmkid) {
+ /* Add the new PMK and PMKID to the PMKSA cache */
+ wpa_sm_pmksa_cache_add(wpa_s->wpa,
+ data->assoc_info.fils_pmk,
+ data->assoc_info.fils_pmk_len,
+ data->assoc_info.fils_pmkid,
+ wpa_s->bssid, fils_cache_id);
+ } else if (data->assoc_info.fils_pmkid) {
+ /* Update the current PMKSA used for this connection */
+ pmksa_cache_set_current(wpa_s->wpa,
+ data->assoc_info.fils_pmkid,
+ NULL, NULL, 0, NULL, 0);
+ }
+ }
+#endif /* CONFIG_FILS */
+}
+
+
+static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ const u8 *bssid = data->assoc_reject.bssid;
+
+ if (!bssid || is_zero_ether_addr(bssid))
+ bssid = wpa_s->pending_bssid;
+
+ if (data->assoc_reject.bssid)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+ "bssid=" MACSTR " status_code=%u%s%s%s",
+ MAC2STR(data->assoc_reject.bssid),
+ data->assoc_reject.status_code,
+ data->assoc_reject.timed_out ? " timeout" : "",
+ data->assoc_reject.timeout_reason ? "=" : "",
+ data->assoc_reject.timeout_reason ?
+ data->assoc_reject.timeout_reason : "");
+ else
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+ "status_code=%u%s%s%s",
+ data->assoc_reject.status_code,
+ data->assoc_reject.timed_out ? " timeout" : "",
+ data->assoc_reject.timeout_reason ? "=" : "",
+ data->assoc_reject.timeout_reason ?
+ data->assoc_reject.timeout_reason : "");
+ wpa_s->assoc_status_code = data->assoc_reject.status_code;
+ wpas_notify_assoc_status_code(wpa_s);
+
+#ifdef CONFIG_OWE
+ if (data->assoc_reject.status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+ wpa_s->current_ssid &&
+ wpa_s->current_ssid->owe_group == 0 &&
+ wpa_s->last_owe_group != 21) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_bss *bss = wpa_s->current_bss;
+
+ if (!bss) {
+ bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+ if (!bss) {
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ return;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "OWE: Try next supported DH group");
+ wpas_connect_work_done(wpa_s);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ return;
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_MBO
+ if (data->assoc_reject.status_code ==
+ WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+ wpa_s->current_bss && data->assoc_reject.bssid &&
+ data->assoc_reject.resp_ies) {
+ const u8 *rssi_rej;
+
+ rssi_rej = mbo_get_attr_from_ies(
+ data->assoc_reject.resp_ies,
+ data->assoc_reject.resp_ies_len,
+ OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT);
+ if (rssi_rej && rssi_rej[1] == 2) {
+ wpa_printf(MSG_DEBUG,
+ "OCE: RSSI-based association rejection from "
+ MACSTR " (Delta RSSI: %u, Retry Delay: %u)",
+ MAC2STR(data->assoc_reject.bssid),
+ rssi_rej[2], rssi_rej[3]);
+ wpa_bss_tmp_disallow(wpa_s,
+ data->assoc_reject.bssid,
+ rssi_rej[3],
+ rssi_rej[2] +
+ wpa_s->current_bss->level);
+ }
+ }
+#endif /* CONFIG_MBO */
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+ sme_event_assoc_reject(wpa_s, data);
+ return;
+ }
+
+ /* Driver-based SME cases */
+
+#ifdef CONFIG_SAE
+ if (wpa_s->current_ssid &&
+ wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt) &&
+ !data->assoc_reject.timed_out) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SAE: Drop PMKSA cache entry");
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_DPP
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+ !data->assoc_reject.timed_out) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "DPP: Drop PMKSA cache entry");
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_FILS
+ /* Update ERP next sequence number */
+ if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) {
+ eapol_sm_update_erp_next_seq_num(
+ wpa_s->eapol,
+ data->assoc_reject.fils_erp_next_seq_num);
+ fils_connection_failure(wpa_s);
+ }
+#endif /* CONFIG_FILS */
+
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
}
@@ -3206,10 +4181,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
{
struct wpa_supplicant *wpa_s = ctx;
int resched;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ int level = MSG_DEBUG;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
event != EVENT_INTERFACE_ENABLED &&
event != EVENT_INTERFACE_STATUS &&
+ event != EVENT_SCAN_RESULTS &&
event != EVENT_SCHED_SCAN_STOPPED) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Ignore event %s (%d) while interface is disabled",
@@ -3218,9 +4197,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#ifndef CONFIG_NO_STDOUT_DEBUG
-{
- int level = MSG_DEBUG;
-
if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
@@ -3233,23 +4209,63 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_dbg(wpa_s, level, "Event %s (%d) received",
event_to_string(event), event);
-}
#endif /* CONFIG_NO_STDOUT_DEBUG */
switch (event) {
case EVENT_AUTH:
+#ifdef CONFIG_FST
+ if (!wpas_fst_update_mbie(wpa_s, data->auth.ies,
+ data->auth.ies_len))
+ wpa_printf(MSG_DEBUG,
+ "FST: MB IEs updated from auth IE");
+#endif /* CONFIG_FST */
sme_event_auth(wpa_s, data);
+ wpa_s->auth_status_code = data->auth.status_code;
+ wpas_notify_auth_status_code(wpa_s);
break;
case EVENT_ASSOC:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO,
+ "EVENT_ASSOC - ignore_auth_resp active!");
+ break;
+ }
+ if (wpa_s->testing_resend_assoc) {
+ wpa_printf(MSG_INFO,
+ "EVENT_DEAUTH - testing_resend_assoc");
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_supplicant_event_assoc(wpa_s, data);
- if (data && data->assoc_info.authorized)
+ wpa_s->assoc_status_code = WLAN_STATUS_SUCCESS;
+ if (data &&
+ (data->assoc_info.authorized ||
+ (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ wpa_fils_is_completed(wpa_s->wpa))))
wpa_supplicant_event_assoc_auth(wpa_s, data);
+ if (data) {
+ wpa_msg(wpa_s, MSG_INFO,
+ WPA_EVENT_SUBNET_STATUS_UPDATE "status=%u",
+ data->assoc_info.subnet_status);
+ }
break;
case EVENT_DISASSOC:
wpas_event_disassoc(wpa_s,
data ? &data->disassoc_info : NULL);
break;
case EVENT_DEAUTH:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO,
+ "EVENT_DEAUTH - ignore_auth_resp active!");
+ break;
+ }
+ if (wpa_s->testing_resend_assoc) {
+ wpa_printf(MSG_INFO,
+ "EVENT_DEAUTH - testing_resend_assoc");
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpas_event_deauth(wpa_s,
data ? &data->deauth_info : NULL);
break;
@@ -3258,10 +4274,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
#ifndef CONFIG_NO_SCAN_PROCESSING
case EVENT_SCAN_STARTED:
- os_get_reltime(&wpa_s->scan_start_time);
- if (wpa_s->own_scan_requested) {
+ if (wpa_s->own_scan_requested ||
+ (data && !data->scan_info.external_scan)) {
struct os_reltime diff;
+ os_get_reltime(&wpa_s->scan_start_time);
os_reltime_sub(&wpa_s->scan_start_time,
&wpa_s->scan_trigger_time, &diff);
wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds",
@@ -3284,7 +4301,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
break;
case EVENT_SCAN_RESULTS:
- if (os_reltime_initialized(&wpa_s->scan_start_time)) {
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ wpa_s->scan_res_handler = NULL;
+ wpa_s->own_scan_running = 0;
+ wpa_s->radio->external_scan_running = 0;
+ wpa_s->last_scan_req = NORMAL_SCAN_REQ;
+ break;
+ }
+
+ if (!(data && data->scan_info.external_scan) &&
+ os_reltime_initialized(&wpa_s->scan_start_time)) {
struct os_reltime now, diff;
os_get_reltime(&now);
os_reltime_sub(&now, &wpa_s->scan_start_time, &diff);
@@ -3295,8 +4321,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
if (wpa_supplicant_event_scan_results(wpa_s, data))
break; /* interface may have been removed */
- wpa_s->own_scan_running = 0;
- wpa_s->radio->external_scan_running = 0;
+ if (!(data && data->scan_info.external_scan))
+ wpa_s->own_scan_running = 0;
+ if (data && data->scan_info.nl_scan_event)
+ wpa_s->radio->external_scan_running = 0;
radio_work_check_next(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -3309,11 +4337,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
case EVENT_PMKID_CANDIDATE:
wpa_supplicant_event_pmkid_candidate(wpa_s, data);
break;
-#ifdef CONFIG_PEERKEY
- case EVENT_STKSTART:
- wpa_supplicant_event_stkstart(wpa_s, data);
- break;
-#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_TDLS
case EVENT_TDLS:
wpa_supplicant_event_tdls(wpa_s, data);
@@ -3335,24 +4358,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
#endif /* CONFIG_IBSS_RSN */
case EVENT_ASSOC_REJECT:
- if (data->assoc_reject.bssid)
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "bssid=" MACSTR " status_code=%u",
- MAC2STR(data->assoc_reject.bssid),
- data->assoc_reject.status_code);
- else
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "status_code=%u",
- data->assoc_reject.status_code);
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
- sme_event_assoc_reject(wpa_s, data);
- else {
- const u8 *bssid = data->assoc_reject.bssid;
- if (bssid == NULL || is_zero_ether_addr(bssid))
- bssid = wpa_s->pending_bssid;
- wpas_connection_failed(wpa_s, bssid);
- wpa_supplicant_mark_disassoc(wpa_s);
- }
+ wpas_event_assoc_reject(wpa_s, data);
break;
case EVENT_AUTH_TIMED_OUT:
/* It is possible to get this event from earlier connection */
@@ -3399,17 +4405,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
#ifdef CONFIG_OFFCHANNEL
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
- MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
+ MACSTR, MAC2STR(wpa_s->p2pdev->pending_action_dst));
/*
* Catch TX status events for Action frames we sent via group
- * interface in GO mode.
+ * interface in GO mode, or via standalone AP interface.
+ * Note, wpa_s->p2pdev will be the same as wpa_s->parent,
+ * except when the primary interface is used as a GO interface
+ * (for drivers which do not have group interface concurrency)
*/
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
- os_memcmp(wpa_s->parent->pending_action_dst,
+ os_memcmp(wpa_s->p2pdev->pending_action_dst,
data->tx_status.dst, ETH_ALEN) == 0) {
offchannel_send_action_tx_status(
- wpa_s->parent, data->tx_status.dst,
+ wpa_s->p2pdev, data->tx_status.dst,
data->tx_status.data,
data->tx_status.data_len,
data->tx_status.ack ?
@@ -3451,27 +4460,58 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
data->rx_from_unknown.wds);
break;
+#endif /* CONFIG_AP */
case EVENT_CH_SWITCH:
- if (!data)
- break;
- if (!wpa_s->ap_iface) {
- wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch "
- "event in non-AP mode");
+ if (!data || !wpa_s->current_ssid)
break;
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH
+ "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+ data->ch_switch.freq,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset,
+ channel_width_to_string(data->ch_switch.ch_width),
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
+
+ wpa_s->assoc_freq = data->ch_switch.freq;
+ wpa_s->current_ssid->frequency = data->ch_switch.freq;
+
+#ifdef CONFIG_AP
+ if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
+ wpa_s->current_ssid->mode == WPAS_MODE_MESH ||
+ wpa_s->current_ssid->mode ==
+ WPAS_MODE_P2P_GROUP_FORMATION) {
+ wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset,
+ data->ch_switch.ch_width,
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
}
+#endif /* CONFIG_AP */
- wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
- data->ch_switch.ht_enabled,
- data->ch_switch.ch_offset,
- data->ch_switch.ch_width,
- data->ch_switch.cf1,
- data->ch_switch.cf2);
+#ifdef CONFIG_IEEE80211W
+ sme_event_ch_switch(wpa_s);
+#endif /* CONFIG_IEEE80211W */
+ wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
+ wnm_clear_coloc_intf_reporting(wpa_s);
break;
+#ifdef CONFIG_AP
#ifdef NEED_AP_MLME
case EVENT_DFS_RADAR_DETECTED:
if (data)
- wpas_event_dfs_radar_detected(wpa_s, &data->dfs_event);
+ wpas_ap_event_dfs_radar_detected(wpa_s,
+ &data->dfs_event);
+ break;
+ case EVENT_DFS_NOP_FINISHED:
+ if (data)
+ wpas_ap_event_dfs_cac_nop_finished(wpa_s,
+ &data->dfs_event);
break;
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_AP */
case EVENT_DFS_CAC_STARTED:
if (data)
wpas_event_dfs_cac_started(wpa_s, &data->dfs_event);
@@ -3484,13 +4524,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (data)
wpas_event_dfs_cac_aborted(wpa_s, &data->dfs_event);
break;
- case EVENT_DFS_NOP_FINISHED:
- if (data)
- wpas_event_dfs_cac_nop_finished(wpa_s,
- &data->dfs_event);
- break;
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_AP */
case EVENT_RX_MGMT: {
u16 fc, stype;
const struct ieee80211_mgmt *mgmt;
@@ -3522,12 +4555,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
#ifdef CONFIG_P2P
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
- data->rx_mgmt.frame_len > 24) {
+ data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
const u8 *src = mgmt->sa;
- const u8 *ie = mgmt->u.probe_req.variable;
- size_t ie_len = data->rx_mgmt.frame_len -
- (mgmt->u.probe_req.variable -
- data->rx_mgmt.frame);
+ const u8 *ie;
+ size_t ie_len;
+
+ ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+ ie_len = data->rx_mgmt.frame_len -
+ IEEE80211_HDRLEN;
wpas_p2p_probe_req_rx(
wpa_s, src, mgmt->da,
mgmt->bssid, ie, ie_len,
@@ -3560,6 +4595,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
+#ifdef CONFIG_SAE
+ if (stype == WLAN_FC_STYPE_AUTH &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+ sme_external_auth_mgmt_rx(
+ wpa_s, data->rx_mgmt.frame,
+ data->rx_mgmt.frame_len);
+ break;
+ }
+#endif /* CONFIG_SAE */
wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
"management frame in non-AP mode");
break;
@@ -3567,11 +4612,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
- data->rx_mgmt.frame_len > 24) {
- const u8 *ie = mgmt->u.probe_req.variable;
- size_t ie_len = data->rx_mgmt.frame_len -
- (mgmt->u.probe_req.variable -
- data->rx_mgmt.frame);
+ data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
+ const u8 *ie;
+ size_t ie_len;
+
+ ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+ ie_len = data->rx_mgmt.frame_len - IEEE80211_HDRLEN;
wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
mgmt->bssid, ie, ie_len,
@@ -3623,6 +4669,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_OFFCHANNEL */
wpas_p2p_cancel_remain_on_channel_cb(
wpa_s, data->remain_on_channel.freq);
+#ifdef CONFIG_DPP
+ wpas_dpp_cancel_remain_on_channel_cb(
+ wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_DPP */
break;
case EVENT_EAPOL_RX:
wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
@@ -3644,6 +4694,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->signal_change.current_noise,
data->signal_change.current_txrate);
break;
+ case EVENT_INTERFACE_MAC_CHANGED:
+ wpa_supplicant_update_mac_addr(wpa_s);
+ break;
case EVENT_INTERFACE_ENABLED:
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
@@ -3714,6 +4767,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
}
wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_bss_flush(wpa_s);
radio_remove_works(wpa_s, NULL, 0);
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -3772,15 +4826,28 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->driver_gtk_rekey.replay_ctr);
break;
case EVENT_SCHED_SCAN_STOPPED:
- wpa_s->pno = 0;
wpa_s->sched_scanning = 0;
- resched = wpa_s->scanning;
+ resched = wpa_s->scanning && wpas_scan_scheduled(wpa_s);
wpa_supplicant_notify_scanning(wpa_s, 0);
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
break;
/*
+ * If the driver stopped scanning without being requested to,
+ * request a new scan to continue scanning for networks.
+ */
+ if (!wpa_s->sched_scan_stop_req &&
+ wpa_s->wpa_state == WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Restart scanning after unexpected sched_scan stop event");
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ break;
+ }
+
+ wpa_s->sched_scan_stop_req = 0;
+
+ /*
* Start a new sched scan to continue searching for more SSIDs
* either if timed out or PNO schedule scan is pending.
*/
@@ -3796,7 +4863,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
case EVENT_WPS_BUTTON_PUSHED:
#ifdef CONFIG_WPS
- wpas_wps_start_pbc(wpa_s, NULL, 0);
+ wpas_wps_start_pbc(wpa_s, NULL, 0, 0);
#endif /* CONFIG_WPS */
break;
case EVENT_AVOID_FREQUENCIES:
@@ -3821,8 +4888,104 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->mesh_peer.ie_len);
#endif /* CONFIG_MESH */
break;
+ case EVENT_SURVEY:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface)
+ break;
+ hostapd_event_get_survey(wpa_s->ap_iface,
+ &data->survey_results);
+#endif /* CONFIG_AP */
+ break;
+ case EVENT_ACS_CHANNEL_SELECTED:
+#ifdef CONFIG_AP
+#ifdef CONFIG_ACS
+ if (!wpa_s->ap_iface)
+ break;
+ hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
+ &data->acs_selected_channels);
+#endif /* CONFIG_ACS */
+#endif /* CONFIG_AP */
+ break;
+ case EVENT_P2P_LO_STOP:
+#ifdef CONFIG_P2P
+ wpa_s->p2p_lo_started = 0;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_LISTEN_OFFLOAD_STOP
+ P2P_LISTEN_OFFLOAD_STOP_REASON "reason=%d",
+ data->p2p_lo_stop.reason_code);
+#endif /* CONFIG_P2P */
+ break;
+ case EVENT_BEACON_LOSS:
+ if (!wpa_s->current_bss || !wpa_s->current_ssid)
+ break;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_BEACON_LOSS);
+ bgscan_notify_beacon_loss(wpa_s);
+ break;
+ case EVENT_EXTERNAL_AUTH:
+#ifdef CONFIG_SAE
+ if (!wpa_s->current_ssid) {
+ wpa_printf(MSG_DEBUG, "SAE: current_ssid is NULL");
+ break;
+ }
+ sme_external_auth_trigger(wpa_s, data);
+#endif /* CONFIG_SAE */
+ break;
+ case EVENT_PORT_AUTHORIZED:
+ wpa_supplicant_event_port_authorized(wpa_s);
+ break;
+ case EVENT_STATION_OPMODE_CHANGED:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface || !data)
+ break;
+
+ hostapd_event_sta_opmode_changed(wpa_s->ap_iface->bss[0],
+ data->sta_opmode.addr,
+ data->sta_opmode.smps_mode,
+ data->sta_opmode.chan_width,
+ data->sta_opmode.rx_nss);
+#endif /* CONFIG_AP */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
}
}
+
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct wpa_supplicant *wpa_s;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname);
+ if (wpa_s && wpa_s->driver->get_ifindex) {
+ unsigned int ifindex;
+
+ ifindex = wpa_s->driver->get_ifindex(wpa_s->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "interface status ifindex %d mismatch (%d)",
+ ifindex, data->interface_status.ifindex);
+ return;
+ }
+ }
+#ifdef CONFIG_MATCH_IFACE
+ else if (data->interface_status.ievent == EVENT_INTERFACE_ADDED) {
+ struct wpa_interface *wpa_i;
+
+ wpa_i = wpa_supplicant_match_iface(
+ ctx, data->interface_status.ifname);
+ if (!wpa_i)
+ return;
+ wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
+ os_free(wpa_i);
+ if (wpa_s)
+ wpa_s->matched = 1;
+ }
+#endif /* CONFIG_MATCH_IFACE */
+
+ if (wpa_s)
+ wpa_supplicant_event(wpa_s, event, data);
+}
diff --git a/contrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py b/contrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py
index 5ac9859..337519f 100755
--- a/contrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py
+++ b/contrib/wpa/wpa_supplicant/examples/dbus-listen-preq.py
@@ -1,5 +1,6 @@
#!/usr/bin/python
+from __future__ import print_function
import dbus
import sys
import time
@@ -12,21 +13,24 @@ WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1"
WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
def usage():
- print "Usage: %s <ifname>" % sys.argv[0]
- print "Press Ctrl-C to stop"
+ print("Usage: %s <ifname>" % sys.argv[0])
+ print("Press Ctrl-C to stop")
def ProbeRequest(args):
if 'addr' in args:
- print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+ print('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+ end=' ')
if 'dst' in args:
- print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+ print('-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+ end=' ')
if 'bssid' in args:
- print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+ print('(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+ end=' ')
if 'signal' in args:
- print 'signal:%d' % args['signal'],
+ print('signal:%d' % args['signal'], end=' ')
if 'ies' in args:
- print 'have IEs (%d bytes)' % len(args['ies']),
- print ''
+ print('have IEs (%d bytes)' % len(args['ies']), end=' ')
+ print('')
if __name__ == "__main__":
global bus
diff --git a/contrib/wpa/wpa_supplicant/examples/dpp-qrcode.py b/contrib/wpa/wpa_supplicant/examples/dpp-qrcode.py
new file mode 100644
index 0000000..b468d15
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/examples/dpp-qrcode.py
@@ -0,0 +1,130 @@
+#!/usr/bin/python
+#
+# Example Android logcat to wpa_supplicant wrapper for QR Code scans
+# Copyright (c) 2017, Qualcomm Atheros, Inc.
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import argparse
+import logging
+import qrcode
+
+scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
+sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
+
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
+ return None
+
+ if len(ifaces) < 1:
+ print("No wpa_supplicant control interface found")
+ return None
+
+ for ctrl in ifaces:
+ try:
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception as e:
+ pass
+ return None
+
+def dpp_logcat():
+ for line in iter(sys.stdin.readline, ''):
+ if "ResultHandler: Launching intent: Intent" not in line:
+ continue
+ if "act=android.intent.action.VIEW" not in line:
+ continue
+ uri = None
+ for val in line.split(' '):
+ if val.startswith('dat='):
+ uri = val.split('=', 1)[1]
+ break
+ if not uri:
+ continue
+ if not uri.startswith('DPP:'):
+ continue
+ print("Found DPP bootstrap info URI:")
+ print(uri)
+ wpas = wpas_connect()
+ if not wpas:
+ print("Could not connect to wpa_supplicant")
+ print('')
+ continue
+ res = wpas.request("DPP_QR_CODE " + uri);
+ try:
+ id = int(res)
+ except ValueError:
+ print("QR Code URI rejected")
+ continue
+ print("QR Code URI accepted - ID=%d" % id)
+ print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id))
+ del wpas
+
+def dpp_display(curve):
+ wpas = wpas_connect()
+ if not wpas:
+ print("Could not connect to wpa_supplicant")
+ return
+ res = wpas.request("STATUS")
+ addr = None
+ for line in res.splitlines():
+ if line.startswith("address="):
+ addr = line.split('=')[1]
+ break
+ cmd = "DPP_BOOTSTRAP_GEN type=qrcode"
+ cmd += " chan=81/1"
+ if addr:
+ cmd += " mac=" + addr.replace(':','')
+ if curve:
+ cmd += " curve=" + curve
+ res = wpas.request(cmd)
+ try:
+ id = int(res)
+ except ValueError:
+ print("Failed to generate bootstrap info URI")
+ return
+ print("Bootstrap information - ID=%d" % id)
+ print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id))
+ uri = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % id)
+ print(uri)
+ print("ID=%d" % id)
+ qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M,
+ border=3)
+ qr.add_data(uri, optimize=5)
+ qr.print_ascii(tty=True)
+ print("ID=%d" % id)
+ del wpas
+
+def main():
+ parser = argparse.ArgumentParser(description='Android logcat to wpa_supplicant integration for DPP QR Code operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('--curve', '-c',
+ help='set a specific curve (P-256, P-384, P-521, BP-256R1, BP-384R1, BP-512R1) for key generation')
+ parser.add_argument('command', choices=['logcat',
+ 'display'],
+ nargs='?')
+ args = parser.parse_args()
+
+ logging.basicConfig(level=args.loglevel)
+
+ if args.command == "logcat":
+ dpp_logcat()
+ elif args.command == "display":
+ dpp_display(args.curve)
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py b/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py
index 91eba28..889ac8b 100755
--- a/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py
@@ -37,7 +37,7 @@ summary_file = None
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -53,12 +53,12 @@ def wpas_connect():
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find wpa_supplicant: ", error
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
return None
if len(ifaces) < 1:
- print "No wpa_supplicant control interface found"
+ print("No wpa_supplicant control interface found")
return None
for ctrl in ifaces:
@@ -66,10 +66,10 @@ def wpas_connect():
if ifname not in ctrl:
continue
try:
- print "Trying to use control interface " + ctrl
+ print("Trying to use control interface " + ctrl)
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -160,30 +160,30 @@ def p2p_handover_client(llc):
if (data == None):
summary("Could not get handover request carrier record from wpa_supplicant")
return
- print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ print("Handover request carrier record from wpa_supplicant: " + data.encode("hex"))
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
global include_wps_req
if include_wps_req:
- print "Handover request (pre-WPS):"
+ print("Handover request (pre-WPS):")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_req_wps()
if data:
- print "Add WPS request in addition to P2P"
+ print("Add WPS request in addition to P2P")
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
- print "Handover request:"
+ print("Handover request:")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
client = nfc.handover.HandoverClient(llc)
try:
@@ -194,7 +194,7 @@ def p2p_handover_client(llc):
summary("Handover connection refused")
client.close()
return
- except Exception, e:
+ except Exception as e:
summary("Other exception: " + str(e))
client.close()
return
@@ -217,41 +217,41 @@ def p2p_handover_client(llc):
client.close()
return
- print "Received message"
+ print("Received message")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
message = nfc.ndef.HandoverSelectMessage(message)
summary("Handover select received")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
for carrier in message.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.p2p":
- print "P2P carrier type match - send to wpa_supplicant"
+ print("P2P carrier type match - send to wpa_supplicant")
if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
success_report("P2P handover reported successfully (initiator)")
else:
summary("P2P handover report rejected")
break
- print "Remove peer"
+ print("Remove peer")
client.close()
- print "Done with handover"
+ print("Done with handover")
global only_one
if only_one:
- print "only_one -> stop loop"
+ print("only_one -> stop loop")
global continue_loop
continue_loop = False
global no_wait
if no_wait:
- print "Trying to exit.."
+ print("Trying to exit..")
global terminate_now
terminate_now = True
@@ -283,33 +283,33 @@ class HandoverServer(nfc.handover.HandoverServer):
def process_request(self, request):
self.ho_server_processing = True
clear_raw_mode()
- print "HandoverServer - request received"
+ print("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
found = False
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.p2p":
- print "P2P carrier type match - add P2P carrier record"
+ print("P2P carrier type match - add P2P carrier record")
found = True
self.received_carrier = carrier.record
- print "Carrier record:"
+ print("Carrier record:")
try:
- print carrier.record.pretty()
- except Exception, e:
- print e
+ print(carrier.record.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_sel()
if data is None:
- print "Could not get handover select carrier record from wpa_supplicant"
+ print("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"):
success_report("P2P handover reported successfully (responder)")
@@ -324,22 +324,22 @@ class HandoverServer(nfc.handover.HandoverServer):
for carrier in request.carriers:
if found:
break
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
- print "WSC carrier type match - add WSC carrier record"
+ print("WSC carrier type match - add WSC carrier record")
found = True
self.received_carrier = carrier.record
- print "Carrier record:"
+ print("Carrier record:")
try:
- print carrier.record.pretty()
- except Exception, e:
- print e
+ print(carrier.record.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_sel_wps()
if data is None:
- print "Could not get handover select carrier record from wpa_supplicant"
+ print("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"):
success_report("WSC handover reported successfully")
@@ -352,12 +352,12 @@ class HandoverServer(nfc.handover.HandoverServer):
found = True
break
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -396,7 +396,7 @@ def p2p_tag_read(tag):
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to wpa_supplicant")
success = wpas_tag_read(tag.ndef.message)
@@ -419,7 +419,7 @@ def rdwr_connected_p2p_write(tag):
global p2p_sel_data
tag.ndef.message = str(p2p_sel_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -428,7 +428,7 @@ def rdwr_connected_p2p_write(tag):
return p2p_sel_wait_remove
def wps_write_p2p_handover_sel(clf, wait_remove=True):
- print "Write P2P handover select"
+ print("Write P2P handover select")
data = wpas_get_handover_sel(tag=True)
if (data == None):
summary("Could not get P2P handover select from wpa_supplicant")
@@ -440,14 +440,14 @@ def wps_write_p2p_handover_sel(clf, wait_remove=True):
p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2")
message = nfc.ndef.Message(data);
p2p_sel_data.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print p2p_sel_data.pretty()
- except Exception, e:
- print e
- print str(p2p_sel_data).encode("hex")
+ print(p2p_sel_data.pretty())
+ except Exception as e:
+ print(e)
+ print(str(p2p_sel_data).encode("hex"))
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write})
@@ -456,11 +456,11 @@ def rdwr_connected(tag):
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = p2p_tag_read(tag)
if only_one and success:
global continue_loop
@@ -475,15 +475,15 @@ def rdwr_connected(tag):
def llcp_worker(llc):
global init_on_touch
if init_on_touch:
- print "Starting handover client"
+ print("Starting handover client")
p2p_handover_client(llc)
return
global no_input
if no_input:
- print "Wait for handover to complete"
+ print("Wait for handover to complete")
else:
- print "Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)"
+ print("Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)")
global srv
global wait_connection
while not wait_connection and srv.sent_carrier is None:
@@ -506,21 +506,21 @@ def llcp_worker(llc):
else:
continue
clear_raw_mode()
- print "Starting handover client"
+ print("Starting handover client")
p2p_handover_client(llc)
return
clear_raw_mode()
- print "Exiting llcp_worker thread"
+ print("Exiting llcp_worker thread")
def llcp_startup(clf, llc):
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global init_on_touch
@@ -587,7 +587,7 @@ def main():
if args.ifname:
global ifname
ifname = args.ifname
- print "Selected ifname " + ifname
+ print("Selected ifname " + ifname)
if args.no_wps_req:
global include_wps_req
@@ -610,7 +610,7 @@ def main():
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-p2p-sel":
@@ -619,7 +619,7 @@ def main():
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if args.tag_read_only:
@@ -636,8 +636,8 @@ def main():
'on-connect': llcp_connected},
terminate=terminate_loop):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py
index 59b0a9d..6e3d94e 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -13,40 +13,40 @@ from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> -m <wps_method> \ " \
- % sys.argv[0]
- print " -a <addr> [-p <pin>] [-g <go_intent>] \ "
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -m = wps method"
- print " -a = peer address"
- print " -p = pin number (8 digits)"
- print " -g = group owner intent"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> -m <wps_method> \ " \
+ % sys.argv[0])
+ print(" -a <addr> [-p <pin>] [-g <go_intent>] \ ")
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -m = wps method")
+ print(" -a = peer address")
+ print(" -p = pin number (8 digits)")
+ print(" -g = group owner intent")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0])
# Required Signals
def GONegotiationSuccess(status):
- print "Go Negotiation Success"
+ print("Go Negotiation Success")
def GONegotiationFailure(status):
- print 'Go Negotiation Failed. Status:'
- print format(status)
+ print('Go Negotiation Failed. Status:')
+ print(format(status))
os._exit(0)
def GroupStarted(properties):
if properties.has_key("group_object"):
- print 'Group Formation Complete %s' \
- % properties["group_object"]
+ print('Group Formation Complete %s' \
+ % properties["group_object"])
os._exit(0)
def WpsFailure(status, etc):
- print "WPS Authentication Failure".format(status)
- print etc
+ print("WPS Authentication Failure".format(status))
+ print(etc)
os._exit(0)
class P2P_Connect():
@@ -118,7 +118,7 @@ class P2P_Connect():
{'Ifname': ifname, 'Driver': 'test'})
time.sleep(1)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith(
self.wpas_dbus_interface + \
".InterfaceExists:"):
@@ -157,12 +157,12 @@ class P2P_Connect():
if (self.pin != None):
self.p2p_connect_arguements.update({'pin':self.pin})
else:
- print "Error:\n Pin required for wps_method=display"
+ print("Error:\n Pin required for wps_method=display")
usage()
quit()
if (self.go_intent != None and int(self.go_intent) != 15):
- print "go_intent overwritten to 15"
+ print("go_intent overwritten to 15")
self.go_intent = '15'
@@ -171,14 +171,14 @@ class P2P_Connect():
if (self.pin != None):
self.p2p_connect_arguements.update({'pin':self.pin})
else:
- print "Error:\n Pin required for wps_method=keypad"
+ print("Error:\n Pin required for wps_method=keypad")
usage()
quit()
if (self.go_intent != None and int(self.go_intent) == 15):
error = "Error :\n Group Owner intent cannot be" + \
" 15 for wps_method=keypad"
- print error
+ print(error)
usage()
quit()
@@ -186,15 +186,15 @@ class P2P_Connect():
# for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad
elif (self.wps_method == 'pin'):
if (self.pin != None):
- print "pin ignored"
+ print("pin ignored")
# No pin is required for pbc so it is ignored
elif (self.wps_method == 'pbc'):
if (self.pin != None):
- print "pin ignored"
+ print("pin ignored")
else:
- print "Error:\n wps_method not supported or does not exist"
+ print("Error:\n wps_method not supported or does not exist")
usage()
quit()
@@ -209,12 +209,12 @@ class P2P_Connect():
result_pin = self.p2p_interface.Connect(
self.p2p_connect_arguements)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
raise exc
if (self.wps_method == 'pin' and \
not self.p2p_connect_arguements.has_key('pin') ):
- print "Connect return with pin value of %d " % int(result_pin)
+ print("Connect return with pin value of %d " % int(result_pin))
gobject.MainLoop().run()
if __name__ == "__main__":
@@ -268,19 +268,19 @@ if __name__ == "__main__":
# Required Arguements check
if (interface_name == None or wps_method == None or addr == None):
- print "Error:\n Required arguements not specified"
+ print("Error:\n Required arguements not specified")
usage()
quit()
# Group Owner Intent Check
if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ):
- print "Error:\n Group Owner Intent must be between 0 and 15 inclusive"
+ print("Error:\n Group Owner Intent must be between 0 and 15 inclusive")
usage()
quit()
# Pin Check
if (pin != None and len(pin) != 8):
- print "Error:\n Pin is not 8 digits"
+ print("Error:\n Pin is not 8 digits")
usage()
quit()
@@ -289,7 +289,7 @@ if __name__ == "__main__":
addr,pin,wps_method,go_intent)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
quit()
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py
index c3e39b3..85b5a8b 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_disconnect.py
@@ -12,19 +12,19 @@ import getopt
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i p2p-wlan0-0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i p2p-wlan0-0" % sys.argv[0])
# Required Signals
def GroupFinished(status, etc):
- print "Disconnected"
+ print("Disconnected")
os._exit(0)
class P2P_Disconnect (threading.Thread):
@@ -81,10 +81,10 @@ class P2P_Disconnect (threading.Thread):
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -142,7 +142,7 @@ if __name__ == "__main__":
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -152,7 +152,7 @@ if __name__ == "__main__":
wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -165,5 +165,5 @@ if __name__ == "__main__":
except:
pass
- print "Disconnect timed out"
+ print("Disconnect timed out")
quit()
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py
index 973d46a..e2df528 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_find.py
@@ -13,23 +13,23 @@ import getopt
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-t <timeout>] \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -t = timeout = 0s (infinite)"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -t 10" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -t = timeout = 0s (infinite)")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -t 10" % sys.argv[0])
# Required Signals
def deviceFound(devicepath):
- print "Device found: %s" % (devicepath)
+ print("Device found: %s" % (devicepath))
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
class P2P_Find (threading.Thread):
# Needed Variables
@@ -85,10 +85,10 @@ class P2P_Find (threading.Thread):
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -150,7 +150,7 @@ if __name__ == "__main__":
if ( int(value) >= 0):
timeout = value
else:
- print "Error:\n Timeout cannot be negative"
+ print("Error:\n Timeout cannot be negative")
usage()
quit()
# Dbus interface
@@ -161,7 +161,7 @@ if __name__ == "__main__":
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -170,7 +170,7 @@ if __name__ == "__main__":
p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py
index ff8509d..42fc7a3 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_flush.py
@@ -13,19 +13,19 @@ import getopt
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals\
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
class P2P_Flush (threading.Thread):
# Needed Variables
@@ -81,10 +81,10 @@ class P2P_Flush (threading.Thread):
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -142,7 +142,7 @@ if __name__ == "__main__":
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -151,7 +151,7 @@ if __name__ == "__main__":
p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -164,5 +164,5 @@ if __name__ == "__main__":
except:
pass
- print "p2p_flush complete"
+ print("p2p_flush complete")
quit()
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py
index 5c8fdaf..6d40821 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_group_add.py
@@ -11,30 +11,30 @@ import threading
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-p <persistent>] \ " \
- % sys.argv[0]
- print " [-f <frequency>] [-o <group_object_path>] \ "
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -p = persistant group = 0 (0=false, 1=true)"
- print " -f = frequency"
- print " -o = persistent group object path"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-p <persistent>] \ " \
+ % sys.argv[0])
+ print(" [-f <frequency>] [-o <group_object_path>] \ ")
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -p = persistant group = 0 (0=false, 1=true)")
+ print(" -f = frequency")
+ print(" -o = persistent group object path")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals
def GroupStarted(properties):
if properties.has_key("group_object"):
- print 'Group Formation Complete %s' \
- % properties["group_object"]
+ print('Group Formation Complete %s' \
+ % properties["group_object"])
os._exit(0)
def WpsFailure(status, etc):
- print "WPS Authentication Failure".format(status)
- print etc
+ print("WPS Authentication Failure".format(status))
+ print(etc)
os._exit(0)
class P2P_Group_Add (threading.Thread):
@@ -99,10 +99,10 @@ class P2P_Group_Add (threading.Thread):
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -127,7 +127,7 @@ class P2P_Group_Add (threading.Thread):
if (int(self.frequency) > 0):
self.P2PDictionary.update({'frequency':int(self.frequency)})
else:
- print "Error:\n Frequency must be greater than 0"
+ print("Error:\n Frequency must be greater than 0")
usage()
os._exit(0)
@@ -141,7 +141,7 @@ class P2P_Group_Add (threading.Thread):
self.p2p_interface.GroupAdd(self.P2PDictionary)
except:
- print "Error:\n Could not preform group add"
+ print("Error:\n Could not preform group add")
usage()
os._exit(0)
@@ -188,7 +188,7 @@ if __name__ == "__main__":
elif (value == '1'):
persistent = True
else:
- print "Error:\n Persistent can only be 1 or 0"
+ print("Error:\n Persistent can only be 1 or 0")
usage()
os._exit(0)
# Frequency
@@ -205,7 +205,7 @@ if __name__ == "__main__":
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -213,10 +213,10 @@ if __name__ == "__main__":
p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface,
persistent,frequency,persistent_group_object)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
p2p_group_add_test.constructArguements()
p2p_group_add_test.start()
time.sleep(5)
- print "Error:\n Group formation timed out"
+ print("Error:\n Group formation timed out")
os._exit(0)
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py
index 6deb397..341dcd0 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_invite.py
@@ -11,29 +11,29 @@ import threading
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> -a <addr> \ " \
- % sys.argv[0]
- print " [-o <persistent_group_object>] [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -a = address of peer"
- print " -o = persistent group object path"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> -a <addr> \ " \
+ % sys.argv[0])
+ print(" [-o <persistent_group_object>] [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -a = address of peer")
+ print(" -o = persistent group object path")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0])
# Required Signals
def InvitationResult(invite_result):
- print "Inviation Result signal :"
+ print("Inviation Result signal :")
status = invite_result['status']
- print "status = ", status
+ print("status = ", status)
if invite_result.has_key('BSSID'):
bssid = invite_result['BSSID']
- print "BSSID = ", hex(bssid[0]) , ":" , \
+ print("BSSID = ", hex(bssid[0]) , ":" , \
hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \
hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \
- hex(bssid[5])
+ hex(bssid[5]))
os._exit(0)
class P2P_Invite (threading.Thread):
@@ -96,10 +96,10 @@ class P2P_Invite (threading.Thread):
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -127,7 +127,7 @@ class P2P_Invite (threading.Thread):
self.p2p_interface.Invite(self.P2PDictionary)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
os._exit(0)
@@ -176,12 +176,12 @@ if __name__ == "__main__":
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
if (addr == None):
- print "Error:\n peer address is required"
+ print("Error:\n peer address is required")
usage()
quit()
@@ -190,12 +190,12 @@ if __name__ == "__main__":
P2P_Invite(interface_name,wpas_dbus_interface,
addr,persistent_group_object)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
os._exit(1)
p2p_invite_test.constructArguements()
p2p_invite_test.start()
time.sleep(10)
- print "Error:\n p2p_invite timed out"
+ print("Error:\n p2p_invite timed out")
os._exit(0)
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py
index bb3c1e4..b0837d9 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_listen.py
@@ -13,20 +13,20 @@ import getopt
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-t <timeout>] \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -t = timeout = 0s (infinite)"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -t 5" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -t = timeout = 0s (infinite)")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -t 5" % sys.argv[0])
# Required Signals
def p2pStateChange(status):
- print status
+ print(status)
class P2P_Listen(threading.Thread):
# Needed Variables
@@ -82,10 +82,10 @@ class P2P_Listen(threading.Thread):
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -140,7 +140,7 @@ if __name__ == "__main__":
if ( int(value) >= 0):
timeout = value
else:
- print "Error:\n Timeout cannot be negative"
+ print("Error:\n Timeout cannot be negative")
usage()
quit()
# Dbus interface
@@ -151,7 +151,7 @@ if __name__ == "__main__":
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -160,7 +160,7 @@ if __name__ == "__main__":
p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
diff --git a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py
index f6c03b0..bdb4c0e 100644
--- a/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py
+++ b/contrib/wpa/wpa_supplicant/examples/p2p/p2p_stop_find.py
@@ -11,22 +11,22 @@ import getopt
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
def p2pStateChange(status):
- print status
+ print(status)
os._exit(0)
class P2P_Stop_Find (threading.Thread):
@@ -83,10 +83,10 @@ class P2P_Stop_Find (threading.Thread):
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -147,7 +147,7 @@ if __name__ == "__main__":
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -157,7 +157,7 @@ if __name__ == "__main__":
wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -170,5 +170,5 @@ if __name__ == "__main__":
except:
pass
- print "p2p find stopped"
+ print("p2p find stopped")
quit()
diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py
index 03da187..732f54d 100755
--- a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py
+++ b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-getall.py
@@ -11,8 +11,8 @@ def main():
"/fi/w1/wpa_supplicant1")
props = wpas_obj.GetAll("fi.w1.wpa_supplicant1",
dbus_interface=dbus.PROPERTIES_IFACE)
- print "GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):"
- print props
+ print("GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):")
+ print(props)
if len(sys.argv) != 2:
os._exit(1)
@@ -24,15 +24,15 @@ def main():
if_obj = bus.get_object("fi.w1.wpa_supplicant1", path)
props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path)
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path))
+ print(props)
props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface.WPS",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path)
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path))
+ print(props)
res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'BSSs',
dbus_interface=dbus.PROPERTIES_IFACE)
@@ -40,9 +40,9 @@ def main():
bss_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0])
props = bss_obj.GetAll("fi.w1.wpa_supplicant1.BSS",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0])
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0]))
+ print(props)
res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'Networks',
dbus_interface=dbus.PROPERTIES_IFACE)
@@ -50,10 +50,9 @@ def main():
net_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0])
props = net_obj.GetAll("fi.w1.wpa_supplicant1.Network",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0])
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0]))
+ print(props)
if __name__ == "__main__":
main()
-
diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py
index d90ef18..366a655 100755
--- a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py
+++ b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-signals.py
@@ -32,17 +32,17 @@ def list_interfaces(wpas_obj):
if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname',
dbus_interface=dbus.PROPERTIES_IFACE)
- print ifname
+ print(ifname)
def interfaceAdded(interface, properties):
- print "InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname'])
+ print("InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname']))
def interfaceRemoved(interface):
- print "InterfaceRemoved(%s)" % (interface)
+ print("InterfaceRemoved(%s)" % (interface))
def propertiesChanged(properties):
for i in properties:
- print "PropertiesChanged: %s=%s" % (i, properties[i])
+ print("PropertiesChanged: %s=%s" % (i, properties[i]))
def showBss(bss):
net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss)
@@ -80,48 +80,48 @@ def showBss(bss):
else:
maxrate = 0
- print " %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)
+ print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq))
def scanDone(success):
gobject.MainLoop().quit()
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
def scanDone2(success, path=None):
- print "Scan done: success=%s [path=%s]" % (success, path)
+ print("Scan done: success=%s [path=%s]" % (success, path))
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
showBss(bss)
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def blobAdded(blob):
- print "BlobAdded(%s)" % (blob)
+ print("BlobAdded(%s)" % (blob))
def blobRemoved(blob):
- print "BlobRemoved(%s)" % (blob)
+ print("BlobRemoved(%s)" % (blob))
def networkAdded(network, properties):
- print "NetworkAdded(%s)" % (network)
+ print("NetworkAdded(%s)" % (network))
def networkRemoved(network):
- print "NetworkRemoved(%s)" % (network)
+ print("NetworkRemoved(%s)" % (network))
def networkSelected(network):
- print "NetworkSelected(%s)" % (network)
+ print("NetworkSelected(%s)" % (network))
def propertiesChangedInterface(properties):
for i in properties:
- print "PropertiesChanged(interface): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(interface): %s=%s" % (i, properties[i]))
def propertiesChangedBss(properties):
for i in properties:
- print "PropertiesChanged(BSS): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(BSS): %s=%s" % (i, properties[i]))
def propertiesChangedNetwork(properties):
for i in properties:
- print "PropertiesChanged(Network): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(Network): %s=%s" % (i, properties[i]))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py
index b886385..7d87b1e 100755
--- a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py
+++ b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new-wps.py
@@ -15,23 +15,23 @@ WPAS_DBUS_WPS_INTERFACE = "fi.w1.wpa_supplicant1.Interface.WPS"
def propertiesChanged(properties):
if properties.has_key("State"):
- print "PropertiesChanged: State: %s" % (properties["State"])
+ print("PropertiesChanged: State: %s" % (properties["State"]))
def scanDone(success):
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def wpsEvent(name, args):
- print "WPS event: %s" % (name)
- print args
+ print("WPS event: %s" % (name))
+ print(args)
def credentials(cred):
- print "WPS credentials: %s" % (cred)
+ print("WPS credentials: %s" % (cred))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -40,7 +40,7 @@ def main():
wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
if len(sys.argv) != 2:
- print "Missing ifname argument"
+ print("Missing ifname argument")
os._exit(1)
wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py
index 25072ce..6bf74ae 100755
--- a/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py
+++ b/contrib/wpa/wpa_supplicant/examples/wpas-dbus-new.py
@@ -31,11 +31,11 @@ def list_interfaces(wpas_obj):
if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname',
dbus_interface=dbus.PROPERTIES_IFACE)
- print ifname
+ print(ifname)
def propertiesChanged(properties):
if properties.has_key("State"):
- print "PropertiesChanged: State: %s" % (properties["State"])
+ print("PropertiesChanged: State: %s" % (properties["State"]))
def showBss(bss):
net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss)
@@ -73,25 +73,25 @@ def showBss(bss):
else:
maxrate = 0
- print " %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)
+ print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq))
def scanDone(success):
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
res = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'BSSs',
dbus_interface=dbus.PROPERTIES_IFACE)
- print "Scanned wireless networks:"
+ print("Scanned wireless networks:")
for opath in res:
- print opath
+ print(opath)
showBss(opath)
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
showBss(bss)
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -123,14 +123,14 @@ def main():
path = None
try:
path = wpas.GetInterface(ifname)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceUnknown:"):
raise exc
try:
path = wpas.CreateInterface({'Ifname': ifname, 'Driver': 'test'})
time.sleep(1)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceExists:"):
raise exc
diff --git a/contrib/wpa/wpa_supplicant/examples/wpas-test.py b/contrib/wpa/wpa_supplicant/examples/wpas-test.py
deleted file mode 100755
index fd7f73d..0000000
--- a/contrib/wpa/wpa_supplicant/examples/wpas-test.py
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/python
-
-import dbus
-import sys, os
-import time
-
-WPAS_DBUS_SERVICE = "fi.epitest.hostap.WPASupplicant"
-WPAS_DBUS_INTERFACE = "fi.epitest.hostap.WPASupplicant"
-WPAS_DBUS_OPATH = "/fi/epitest/hostap/WPASupplicant"
-
-WPAS_DBUS_INTERFACES_INTERFACE = "fi.epitest.hostap.WPASupplicant.Interface"
-WPAS_DBUS_INTERFACES_OPATH = "/fi/epitest/hostap/WPASupplicant/Interfaces"
-WPAS_DBUS_BSSID_INTERFACE = "fi.epitest.hostap.WPASupplicant.BSSID"
-
-def byte_array_to_string(s):
- import urllib
- r = ""
- for c in s:
- if c >= 32 and c < 127:
- r += "%c" % c
- else:
- r += urllib.quote(chr(c))
- return r
-
-def main():
- if len(sys.argv) != 2:
- print "Usage: wpas-test.py <interface>"
- os._exit(1)
-
- ifname = sys.argv[1]
-
- bus = dbus.SystemBus()
- wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
- wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
-
- # See if wpa_supplicant already knows about this interface
- path = None
- try:
- path = wpas.getInterface(ifname)
- except dbus.dbus_bindings.DBusException, exc:
- if str(exc) != "wpa_supplicant knows nothing about this interface.":
- raise exc
- try:
- path = wpas.addInterface(ifname, {'driver': dbus.Variant('wext')})
- except dbus.dbus_bindings.DBusException, exc:
- if str(exc) != "wpa_supplicant already controls this interface.":
- raise exc
-
- if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
- iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
- iface.scan()
- # Should really wait for the "scanResults" signal instead of sleeping
- time.sleep(5)
- res = iface.scanResults()
-
- print "Scanned wireless networks:"
- for opath in res:
- net_obj = bus.get_object(WPAS_DBUS_SERVICE, opath)
- net = dbus.Interface(net_obj, WPAS_DBUS_BSSID_INTERFACE)
- props = net.properties()
-
- # Convert the byte-array for SSID and BSSID to printable strings
- bssid = ""
- for item in props["bssid"]:
- bssid = bssid + ":%02x" % item
- bssid = bssid[1:]
- ssid = byte_array_to_string(props["ssid"])
- wpa = "no"
- if props.has_key("wpaie"):
- wpa = "yes"
- wpa2 = "no"
- if props.has_key("rsnie"):
- wpa2 = "yes"
- freq = 0
- if props.has_key("frequency"):
- freq = props["frequency"]
- caps = props["capabilities"]
- qual = props["quality"]
- level = props["level"]
- noise = props["noise"]
- maxrate = props["maxrate"] / 1000000
-
- print " %s :: ssid='%s' wpa=%s wpa2=%s quality=%d%% rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, qual, maxrate, freq)
-
- wpas.removeInterface(dbus.ObjectPath(path))
- # Should fail here with unknown interface error
- iface.scan()
-
-if __name__ == "__main__":
- main()
-
diff --git a/contrib/wpa/wpa_supplicant/examples/wps-ap-cli b/contrib/wpa/wpa_supplicant/examples/wps-ap-cli
index cc2cff2..15d913e 100755
--- a/contrib/wpa/wpa_supplicant/examples/wps-ap-cli
+++ b/contrib/wpa/wpa_supplicant/examples/wps-ap-cli
@@ -14,12 +14,12 @@ pbc()
enter_pin()
{
echo "Enter a PIN from a station to be enrolled to the network."
- echo -n "Enrollee PIN: "
+ printf "Enrollee PIN: "
read pin
cpin=`$CLI wps_check_pin "$pin" | tail -1`
if [ "$cpin" = "FAIL-CHECKSUM" ]; then
echo "Checksum digit is not valid"
- echo -n "Do you want to use this PIN (y/n)? "
+ printf "Do you want to use this PIN (y/n)? "
read resp
case "$resp" in
y*)
@@ -52,7 +52,7 @@ main_menu()
echo "3: Show current configuration"
echo "0: Exit wps-ap-cli"
- echo -n "Command: "
+ printf "Command: "
read cmd
case "$cmd" in
diff --git a/contrib/wpa/wpa_supplicant/examples/wps-nfc.py b/contrib/wpa/wpa_supplicant/examples/wps-nfc.py
index 7459eb9..bb458fb 100755
--- a/contrib/wpa/wpa_supplicant/examples/wps-nfc.py
+++ b/contrib/wpa/wpa_supplicant/examples/wps-nfc.py
@@ -30,7 +30,7 @@ summary_file = None
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -46,19 +46,19 @@ def wpas_connect():
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find wpa_supplicant: ", error
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
return None
if len(ifaces) < 1:
- print "No wpa_supplicant control interface found"
+ print("No wpa_supplicant control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -163,22 +163,22 @@ class HandoverServer(nfc.handover.HandoverServer):
self.ho_server_processing = True
summary("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
summary("WPS carrier type match - add WPS carrier record")
data = wpas_get_handover_sel(self.uuid)
if data is None:
summary("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"):
success_report("Handover reported successfully (responder)")
@@ -188,12 +188,12 @@ class HandoverServer(nfc.handover.HandoverServer):
message = nfc.ndef.Message(data);
sel.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -207,19 +207,19 @@ def wps_handover_init(llc):
if (data == None):
summary("Could not get handover request carrier record from wpa_supplicant")
return
- print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ print("Handover request carrier record from wpa_supplicant: " + data.encode("hex"))
message = nfc.ndef.HandoverRequestMessage(version="1.2")
message.nonce = random.randint(0, 0xffff)
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
- print "Handover request:"
+ print("Handover request:")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
client = nfc.handover.HandoverClient(llc)
try:
@@ -230,7 +230,7 @@ def wps_handover_init(llc):
summary("Handover connection refused")
client.close()
return
- except Exception, e:
+ except Exception as e:
summary("Other exception: " + str(e))
client.close()
return
@@ -253,23 +253,23 @@ def wps_handover_init(llc):
client.close()
return
- print "Received message"
+ print("Received message")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
message = nfc.ndef.HandoverSelectMessage(message)
summary("Handover select received")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
for carrier in message.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
- print "WPS carrier type match - send to wpa_supplicant"
+ print("WPS carrier type match - send to wpa_supplicant")
if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
success_report("Handover reported successfully (initiator)")
else:
@@ -278,9 +278,9 @@ def wps_handover_init(llc):
#wifi = nfc.ndef.WifiConfigRecord(carrier.record)
#print wifi.pretty()
- print "Remove peer"
+ print("Remove peer")
client.close()
- print "Done with handover"
+ print("Done with handover")
global only_one
if only_one:
global continue_loop
@@ -288,7 +288,7 @@ def wps_handover_init(llc):
global no_wait
if no_wait:
- print "Trying to exit.."
+ print("Trying to exit..")
global terminate_now
terminate_now = True
@@ -296,7 +296,7 @@ def wps_tag_read(tag, wait_remove=True):
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to wpa_supplicant")
success = wpas_tag_read(tag.ndef.message)
@@ -308,7 +308,7 @@ def wps_tag_read(tag, wait_remove=True):
success_report("Tag read succeeded")
if wait_remove:
- print "Remove tag"
+ print("Remove tag")
while tag.is_present:
time.sleep(0.1)
@@ -320,7 +320,7 @@ def rdwr_connected_write(tag):
global write_data
tag.ndef.message = str(write_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -330,41 +330,41 @@ def rdwr_connected_write(tag):
time.sleep(0.1)
def wps_write_config_tag(clf, id=None, wait_remove=True):
- print "Write WPS config token"
+ print("Write WPS config token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_config_token(id)
if write_data == None:
- print "Could not get WPS config token from wpa_supplicant"
+ print("Could not get WPS config token from wpa_supplicant")
sys.exit(1)
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def wps_write_er_config_tag(clf, uuid, wait_remove=True):
- print "Write WPS ER config token"
+ print("Write WPS ER config token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_er_config_token(uuid)
if write_data == None:
- print "Could not get WPS config token from wpa_supplicant"
+ print("Could not get WPS config token from wpa_supplicant")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def wps_write_password_tag(clf, wait_remove=True):
- print "Write WPS password token"
+ print("Write WPS password token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_password_token()
if write_data == None:
- print "Could not get WPS password token from wpa_supplicant"
+ print("Could not get WPS password token from wpa_supplicant")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -373,11 +373,11 @@ def rdwr_connected(tag):
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = wps_tag_read(tag, not only_one)
if only_one and success:
global continue_loop
@@ -393,7 +393,7 @@ def llcp_worker(llc):
global arg_uuid
if arg_uuid is None:
wps_handover_init(llc)
- print "Exiting llcp_worker thread"
+ print("Exiting llcp_worker thread")
return
global srv
@@ -405,19 +405,19 @@ def llcp_worker(llc):
def llcp_startup(clf, llc):
global arg_uuid
if arg_uuid:
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
if arg_uuid is "ap":
- print "Trying to handle WPS handover"
+ print("Trying to handle WPS handover")
srv.uuid = None
else:
- print "Trying to handle WPS handover with AP " + arg_uuid
+ print("Trying to handle WPS handover with AP " + arg_uuid)
srv.uuid = arg_uuid
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global arg_uuid
@@ -426,7 +426,7 @@ def llcp_connected(llc):
srv.start()
else:
threading.Thread(target=llcp_worker, args=(llc,)).start()
- print "llcp_connected returning"
+ print("llcp_connected returning")
return True
@@ -482,7 +482,7 @@ def main():
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-config":
@@ -499,7 +499,7 @@ def main():
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if not clf.connect(rdwr={'on-connect': rdwr_connected},
@@ -507,8 +507,8 @@ def main():
'on-connect': llcp_connected},
terminate=terminate_loop):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/contrib/wpa/wpa_supplicant/gas_query.c b/contrib/wpa/wpa_supplicant/gas_query.c
index 10ecce7..8e977a3 100644
--- a/contrib/wpa/wpa_supplicant/gas_query.c
+++ b/contrib/wpa/wpa_supplicant/gas_query.c
@@ -17,6 +17,7 @@
#include "common/wpa_ctrl.h"
#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
+#include "config.h"
#include "driver_i.h"
#include "offchannel.h"
#include "gas_query.h"
@@ -25,6 +26,9 @@
/** GAS query timeout in seconds */
#define GAS_QUERY_TIMEOUT_PERIOD 2
+/* GAS query wait-time / duration in ms */
+#define GAS_QUERY_WAIT_TIME_INITIAL 1000
+#define GAS_QUERY_WAIT_TIME_COMEBACK 150
/**
* struct gas_query_pending - Pending GAS query
@@ -37,6 +41,8 @@ struct gas_query_pending {
u8 next_frag_id;
unsigned int wait_comeback:1;
unsigned int offchannel_tx_started:1;
+ unsigned int retry:1;
+ unsigned int wildcard_bssid:1;
int freq;
u16 status_code;
struct wpabuf *req;
@@ -48,6 +54,7 @@ struct gas_query_pending {
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code);
void *ctx;
+ u8 sa[ETH_ALEN];
};
/**
@@ -58,11 +65,18 @@ struct gas_query {
struct dl_list pending; /* struct gas_query_pending */
struct gas_query_pending *current;
struct wpa_radio_work *work;
+ struct os_reltime last_mac_addr_rand;
+ int last_rand_sa_type;
+ u8 rand_addr[ETH_ALEN];
};
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
static void gas_query_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_tx_initial_req(struct gas_query *gas,
+ struct gas_query_pending *query);
+static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst);
static int ms_from_time(struct os_reltime *last)
@@ -108,8 +122,8 @@ static const char * gas_result_txt(enum gas_query_result result)
return "PEER_ERROR";
case GAS_QUERY_INTERNAL_ERROR:
return "INTERNAL_ERROR";
- case GAS_QUERY_CANCELLED:
- return "CANCELLED";
+ case GAS_QUERY_STOPPED:
+ return "STOPPED";
case GAS_QUERY_DELETED_AT_DEINIT:
return "DELETED_AT_DEINIT";
}
@@ -151,6 +165,7 @@ static void gas_query_done(struct gas_query *gas,
offchannel_send_action_done(gas->wpa_s);
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
dl_list_del(&query->list);
query->cb(query->ctx, query->addr, query->dialog_token, result,
query->adv_proto, query->resp, query->status_code);
@@ -231,10 +246,24 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
}
os_get_reltime(&query->last_oper);
- if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+ if (result == OFFCHANNEL_SEND_ACTION_SUCCESS ||
+ result == OFFCHANNEL_SEND_ACTION_NO_ACK) {
eloop_cancel_timeout(gas_query_timeout, gas, query);
- eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
- gas_query_timeout, gas, query);
+ if (result == OFFCHANNEL_SEND_ACTION_NO_ACK) {
+ wpa_printf(MSG_DEBUG, "GAS: No ACK to GAS request");
+ eloop_register_timeout(0, 250000,
+ gas_query_timeout, gas, query);
+ } else {
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+ gas_query_timeout, gas, query);
+ }
+ if (query->wait_comeback && !query->retry) {
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout,
+ gas, query);
+ eloop_register_timeout(
+ 0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000,
+ gas_query_rx_comeback_timeout, gas, query);
+ }
}
if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
eloop_cancel_timeout(gas_query_timeout, gas, query);
@@ -243,7 +272,7 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
}
-static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
{
if (wpa_s->current_ssid == NULL ||
wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
@@ -254,27 +283,40 @@ static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
- struct wpabuf *req)
+ struct wpabuf *req, unsigned int wait_time)
{
- unsigned int wait_time;
int res, prot = pmf_in_use(gas->wpa_s, query->addr);
+ const u8 *bssid;
+ const u8 wildcard_bssid[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
- "freq=%d prot=%d", MAC2STR(query->addr),
- (unsigned int) wpabuf_len(req), query->freq, prot);
+ "freq=%d prot=%d using src addr " MACSTR,
+ MAC2STR(query->addr), (unsigned int) wpabuf_len(req),
+ query->freq, prot, MAC2STR(query->sa));
if (prot) {
u8 *categ = wpabuf_mhead_u8(req);
*categ = WLAN_ACTION_PROTECTED_DUAL;
}
os_get_reltime(&query->last_oper);
- wait_time = 1000;
if (gas->wpa_s->max_remain_on_chan &&
wait_time > gas->wpa_s->max_remain_on_chan)
wait_time = gas->wpa_s->max_remain_on_chan;
+ if (!query->wildcard_bssid &&
+ (!gas->wpa_s->conf->gas_address3 ||
+ (gas->wpa_s->current_ssid &&
+ gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
+ os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0)))
+ bssid = query->addr;
+ else
+ bssid = wildcard_bssid;
+
res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
- gas->wpa_s->own_addr, query->addr,
- wpabuf_head(req), wpabuf_len(req),
- wait_time, gas_query_tx_status, 0);
+ query->sa, bssid, wpabuf_head(req),
+ wpabuf_len(req), wait_time,
+ gas_query_tx_status, 0);
+
if (res == 0)
query->offchannel_tx_started = 1;
return res;
@@ -285,6 +327,7 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
struct gas_query_pending *query)
{
struct wpabuf *req;
+ unsigned int wait_time;
req = gas_build_comeback_req(query->dialog_token);
if (req == NULL) {
@@ -292,7 +335,10 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
return;
}
- if (gas_query_tx(gas, query, req) < 0) {
+ wait_time = (query->retry || !query->offchannel_tx_started) ?
+ GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK;
+
+ if (gas_query_tx(gas, query, req, wait_time) < 0) {
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
MACSTR, MAC2STR(query->addr));
gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
@@ -302,6 +348,35 @@ static void gas_query_tx_comeback_req(struct gas_query *gas,
}
+static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx)
+{
+ struct gas_query *gas = eloop_data;
+ struct gas_query_pending *query = user_ctx;
+ int dialog_token;
+
+ wpa_printf(MSG_DEBUG,
+ "GAS: No response to comeback request received (retry=%u)",
+ query->retry);
+ if (gas->current != query || query->retry)
+ return;
+ dialog_token = gas_query_new_dialog_token(gas, query->addr);
+ if (dialog_token < 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "GAS: Retry GAS query due to comeback response timeout");
+ query->retry = 1;
+ query->dialog_token = dialog_token;
+ *(wpabuf_mhead_u8(query->req) + 2) = dialog_token;
+ query->wait_comeback = 0;
+ query->next_frag_id = 0;
+ wpabuf_free(query->adv_proto);
+ query->adv_proto = NULL;
+ eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ gas_query_tx_initial_req(gas, query);
+}
+
+
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
{
struct gas_query *gas = eloop_data;
@@ -319,6 +394,11 @@ static void gas_query_tx_comeback_req_delay(struct gas_query *gas,
{
unsigned int secs, usecs;
+ if (comeback_delay > 1 && query->offchannel_tx_started) {
+ offchannel_send_action_done(gas->wpa_s);
+ query->offchannel_tx_started = 0;
+ }
+
secs = (comeback_delay * 1024) / 1000000;
usecs = comeback_delay * 1024 - secs * 1000000;
wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
@@ -345,6 +425,7 @@ static void gas_query_rx_initial(struct gas_query *gas,
}
if (comeback_delay) {
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
query->wait_comeback = 1;
gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
return;
@@ -371,6 +452,7 @@ static void gas_query_rx_comeback(struct gas_query *gas,
"comeback_delay=%u)",
MAC2STR(query->addr), query->dialog_token, frag_id,
more_frags, comeback_delay);
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
@@ -447,8 +529,16 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
if (gas == NULL || len < 4)
return -1;
+ pos = data;
+ action = *pos++;
+ dialog_token = *pos++;
+
+ if (action != WLAN_PA_GAS_INITIAL_RESP &&
+ action != WLAN_PA_GAS_COMEBACK_RESP)
+ return -1; /* Not a GAS response */
+
prot = categ == WLAN_ACTION_PROTECTED_DUAL;
- pmf = pmf_in_use(gas->wpa_s, bssid);
+ pmf = pmf_in_use(gas->wpa_s, sa);
if (prot && !pmf) {
wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
return 0;
@@ -458,14 +548,6 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
return 0;
}
- pos = data;
- action = *pos++;
- dialog_token = *pos++;
-
- if (action != WLAN_PA_GAS_INITIAL_RESP &&
- action != WLAN_PA_GAS_COMEBACK_RESP)
- return -1; /* Not a GAS response */
-
query = gas_query_get_pending(gas, sa, dialog_token);
if (query == NULL) {
wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
@@ -620,11 +702,18 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
}
gas->work = work;
+ gas_query_tx_initial_req(gas, query);
+}
- if (gas_query_tx(gas, query, query->req) < 0) {
+
+static void gas_query_tx_initial_req(struct gas_query *gas,
+ struct gas_query_pending *query)
+{
+ if (gas_query_tx(gas, query, query->req,
+ GAS_QUERY_WAIT_TIME_INITIAL) < 0) {
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
MACSTR, MAC2STR(query->addr));
- gas_query_free(query, 1);
+ gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
return;
}
gas->current = query;
@@ -633,7 +722,76 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
query->dialog_token);
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
gas_query_timeout, gas, query);
+}
+
+
+static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst)
+{
+ static int next_start = 0;
+ int dialog_token;
+
+ for (dialog_token = 0; dialog_token < 256; dialog_token++) {
+ if (gas_query_dialog_token_available(
+ gas, dst, (next_start + dialog_token) % 256))
+ break;
+ }
+ if (dialog_token == 256)
+ return -1; /* Too many pending queries */
+ dialog_token = (next_start + dialog_token) % 256;
+ next_start = (dialog_token + 1) % 256;
+ return dialog_token;
+}
+
+
+static int gas_query_set_sa(struct gas_query *gas,
+ struct gas_query_pending *query)
+{
+ struct wpa_supplicant *wpa_s = gas->wpa_s;
+ struct os_reltime now;
+
+ if (!wpa_s->conf->gas_rand_mac_addr ||
+ !(wpa_s->current_bss ?
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA))) {
+ /* Use own MAC address as the transmitter address */
+ os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
+ return 0;
+ }
+
+ os_get_reltime(&now);
+
+ if (wpa_s->conf->gas_rand_mac_addr == gas->last_rand_sa_type &&
+ gas->last_mac_addr_rand.sec != 0 &&
+ !os_reltime_expired(&now, &gas->last_mac_addr_rand,
+ wpa_s->conf->gas_rand_addr_lifetime)) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: Use the previously selected random transmitter address "
+ MACSTR, MAC2STR(gas->rand_addr));
+ os_memcpy(query->sa, gas->rand_addr, ETH_ALEN);
+ return 0;
+ }
+
+ if (wpa_s->conf->gas_rand_mac_addr == 1 &&
+ random_mac_addr(gas->rand_addr) < 0) {
+ wpa_printf(MSG_ERROR, "GAS: Failed to get random address");
+ return -1;
+ }
+
+ if (wpa_s->conf->gas_rand_mac_addr == 2 &&
+ random_mac_addr_keep_oui(gas->rand_addr) < 0) {
+ wpa_printf(MSG_ERROR,
+ "GAS: Failed to get random address with same OUI");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "GAS: Use a new random transmitter address "
+ MACSTR, MAC2STR(gas->rand_addr));
+ os_memcpy(query->sa, gas->rand_addr, ETH_ALEN);
+ os_get_reltime(&gas->last_mac_addr_rand);
+ gas->last_rand_sa_type = wpa_s->conf->gas_rand_mac_addr;
+
+ return 0;
}
@@ -649,7 +807,7 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
* Returns: dialog token (>= 0) on success or -1 on failure
*/
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- struct wpabuf *req,
+ int wildcard_bssid, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -658,28 +816,26 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
{
struct gas_query_pending *query;
int dialog_token;
- static int next_start = 0;
if (wpabuf_len(req) < 3)
return -1;
- for (dialog_token = 0; dialog_token < 256; dialog_token++) {
- if (gas_query_dialog_token_available(
- gas, dst, (next_start + dialog_token) % 256))
- break;
- }
- if (dialog_token == 256)
- return -1; /* Too many pending queries */
- dialog_token = (next_start + dialog_token) % 256;
- next_start = (dialog_token + 1) % 256;
+ dialog_token = gas_query_new_dialog_token(gas, dst);
+ if (dialog_token < 0)
+ return -1;
query = os_zalloc(sizeof(*query));
if (query == NULL)
return -1;
query->gas = gas;
+ if (gas_query_set_sa(gas, query)) {
+ os_free(query);
+ return -1;
+ }
os_memcpy(query->addr, dst, ETH_ALEN);
query->dialog_token = dialog_token;
+ query->wildcard_bssid = !!wildcard_bssid;
query->freq = freq;
query->cb = cb;
query->ctx = ctx;
@@ -694,6 +850,7 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb,
query) < 0) {
+ query->req = NULL; /* caller will free this in error case */
gas_query_free(query, 1);
return -1;
}
@@ -702,18 +859,25 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
}
-/**
- * gas_query_cancel - Cancel a pending GAS query
- * @gas: GAS query data from gas_query_init()
- * @dst: Destination MAC address for the query
- * @dialog_token: Dialog token from gas_query_req()
- */
-void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token)
+int gas_query_stop(struct gas_query *gas, u8 dialog_token)
{
struct gas_query_pending *query;
- query = gas_query_get_pending(gas, dst, dialog_token);
- if (query)
- gas_query_done(gas, query, GAS_QUERY_CANCELLED);
+ dl_list_for_each(query, &gas->pending, struct gas_query_pending, list) {
+ if (query->dialog_token == dialog_token) {
+ if (!gas->work) {
+ /* The pending radio work has not yet been
+ * started, but the pending entry has a
+ * reference to the soon to be freed query.
+ * Need to remove that radio work now to avoid
+ * leaving behind a reference to freed memory.
+ */
+ radio_remove_pending_work(gas->wpa_s, query);
+ }
+ gas_query_done(gas, query, GAS_QUERY_STOPPED);
+ return 0;
+ }
+ }
+ return -1;
}
diff --git a/contrib/wpa/wpa_supplicant/gas_query.h b/contrib/wpa/wpa_supplicant/gas_query.h
index ad13490..d2b4554 100644
--- a/contrib/wpa/wpa_supplicant/gas_query.h
+++ b/contrib/wpa/wpa_supplicant/gas_query.h
@@ -19,6 +19,7 @@ void gas_query_deinit(struct gas_query *gas);
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
const u8 *bssid, u8 categ, const u8 *data, size_t len,
int freq);
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr);
/**
* enum gas_query_result - GAS query result
@@ -29,18 +30,18 @@ enum gas_query_result {
GAS_QUERY_TIMEOUT,
GAS_QUERY_PEER_ERROR,
GAS_QUERY_INTERNAL_ERROR,
- GAS_QUERY_CANCELLED,
+ GAS_QUERY_STOPPED,
GAS_QUERY_DELETED_AT_DEINIT
};
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- struct wpabuf *req,
+ int wildcard_bssid, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code),
void *ctx);
-void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token);
+int gas_query_stop(struct gas_query *gas, u8 dialog_token);
#else /* CONFIG_GAS */
diff --git a/contrib/wpa/wpa_supplicant/hs20_supplicant.c b/contrib/wpa/wpa_supplicant/hs20_supplicant.c
index a1afc85..cb236df 100644
--- a/contrib/wpa/wpa_supplicant/hs20_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/hs20_supplicant.c
@@ -25,6 +25,7 @@
#include "gas_query.h"
#include "interworking.h"
#include "hs20_supplicant.h"
+#include "base64.h"
#define OSU_MAX_ITEMS 10
@@ -48,9 +49,12 @@ struct osu_provider {
u8 bssid[ETH_ALEN];
u8 osu_ssid[SSID_MAX_LEN];
u8 osu_ssid_len;
+ u8 osu_ssid2[SSID_MAX_LEN];
+ u8 osu_ssid2_len;
char server_uri[256];
u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
char osu_nai[256];
+ char osu_nai2[256];
struct osu_lang_string friendly_name[OSU_MAX_ITEMS];
size_t friendly_name_count;
struct osu_lang_string serv_desc[OSU_MAX_ITEMS];
@@ -60,15 +64,61 @@ struct osu_provider {
};
-void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
+void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
{
+ struct wpa_bss *bss = wpa_s->current_bss;
+ u8 *bssid = wpa_s->bssid;
+ const u8 *ie;
+ const u8 *ext_capa;
+ u32 filter = 0;
+
+ if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) {
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - BSS " MACSTR
+ " is not a Hotspot 2.0 network", MAC2STR(bssid));
+ return;
+ }
+
+ ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+
+ /* Check if DGAF disabled bit is zero (5th byte in the IE) */
+ if (!ie || ie[1] < 5)
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - Can't extract DGAF bit");
+ else if (!(ie[6] & HS20_DGAF_DISABLED))
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK;
+
+ ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
+ if (!ext_capa || ext_capa[1] < 2) {
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - Can't extract Proxy ARP bit");
+ return;
+ }
+
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_PROXY_ARP))
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
+ WPA_DATA_FRAME_FILTER_FLAG_NA;
+
+ wpa_drv_configure_frame_filters(wpa_s, filter);
+}
+
+
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id, int ap_release)
+{
+ int release;
u8 conf;
+ release = (HS20_VERSION >> 4) + 1;
+ if (ap_release > 0 && release > ap_release)
+ release = ap_release;
+ if (release < 2)
+ pps_mo_id = -1;
+
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
- conf = HS20_VERSION;
+ conf = (release - 1) << 4;
if (pps_mo_id >= 0)
conf |= HS20_PPS_MO_ID_PRESENT;
wpabuf_put_u8(buf, conf);
@@ -77,6 +127,37 @@ void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
}
+void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
+ const struct wpa_ssid *ssid)
+{
+ if (!ssid->roaming_consortium_selection ||
+ !ssid->roaming_consortium_selection_len)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + ssid->roaming_consortium_selection_len);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ROAMING_CONS_SEL_OUI_TYPE);
+ wpabuf_put_data(buf, ssid->roaming_consortium_selection,
+ ssid->roaming_consortium_selection_len);
+}
+
+
+int get_hs20_version(struct wpa_bss *bss)
+{
+ const u8 *ie;
+
+ if (!bss)
+ return 0;
+
+ ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+ if (!ie || ie[1] < 5)
+ return 0;
+
+ return ((ie[6] >> 4) & 0x0f) + 1;
+}
+
+
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss)
{
@@ -164,8 +245,8 @@ void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
}
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len)
+static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+ size_t payload_len)
{
struct wpabuf *buf;
@@ -180,13 +261,14 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
- const u8 *payload, size_t payload_len)
+ const u8 *payload, size_t payload_len, int inmem)
{
struct wpabuf *buf;
int ret = 0;
int freq;
struct wpa_bss *bss;
int res;
+ struct icon_entry *icon_entry;
bss = wpa_bss_get_bssid(wpa_s, dst);
if (!bss) {
@@ -206,19 +288,131 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
- ret = -1;
+ return -1;
} else
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
+ if (inmem) {
+ icon_entry = os_zalloc(sizeof(struct icon_entry));
+ if (!icon_entry)
+ return -1;
+ os_memcpy(icon_entry->bssid, dst, ETH_ALEN);
+ icon_entry->file_name = os_malloc(payload_len + 1);
+ if (!icon_entry->file_name) {
+ os_free(icon_entry);
+ return -1;
+ }
+ os_memcpy(icon_entry->file_name, payload, payload_len);
+ icon_entry->file_name[payload_len] = '\0';
+ icon_entry->dialog_token = res;
+
+ dl_list_add(&wpa_s->icon_head, &icon_entry->list);
+ }
+
return ret;
}
+static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s,
+ const u8 *bssid,
+ const char *file_name)
+{
+ struct icon_entry *icon;
+
+ dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
+ if (os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0 &&
+ os_strcmp(icon->file_name, file_name) == 0 && icon->image)
+ return icon;
+ }
+
+ return NULL;
+}
+
+
+int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name, size_t offset, size_t size,
+ char *reply, size_t buf_len)
+{
+ struct icon_entry *icon;
+ size_t out_size;
+ unsigned char *b64;
+ size_t b64_size;
+ int reply_size;
+
+ wpa_printf(MSG_DEBUG, "HS20: Get icon " MACSTR " %s @ %u +%u (%u)",
+ MAC2STR(bssid), file_name, (unsigned int) offset,
+ (unsigned int) size, (unsigned int) buf_len);
+
+ icon = hs20_find_icon(wpa_s, bssid, file_name);
+ if (!icon || !icon->image || offset >= icon->image_len)
+ return -1;
+ if (size > icon->image_len - offset)
+ size = icon->image_len - offset;
+ out_size = buf_len - 3 /* max base64 padding */;
+ if (size * 4 > out_size * 3)
+ size = out_size * 3 / 4;
+ if (size == 0)
+ return -1;
+
+ b64 = base64_encode(&icon->image[offset], size, &b64_size);
+ if (b64 && buf_len >= b64_size) {
+ os_memcpy(reply, b64, b64_size);
+ reply_size = b64_size;
+ } else {
+ reply_size = -1;
+ }
+ os_free(b64);
+ return reply_size;
+}
+
+
+static void hs20_free_icon_entry(struct icon_entry *icon)
+{
+ wpa_printf(MSG_DEBUG, "HS20: Free stored icon from " MACSTR
+ " dialog_token=%u file_name=%s image_len=%u",
+ MAC2STR(icon->bssid), icon->dialog_token,
+ icon->file_name ? icon->file_name : "N/A",
+ (unsigned int) icon->image_len);
+ os_free(icon->file_name);
+ os_free(icon->image);
+ os_free(icon);
+}
+
+
+int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name)
+{
+ struct icon_entry *icon, *tmp;
+ int count = 0;
+
+ if (!bssid)
+ wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons");
+ else if (!file_name)
+ wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons for "
+ MACSTR, MAC2STR(bssid));
+ else
+ wpa_printf(MSG_DEBUG, "HS20: Delete stored icons for "
+ MACSTR " file name %s", MAC2STR(bssid), file_name);
+
+ dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
+ list) {
+ if ((!bssid || os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0) &&
+ (!file_name ||
+ os_strcmp(icon->file_name, file_name) == 0)) {
+ dl_list_del(&icon->list);
+ hs20_free_icon_entry(icon);
+ count++;
+ }
+ }
+ return count == 0 ? -1 : 0;
+}
+
+
static void hs20_set_osu_access_permission(const char *osu_dir,
const char *fname)
{
@@ -237,22 +431,58 @@ static void hs20_set_osu_access_permission(const char *osu_dir,
return;
}
- if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
+ if (lchown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
fname);
}
}
+
+static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s,
+ struct icon_entry *new_icon)
+{
+ struct icon_entry *icon, *tmp;
+
+ dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
+ list) {
+ if (icon == new_icon)
+ continue;
+ if (os_memcmp(icon->bssid, new_icon->bssid, ETH_ALEN) == 0 &&
+ os_strcmp(icon->file_name, new_icon->file_name) == 0) {
+ dl_list_del(&icon->list);
+ hs20_free_icon_entry(icon);
+ }
+ }
+}
+
+
static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *pos,
- size_t slen)
+ size_t slen, u8 dialog_token)
{
char fname[256];
int png;
FILE *f;
u16 data_len;
+ struct icon_entry *icon;
+
+ dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
+ if (icon->dialog_token == dialog_token && !icon->image &&
+ os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) {
+ icon->image = os_memdup(pos, slen);
+ if (!icon->image)
+ return -1;
+ icon->image_len = slen;
+ hs20_remove_duplicate_icons(wpa_s, icon);
+ wpa_msg(wpa_s, MSG_INFO,
+ RX_HS20_ICON MACSTR " %s %u",
+ MAC2STR(sa), icon->file_name,
+ (unsigned int) icon->image_len);
+ return 0;
+ }
+ }
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File",
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File",
MAC2STR(sa));
if (slen < 4) {
@@ -315,7 +545,7 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
}
fclose(f);
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname);
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname);
return 0;
}
@@ -358,7 +588,7 @@ static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res)
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
- const u8 *data, size_t slen)
+ const u8 *data, size_t slen, u8 dialog_token)
{
const u8 *pos = data;
u8 subtype;
@@ -379,7 +609,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
switch (subtype) {
case HS20_STYPE_CAPABILITY_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" HS Capability List", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
if (anqp) {
@@ -389,7 +619,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Operator Friendly Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
if (anqp) {
@@ -405,7 +635,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
"Metrics value from " MACSTR, MAC2STR(sa));
break;
}
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
pos[9], pos[10], WPA_GET_LE16(pos + 11));
@@ -415,7 +645,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Connection Capability", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
if (anqp) {
@@ -425,7 +655,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_OPERATING_CLASS:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Operating Class", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
if (anqp) {
@@ -435,7 +665,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_OSU_PROVIDERS_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" OSU Providers list", MAC2STR(sa));
wpa_s->num_prov_found++;
if (anqp) {
@@ -445,7 +675,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case HS20_STYPE_ICON_BINARY_FILE:
- ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen);
+ ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen,
+ dialog_token);
if (wpa_s->fetch_osu_icon_in_progress) {
hs20_osu_icon_fetch_result(wpa_s, ret);
eloop_cancel_timeout(hs20_continue_icon_fetch,
@@ -454,6 +685,25 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
wpa_s, NULL);
}
break;
+ case HS20_STYPE_OPERATOR_ICON_METADATA:
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
+ " Operator Icon Metadata", MAC2STR(sa));
+ wpa_hexdump(MSG_DEBUG, "Operator Icon Metadata", pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->hs20_operator_icon_metadata);
+ anqp->hs20_operator_icon_metadata =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
+ " OSU Providers NAI List", MAC2STR(sa));
+ if (anqp) {
+ wpabuf_free(anqp->hs20_osu_providers_nai_list);
+ anqp->hs20_osu_providers_nai_list =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
default:
wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
break;
@@ -511,7 +761,10 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
wpa_s->conf->osu_dir);
f = fopen(fname, "w");
if (f == NULL) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not write OSU provider information");
hs20_free_osu_prov(wpa_s);
+ wpa_s->fetch_anqp_in_progress = 0;
return;
}
@@ -530,8 +783,15 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
wpa_ssid_txt(osu->osu_ssid,
osu->osu_ssid_len));
}
+ if (osu->osu_ssid2_len) {
+ fprintf(f, "osu_ssid2=%s\n",
+ wpa_ssid_txt(osu->osu_ssid2,
+ osu->osu_ssid2_len));
+ }
if (osu->osu_nai[0])
fprintf(f, "osu_nai=%s\n", osu->osu_nai);
+ if (osu->osu_nai2[0])
+ fprintf(f, "osu_nai2=%s\n", osu->osu_nai2);
for (j = 0; j < osu->friendly_name_count; j++) {
fprintf(f, "friendly_name=%s:%s\n",
osu->friendly_name[j].lang,
@@ -579,7 +839,8 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
if (hs20_anqp_send_req(wpa_s, osu->bssid,
BIT(HS20_STYPE_ICON_REQUEST),
(u8 *) icon->filename,
- os_strlen(icon->filename)) < 0) {
+ os_strlen(icon->filename),
+ 0) < 0) {
icon->failed = 1;
continue;
}
@@ -594,6 +855,7 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
const u8 *osu_ssid, u8 osu_ssid_len,
+ const u8 *osu_ssid2, u8 osu_ssid2_len,
const u8 *pos, size_t len)
{
struct osu_provider *prov;
@@ -615,9 +877,12 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
os_memcpy(prov->bssid, bss->bssid, ETH_ALEN);
os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len);
prov->osu_ssid_len = osu_ssid_len;
+ if (osu_ssid2)
+ os_memcpy(prov->osu_ssid2, osu_ssid2, osu_ssid2_len);
+ prov->osu_ssid2_len = osu_ssid2_len;
/* OSU Friendly Name Length */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
"Friendly Name Length");
return;
@@ -633,9 +898,9 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos += len2;
/* OSU Friendly Name Duples */
- while (pos2 + 4 <= pos && prov->friendly_name_count < OSU_MAX_ITEMS) {
+ while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) {
struct osu_lang_string *f;
- if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
+ if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) {
wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
break;
}
@@ -646,7 +911,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
/* OSU Server URI */
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG,
"HS 2.0: Not enough room for OSU Server URI length");
return;
@@ -661,7 +926,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos += uri_len;
/* OSU Method list */
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
"list length");
return;
@@ -681,7 +946,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
/* Icons Available Length */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
"Available Length");
return;
@@ -701,7 +966,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
struct osu_icon *icon = &prov->icon[prov->icon_count];
u8 flen;
- if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) {
+ if (2 + 2 + 3 + 1 + 1 > pos - pos2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
break;
}
@@ -713,46 +978,46 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
os_memcpy(icon->lang, pos2, 3);
pos2 += 3;
- flen = pos2[0];
- if (flen > pos - pos2 - 1) {
+ flen = *pos2++;
+ if (flen > pos - pos2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
break;
}
- os_memcpy(icon->icon_type, pos2 + 1, flen);
- pos2 += 1 + flen;
+ os_memcpy(icon->icon_type, pos2, flen);
+ pos2 += flen;
- if (pos2 + 1 > pos) {
+ if (pos - pos2 < 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
"Filename length");
break;
}
- flen = pos2[0];
- if (flen > pos - pos2 - 1) {
+ flen = *pos2++;
+ if (flen > pos - pos2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
"Filename");
break;
}
- os_memcpy(icon->filename, pos2 + 1, flen);
- pos2 += 1 + flen;
+ os_memcpy(icon->filename, pos2, flen);
+ pos2 += flen;
prov->icon_count++;
}
/* OSU_NAI */
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
return;
}
- osu_nai_len = pos[0];
- if (osu_nai_len > end - pos - 1) {
+ osu_nai_len = *pos++;
+ if (osu_nai_len > end - pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
return;
}
- os_memcpy(prov->osu_nai, pos + 1, osu_nai_len);
- pos += 1 + osu_nai_len;
+ os_memcpy(prov->osu_nai, pos, osu_nai_len);
+ pos += osu_nai_len;
/* OSU Service Description Length */
- if (pos + 2 > end) {
+ if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
"Service Description Length");
return;
@@ -768,20 +1033,20 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos += len2;
/* OSU Service Description Duples */
- while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) {
+ while (pos - pos2 >= 4 && prov->serv_desc_count < OSU_MAX_ITEMS) {
struct osu_lang_string *f;
u8 descr_len;
- descr_len = pos2[0];
- if (descr_len > pos - pos2 - 1 || descr_len < 3) {
+ descr_len = *pos2++;
+ if (descr_len > pos - pos2 || descr_len < 3) {
wpa_printf(MSG_DEBUG, "Invalid OSU Service "
"Description");
break;
}
f = &prov->serv_desc[prov->serv_desc_count++];
- os_memcpy(f->lang, pos2 + 1, 3);
- os_memcpy(f->text, pos2 + 1 + 3, descr_len - 3);
- pos2 += 1 + descr_len;
+ os_memcpy(f->lang, pos2, 3);
+ os_memcpy(f->text, pos2 + 3, descr_len - 3);
+ pos2 += descr_len;
}
wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
@@ -796,18 +1061,30 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
struct wpabuf *prov_anqp;
const u8 *pos, *end;
u16 len;
- const u8 *osu_ssid;
- u8 osu_ssid_len;
+ const u8 *osu_ssid, *osu_ssid2;
+ u8 osu_ssid_len, osu_ssid2_len;
u8 num_providers;
hs20_free_osu_prov(wpa_s);
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ struct wpa_ie_data data;
+ const u8 *ie;
+
if (bss->anqp == NULL)
continue;
prov_anqp = bss->anqp->hs20_osu_providers_list;
if (prov_anqp == NULL)
continue;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &data) == 0 &&
+ (data.key_mgmt & WPA_KEY_MGMT_OSEN)) {
+ osu_ssid2 = bss->ssid;
+ osu_ssid2_len = bss->ssid_len;
+ } else {
+ osu_ssid2 = NULL;
+ osu_ssid2_len = 0;
+ }
wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from "
MACSTR, MAC2STR(bss->bssid));
wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list",
@@ -816,9 +1093,9 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
end = pos + wpabuf_len(prov_anqp);
/* OSU SSID */
- if (pos + 1 > end)
+ if (end - pos < 1)
continue;
- if (pos + 1 + pos[0] > end) {
+ if (1 + pos[0] > end - pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
"OSU SSID");
continue;
@@ -832,7 +1109,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
osu_ssid = pos;
pos += osu_ssid_len;
- if (pos + 1 > end) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
"Number of OSU Providers");
continue;
@@ -842,14 +1119,15 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
num_providers);
/* OSU Providers */
- while (pos + 2 < end && num_providers > 0) {
+ while (end - pos > 2 && num_providers > 0) {
num_providers--;
len = WPA_GET_LE16(pos);
pos += 2;
if (len > (unsigned int) (end - pos))
break;
hs20_osu_add_prov(wpa_s, bss, osu_ssid,
- osu_ssid_len, pos, len);
+ osu_ssid_len, osu_ssid2,
+ osu_ssid2_len, pos, len);
pos += len;
}
@@ -858,6 +1136,35 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
"extra data after OSU Providers",
(int) (end - pos));
}
+
+ prov_anqp = bss->anqp->hs20_osu_providers_nai_list;
+ if (!prov_anqp)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Parsing OSU Providers NAI List from "
+ MACSTR, MAC2STR(bss->bssid));
+ wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers NAI List",
+ prov_anqp);
+ pos = wpabuf_head(prov_anqp);
+ end = pos + wpabuf_len(prov_anqp);
+ num_providers = 0;
+ while (end - pos > 0) {
+ len = *pos++;
+ if (end - pos < len) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Not enough room for OSU_NAI");
+ break;
+ }
+ if (num_providers >= wpa_s->osu_prov_count) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Ignore unexpected OSU Provider NAI List entries");
+ break;
+ }
+ os_memcpy(wpa_s->osu_prov[num_providers].osu_nai2,
+ pos, len);
+ pos += len;
+ num_providers++;
+ }
}
wpa_s->fetch_osu_icon_in_progress = 1;
@@ -882,7 +1189,7 @@ static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s,
}
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan)
{
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
@@ -913,7 +1220,16 @@ int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
wpa_s->num_osu_scans = 0;
wpa_s->num_prov_found = 0;
- hs20_start_osu_scan(wpa_s);
+ if (skip_scan) {
+ wpa_s->network_select = 0;
+ wpa_s->fetch_all_anqp = 1;
+ wpa_s->fetch_osu_info = 1;
+ wpa_s->fetch_osu_icon_in_progress = 0;
+
+ interworking_start_fetch_anqp(wpa_s);
+ } else {
+ hs20_start_osu_scan(wpa_s);
+ }
return 0;
}
@@ -1002,8 +1318,28 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
}
+void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url)
+{
+ if (!wpa_sm_pmf_enabled(wpa_s->wpa)) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Ignore Terms and Conditions Acceptance since PMF was not enabled");
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url);
+}
+
+
+void hs20_init(struct wpa_supplicant *wpa_s)
+{
+ dl_list_init(&wpa_s->icon_head);
+}
+
+
void hs20_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
hs20_free_osu_prov(wpa_s);
+ if (wpa_s->icon_head.next)
+ hs20_del_icon(wpa_s, NULL, NULL);
}
diff --git a/contrib/wpa/wpa_supplicant/hs20_supplicant.h b/contrib/wpa/wpa_supplicant/hs20_supplicant.h
index 85b5120..e43414b 100644
--- a/contrib/wpa/wpa_supplicant/hs20_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/hs20_supplicant.h
@@ -8,17 +8,20 @@
#ifndef HS20_SUPPLICANT_H
#define HS20_SUPPLICANT_H
-void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id);
+void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s);
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id,
+ int ap_release);
+void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
+ const struct wpa_ssid *ssid);
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
- const u8 *payload, size_t payload_len);
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len);
+ const u8 *payload, size_t payload_len, int inmem);
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
struct wpabuf *buf);
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
- const u8 *data, size_t slen);
+ const u8 *data, size_t slen, u8 dialog_token);
+int get_hs20_version(struct wpa_bss *bss);
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
@@ -28,14 +31,21 @@ void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
const char *url, u8 osu_method);
void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
u16 reauth_delay, const char *url);
+void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url);
void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s);
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s);
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan);
void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s);
void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s);
void hs20_start_osu_scan(struct wpa_supplicant *wpa_s);
+void hs20_init(struct wpa_supplicant *wpa_s);
void hs20_deinit(struct wpa_supplicant *wpa_s);
+int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name, size_t offset, size_t size,
+ char *reply, size_t buf_len);
+int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name);
#endif /* HS20_SUPPLICANT_H */
diff --git a/contrib/wpa/wpa_supplicant/ibss_rsn.c b/contrib/wpa/wpa_supplicant/ibss_rsn.c
index d9d0ae7..e96ea65 100644
--- a/contrib/wpa/wpa_supplicant/ibss_rsn.c
+++ b/contrib/wpa/wpa_supplicant/ibss_rsn.c
@@ -221,6 +221,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
peer->supp = wpa_sm_init(ctx);
if (peer->supp == NULL) {
wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+ os_free(ctx);
return -1;
}
@@ -230,7 +231,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
- wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL);
+ wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL, NULL);
peer->supp_ie_len = sizeof(peer->supp_ie);
if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
@@ -258,9 +259,15 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level,
static const u8 * auth_get_psk(void *ctx, const u8 *addr,
- const u8 *p2p_dev_addr, const u8 *prev_psk)
+ const u8 *p2p_dev_addr, const u8 *prev_psk,
+ size_t *psk_len, int *vlan_id)
{
struct ibss_rsn *ibss_rsn = ctx;
+
+ if (psk_len)
+ *psk_len = PMK_LEN;
+ if (vlan_id)
+ *vlan_id = 0;
wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
__func__, MAC2STR(addr), prev_psk);
if (prev_psk)
@@ -404,10 +411,18 @@ static void auth_set_eapol(void *ctx, const u8 *addr,
static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
- const u8 *own_addr)
+ const u8 *own_addr, struct wpa_ssid *ssid)
{
struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
+ static const struct wpa_auth_callbacks cb = {
+ .logger = auth_logger,
+ .set_eapol = auth_set_eapol,
+ .send_eapol = auth_send_eapol,
+ .get_psk = auth_get_psk,
+ .set_key = auth_set_key,
+ .for_each_sta = auth_for_each_sta,
+ .disconnect = ibss_rsn_disconnect,
+ };
wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
@@ -418,19 +433,11 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
conf.rsn_pairwise = WPA_CIPHER_CCMP;
conf.wpa_group = WPA_CIPHER_CCMP;
conf.eapol_version = 2;
- conf.wpa_group_rekey = 600;
-
- os_memset(&cb, 0, sizeof(cb));
- cb.ctx = ibss_rsn;
- cb.logger = auth_logger;
- cb.set_eapol = auth_set_eapol;
- cb.send_eapol = auth_send_eapol;
- cb.get_psk = auth_get_psk;
- cb.set_key = auth_set_key;
- cb.for_each_sta = auth_for_each_sta;
- cb.disconnect = ibss_rsn_disconnect;
-
- ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
+ conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600;
+ conf.wpa_group_update_count = 4;
+ conf.wpa_pairwise_update_count = 4;
+
+ ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb, ibss_rsn);
if (ibss_rsn->auth_group == NULL) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
return -1;
@@ -452,12 +459,12 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
}
/* TODO: get peer RSN IE with Probe Request */
- if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth,
+ if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, 0,
(u8 *) "\x30\x14\x01\x00"
"\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x02"
- "\x00\x00", 22, NULL, 0) !=
+ "\x00\x00", 22, NULL, 0, NULL, 0) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
@@ -665,7 +672,8 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
}
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
struct ibss_rsn *ibss_rsn;
@@ -674,7 +682,7 @@ struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
return NULL;
ibss_rsn->wpa_s = wpa_s;
- if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) {
+ if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr, ssid) < 0) {
ibss_rsn_deinit(ibss_rsn);
return NULL;
}
@@ -758,10 +766,9 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
if (supp < 0)
return -1;
- tmp = os_malloc(len);
+ tmp = os_memdup(buf, len);
if (tmp == NULL)
return -1;
- os_memcpy(tmp, buf, len);
if (supp) {
peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER;
wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from "
@@ -836,6 +843,18 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
MAC2STR(addr));
if (peer &&
+ peer->authentication_status & (IBSS_RSN_SET_PTK_SUPP |
+ IBSS_RSN_SET_PTK_AUTH)) {
+ /* Clear the TK for this pair to allow recovery from the case
+ * where the peer STA has restarted and lost its key while we
+ * still have a pairwise key configured. */
+ wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
+ MACSTR, MAC2STR(addr));
+ wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
+ NULL, 0, NULL, 0);
+ }
+
+ if (peer &&
peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
if (peer->own_auth_tx.sec) {
struct os_reltime now, diff;
diff --git a/contrib/wpa/wpa_supplicant/ibss_rsn.h b/contrib/wpa/wpa_supplicant/ibss_rsn.h
index 67fae2d..626c543 100644
--- a/contrib/wpa/wpa_supplicant/ibss_rsn.h
+++ b/contrib/wpa/wpa_supplicant/ibss_rsn.h
@@ -51,7 +51,8 @@ struct ibss_rsn {
};
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn);
int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
diff --git a/contrib/wpa/wpa_supplicant/interworking.c b/contrib/wpa/wpa_supplicant/interworking.c
index fd47c179..f94cd16 100644
--- a/contrib/wpa/wpa_supplicant/interworking.c
+++ b/contrib/wpa/wpa_supplicant/interworking.c
@@ -106,10 +106,12 @@ static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
if (buf == NULL)
return NULL;
- len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
- for (i = 0; i < num_ids; i++)
- wpabuf_put_le16(buf, info_ids[i]);
- gas_anqp_set_element_len(buf, len_pos);
+ if (num_ids > 0) {
+ len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
+ for (i = 0; i < num_ids; i++)
+ wpabuf_put_le16(buf, info_ids[i]);
+ gas_anqp_set_element_len(buf, len_pos);
+ }
if (extra)
wpabuf_put_buf(buf, extra);
@@ -146,6 +148,8 @@ static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
return 1;
if (cred->required_roaming_consortium_len)
return 1;
+ if (cred->num_roaming_consortiums)
+ return 1;
}
return 0;
}
@@ -299,8 +303,10 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
if (all)
wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
- if (all)
+ if (all) {
wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST);
+ wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
+ }
gas_anqp_set_element_len(extra, len_pos);
}
#endif /* CONFIG_HS20 */
@@ -310,7 +316,7 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
+ res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf,
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
@@ -362,13 +368,13 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
u8 elen, auth_count, a;
const u8 *e_end;
- if (pos + 3 > end) {
+ if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
return NULL;
}
elen = *pos++;
- if (pos + elen > end || elen < 2) {
+ if (elen > end - pos || elen < 2) {
wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
return NULL;
}
@@ -381,14 +387,19 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
for (a = 0; a < auth_count; a++) {
u8 id, len;
- if (pos + 2 > end || pos + 2 + pos[1] > end) {
- wpa_printf(MSG_DEBUG, "No room for Authentication "
- "Parameter subfield");
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG,
+ "No room for Authentication Parameter subfield header");
return NULL;
}
id = *pos++;
len = *pos++;
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "No room for Authentication Parameter subfield");
+ return NULL;
+ }
switch (id) {
case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
@@ -463,7 +474,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
pos += 2;
- if (pos + len > end || len < 3) {
+ if (len > end - pos || len < 3) {
wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
"(len=%u; left=%u)",
len, (unsigned int) (end - pos));
@@ -473,7 +484,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
r->encoding = *pos++;
realm_len = *pos++;
- if (pos + realm_len > f_end) {
+ if (realm_len > f_end - pos) {
wpa_printf(MSG_DEBUG, "No room for NAI Realm "
"(len=%u; left=%u)",
realm_len, (unsigned int) (f_end - pos));
@@ -485,13 +496,13 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
return NULL;
pos += realm_len;
- if (pos + 1 > f_end) {
+ if (f_end - pos < 1) {
wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
return NULL;
}
r->eap_count = *pos++;
wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
- if (pos + r->eap_count * 3 > f_end) {
+ if (r->eap_count * 3 > f_end - pos) {
wpa_printf(MSG_DEBUG, "No room for EAP Methods");
return NULL;
}
@@ -746,7 +757,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
return 0;
pos = wpabuf_head_u8(anqp);
end = pos + wpabuf_len(anqp);
- if (pos + 2 > end)
+ if (end - pos < 2)
return 0;
if (*pos != 0) {
wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
@@ -754,7 +765,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
}
pos++;
udhl = *pos++;
- if (pos + udhl > end) {
+ if (udhl > end - pos) {
wpa_printf(MSG_DEBUG, "Invalid UDHL");
return 0;
}
@@ -764,12 +775,12 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
imsi, mnc_len);
- while (pos + 2 <= end) {
+ while (end - pos >= 2) {
u8 iei, len;
const u8 *l_end;
iei = *pos++;
len = *pos++ & 0x7f;
- if (pos + len > end)
+ if (len > end - pos)
break;
l_end = pos + len;
@@ -780,7 +791,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
pos, len);
num = *pos++;
for (i = 0; i < num; i++) {
- if (pos + 3 > l_end)
+ if (l_end - pos < 3)
break;
if (os_memcmp(pos, plmn, 3) == 0 ||
os_memcmp(pos, plmn2, 3) == 0)
@@ -945,11 +956,10 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
if (!key_mgmt)
key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
- if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0)
- return -1;
- if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
- return -1;
- if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+ if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
+ wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
+ wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 ||
+ wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
}
@@ -1082,12 +1092,12 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
* OI #1, [OI #2], [OI #3]
*/
- if (pos + 2 > end)
+ if (end - pos < 2)
return 0;
pos++; /* skip Number of ANQP OIs */
lens = *pos++;
- if (pos + (lens & 0x0f) + (lens >> 4) > end)
+ if ((lens & 0x0f) + (lens >> 4) > end - pos)
return 0;
if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
@@ -1121,7 +1131,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
/* Set of <OI Length, OI> duples */
while (pos < end) {
len = *pos++;
- if (pos + len > end)
+ if (len > end - pos)
break;
if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
return 1;
@@ -1140,6 +1150,23 @@ static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
}
+static int cred_roaming_consortiums_match(const u8 *ie,
+ const struct wpabuf *anqp,
+ const struct wpa_cred *cred)
+{
+ unsigned int i;
+
+ for (i = 0; i < cred->num_roaming_consortiums; i++) {
+ if (roaming_consortium_match(ie, anqp,
+ cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
{
const u8 *ie;
@@ -1182,6 +1209,7 @@ static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred, struct wpa_bss *bss)
{
+#ifdef CONFIG_HS20
int res;
unsigned int dl_bandwidth, ul_bandwidth;
const u8 *wan;
@@ -1233,6 +1261,7 @@ static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s,
if (cred->min_ul_bandwidth_roaming > ul_bandwidth)
return 1;
}
+#endif /* CONFIG_HS20 */
return 0;
}
@@ -1260,9 +1289,11 @@ static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_HS20
+
static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
{
- while (pos + 4 <= end) {
+ while (end - pos >= 4) {
if (pos[0] == proto && pos[3] == 1 /* Open */)
return 1;
pos += 4;
@@ -1275,7 +1306,7 @@ static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
u16 port)
{
- while (pos + 4 <= end) {
+ while (end - pos >= 4) {
if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port &&
pos[3] == 1 /* Open */)
return 1;
@@ -1285,10 +1316,13 @@ static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
return 0;
}
+#endif /* CONFIG_HS20 */
+
static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred, struct wpa_bss *bss)
{
+#ifdef CONFIG_HS20
int res;
const u8 *capab, *end;
unsigned int i, j;
@@ -1325,6 +1359,7 @@ static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
}
}
}
+#endif /* CONFIG_HS20 */
return 0;
}
@@ -1336,27 +1371,28 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
{
struct wpa_cred *cred, *selected = NULL;
const u8 *ie;
+ const struct wpabuf *anqp;
int is_excluded = 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+ anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
- if (ie == NULL &&
- (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+ if (!ie && !anqp)
return NULL;
if (wpa_s->conf->cred == NULL)
return NULL;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- if (cred->roaming_consortium_len == 0)
+ if (cred->roaming_consortium_len == 0 &&
+ cred->num_roaming_consortiums == 0)
continue;
- if (!roaming_consortium_match(ie,
- bss->anqp ?
- bss->anqp->roaming_consortium :
- NULL,
- cred->roaming_consortium,
- cred->roaming_consortium_len))
+ if ((cred->roaming_consortium_len == 0 ||
+ !roaming_consortium_match(ie, anqp,
+ cred->roaming_consortium,
+ cred->roaming_consortium_len)) &&
+ !cred_roaming_consortiums_match(ie, anqp, cred))
continue;
if (cred_no_required_oi_match(cred, bss))
@@ -1438,7 +1474,24 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid,
os_free(anon);
}
- if (cred->username && cred->username[0] &&
+ if (!ttls && cred->username && cred->username[0] && cred->realm &&
+ !os_strchr(cred->username, '@')) {
+ char *id;
+ size_t buflen;
+ int res;
+
+ buflen = os_strlen(cred->username) + 1 +
+ os_strlen(cred->realm) + 1;
+
+ id = os_malloc(buflen);
+ if (!id)
+ return -1;
+ os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm);
+ res = wpa_config_set_quoted(ssid, "identity", id);
+ os_free(id);
+ if (res < 0)
+ return -1;
+ } else if (cred->username && cred->username[0] &&
wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
return -1;
@@ -1505,6 +1558,9 @@ static int interworking_connect_roaming_consortium(
struct wpa_bss *bss, int only_add)
{
struct wpa_ssid *ssid;
+ const u8 *ie;
+ const struct wpabuf *anqp;
+ unsigned int i;
wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
" based on roaming consortium match", MAC2STR(bss->bssid));
@@ -1534,6 +1590,26 @@ static int interworking_connect_roaming_consortium(
if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+ anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
+ for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) {
+ if (!roaming_consortium_match(
+ ie, anqp, cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]))
+ continue;
+
+ ssid->roaming_consortium_selection =
+ os_malloc(cred->roaming_consortiums_len[i]);
+ if (!ssid->roaming_consortium_selection)
+ goto fail;
+ os_memcpy(ssid->roaming_consortium_selection,
+ cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]);
+ ssid->roaming_consortium_selection_len =
+ cred->roaming_consortiums_len[i];
+ break;
+ }
+
if (cred->eap_method == NULL) {
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: No EAP method set for credential using roaming consortium");
@@ -1560,9 +1636,8 @@ fail:
}
-static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss, int allow_excluded,
- int only_add)
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ int only_add)
{
struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
@@ -1570,7 +1645,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
struct nai_realm_eap *eap = NULL;
u16 count, i;
char buf[100];
- int excluded = 0, *excl = allow_excluded ? &excluded : NULL;
+ int excluded = 0, *excl = &excluded;
const char *name;
if (wpa_s->conf->cred == NULL || bss == NULL)
@@ -1584,8 +1659,8 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
}
wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR
- " for connection (allow_excluded=%d)",
- MAC2STR(bss->bssid), allow_excluded);
+ " for connection",
+ MAC2STR(bss->bssid));
if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
/*
@@ -1603,7 +1678,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d",
cred_rc->priority, cred_rc->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1612,7 +1687,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d",
cred->priority, cred->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1622,7 +1697,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest 3GPP matching credential priority %d sp_priority %d",
cred_3gpp->priority, cred_3gpp->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1635,7 +1710,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)",
cred_rc->priority, cred_rc->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1645,7 +1720,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)",
cred->priority, cred->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1655,7 +1730,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)",
cred_3gpp->priority, cred_3gpp->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
}
@@ -1742,9 +1817,10 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
switch (eap->method) {
case EAP_TYPE_TTLS:
if (eap->inner_method) {
- os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
- eap_get_name(EAP_VENDOR_IETF,
- eap->inner_method));
+ name = eap_get_name(EAP_VENDOR_IETF, eap->inner_method);
+ if (!name)
+ goto fail;
+ os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", name);
if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
goto fail;
break;
@@ -1820,13 +1896,6 @@ fail:
}
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- int only_add)
-{
- return interworking_connect_helper(wpa_s, bss, 1, only_add);
-}
-
-
#ifdef PCSC_FUNCS
static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s)
{
@@ -1874,7 +1943,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
size_t len;
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: IMSI not available - try to read again through eap_proxy");
- wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
+ wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
wpa_s->imsi,
&len);
if (wpa_s->mnc_len > 0) {
@@ -2125,23 +2194,27 @@ int domain_name_list_contains(struct wpabuf *domain_names,
pos = wpabuf_head(domain_names);
end = pos + wpabuf_len(domain_names);
- while (pos + 1 < end) {
- if (pos + 1 + pos[0] > end)
+ while (end - pos > 1) {
+ u8 elen;
+
+ elen = *pos++;
+ if (elen > end - pos)
break;
wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
- pos + 1, pos[0]);
- if (pos[0] == len &&
- os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
+ pos, elen);
+ if (elen == len &&
+ os_strncasecmp(domain, (const char *) pos, len) == 0)
return 1;
- if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') {
- const char *ap = (const char *) (pos + 1);
- int offset = pos[0] - len;
+ if (!exact_match && elen > len && pos[elen - len - 1] == '.') {
+ const char *ap = (const char *) pos;
+ int offset = elen - len;
+
if (os_strncasecmp(domain, ap + offset, len) == 0)
return 1;
}
- pos += 1 + pos[0];
+ pos += elen;
}
return 0;
@@ -2506,7 +2579,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
MAC2STR(selected->bssid));
interworking_connect(wpa_s, selected, 0);
- }
+ } else if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
}
@@ -2552,7 +2626,6 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
int found = 0;
- const u8 *ie;
wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - "
"fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d",
@@ -2564,17 +2637,18 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
return;
}
+#ifdef CONFIG_HS20
if (wpa_s->fetch_osu_icon_in_progress) {
wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)");
hs20_next_osu_icon(wpa_s);
return;
}
+#endif /* CONFIG_HS20 */
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (!(bss->caps & IEEE80211_CAP_ESS))
continue;
- ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
- if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
+ if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_INTERWORKING))
continue; /* AP does not support Interworking */
if (disallowed_bssid(wpa_s, bss->bssid) ||
disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
@@ -2602,6 +2676,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
}
if (found == 0) {
+#ifdef CONFIG_HS20
if (wpa_s->fetch_osu_info) {
if (wpa_s->num_prov_found == 0 &&
wpa_s->fetch_osu_waiting_scan &&
@@ -2614,6 +2689,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
hs20_osu_icon_fetch(wpa_s);
return;
}
+#endif /* CONFIG_HS20 */
wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
wpa_s->fetch_anqp_in_progress = 0;
if (wpa_s->network_select)
@@ -2664,10 +2740,11 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
- u16 info_ids[], size_t num_ids, u32 subtypes)
+ u16 info_ids[], size_t num_ids, u32 subtypes,
+ u32 mbo_subtypes)
{
struct wpabuf *buf;
- struct wpabuf *hs20_buf = NULL;
+ struct wpabuf *extra_buf = NULL;
int ret = 0;
int freq;
struct wpa_bss *bss;
@@ -2690,19 +2767,36 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
#ifdef CONFIG_HS20
if (subtypes != 0) {
- hs20_buf = wpabuf_alloc(100);
- if (hs20_buf == NULL)
+ extra_buf = wpabuf_alloc(100);
+ if (extra_buf == NULL)
return -1;
- hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf);
+ hs20_put_anqp_req(subtypes, NULL, 0, extra_buf);
}
#endif /* CONFIG_HS20 */
- buf = anqp_build_req(info_ids, num_ids, hs20_buf);
- wpabuf_free(hs20_buf);
+#ifdef CONFIG_MBO
+ if (mbo_subtypes) {
+ struct wpabuf *mbo;
+
+ mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes);
+ if (mbo) {
+ if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
+ wpabuf_free(extra_buf);
+ wpabuf_free(mbo);
+ return -1;
+ }
+ wpabuf_put_buf(extra_buf, mbo);
+ wpabuf_free(mbo);
+ }
+ }
+#endif /* CONFIG_MBO */
+
+ buf = anqp_build_req(info_ids, num_ids, extra_buf);
+ wpabuf_free(extra_buf);
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
@@ -2716,23 +2810,82 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
}
+static void anqp_add_extra(struct wpa_supplicant *wpa_s,
+ struct wpa_bss_anqp *anqp, u16 info_id,
+ const u8 *data, size_t slen)
+{
+ struct wpa_bss_anqp_elem *tmp, *elem = NULL;
+
+ if (!anqp)
+ return;
+
+ dl_list_for_each(tmp, &anqp->anqp_elems, struct wpa_bss_anqp_elem,
+ list) {
+ if (tmp->infoid == info_id) {
+ elem = tmp;
+ break;
+ }
+ }
+
+ if (!elem) {
+ elem = os_zalloc(sizeof(*elem));
+ if (!elem)
+ return;
+ elem->infoid = info_id;
+ dl_list_add(&anqp->anqp_elems, &elem->list);
+ } else {
+ wpabuf_free(elem->payload);
+ }
+
+ elem->payload = wpabuf_alloc_copy(data, slen);
+ if (!elem->payload) {
+ dl_list_del(&elem->list);
+ os_free(elem);
+ }
+}
+
+
+static void interworking_parse_venue_url(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t len)
+{
+ const u8 *pos = data, *end = data + len;
+ char url[255];
+
+ while (end - pos >= 2) {
+ u8 slen, num;
+
+ slen = *pos++;
+ if (slen < 1 || slen > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Truncated Venue URL Duple field");
+ return;
+ }
+
+ num = *pos++;
+ os_memcpy(url, pos, slen - 1);
+ url[slen - 1] = '\0';
+ wpa_msg(wpa_s, MSG_INFO, RX_VENUE_URL "%u %s", num, url);
+ pos += slen - 1;
+ }
+}
+
+
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
u16 info_id,
- const u8 *data, size_t slen)
+ const u8 *data, size_t slen,
+ u8 dialog_token)
{
const u8 *pos = data;
struct wpa_bss_anqp *anqp = NULL;
-#ifdef CONFIG_HS20
u8 type;
-#endif /* CONFIG_HS20 */
if (bss)
anqp = bss->anqp;
switch (info_id) {
case ANQP_CAPABILITY_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" ANQP Capability list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list",
pos, slen);
@@ -2742,7 +2895,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_VENUE_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Venue Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
if (anqp) {
@@ -2751,7 +2904,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_NETWORK_AUTH_TYPE:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Network Authentication Type information",
MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
@@ -2762,7 +2915,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_ROAMING_CONSORTIUM:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Roaming Consortium list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
pos, slen);
@@ -2772,7 +2925,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" IP Address Type Availability information",
MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
@@ -2784,7 +2937,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_NAI_REALM:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" NAI Realm list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
if (anqp) {
@@ -2793,7 +2946,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_3GPP_CELLULAR_NETWORK:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" 3GPP Cellular Network information", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
pos, slen);
@@ -2803,7 +2956,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
}
break;
case ANQP_DOMAIN_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Domain Name list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
if (anqp) {
@@ -2811,12 +2964,35 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
anqp->domain_name = wpabuf_alloc_copy(pos, slen);
}
break;
+#ifdef CONFIG_FILS
+ case ANQP_FILS_REALM_INFO:
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
+ " FILS Realm Information", MAC2STR(sa));
+ wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: FILS Realm Information",
+ pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->fils_realm_info);
+ anqp->fils_realm_info = wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+#endif /* CONFIG_FILS */
+ case ANQP_VENUE_URL:
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL",
+ MAC2STR(sa));
+ anqp_add_extra(wpa_s, anqp, info_id, pos, slen);
+
+ if (!pmf_in_use(wpa_s, sa)) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Ignore Venue URL since PMF was not enabled");
+ break;
+ }
+ interworking_parse_venue_url(wpa_s, pos, slen);
+ break;
case ANQP_VENDOR_SPECIFIC:
if (slen < 3)
return;
switch (WPA_GET_BE24(pos)) {
-#ifdef CONFIG_HS20
case OUI_WFA:
pos += 3;
slen -= 3;
@@ -2827,18 +3003,26 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
slen--;
switch (type) {
+#ifdef CONFIG_HS20
case HS20_ANQP_OUI_TYPE:
hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa,
- pos, slen);
+ pos, slen,
+ dialog_token);
break;
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ case MBO_ANQP_OUI_TYPE:
+ mbo_parse_rx_anqp_resp(wpa_s, bss, sa,
+ pos, slen);
+ break;
+#endif /* CONFIG_MBO */
default:
wpa_msg(wpa_s, MSG_DEBUG,
- "HS20: Unsupported ANQP vendor type %u",
+ "ANQP: Unsupported ANQP vendor type %u",
type);
break;
}
break;
-#endif /* CONFIG_HS20 */
default:
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Unsupported vendor-specific ANQP OUI %06x",
@@ -2849,6 +3033,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
default:
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Unsupported ANQP Info ID %u", info_id);
+ anqp_add_extra(wpa_s, anqp, info_id, data, slen);
break;
}
}
@@ -2871,8 +3056,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
" dialog_token=%u result=%d status_code=%u",
MAC2STR(dst), dialog_token, result, status_code);
if (result != GAS_QUERY_SUCCESS) {
+#ifdef CONFIG_HS20
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
+#endif /* CONFIG_HS20 */
anqp_result = "FAILURE";
goto out;
}
@@ -2882,8 +3069,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(wpa_s, MSG_DEBUG,
"ANQP: Unexpected Advertisement Protocol in response");
+#ifdef CONFIG_HS20
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
+#endif /* CONFIG_HS20 */
anqp_result = "INVALID_FRAME";
goto out;
}
@@ -2927,12 +3116,14 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
goto out_parse_done;
}
interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
- slen);
+ slen, dialog_token);
pos += slen;
}
out_parse_done:
+#ifdef CONFIG_HS20
hs20_notify_parse_done(wpa_s);
+#endif /* CONFIG_HS20 */
out:
wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
MAC2STR(dst), anqp_result);
@@ -3044,7 +3235,7 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
} else
wpabuf_put_le16(buf, 0);
- res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
wpabuf_free(buf);
diff --git a/contrib/wpa/wpa_supplicant/interworking.h b/contrib/wpa/wpa_supplicant/interworking.h
index 3743dc0..37ee2e9 100644
--- a/contrib/wpa/wpa_supplicant/interworking.h
+++ b/contrib/wpa/wpa_supplicant/interworking.h
@@ -12,7 +12,8 @@
enum gas_query_result;
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
- u16 info_ids[], size_t num_ids, u32 subtypes);
+ u16 info_ids[], size_t num_ids, u32 subtypes,
+ u32 mbo_subtypes);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
diff --git a/contrib/wpa/wpa_supplicant/libwpa_test.c b/contrib/wpa/wpa_supplicant/libwpa_test.c
new file mode 100644
index 0000000..e51ab72
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/libwpa_test.c
@@ -0,0 +1,32 @@
+/*
+ * libwpa_test - Test program for libwpa_client.* library linking
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common/wpa_ctrl.h"
+
+int main(int argc, char *argv[])
+{
+ struct wpa_ctrl *ctrl;
+
+ ctrl = wpa_ctrl_open("foo");
+ if (!ctrl)
+ return -1;
+ if (wpa_ctrl_attach(ctrl) == 0)
+ wpa_ctrl_detach(ctrl);
+ if (wpa_ctrl_pending(ctrl)) {
+ char buf[10];
+ size_t len;
+
+ len = sizeof(buf);
+ wpa_ctrl_recv(ctrl, buf, &len);
+ }
+ wpa_ctrl_close(ctrl);
+
+ return 0;
+}
diff --git a/contrib/wpa/wpa_supplicant/main.c b/contrib/wpa/wpa_supplicant/main.c
index d5d47e1..51a8a02 100644
--- a/contrib/wpa/wpa_supplicant/main.c
+++ b/contrib/wpa/wpa_supplicant/main.c
@@ -28,9 +28,9 @@ static void usage(void)
"s"
#endif /* CONFIG_DEBUG_SYSLOG */
"t"
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
"u"
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
"vW] [-P<pid file>] "
"[-g<global ctrl>] \\\n"
" [-G<group>] \\\n"
@@ -65,41 +65,44 @@ static void usage(void)
" -B = run daemon in the background\n"
" -c = Configuration file\n"
" -C = ctrl_interface parameter (only used if -c is not)\n"
- " -i = interface name\n"
- " -I = additional configuration file\n"
" -d = increase debugging verbosity (-dd even more)\n"
" -D = driver name (can be multiple drivers: nl80211,wext)\n"
- " -e = entropy file\n");
+ " -e = entropy file\n"
#ifdef CONFIG_DEBUG_FILE
- printf(" -f = log output to debug file instead of stdout\n");
+ " -f = log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
- printf(" -g = global ctrl_interface\n"
+ " -g = global ctrl_interface\n"
" -G = global ctrl_interface group\n"
- " -K = include keys (passwords, etc.) in debug output\n");
-#ifdef CONFIG_DEBUG_SYSLOG
- printf(" -s = log output to syslog instead of stdout\n");
-#endif /* CONFIG_DEBUG_SYSLOG */
-#ifdef CONFIG_DEBUG_LINUX_TRACING
- printf(" -T = record to Linux tracing in addition to logging\n");
- printf(" (records all messages regardless of debug verbosity)\n");
-#endif /* CONFIG_DEBUG_LINUX_TRACING */
- printf(" -t = include timestamp in debug messages\n"
" -h = show this help text\n"
+ " -i = interface name\n"
+ " -I = additional configuration file\n"
+ " -K = include keys (passwords, etc.) in debug output\n"
" -L = show license (BSD)\n"
+#ifdef CONFIG_P2P
+ " -m = Configuration file for the P2P Device interface\n"
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ " -M = start describing new matching interface\n"
+#endif /* CONFIG_MATCH_IFACE */
+ " -N = start describing new interface\n"
" -o = override driver parameter for new interfaces\n"
" -O = override ctrl_interface parameter for new interfaces\n"
" -p = driver parameters\n"
" -P = PID file\n"
- " -q = decrease debugging verbosity (-qq even less)\n");
-#ifdef CONFIG_DBUS
- printf(" -u = enable DBus control interface\n");
-#endif /* CONFIG_DBUS */
- printf(" -v = show version\n"
- " -W = wait for a control interface monitor before starting\n"
-#ifdef CONFIG_P2P
- " -m = Configuration file for the P2P Device interface\n"
-#endif /* CONFIG_P2P */
- " -N = start describing new interface\n");
+ " -q = decrease debugging verbosity (-qq even less)\n"
+#ifdef CONFIG_DEBUG_SYSLOG
+ " -s = log output to syslog instead of stdout\n"
+#endif /* CONFIG_DEBUG_SYSLOG */
+ " -t = include timestamp in debug messages\n"
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ " -T = record to Linux tracing in addition to logging\n"
+ " (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+ " -u = enable DBus control interface\n"
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+ " -v = show version\n"
+ " -W = wait for a control interface monitor before starting\n");
printf("example:\n"
" wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
@@ -153,6 +156,28 @@ static void wpa_supplicant_fd_workaround(int start)
}
+#ifdef CONFIG_MATCH_IFACE
+static int wpa_supplicant_init_match(struct wpa_global *global)
+{
+ /*
+ * The assumption is that the first driver is the primary driver and
+ * will handle the arrival / departure of interfaces.
+ */
+ if (wpa_drivers[0]->global_init && !global->drv_priv[0]) {
+ global->drv_priv[0] = wpa_drivers[0]->global_init(global);
+ if (!global->drv_priv[0]) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize driver '%s'",
+ wpa_drivers[0]->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_MATCH_IFACE */
+
+
int main(int argc, char *argv[])
{
int c, i;
@@ -176,7 +201,7 @@ int main(int argc, char *argv[])
for (;;) {
c = getopt(argc, argv,
- "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW");
+ "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {
@@ -270,11 +295,11 @@ int main(int argc, char *argv[])
case 't':
params.wpa_debug_timestamp++;
break;
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
case 'u':
params.dbus_ctrl_interface = 1;
break;
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
case 'v':
printf("%s\n", wpa_supplicant_version);
exitcode = 0;
@@ -282,6 +307,20 @@ int main(int argc, char *argv[])
case 'W':
params.wait_for_monitor++;
break;
+#ifdef CONFIG_MATCH_IFACE
+ case 'M':
+ params.match_iface_count++;
+ iface = os_realloc_array(params.match_ifaces,
+ params.match_iface_count,
+ sizeof(struct wpa_interface));
+ if (!iface)
+ goto out;
+ params.match_ifaces = iface;
+ iface = &params.match_ifaces[params.match_iface_count -
+ 1];
+ os_memset(iface, 0, sizeof(*iface));
+ break;
+#endif /* CONFIG_MATCH_IFACE */
case 'N':
iface_count++;
iface = os_realloc_array(ifaces, iface_count,
@@ -328,6 +367,9 @@ int main(int argc, char *argv[])
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
if (iface_count == 1 && (params.ctrl_interface ||
+#ifdef CONFIG_MATCH_IFACE
+ params.match_iface_count ||
+#endif /* CONFIG_MATCH_IFACE */
params.dbus_ctrl_interface))
break;
usage();
@@ -341,6 +383,11 @@ int main(int argc, char *argv[])
}
}
+#ifdef CONFIG_MATCH_IFACE
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_init_match(global);
+#endif /* CONFIG_MATCH_IFACE */
+
if (exitcode == 0)
exitcode = wpa_supplicant_run(global);
@@ -351,6 +398,9 @@ int main(int argc, char *argv[])
out:
wpa_supplicant_fd_workaround(0);
os_free(ifaces);
+#ifdef CONFIG_MATCH_IFACE
+ os_free(params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
os_free(params.pid_file);
os_program_deinit();
diff --git a/contrib/wpa/wpa_supplicant/mbo.c b/contrib/wpa/wpa_supplicant/mbo.c
new file mode 100644
index 0000000..43b1fa7
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/mbo.c
@@ -0,0 +1,635 @@
+/*
+ * wpa_supplicant - MBO
+ *
+ * Copyright(c) 2015 Intel Deutschland GmbH
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "scan.h"
+
+/* type + length + oui + oui type */
+#define MBO_IE_HEADER 6
+
+
+static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason)
+{
+ if (reason > MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE)
+ return -1;
+
+ /* Only checking the validity of the channel and oper_class */
+ if (ieee80211_chan_to_freq(NULL, oper_class, chan) == -1)
+ return -1;
+
+ return 0;
+}
+
+
+const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr)
+{
+ const u8 *mbo;
+ u8 ie_len = mbo_ie[1];
+
+ if (ie_len < MBO_IE_HEADER - 2)
+ return NULL;
+ mbo = mbo_ie + MBO_IE_HEADER;
+
+ return get_ie(mbo, 2 + ie_len - MBO_IE_HEADER, attr);
+}
+
+
+const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
+ enum mbo_attr_id attr)
+{
+ const u8 *mbo_ie;
+
+ mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE);
+ if (!mbo_ie)
+ return NULL;
+
+ return mbo_attr_from_mbo_ie(mbo_ie, attr);
+}
+
+
+const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
+{
+ const u8 *mbo, *end;
+
+ if (!bss)
+ return NULL;
+
+ mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+ if (!mbo)
+ return NULL;
+
+ end = mbo + 2 + mbo[1];
+ mbo += MBO_IE_HEADER;
+
+ return get_ie(mbo, end - mbo, attr);
+}
+
+
+static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
+ struct wpabuf *mbo,
+ u8 start, u8 end)
+{
+ u8 i;
+
+ wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].oper_class);
+
+ for (i = start; i < end; i++)
+ wpabuf_put_u8(mbo, wpa_s->non_pref_chan[i].chan);
+
+ wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference);
+ wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason);
+}
+
+
+static void wpas_mbo_non_pref_chan_attr_hdr(struct wpabuf *mbo, size_t size)
+{
+ wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
+ wpabuf_put_u8(mbo, size); /* Length */
+}
+
+
+static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s,
+ struct wpabuf *mbo, u8 start, u8 end)
+{
+ size_t size = end - start + 3;
+
+ if (size + 2 > wpabuf_tailroom(mbo))
+ return;
+
+ wpas_mbo_non_pref_chan_attr_hdr(mbo, size);
+ wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
+}
+
+
+static void wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf *mbo, u8 len)
+{
+ wpabuf_put_u8(mbo, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(mbo, len); /* Length */
+ wpabuf_put_be24(mbo, OUI_WFA);
+ wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
+}
+
+
+static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s,
+ struct wpabuf *mbo, u8 start,
+ u8 end)
+{
+ size_t size = end - start + 7;
+
+ if (size + 2 > wpabuf_tailroom(mbo))
+ return;
+
+ wpas_mbo_non_pref_chan_subelem_hdr(mbo, size);
+ wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
+}
+
+
+static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s,
+ struct wpabuf *mbo, int subelement)
+{
+ u8 i, start = 0;
+ struct wpa_mbo_non_pref_channel *start_pref;
+
+ if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) {
+ if (subelement)
+ wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4);
+ else
+ wpas_mbo_non_pref_chan_attr_hdr(mbo, 0);
+ return;
+ }
+ start_pref = &wpa_s->non_pref_chan[0];
+
+ for (i = 1; i <= wpa_s->non_pref_chan_num; i++) {
+ struct wpa_mbo_non_pref_channel *non_pref = NULL;
+
+ if (i < wpa_s->non_pref_chan_num)
+ non_pref = &wpa_s->non_pref_chan[i];
+ if (!non_pref ||
+ non_pref->oper_class != start_pref->oper_class ||
+ non_pref->reason != start_pref->reason ||
+ non_pref->preference != start_pref->preference) {
+ if (subelement)
+ wpas_mbo_non_pref_chan_subelement(wpa_s, mbo,
+ start, i);
+ else
+ wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start,
+ i);
+
+ if (!non_pref)
+ return;
+
+ start = i;
+ start_pref = non_pref;
+ }
+ }
+}
+
+
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
+ int add_oce_capa)
+{
+ struct wpabuf *mbo;
+ int res;
+
+ if (len < MBO_IE_HEADER + 3 + 7 +
+ ((wpa_s->enable_oce & OCE_STA) ? 3 : 0))
+ return 0;
+
+ /* Leave room for the MBO IE header */
+ mbo = wpabuf_alloc(len - MBO_IE_HEADER);
+ if (!mbo)
+ return 0;
+
+ /* Add non-preferred channels attribute */
+ wpas_mbo_non_pref_chan_attrs(wpa_s, mbo, 0);
+
+ /*
+ * Send cellular capabilities attribute even if AP does not advertise
+ * cellular capabilities.
+ */
+ wpabuf_put_u8(mbo, MBO_ATTR_ID_CELL_DATA_CAPA);
+ wpabuf_put_u8(mbo, 1);
+ wpabuf_put_u8(mbo, wpa_s->conf->mbo_cell_capa);
+
+ /* Add OCE capability indication attribute if OCE is enabled */
+ if ((wpa_s->enable_oce & OCE_STA) && add_oce_capa) {
+ wpabuf_put_u8(mbo, OCE_ATTR_ID_CAPA_IND);
+ wpabuf_put_u8(mbo, 1);
+ wpabuf_put_u8(mbo, OCE_RELEASE);
+ }
+
+ res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo));
+ if (!res)
+ wpa_printf(MSG_ERROR, "Failed to add MBO/OCE IE");
+
+ wpabuf_free(mbo);
+ return res;
+}
+
+
+static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t len)
+{
+ struct wpabuf *buf;
+ int res;
+
+ /*
+ * Send WNM-Notification Request frame only in case of a change in
+ * non-preferred channels list during association, if the AP supports
+ * MBO.
+ */
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_bss ||
+ !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
+ return;
+
+ buf = wpabuf_alloc(4 + len);
+ if (!buf)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+ wpa_s->mbo_wnm_token++;
+ if (wpa_s->mbo_wnm_token == 0)
+ wpa_s->mbo_wnm_token++;
+ wpabuf_put_u8(buf, wpa_s->mbo_wnm_token);
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */
+
+ wpabuf_put_data(buf, data, len);
+
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG,
+ "Failed to send WNM-Notification Request frame with non-preferred channel list");
+
+ wpabuf_free(buf);
+}
+
+
+static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(512);
+ if (!buf)
+ return;
+
+ wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
+ wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf),
+ wpabuf_len(buf));
+ wpas_update_mbo_connect_params(wpa_s);
+ wpabuf_free(buf);
+}
+
+
+static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a,
+ struct wpa_mbo_non_pref_channel *b)
+{
+ return a->oper_class == b->oper_class && a->chan == b->chan;
+}
+
+
+/*
+ * wpa_non_pref_chan_cmp - Compare two channels for sorting
+ *
+ * In MBO IE non-preferred channel subelement we can put many channels in an
+ * attribute if they are in the same operating class and have the same
+ * preference and reason. To make it easy for the functions that build
+ * the IE attributes and WNM Request subelements, save the channels sorted
+ * by their oper_class and reason.
+ */
+static int wpa_non_pref_chan_cmp(const void *_a, const void *_b)
+{
+ const struct wpa_mbo_non_pref_channel *a = _a, *b = _b;
+
+ if (a->oper_class != b->oper_class)
+ return (int) a->oper_class - (int) b->oper_class;
+ if (a->reason != b->reason)
+ return (int) a->reason - (int) b->reason;
+ return (int) a->preference - (int) b->preference;
+}
+
+
+int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
+ const char *non_pref_chan)
+{
+ char *cmd, *token, *context = NULL;
+ struct wpa_mbo_non_pref_channel *chans = NULL, *tmp_chans;
+ size_t num = 0, size = 0;
+ unsigned i;
+
+ wpa_printf(MSG_DEBUG, "MBO: Update non-preferred channels, non_pref_chan=%s",
+ non_pref_chan ? non_pref_chan : "N/A");
+
+ /*
+ * The shortest channel configuration is 7 characters - 3 colons and
+ * 4 values.
+ */
+ if (!non_pref_chan || os_strlen(non_pref_chan) < 7)
+ goto update;
+
+ cmd = os_strdup(non_pref_chan);
+ if (!cmd)
+ return -1;
+
+ while ((token = str_token(cmd, " ", &context))) {
+ struct wpa_mbo_non_pref_channel *chan;
+ int ret;
+ unsigned int _oper_class;
+ unsigned int _chan;
+ unsigned int _preference;
+ unsigned int _reason;
+
+ if (num == size) {
+ size = size ? size * 2 : 1;
+ tmp_chans = os_realloc_array(chans, size,
+ sizeof(*chans));
+ if (!tmp_chans) {
+ wpa_printf(MSG_ERROR,
+ "Couldn't reallocate non_pref_chan");
+ goto fail;
+ }
+ chans = tmp_chans;
+ }
+
+ chan = &chans[num];
+
+ ret = sscanf(token, "%u:%u:%u:%u", &_oper_class,
+ &_chan, &_preference, &_reason);
+ if (ret != 4 ||
+ _oper_class > 255 || _chan > 255 ||
+ _preference > 255 || _reason > 65535 ) {
+ wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s",
+ token);
+ goto fail;
+ }
+ chan->oper_class = _oper_class;
+ chan->chan = _chan;
+ chan->preference = _preference;
+ chan->reason = _reason;
+
+ if (wpas_mbo_validate_non_pref_chan(chan->oper_class,
+ chan->chan, chan->reason)) {
+ wpa_printf(MSG_ERROR,
+ "Invalid non_pref_chan: oper class %d chan %d reason %d",
+ chan->oper_class, chan->chan, chan->reason);
+ goto fail;
+ }
+
+ for (i = 0; i < num; i++)
+ if (wpa_non_pref_chan_is_eq(chan, &chans[i]))
+ break;
+ if (i != num) {
+ wpa_printf(MSG_ERROR,
+ "oper class %d chan %d is duplicated",
+ chan->oper_class, chan->chan);
+ goto fail;
+ }
+
+ num++;
+ }
+
+ os_free(cmd);
+
+ if (chans) {
+ qsort(chans, num, sizeof(struct wpa_mbo_non_pref_channel),
+ wpa_non_pref_chan_cmp);
+ }
+
+update:
+ os_free(wpa_s->non_pref_chan);
+ wpa_s->non_pref_chan = chans;
+ wpa_s->non_pref_chan_num = num;
+ wpas_mbo_non_pref_chan_changed(wpa_s);
+
+ return 0;
+
+fail:
+ os_free(chans);
+ os_free(cmd);
+ return -1;
+}
+
+
+void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie)
+{
+ u8 *len;
+
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ len = wpabuf_put(ie, 1);
+
+ wpabuf_put_be24(ie, OUI_WFA);
+ wpabuf_put_u8(ie, MBO_OUI_TYPE);
+
+ wpabuf_put_u8(ie, MBO_ATTR_ID_CELL_DATA_CAPA);
+ wpabuf_put_u8(ie, 1);
+ wpabuf_put_u8(ie, wpa_s->conf->mbo_cell_capa);
+ if (wpa_s->enable_oce & OCE_STA) {
+ wpabuf_put_u8(ie, OCE_ATTR_ID_CAPA_IND);
+ wpabuf_put_u8(ie, 1);
+ wpabuf_put_u8(ie, OCE_RELEASE);
+ }
+ *len = (u8 *) wpabuf_put(ie, 0) - len - 1;
+}
+
+
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
+ size_t len)
+{
+ const u8 *pos, *cell_pref = NULL;
+ u8 id, elen;
+ u16 disallowed_sec = 0;
+
+ if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
+ mbo_ie[3] != MBO_OUI_TYPE)
+ return;
+
+ pos = mbo_ie + 4;
+ len -= 4;
+
+ while (len >= 2) {
+ id = *pos++;
+ elen = *pos++;
+ len -= 2;
+
+ if (elen > len)
+ goto fail;
+
+ switch (id) {
+ case MBO_ATTR_ID_CELL_DATA_PREF:
+ if (elen != 1)
+ goto fail;
+
+ if (wpa_s->conf->mbo_cell_capa ==
+ MBO_CELL_CAPA_AVAILABLE)
+ cell_pref = pos;
+ else
+ wpa_printf(MSG_DEBUG,
+ "MBO: Station does not support Cellular data connection");
+ break;
+ case MBO_ATTR_ID_TRANSITION_REASON:
+ if (elen != 1)
+ goto fail;
+
+ wpa_s->wnm_mbo_trans_reason_present = 1;
+ wpa_s->wnm_mbo_transition_reason = *pos;
+ break;
+ case MBO_ATTR_ID_ASSOC_RETRY_DELAY:
+ if (elen != 2)
+ goto fail;
+
+ if (wpa_s->wnm_mode &
+ WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Unexpected association retry delay, BSS is terminating");
+ goto fail;
+ } else if (wpa_s->wnm_mode &
+ WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ disallowed_sec = WPA_GET_LE16(pos);
+ wpa_printf(MSG_DEBUG,
+ "MBO: Association retry delay: %u",
+ disallowed_sec);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Association retry delay attribute not in disassoc imminent mode");
+ }
+
+ break;
+ case MBO_ATTR_ID_AP_CAPA_IND:
+ case MBO_ATTR_ID_NON_PREF_CHAN_REPORT:
+ case MBO_ATTR_ID_CELL_DATA_CAPA:
+ case MBO_ATTR_ID_ASSOC_DISALLOW:
+ case MBO_ATTR_ID_TRANSITION_REJECT_REASON:
+ wpa_printf(MSG_DEBUG,
+ "MBO: Attribute %d should not be included in BTM Request frame",
+ id);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u",
+ id);
+ return;
+ }
+
+ pos += elen;
+ len -= elen;
+ }
+
+ if (cell_pref)
+ wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u",
+ *cell_pref);
+
+ if (wpa_s->wnm_mbo_trans_reason_present)
+ wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u",
+ wpa_s->wnm_mbo_transition_reason);
+
+ if (disallowed_sec && wpa_s->current_bss)
+ wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
+ disallowed_sec, 0);
+
+ return;
+fail:
+ wpa_printf(MSG_DEBUG, "MBO IE parsing failed (id=%u len=%u left=%zu)",
+ id, elen, len);
+}
+
+
+size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
+ size_t len,
+ enum mbo_transition_reject_reason reason)
+{
+ u8 reject_attr[3];
+
+ reject_attr[0] = MBO_ATTR_ID_TRANSITION_REJECT_REASON;
+ reject_attr[1] = 1;
+ reject_attr[2] = reason;
+
+ return mbo_add_ie(pos, len, reject_attr, sizeof(reject_attr));
+}
+
+
+void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa)
+{
+ u8 cell_capa[7];
+
+ if (wpa_s->conf->mbo_cell_capa == mbo_cell_capa) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Cellular capability already set to %u",
+ mbo_cell_capa);
+ return;
+ }
+
+ wpa_s->conf->mbo_cell_capa = mbo_cell_capa;
+
+ cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC;
+ cell_capa[1] = 5; /* Length */
+ WPA_PUT_BE24(cell_capa + 2, OUI_WFA);
+ cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA;
+ cell_capa[6] = mbo_cell_capa;
+
+ wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+ wpas_update_mbo_connect_params(wpa_s);
+}
+
+
+struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, u32 mbo_subtypes)
+{
+ struct wpabuf *anqp_buf;
+ u8 *len_pos;
+ u8 i;
+
+ if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
+ wpa_printf(MSG_INFO, "MBO: " MACSTR
+ " does not support MBO - cannot request MBO ANQP elements from it",
+ MAC2STR(bss->bssid));
+ return NULL;
+ }
+
+ /* Allocate size for the maximum case - all MBO subtypes are set */
+ anqp_buf = wpabuf_alloc(9 + MAX_MBO_ANQP_SUBTYPE);
+ if (!anqp_buf)
+ return NULL;
+
+ len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(anqp_buf, OUI_WFA);
+ wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE);
+
+ wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_QUERY_LIST);
+
+ /* The first valid MBO subtype is 1 */
+ for (i = 1; i <= MAX_MBO_ANQP_SUBTYPE; i++) {
+ if (mbo_subtypes & BIT(i))
+ wpabuf_put_u8(anqp_buf, i);
+ }
+
+ gas_anqp_set_element_len(anqp_buf, len_pos);
+
+ return anqp_buf;
+}
+
+
+void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, const u8 *sa,
+ const u8 *data, size_t slen)
+{
+ const u8 *pos = data;
+ u8 subtype;
+
+ if (slen < 1)
+ return;
+
+ subtype = *pos++;
+ slen--;
+
+ switch (subtype) {
+ case MBO_ANQP_SUBTYPE_CELL_CONN_PREF:
+ if (slen < 1)
+ break;
+ wpa_msg(wpa_s, MSG_INFO, RX_MBO_ANQP MACSTR
+ " cell_conn_pref=%u", MAC2STR(sa), *pos);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "MBO: Unsupported ANQP subtype %u",
+ subtype);
+ break;
+ }
+}
diff --git a/contrib/wpa/wpa_supplicant/mesh.c b/contrib/wpa/wpa_supplicant/mesh.c
index 77f708b..9260021 100644
--- a/contrib/wpa/wpa_supplicant/mesh.c
+++ b/contrib/wpa/wpa_supplicant/mesh.c
@@ -34,6 +34,8 @@ static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
wpa_s->current_ssid = NULL;
os_free(wpa_s->mesh_rsn);
wpa_s->mesh_rsn = NULL;
+ os_free(wpa_s->mesh_params);
+ wpa_s->mesh_params = NULL;
/* TODO: leave mesh (stop beacon). This will happen on link down
* anyway, so it's not urgent */
}
@@ -66,9 +68,11 @@ void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
}
-static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
+static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
struct mesh_conf *conf;
+ int cipher;
conf = os_zalloc(sizeof(struct mesh_conf));
if (!conf)
@@ -82,6 +86,38 @@ static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
MESH_CONF_SEC_AMPE;
else
conf->security |= MESH_CONF_SEC_NONE;
+#ifdef CONFIG_IEEE80211W
+ conf->ieee80211w = ssid->ieee80211w;
+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+ if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
+ conf->ieee80211w = wpa_s->conf->pmf;
+ else
+ conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
+ }
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ conf->ocv = ssid->ocv;
+#endif /* CONFIG_OCV */
+
+ cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
+ if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
+ wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher");
+ os_free(conf);
+ return NULL;
+ }
+ conf->pairwise_cipher = cipher;
+
+ cipher = wpa_pick_group_cipher(ssid->group_cipher);
+ if (cipher < 0 || cipher == WPA_CIPHER_TKIP ||
+ cipher == WPA_CIPHER_GTK_NOT_USED) {
+ wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher");
+ os_free(conf);
+ return NULL;
+ }
+
+ conf->group_cipher = cipher;
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+ conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
/* defaults */
conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
@@ -116,17 +152,104 @@ static void wpas_mesh_copy_groups(struct hostapd_data *bss,
}
+static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_data *bss = ifmsh->bss[0];
+ static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
+ const char *password;
+ size_t len;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+ if (!password) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Passphrase for SAE not configured");
+ return -1;
+ }
+
+ bss->conf->wpa = ssid->proto;
+ bss->conf->wpa_key_mgmt = ssid->key_mgmt;
+
+ if (wpa_s->conf->sae_groups && wpa_s->conf->sae_groups[0] > 0) {
+ wpas_mesh_copy_groups(bss, wpa_s);
+ } else {
+ bss->conf->sae_groups = os_memdup(default_groups,
+ sizeof(default_groups));
+ if (!bss->conf->sae_groups)
+ return -1;
+ }
+
+ len = os_strlen(password);
+ bss->conf->ssid.wpa_passphrase = dup_binstr(password, len);
+
+ wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, ifmsh->mconf);
+ return !wpa_s->mesh_rsn ? -1 : 0;
+}
+
+
+static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int ret;
+
+ if (!params || !ssid || !ifmsh) {
+ wpa_printf(MSG_ERROR, "mesh: %s called without active mesh",
+ __func__);
+ return -1;
+ }
+
+ if (ifmsh->mconf->security != MESH_CONF_SEC_NONE &&
+ wpas_mesh_init_rsn(wpa_s)) {
+ wpa_printf(MSG_ERROR,
+ "mesh: RSN initialization failed - deinit mesh");
+ wpa_supplicant_mesh_deinit(wpa_s);
+ return -1;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
+ wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
+ wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
+ }
+
+ params->ies = ifmsh->mconf->rsn_ie;
+ params->ie_len = ifmsh->mconf->rsn_ie_len;
+ params->basic_rates = ifmsh->basic_rates;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+ params->conf.ht_opmode = ifmsh->bss[0]->iface->ht_op_mode;
+
+ wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ret = wpa_drv_join_mesh(wpa_s, params);
+ if (ret)
+ wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
+
+ /* hostapd sets the interface down until we associate */
+ wpa_drv_set_operstate(wpa_s, 1);
+
+ if (!ret)
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+ return ret;
+}
+
+
static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+ struct wpa_ssid *ssid,
+ struct hostapd_freq_params *freq)
{
struct hostapd_iface *ifmsh;
struct hostapd_data *bss;
struct hostapd_config *conf;
struct mesh_conf *mconf;
int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
- static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
- size_t len;
int rate_len;
+ int frequency;
if (!wpa_s->conf->user_mpm) {
/* not much for us to do here */
@@ -135,7 +258,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
return 0;
}
- wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
+ wpa_s->ifmsh = ifmsh = hostapd_alloc_iface();
if (!ifmsh)
return -ENOMEM;
@@ -146,16 +269,23 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
if (!ifmsh->bss)
goto out_free;
- ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
+ ifmsh->bss[0] = bss = hostapd_alloc_bss_data(NULL, NULL, NULL);
if (!bss)
goto out_free;
+ ifmsh->bss[0]->msg_ctx = wpa_s;
os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
bss->driver = wpa_s->driver;
bss->drv_priv = wpa_s->drv_priv;
bss->iface = ifmsh;
bss->mesh_sta_free_cb = mesh_mpm_free_sta;
- wpa_s->assoc_freq = ssid->frequency;
+ frequency = ssid->frequency;
+ if (frequency != freq->freq &&
+ frequency == freq->freq + freq->sec_channel_offset * 20) {
+ wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched");
+ frequency = freq->freq;
+ }
+ wpa_s->assoc_freq = frequency;
wpa_s->current_ssid = ssid;
/* setup an AP config for auth processing */
@@ -167,6 +297,16 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
bss->conf->start_disabled = 1;
bss->conf->mesh = MESH_ENABLED;
bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
+
+ if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
+ wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
+ conf->ieee80211h = 1;
+ conf->ieee80211d = 1;
+ conf->country[0] = wpa_s->conf->country[0];
+ conf->country[1] = wpa_s->conf->country[1];
+ conf->country[2] = ' ';
+ }
+
bss->iconf = conf;
ifmsh->conf = conf;
@@ -175,24 +315,42 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
wpa_s->conf->dot11RSNASAERetransPeriod;
os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
- mconf = mesh_config_create(ssid);
+ mconf = mesh_config_create(wpa_s, ssid);
if (!mconf)
goto out_free;
ifmsh->mconf = mconf;
/* need conf->hw_mode for supported rates. */
- if (ssid->frequency == 0) {
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- conf->channel = 1;
- } else {
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
- }
+ conf->hw_mode = ieee80211_freq_to_chan(frequency, &conf->channel);
if (conf->hw_mode == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
- ssid->frequency);
+ frequency);
goto out_free;
}
+ if (ssid->ht40)
+ conf->secondary_channel = ssid->ht40;
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
+ if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH)
+ conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+ switch (conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ case VHT_CHANWIDTH_80P80MHZ:
+ ieee80211_freq_to_chan(
+ frequency,
+ &conf->vht_oper_centr_freq_seg0_idx);
+ conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ ieee80211_freq_to_chan(
+ frequency,
+ &conf->vht_oper_centr_freq_seg0_idx);
+ conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
+ conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
+ break;
+ }
+ ieee80211_freq_to_chan(ssid->vht_center_freq2,
+ &conf->vht_oper_centr_freq_seg1_idx);
+ }
if (ssid->mesh_basic_rates == NULL) {
/*
@@ -203,11 +361,10 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
* advertised in beacons match the one in peering frames, sigh.
*/
if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
- conf->basic_rates = os_malloc(sizeof(basic_rates_erp));
+ conf->basic_rates = os_memdup(basic_rates_erp,
+ sizeof(basic_rates_erp));
if (!conf->basic_rates)
goto out_free;
- os_memcpy(conf->basic_rates, basic_rates_erp,
- sizeof(basic_rates_erp));
}
} else {
rate_len = 0;
@@ -224,46 +381,15 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
conf->basic_rates[rate_len] = -1;
}
- if (hostapd_setup_interface(ifmsh)) {
- wpa_printf(MSG_ERROR,
- "Failed to initialize hostapd interface for mesh");
- return -1;
- }
-
if (wpa_drv_init_mesh(wpa_s)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
return -1;
}
- if (mconf->security != MESH_CONF_SEC_NONE) {
- if (ssid->passphrase == NULL) {
- wpa_printf(MSG_ERROR,
- "mesh: Passphrase for SAE not configured");
- goto out_free;
- }
-
- bss->conf->wpa = ssid->proto;
- bss->conf->wpa_key_mgmt = ssid->key_mgmt;
-
- if (wpa_s->conf->sae_groups &&
- wpa_s->conf->sae_groups[0] > 0) {
- wpas_mesh_copy_groups(bss, wpa_s);
- } else {
- bss->conf->sae_groups =
- os_malloc(sizeof(default_groups));
- if (!bss->conf->sae_groups)
- goto out_free;
- os_memcpy(bss->conf->sae_groups, default_groups,
- sizeof(default_groups));
- }
-
- len = os_strlen(ssid->passphrase);
- bss->conf->ssid.wpa_passphrase =
- dup_binstr(ssid->passphrase, len);
-
- wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
- if (!wpa_s->mesh_rsn)
- goto out_free;
+ if (hostapd_setup_interface(ifmsh)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize hostapd interface for mesh");
+ return -1;
}
wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
@@ -308,64 +434,90 @@ void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
- struct wpa_driver_mesh_join_params params;
+ struct wpa_driver_mesh_join_params *params = os_zalloc(sizeof(*params));
int ret = 0;
- if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
+ if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency ||
+ !params) {
ret = -ENOENT;
+ os_free(params);
goto out;
}
wpa_supplicant_mesh_deinit(wpa_s);
- os_memset(&params, 0, sizeof(params));
- params.meshid = ssid->ssid;
- params.meshid_len = ssid->ssid_len;
- ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
- wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
+ wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+ wpa_s->group_cipher = WPA_CIPHER_NONE;
+ wpa_s->mgmt_group_cipher = 0;
+
+ params->meshid = ssid->ssid;
+ params->meshid_len = ssid->ssid_len;
+ ibss_mesh_setup_freq(wpa_s, ssid, &params->freq);
+ wpa_s->mesh_ht_enabled = !!params->freq.ht_enabled;
+ wpa_s->mesh_vht_enabled = !!params->freq.vht_enabled;
+ if (params->freq.ht_enabled && params->freq.sec_channel_offset)
+ ssid->ht40 = params->freq.sec_channel_offset;
+
+ if (wpa_s->mesh_vht_enabled) {
+ ssid->vht = 1;
+ ssid->vht_center_freq1 = params->freq.center_freq1;
+ switch (params->freq.bandwidth) {
+ case 80:
+ if (params->freq.center_freq2) {
+ ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+ ssid->vht_center_freq2 =
+ params->freq.center_freq2;
+ } else {
+ ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ }
+ break;
+ case 160:
+ ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+ }
if (ssid->beacon_int > 0)
- params.beacon_int = ssid->beacon_int;
+ params->beacon_int = ssid->beacon_int;
else if (wpa_s->conf->beacon_int > 0)
- params.beacon_int = wpa_s->conf->beacon_int;
- params.max_peer_links = wpa_s->conf->max_peer_links;
+ params->beacon_int = wpa_s->conf->beacon_int;
+ if (ssid->dtim_period > 0)
+ params->dtim_period = ssid->dtim_period;
+ else if (wpa_s->conf->dtim_period > 0)
+ params->dtim_period = wpa_s->conf->dtim_period;
+ params->conf.max_peer_links = wpa_s->conf->max_peer_links;
+ if (ssid->mesh_rssi_threshold < DEFAULT_MESH_RSSI_THRESHOLD) {
+ params->conf.rssi_threshold = ssid->mesh_rssi_threshold;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD;
+ }
if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
- params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
- params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
+ params->flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
+ params->flags |= WPA_DRIVER_MESH_FLAG_AMPE;
wpa_s->conf->user_mpm = 1;
}
if (wpa_s->conf->user_mpm) {
- params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
- params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params->flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
+ params->conf.auto_plinks = 0;
} else {
- params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
- params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params->flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
+ params->conf.auto_plinks = 1;
}
- params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
+ params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
- if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
+ os_free(wpa_s->mesh_params);
+ wpa_s->mesh_params = params;
+ if (wpa_supplicant_mesh_init(wpa_s, ssid, &params->freq)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
wpa_drv_leave_mesh(wpa_s);
ret = -1;
goto out;
}
- if (wpa_s->ifmsh) {
- params.ies = wpa_s->ifmsh->mconf->rsn_ie;
- params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
- params.basic_rates = wpa_s->ifmsh->basic_rates;
- }
-
- wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- ret = wpa_drv_join_mesh(wpa_s, &params);
- if (ret)
- wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d\n", ret);
-
- /* hostapd sets the interface down until we associate */
- wpa_drv_set_operstate(wpa_s, 1);
-
+ ret = wpas_mesh_complete(wpa_s);
out:
return ret;
}
@@ -535,9 +687,22 @@ int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
if (!mesh_wpa_s) {
wpa_printf(MSG_ERROR,
"mesh: Failed to create new wpa_supplicant interface");
- wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+ wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
return -1;
}
mesh_wpa_s->mesh_if_created = 1;
return 0;
}
+
+
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ return mesh_mpm_close_peer(wpa_s, addr);
+}
+
+
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration)
+{
+ return mesh_mpm_connect_peer(wpa_s, addr, duration);
+}
diff --git a/contrib/wpa/wpa_supplicant/mesh.h b/contrib/wpa/wpa_supplicant/mesh.h
index 3cb7f1b..7317083 100644
--- a/contrib/wpa/wpa_supplicant/mesh.h
+++ b/contrib/wpa/wpa_supplicant/mesh.h
@@ -18,6 +18,9 @@ int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
char *end);
int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
size_t len);
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr);
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration);
#ifdef CONFIG_MESH
diff --git a/contrib/wpa/wpa_supplicant/mesh_mpm.c b/contrib/wpa/wpa_supplicant/mesh_mpm.c
index f81b88c8..9d6ab8d 100644
--- a/contrib/wpa/wpa_supplicant/mesh_mpm.c
+++ b/contrib/wpa/wpa_supplicant/mesh_mpm.c
@@ -11,20 +11,24 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
+#include "common/ocv.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ieee802_11.h"
+#include "ap/wpa_auth.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "mesh_mpm.h"
#include "mesh_rsn.h"
+#include "notify.h"
struct mesh_peer_mgmt_ie {
- const u8 *proto_id;
- const u8 *llid;
- const u8 *plid;
- const u8 *reason;
- const u8 *pmk;
+ const u8 *proto_id; /* Mesh Peering Protocol Identifier (2 octets) */
+ const u8 *llid; /* Local Link ID (2 octets) */
+ const u8 *plid; /* Peer Link ID (conditional, 2 octets) */
+ const u8 *reason; /* Reason Code (conditional, 2 octets) */
+ const u8 *chosen_pmk; /* Chosen PMK (optional, 16 octets) */
};
static void plink_timer(void *eloop_ctx, void *user_data);
@@ -34,18 +38,17 @@ enum plink_event {
PLINK_UNDEFINED,
OPN_ACPT,
OPN_RJCT,
- OPN_IGNR,
CNF_ACPT,
CNF_RJCT,
- CNF_IGNR,
CLS_ACPT,
- CLS_IGNR
+ REQ_RJCT
};
static const char * const mplstate[] = {
- [PLINK_LISTEN] = "LISTEN",
- [PLINK_OPEN_SENT] = "OPEN_SENT",
- [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+ [0] = "UNINITIALIZED",
+ [PLINK_IDLE] = "IDLE",
+ [PLINK_OPN_SNT] = "OPN_SNT",
+ [PLINK_OPN_RCVD] = "OPN_RCVD",
[PLINK_CNF_RCVD] = "CNF_RCVD",
[PLINK_ESTAB] = "ESTAB",
[PLINK_HOLDING] = "HOLDING",
@@ -56,12 +59,10 @@ static const char * const mplevent[] = {
[PLINK_UNDEFINED] = "UNDEFINED",
[OPN_ACPT] = "OPN_ACPT",
[OPN_RJCT] = "OPN_RJCT",
- [OPN_IGNR] = "OPN_IGNR",
[CNF_ACPT] = "CNF_ACPT",
[CNF_RJCT] = "CNF_RJCT",
- [CNF_IGNR] = "CNF_IGNR",
[CLS_ACPT] = "CLS_ACPT",
- [CLS_IGNR] = "CLS_IGNR"
+ [REQ_RJCT] = "REQ_RJCT",
};
@@ -72,10 +73,10 @@ static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
{
os_memset(mpm_ie, 0, sizeof(*mpm_ie));
- /* remove optional PMK at end */
- if (len >= 16) {
- len -= 16;
- mpm_ie->pmk = ie + len - 16;
+ /* Remove optional Chosen PMK field at end */
+ if (len >= SAE_PMKID_LEN) {
+ mpm_ie->chosen_pmk = ie + len - SAE_PMKID_LEN;
+ len -= SAE_PMKID_LEN;
}
if ((action_field == PLINK_OPEN && len != 4) ||
@@ -101,8 +102,8 @@ static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
len -= 2;
}
- /* plid, present for confirm, and possibly close */
- if (len)
+ /* Peer Link ID, present for confirm, and possibly close */
+ if (len >= 2)
mpm_ie->plid = ie;
return 0;
@@ -188,17 +189,18 @@ static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s,
do {
if (os_get_random((u8 *) &llid, sizeof(llid)) < 0)
- continue;
+ llid = 0; /* continue */
} while (!llid || llid_in_use(wpa_s, llid));
sta->my_lid = llid;
sta->peer_lid = 0;
+ sta->peer_aid = 0;
/*
* We do not use wpa_mesh_set_plink_state() here because there is no
* entry in kernel yet.
*/
- sta->plink_state = PLINK_LISTEN;
+ sta->plink_state = PLINK_IDLE;
}
@@ -212,9 +214,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
struct hostapd_data *bss = ifmsh->bss[0];
struct mesh_conf *conf = ifmsh->mconf;
u8 supp_rates[2 + 2 + 32];
-#ifdef CONFIG_IEEE80211N
- u8 ht_capa_oper[2 + 26 + 2 + 22];
-#endif /* CONFIG_IEEE80211N */
u8 *pos, *cat;
u8 ie_len, add_plid = 0;
int ret;
@@ -224,13 +223,14 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
if (!sta)
return;
- buf_len = 2 + /* capability info */
+ buf_len = 2 + /* Category and Action */
+ 2 + /* capability info */
2 + /* AID */
2 + 8 + /* supported rates */
2 + (32 - 8) +
2 + 32 + /* mesh ID */
2 + 7 + /* mesh config */
- 2 + 23 + /* peering management */
+ 2 + 24 + /* peering management */
2 + 96 + /* AMPE */
2 + 16; /* MIC */
#ifdef CONFIG_IEEE80211N
@@ -239,8 +239,19 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
2 + 22; /* HT operation */
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
+ buf_len += 2 + 12 + /* VHT Capabilities */
+ 2 + 5; /* VHT Operation */
+ }
+#endif /* CONFIG_IEEE80211AC */
if (type != PLINK_CLOSE)
buf_len += conf->rsn_ie_len; /* RSN IE */
+#ifdef CONFIG_OCV
+ /* OCI is included even when the other STA doesn't support OCV */
+ if (type != PLINK_CLOSE && conf->ocv)
+ buf_len += OCV_OCI_EXTENDED_LEN;
+#endif /* CONFIG_OCV */
buf = wpabuf_alloc(buf_len);
if (!buf)
@@ -258,7 +269,7 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
/* aid */
if (type == PLINK_CONFIRM)
- wpabuf_put_le16(buf, sta->peer_lid);
+ wpabuf_put_le16(buf, sta->aid);
/* IE: supp + ext. supp rates */
pos = hostapd_eid_supp_rates(bss, supp_rates);
@@ -285,7 +296,8 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
/* TODO: Add Connected to Mesh Gate/AS subfields */
wpabuf_put_u8(buf, info);
/* always forwarding & accepting plinks for now */
- wpabuf_put_u8(buf, 0x1 | 0x8);
+ wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER |
+ MESH_CAP_FORWARDING);
} else { /* Peer closing frame */
/* IE: Mesh ID */
wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
@@ -334,11 +346,38 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211N
if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
+ u8 ht_capa_oper[2 + 26 + 2 + 22];
+
pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
pos = hostapd_eid_ht_operation(bss, pos);
wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
+ u8 vht_capa_oper[2 + 12 + 2 + 5];
+
+ pos = hostapd_eid_vht_capabilities(bss, vht_capa_oper, 0);
+ pos = hostapd_eid_vht_operation(bss, pos);
+ wpabuf_put_data(buf, vht_capa_oper, pos - vht_capa_oper);
+ }
+#endif /* CONFIG_IEEE80211AC */
+
+#ifdef CONFIG_OCV
+ if (type != PLINK_CLOSE && conf->ocv) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Mesh MPM: Failed to get channel info for OCI element");
+ goto fail;
+ }
+
+ pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_OCV */
if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
wpa_msg(wpa_s, MSG_INFO,
@@ -346,6 +385,9 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
goto fail;
}
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh MPM: Sending peering frame type %d to "
+ MACSTR " (my_lid=0x%x peer_lid=0x%x)",
+ type, MAC2STR(sta->addr), sta->my_lid, sta->peer_lid);
ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
sta->addr, wpa_s->own_addr, wpa_s->own_addr,
wpabuf_head(buf), wpabuf_len(buf), 0);
@@ -366,15 +408,17 @@ void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
struct hostapd_sta_add_params params;
int ret;
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " from %s into %s",
+ MAC2STR(sta->addr), mplstate[sta->plink_state],
+ mplstate[state]);
sta->plink_state = state;
os_memset(&params, 0, sizeof(params));
params.addr = sta->addr;
params.plink_state = state;
+ params.peer_aid = sta->peer_aid;
params.set = 1;
- wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s",
- MAC2STR(sta->addr), mplstate[state]);
ret = wpa_drv_sta_add(wpa_s, &params);
if (ret) {
wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR
@@ -400,10 +444,11 @@ static void plink_timer(void *eloop_ctx, void *user_data)
struct sta_info *sta = user_data;
u16 reason = 0;
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
switch (sta->plink_state) {
- case PLINK_OPEN_RCVD:
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_RCVD:
+ case PLINK_OPN_SNT:
/* retry timer */
if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
eloop_register_timeout(
@@ -415,7 +460,7 @@ static void plink_timer(void *eloop_ctx, void *user_data)
break;
}
reason = WLAN_REASON_MESH_MAX_RETRIES;
- /* fall through on else */
+ /* fall through */
case PLINK_CNF_RCVD:
/* confirm timer */
@@ -429,6 +474,13 @@ static void plink_timer(void *eloop_ctx, void *user_data)
break;
case PLINK_HOLDING:
/* holding timer */
+
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG, "MPM: Peer " MACSTR
+ " looks like it does not support mesh SAE PMKSA caching, so remove the cached entry for it",
+ MAC2STR(sta->addr));
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ }
mesh_mpm_fsm_restart(wpa_s, sta);
break;
default:
@@ -453,8 +505,8 @@ mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
}
-int mesh_mpm_plink_close(struct hostapd_data *hapd,
- struct sta_info *sta, void *ctx)
+static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
+ void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
@@ -472,6 +524,85 @@ int mesh_mpm_plink_close(struct hostapd_data *hapd,
}
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+
+ if (!wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+ return -1;
+ }
+
+ hapd = wpa_s->ifmsh->bss[0];
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+ return -1;
+ }
+
+ return mesh_mpm_plink_close(hapd, sta, wpa_s) == 0 ? 0 : -1;
+}
+
+
+static void peer_add_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ os_memset(hapd->mesh_required_peer, 0, ETH_ALEN);
+}
+
+
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+ struct mesh_conf *conf;
+
+ if (!wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+ return -1;
+ }
+
+ if (!ssid || !ssid->no_auto_peer) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "This command is available only with no_auto_peer mesh network");
+ return -1;
+ }
+
+ hapd = wpa_s->ifmsh->bss[0];
+ conf = wpa_s->ifmsh->mconf;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+ return -1;
+ }
+
+ if ((PLINK_OPN_SNT <= sta->plink_state &&
+ sta->plink_state <= PLINK_ESTAB) ||
+ (sta->sae && sta->sae->state > SAE_NOTHING)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Specified peer is connecting/connected");
+ return -1;
+ }
+
+ if (conf->security == MESH_CONF_SEC_NONE) {
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
+ } else {
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
+ eloop_register_timeout(duration == -1 ? 10 : duration, 0,
+ peer_add_timer, wpa_s, NULL);
+ }
+
+ return 0;
+}
+
+
void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
{
struct hostapd_data *hapd = ifmsh->bss[0];
@@ -481,6 +612,7 @@ void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
hapd->num_plinks = 0;
hostapd_free_stas(hapd);
+ eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
}
@@ -522,7 +654,7 @@ void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
}
/*
@@ -539,8 +671,19 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
struct hostapd_data *data = wpa_s->ifmsh->bss[0];
struct sta_info *sta;
+#ifdef CONFIG_IEEE80211N
+ struct ieee80211_ht_operation *oper;
+#endif /* CONFIG_IEEE80211N */
int ret;
+ if (elems->mesh_config_len >= 7 &&
+ !(elems->mesh_config[6] & MESH_CAP_ACCEPT_ADDITIONAL_PEER)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "mesh: Ignore a crowded peer " MACSTR,
+ MAC2STR(addr));
+ return NULL;
+ }
+
sta = ap_get_sta(data, addr);
if (!sta) {
sta = ap_sta_add(data, addr);
@@ -548,28 +691,57 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
return NULL;
}
+ /* Set WMM by default since Mesh STAs are QoS STAs */
+ sta->flags |= WLAN_STA_WMM;
+
/* initialize sta */
if (copy_supp_rates(wpa_s, sta, elems)) {
ap_free_sta(data, sta);
return NULL;
}
- mesh_mpm_init_link(wpa_s, sta);
+ if (!sta->my_lid)
+ mesh_mpm_init_link(wpa_s, sta);
#ifdef CONFIG_IEEE80211N
copy_sta_ht_capab(data, sta, elems->ht_capabilities);
+
+ oper = (struct ieee80211_ht_operation *) elems->ht_operation;
+ if (oper &&
+ !(oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) &&
+ sta->ht_capabilities) {
+ wpa_msg(wpa_s, MSG_DEBUG, MACSTR
+ " does not support 40 MHz bandwidth",
+ MAC2STR(sta->addr));
+ set_disable_ht40(sta->ht_capabilities, 1);
+ }
+
update_ht_state(data, sta);
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ copy_sta_vht_capab(data, sta, elems->vht_capabilities);
+ copy_sta_vht_oper(data, sta, elems->vht_operation);
+ set_sta_vht_opmode(data, sta, elems->vht_opmode_notif);
+#endif /* CONFIG_IEEE80211AC */
+
+ if (hostapd_get_aid(data, sta) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "No AIDs available");
+ ap_free_sta(data, sta);
+ return NULL;
+ }
+
/* insert into driver */
os_memset(&params, 0, sizeof(params));
params.supp_rates = sta->supported_rates;
params.supp_rates_len = sta->supported_rates_len;
params.addr = addr;
params.plink_state = sta->plink_state;
- params.aid = sta->peer_lid;
+ params.aid = sta->aid;
+ params.peer_aid = sta->peer_aid;
params.listen_interval = 100;
params.ht_capabilities = sta->ht_capabilities;
+ params.vht_capabilities = sta->vht_capabilities;
params.flags |= WPA_STA_WMM;
params.flags_mask |= WPA_STA_AUTHENTICATED;
if (conf->security == MESH_CONF_SEC_NONE) {
@@ -605,7 +777,9 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
if (!sta)
return;
- if (ssid && ssid->no_auto_peer) {
+ if (ssid && ssid->no_auto_peer &&
+ (is_zero_ether_addr(data->mesh_required_peer) ||
+ os_memcmp(data->mesh_required_peer, addr, ETH_ALEN) != 0)) {
wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
MACSTR " because of no_auto_peer", MAC2STR(addr));
if (data->mesh_pending_auth) {
@@ -634,10 +808,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
return;
}
- if (conf->security == MESH_CONF_SEC_NONE)
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
- else
+ if (conf->security == MESH_CONF_SEC_NONE) {
+ if (sta->plink_state < PLINK_OPN_SNT ||
+ sta->plink_state > PLINK_ESTAB)
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
+ } else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
+ }
}
@@ -664,64 +841,88 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
MAC2STR(sta->addr));
if (conf->security & MESH_CONF_SEC_AMPE) {
- wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
- seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
- wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
- seq, sizeof(seq),
- sta->mgtk, sizeof(sta->mgtk));
- wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
- seq, sizeof(seq),
- sta->mgtk, sizeof(sta->mgtk));
-
- wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
- wpa_hexdump_key(MSG_DEBUG, "mgtk:",
- sta->mgtk, sizeof(sta->mgtk));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
+ wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
+ sta->addr, 0, 0, seq, sizeof(seq),
+ sta->mtk, sta->mtk_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
+ sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK",
+ sta->mgtk, sta->mgtk_len);
+ wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
+ sta->addr, sta->mgtk_key_id, 0,
+ sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
+ sta->mgtk, sta->mgtk_len);
+
+ if (sta->igtk_len) {
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
+ sta->igtk_rsc, sizeof(sta->igtk_rsc));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK",
+ sta->igtk, sta->igtk_len);
+ wpa_drv_set_key(
+ wpa_s,
+ wpa_cipher_to_alg(conf->mgmt_group_cipher),
+ sta->addr, sta->igtk_key_id, 0,
+ sta->igtk_rsc, sizeof(sta->igtk_rsc),
+ sta->igtk, sta->igtk_len);
+ }
}
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
hapd->num_plinks++;
sta->flags |= WLAN_STA_ASSOC;
+ sta->mesh_sae_pmksa_caching = 0;
+ eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
+ peer_add_timer(wpa_s, NULL);
eloop_cancel_timeout(plink_timer, wpa_s, sta);
/* Send ctrl event */
- wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
- MAC2STR(sta->addr));
+ wpa_msg(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
+ MAC2STR(sta->addr));
+
+ /* Send D-Bus event */
+ wpas_notify_mesh_peer_connected(wpa_s, sta->addr);
}
static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
- enum plink_event event)
+ enum plink_event event, u16 reason)
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
- u16 reason = 0;
wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
MAC2STR(sta->addr), mplstate[sta->plink_state],
mplevent[event]);
switch (sta->plink_state) {
- case PLINK_LISTEN:
+ case PLINK_IDLE:
switch (event) {
case CLS_ACPT:
mesh_mpm_fsm_restart(wpa_s, sta);
break;
case OPN_ACPT:
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
0);
break;
+ case REQ_RJCT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
default:
break;
}
break;
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_SNT:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -736,12 +937,13 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
break;
case OPN_ACPT:
/* retry timer is left untouched */
- wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta,
PLINK_CONFIRM, 0);
break;
case CNF_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
eloop_register_timeout(
conf->dot11MeshConfirmTimeout / 1000,
(conf->dot11MeshConfirmTimeout % 1000) * 1000,
@@ -751,11 +953,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
break;
}
break;
- case PLINK_OPEN_RCVD:
+ case PLINK_OPN_RCVD:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -786,7 +989,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -801,6 +1005,8 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
PLINK_CLOSE, reason);
break;
case OPN_ACPT:
+ if (conf->security & MESH_CONF_SEC_AMPE)
+ mesh_rsn_derive_mtk(wpa_s, sta);
mesh_mpm_plink_estab(wpa_s, sta);
mesh_mpm_send_plink_action(wpa_s, sta,
PLINK_CONFIRM, 0);
@@ -811,9 +1017,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
break;
case PLINK_ESTAB:
switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
- reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
eloop_register_timeout(
conf->dot11MeshHoldingTimeout / 1000,
@@ -825,9 +1034,12 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
" closed with reason %d",
MAC2STR(sta->addr), reason);
- wpa_msg_ctrl(wpa_s, MSG_INFO,
- MESH_PEER_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
+ wpa_msg(wpa_s, MSG_INFO, MESH_PEER_DISCONNECTED MACSTR,
+ MAC2STR(sta->addr));
+
+ /* Send D-Bus event */
+ wpas_notify_mesh_peer_disconnected(wpa_s, sta->addr,
+ reason);
hapd->num_plinks--;
@@ -875,13 +1087,14 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
struct sta_info *sta;
- u16 plid = 0, llid = 0;
+ u16 plid = 0, llid = 0, aid = 0;
enum plink_event event;
struct ieee802_11_elems elems;
struct mesh_peer_mgmt_ie peer_mgmt_ie;
const u8 *ies;
size_t ie_len;
int ret;
+ u16 reason = 0;
if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
return;
@@ -912,7 +1125,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
ie_len -= 2;
}
if (action_field == PLINK_CONFIRM) {
- wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+ aid = WPA_GET_LE16(ies);
+ wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", aid);
ies += 2; /* aid */
ie_len -= 2;
}
@@ -956,6 +1170,10 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
llid = WPA_GET_LE16(peer_mgmt_ie.plid);
wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
+ if (action_field == PLINK_CLOSE)
+ wpa_printf(MSG_DEBUG, "MPM: close reason=%u",
+ WPA_GET_LE16(peer_mgmt_ie.reason));
+
sta = ap_get_sta(hapd, mgmt->sa);
/*
@@ -963,7 +1181,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
* open mesh, then go ahead and add the peer before proceeding.
*/
if (!sta && action_field == PLINK_OPEN &&
- !(mconf->security & MESH_CONF_SEC_AMPE))
+ (!(mconf->security & MESH_CONF_SEC_AMPE) ||
+ wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa, NULL)))
sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
if (!sta) {
@@ -982,12 +1201,74 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- if ((mconf->security & MESH_CONF_SEC_AMPE) &&
- mesh_rsn_process_ampe(wpa_s, sta, &elems,
- &mgmt->u.action.category,
- ies, ie_len)) {
- wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
- return;
+ if (mconf->security & MESH_CONF_SEC_AMPE) {
+ int res;
+
+ res = mesh_rsn_process_ampe(wpa_s, sta, &elems,
+ &mgmt->u.action.category,
+ peer_mgmt_ie.chosen_pmk,
+ ies, ie_len);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: RSN process rejected frame (res=%d)",
+ res);
+ if (action_field == PLINK_OPEN && res == -2) {
+ /* AES-SIV decryption failed */
+ mesh_mpm_fsm(wpa_s, sta, OPN_RJCT,
+ WLAN_REASON_MESH_INVALID_GTK);
+ }
+ return;
+ }
+
+#ifdef CONFIG_OCV
+ if (action_field == PLINK_OPEN && elems.rsn_ie) {
+ struct wpa_state_machine *sm = sta->wpa_sm;
+ struct wpa_ie_data data;
+
+ res = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2,
+ elems.rsn_ie_len + 2,
+ &data);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to parse RSN IE (res=%d)",
+ res);
+ wpa_hexdump(MSG_DEBUG, "RSN IE", elems.rsn_ie,
+ elems.rsn_ie_len);
+ return;
+ }
+
+ wpa_auth_set_ocv(sm, mconf->ocv &&
+ (data.capabilities &
+ WPA_CAPABILITY_OCVC));
+ }
+
+ if (action_field != PLINK_CLOSE &&
+ wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "MPM: Failed to get channel info to validate received OCI in MPM Confirm");
+ return;
+ }
+
+ if (get_tx_parameters(
+ sta, channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) !=
+ 0) {
+ wpa_printf(MSG_WARNING, "MPM: %s",
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
}
if (sta->plink_state == PLINK_BLOCKED) {
@@ -999,12 +1280,16 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
switch (action_field) {
case PLINK_OPEN:
if (plink_free_count(hapd) == 0) {
- event = OPN_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->peer_lid && sta->peer_lid != plid) {
- event = OPN_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
sta->peer_lid = plid;
event = OPN_ACPT;
@@ -1012,16 +1297,21 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
break;
case PLINK_CONFIRM:
if (plink_free_count(hapd) == 0) {
- event = CNF_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->my_lid != llid ||
(sta->peer_lid && sta->peer_lid != plid)) {
- event = CNF_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: lid mismatch: my_lid: 0x%x != 0x%x or peer_lid: 0x%x != 0x%x",
+ sta->my_lid, llid, sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
if (!sta->peer_lid)
sta->peer_lid = plid;
+ sta->peer_aid = aid;
event = CNF_ACPT;
}
break;
@@ -1037,12 +1327,19 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
* restarted.
*/
event = CLS_ACPT;
- else if (sta->peer_lid != plid)
- event = CLS_IGNR;
- else if (peer_mgmt_ie.plid && sta->my_lid != llid)
- event = CLS_IGNR;
- else
+ else if (sta->peer_lid != plid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
+ } else if (peer_mgmt_ie.plid && sta->my_lid != llid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: my_lid mismatch: 0x%x != 0x%x",
+ sta->my_lid, llid);
+ return; /* no FSM event */
+ } else {
event = CLS_ACPT;
+ }
break;
default:
/*
@@ -1052,13 +1349,15 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
*/
return;
}
- mesh_mpm_fsm(wpa_s, sta, event);
+ mesh_mpm_fsm(wpa_s, sta, event, reason);
}
/* called by ap_free_sta */
-void mesh_mpm_free_sta(struct sta_info *sta)
+void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
+ if (sta->plink_state == PLINK_ESTAB)
+ hapd->num_plinks--;
eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta);
eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta);
}
diff --git a/contrib/wpa/wpa_supplicant/mesh_mpm.h b/contrib/wpa/wpa_supplicant/mesh_mpm.h
index 7ebaef0..5fc1e61 100644
--- a/contrib/wpa/wpa_supplicant/mesh_mpm.h
+++ b/contrib/wpa/wpa_supplicant/mesh_mpm.h
@@ -14,10 +14,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
struct ieee802_11_elems *elems);
void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh);
void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
-void mesh_mpm_free_sta(struct sta_info *sta);
+void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
struct sta_info *sta,
enum mesh_plink_state state);
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration);
#ifdef CONFIG_MESH
diff --git a/contrib/wpa/wpa_supplicant/mesh_rsn.c b/contrib/wpa/wpa_supplicant/mesh_rsn.c
index 747f1ae..4b8d6c46 100644
--- a/contrib/wpa/wpa_supplicant/mesh_rsn.c
+++ b/contrib/wpa/wpa_supplicant/mesh_rsn.c
@@ -27,12 +27,12 @@
#define MESH_AUTH_TIMEOUT 10
#define MESH_AUTH_RETRY 3
-#define MESH_AUTH_BLOCK_DURATION 3600
void mesh_auth_timer(void *eloop_ctx, void *user_data)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct sta_info *sta = user_data;
+ struct hostapd_data *hapd;
if (sta->sae->state != SAE_ACCEPTED) {
wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
@@ -43,23 +43,20 @@ void mesh_auth_timer(void *eloop_ctx, void *user_data)
if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
mesh_rsn_auth_sae_sta(wpa_s, sta);
} else {
+ hapd = wpa_s->ifmsh->bss[0];
+
if (sta->sae_auth_retry > MESH_AUTH_RETRY) {
- ap_free_sta(wpa_s->ifmsh->bss[0], sta);
+ ap_free_sta(hapd, sta);
return;
}
/* block the STA if exceeded the number of attempts */
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED);
sta->sae->state = SAE_NOTHING;
- if (wpa_s->mesh_auth_block_duration <
- MESH_AUTH_BLOCK_DURATION)
- wpa_s->mesh_auth_block_duration += 60;
- eloop_register_timeout(wpa_s->mesh_auth_block_duration,
- 0, mesh_auth_timer, wpa_s, sta);
wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr="
MACSTR " duration=%d",
MAC2STR(sta->addr),
- wpa_s->mesh_auth_block_duration);
+ hapd->conf->ap_max_inactivity);
}
sta->sae_auth_retry++;
}
@@ -78,12 +75,17 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level,
static const u8 *auth_get_psk(void *ctx, const u8 *addr,
- const u8 *p2p_dev_addr, const u8 *prev_psk)
+ const u8 *p2p_dev_addr, const u8 *prev_psk,
+ size_t *psk_len, int *vlan_id)
{
struct mesh_rsn *mesh_rsn = ctx;
struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
struct sta_info *sta = ap_get_sta(hapd, addr);
+ if (psk_len)
+ *psk_len = PMK_LEN;
+ if (vlan_id)
+ *vlan_id = 0;
wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
__func__, MAC2STR(addr), prev_psk);
@@ -139,49 +141,74 @@ static int auth_start_ampe(void *ctx, const u8 *addr)
}
-static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
+ enum mfp_options ieee80211w, int ocv)
{
struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
+ static const struct wpa_auth_callbacks cb = {
+ .logger = auth_logger,
+ .get_psk = auth_get_psk,
+ .set_key = auth_set_key,
+ .start_ampe = auth_start_ampe,
+ };
u8 seq[6] = {};
wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
os_memset(&conf, 0, sizeof(conf));
- conf.wpa = 2;
+ conf.wpa = WPA_PROTO_RSN;
conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
- conf.wpa_pairwise = WPA_CIPHER_CCMP;
- conf.rsn_pairwise = WPA_CIPHER_CCMP;
- conf.wpa_group = WPA_CIPHER_CCMP;
+ conf.wpa_pairwise = rsn->pairwise_cipher;
+ conf.rsn_pairwise = rsn->pairwise_cipher;
+ conf.wpa_group = rsn->group_cipher;
conf.eapol_version = 0;
conf.wpa_group_rekey = -1;
-
- os_memset(&cb, 0, sizeof(cb));
- cb.ctx = rsn;
- cb.logger = auth_logger;
- cb.get_psk = auth_get_psk;
- cb.set_key = auth_set_key;
- cb.start_ampe = auth_start_ampe;
-
- rsn->auth = wpa_init(addr, &conf, &cb);
+ conf.wpa_group_update_count = 4;
+ conf.wpa_pairwise_update_count = 4;
+#ifdef CONFIG_IEEE80211W
+ conf.ieee80211w = ieee80211w;
+ if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
+ conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ conf.ocv = ocv;
+#endif /* CONFIG_OCV */
+
+ rsn->auth = wpa_init(addr, &conf, &cb, rsn);
if (rsn->auth == NULL) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
return -1;
}
/* TODO: support rekeying */
- if (random_get_bytes(rsn->mgtk, 16) < 0) {
- wpa_deinit(rsn->auth);
+ rsn->mgtk_len = wpa_cipher_key_len(conf.wpa_group);
+ if (random_get_bytes(rsn->mgtk, rsn->mgtk_len) < 0)
return -1;
- }
+ rsn->mgtk_key_id = 1;
- /* group mgmt */
- wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
- seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+#ifdef CONFIG_IEEE80211W
+ if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
+ if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
+ return -1;
+ rsn->igtk_key_id = 4;
+
+ /* group mgmt */
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
+ rsn->igtk, rsn->igtk_len);
+ wpa_drv_set_key(rsn->wpa_s,
+ wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
+ rsn->igtk_key_id, 1,
+ seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
/* group privacy / data frames */
- wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1,
- seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
+ rsn->mgtk, rsn->mgtk_len);
+ wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
+ rsn->mgtk_key_id, 1, seq, sizeof(seq),
+ rsn->mgtk, rsn->mgtk_len);
return 0;
}
@@ -190,6 +217,9 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
static void mesh_rsn_deinit(struct mesh_rsn *rsn)
{
os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+ rsn->mgtk_len = 0;
+ os_memset(rsn->igtk, 0, sizeof(rsn->igtk));
+ rsn->igtk_len = 0;
if (rsn->auth)
wpa_deinit(rsn->auth);
}
@@ -202,13 +232,20 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
const u8 *ie;
size_t ie_len;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ struct external_pmksa_cache *entry;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
if (mesh_rsn == NULL)
return NULL;
mesh_rsn->wpa_s = wpa_s;
+ mesh_rsn->pairwise_cipher = conf->pairwise_cipher;
+ mesh_rsn->group_cipher = conf->group_cipher;
+ mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
- if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+ if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
+ conf->ieee80211w, conf->ocv) < 0) {
mesh_rsn_deinit(mesh_rsn);
os_free(mesh_rsn);
return NULL;
@@ -216,6 +253,22 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
bss->wpa_auth = mesh_rsn->auth;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+ struct external_pmksa_cache,
+ list)) != NULL) {
+ int ret;
+
+ ret = wpa_auth_pmksa_add_entry(bss->wpa_auth,
+ entry->pmksa_cache);
+ dl_list_del(&entry->list);
+ os_free(entry);
+
+ if (ret < 0)
+ return NULL;
+ }
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len);
conf->rsn_ie = (u8 *) ie;
conf->rsn_ie_len = ie_len;
@@ -269,7 +322,12 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct sta_info *sta)
{
- if (ssid->passphrase == NULL) {
+ const char *password;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+ if (!password) {
wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available");
return -1;
}
@@ -279,9 +337,15 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
return -1;
}
+ if (sta->sae->tmp && !sta->sae->tmp->pw_id && ssid->sae_password_id) {
+ sta->sae->tmp->pw_id = os_strdup(ssid->sae_password_id);
+ if (!sta->sae->tmp->pw_id)
+ return -1;
+ }
return sae_prepare_commit(wpa_s->own_addr, sta->addr,
- (u8 *) ssid->passphrase,
- os_strlen(ssid->passphrase), sta->sae);
+ (u8 *) password, os_strlen(password),
+ ssid->sae_password_id,
+ sta->sae);
}
@@ -291,6 +355,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct rsn_pmksa_cache_entry *pmksa;
unsigned int rnd;
int ret;
@@ -306,6 +371,29 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
return -1;
}
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, NULL);
+ if (pmksa) {
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Failed to initialize RSN state machine");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "AUTH: Mesh PMKSA cache entry found for " MACSTR
+ " - try to use PMKSA caching instead of new SAE authentication",
+ MAC2STR(sta->addr));
+ wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth,
+ sta->sae->pmkid, sta->sae->pmk);
+ sae_accept_sta(hapd, sta);
+ sta->mesh_sae_pmksa_caching = 1;
+ return 0;
+ }
+ sta->mesh_sae_pmksa_caching = 0;
+
if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
return -1;
@@ -313,7 +401,6 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
"AUTH: started authentication with SAE peer: " MACSTR,
MAC2STR(sta->addr));
- wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
ret = auth_sae_init_committed(hapd, sta);
if (ret)
return ret;
@@ -328,10 +415,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid)
{
- /* don't expect wpa auth to cache the pmkid for now */
- rsn_pmkid(sta->sae->pmk, PMK_LEN, rsn->wpa_s->own_addr,
- sta->addr, pmkid,
- wpa_key_mgmt_sha256(wpa_auth_sta_key_mgmt(sta->wpa_sm)));
+ os_memcpy(pmkid, sta->sae->pmkid, SAE_PMKID_LEN);
}
@@ -340,18 +424,27 @@ mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta)
{
u8 *myaddr = rsn->wpa_s->own_addr;
u8 *peer = sta->addr;
- u8 *addr1 = peer, *addr2 = myaddr;
- u8 context[AES_BLOCK_SIZE];
+ u8 *addr1, *addr2;
+ u8 context[RSN_SELECTOR_LEN + 2 * ETH_ALEN], *ptr = context;
- /* SAE */
- RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+ /*
+ * AEK = KDF-Hash-256(PMK, "AEK Derivation", Selected AKM Suite ||
+ * min(localMAC, peerMAC) || max(localMAC, peerMAC))
+ */
+ /* Selected AKM Suite: SAE */
+ RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+ ptr += RSN_SELECTOR_LEN;
if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
addr1 = myaddr;
addr2 = peer;
+ } else {
+ addr1 = peer;
+ addr2 = myaddr;
}
- os_memcpy(context + 4, addr1, ETH_ALEN);
- os_memcpy(context + 10, addr2, ETH_ALEN);
+ os_memcpy(ptr, addr1, ETH_ALEN);
+ ptr += ETH_ALEN;
+ os_memcpy(ptr, addr2, ETH_ALEN);
sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
context, sizeof(context), sta->aek, sizeof(sta->aek));
@@ -363,40 +456,44 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
{
u8 *ptr;
u8 *min, *max;
- u16 min_lid, max_lid;
- size_t nonce_len = sizeof(sta->my_nonce);
- size_t lid_len = sizeof(sta->my_lid);
u8 *myaddr = wpa_s->own_addr;
u8 *peer = sta->addr;
- /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
- u8 context[64 + 4 + 4 + 12];
-
+ u8 context[2 * WPA_NONCE_LEN + 2 * 2 + RSN_SELECTOR_LEN + 2 * ETH_ALEN];
+
+ /*
+ * MTK = KDF-Hash-Length(PMK, "Temporal Key Derivation", min(localNonce,
+ * peerNonce) || max(localNonce, peerNonce) || min(localLinkID,
+ * peerLinkID) || max(localLinkID, peerLinkID) || Selected AKM Suite ||
+ * min(localMAC, peerMAC) || max(localMAC, peerMAC))
+ */
ptr = context;
- if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) {
+ if (os_memcmp(sta->my_nonce, sta->peer_nonce, WPA_NONCE_LEN) < 0) {
min = sta->my_nonce;
max = sta->peer_nonce;
} else {
min = sta->peer_nonce;
max = sta->my_nonce;
}
- os_memcpy(ptr, min, nonce_len);
- os_memcpy(ptr + nonce_len, max, nonce_len);
- ptr += 2 * nonce_len;
+ os_memcpy(ptr, min, WPA_NONCE_LEN);
+ ptr += WPA_NONCE_LEN;
+ os_memcpy(ptr, max, WPA_NONCE_LEN);
+ ptr += WPA_NONCE_LEN;
if (sta->my_lid < sta->peer_lid) {
- min_lid = host_to_le16(sta->my_lid);
- max_lid = host_to_le16(sta->peer_lid);
+ WPA_PUT_LE16(ptr, sta->my_lid);
+ ptr += 2;
+ WPA_PUT_LE16(ptr, sta->peer_lid);
+ ptr += 2;
} else {
- min_lid = host_to_le16(sta->peer_lid);
- max_lid = host_to_le16(sta->my_lid);
+ WPA_PUT_LE16(ptr, sta->peer_lid);
+ ptr += 2;
+ WPA_PUT_LE16(ptr, sta->my_lid);
+ ptr += 2;
}
- os_memcpy(ptr, &min_lid, lid_len);
- os_memcpy(ptr + lid_len, &max_lid, lid_len);
- ptr += 2 * lid_len;
- /* SAE */
- RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
- ptr += 4;
+ /* Selected AKM Suite: SAE */
+ RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+ ptr += RSN_SELECTOR_LEN;
if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
min = myaddr;
@@ -406,22 +503,24 @@ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
max = myaddr;
}
os_memcpy(ptr, min, ETH_ALEN);
- os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+ ptr += ETH_ALEN;
+ os_memcpy(ptr, max, ETH_ALEN);
- sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+ sta->mtk_len = wpa_cipher_key_len(wpa_s->mesh_rsn->pairwise_cipher);
+ sha256_prf(sta->sae->pmk, SAE_PMK_LEN,
"Temporal Key Derivation", context, sizeof(context),
- sta->mtk, sizeof(sta->mtk));
+ sta->mtk, sta->mtk_len);
return 0;
}
void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta)
{
- if (random_get_bytes(sta->my_nonce, 32) < 0) {
+ if (random_get_bytes(sta->my_nonce, WPA_NONCE_LEN) < 0) {
wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
/* TODO: How to handle this more cleanly? */
}
- os_memset(sta->peer_nonce, 0, 32);
+ os_memset(sta->peer_nonce, 0, WPA_NONCE_LEN);
mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
}
@@ -437,65 +536,94 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
{
struct ieee80211_ampe_ie *ampe;
u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
- u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload;
+ u8 *ampe_ie, *pos, *mic_payload;
const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat };
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat };
int ret = 0;
+ size_t len;
+
+ len = sizeof(*ampe);
+ if (cat[1] == PLINK_OPEN)
+ len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
+#ifdef CONFIG_IEEE80211W
+ if (cat[1] == PLINK_OPEN && rsn->igtk_len)
+ len += 2 + 6 + rsn->igtk_len;
+#endif /* CONFIG_IEEE80211W */
- if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+ if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
wpa_printf(MSG_ERROR, "protect frame: buffer too small");
return -EINVAL;
}
- ampe_ie = os_zalloc(2 + sizeof(*ampe));
+ ampe_ie = os_zalloc(2 + len);
if (!ampe_ie) {
wpa_printf(MSG_ERROR, "protect frame: out of memory");
return -ENOMEM;
}
- mic_ie = os_zalloc(2 + AES_BLOCK_SIZE);
- if (!mic_ie) {
- wpa_printf(MSG_ERROR, "protect frame: out of memory");
- ret = -ENOMEM;
- goto free;
- }
-
/* IE: AMPE */
ampe_ie[0] = WLAN_EID_AMPE;
- ampe_ie[1] = sizeof(*ampe);
+ ampe_ie[1] = len;
ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
- wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP));
- os_memcpy(ampe->local_nonce, sta->my_nonce, 32);
- os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32);
- /* incomplete: see 13.5.4 */
+ RSN_CIPHER_SUITE_CCMP);
+ os_memcpy(ampe->local_nonce, sta->my_nonce, WPA_NONCE_LEN);
+ os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN);
+
+ pos = (u8 *) (ampe + 1);
+ if (cat[1] != PLINK_OPEN)
+ goto skip_keys;
+
+ /* TODO: Key Replay Counter[8] optionally for
+ * Mesh Group Key Inform/Acknowledge frames */
+
/* TODO: static mgtk for now since we don't support rekeying! */
- os_memcpy(ampe->mgtk, rsn->mgtk, 16);
- /* TODO: Populate Key RSC */
- /* expire in 13 decades or so */
- os_memset(ampe->key_expiration, 0xff, 4);
+ /*
+ * GTKdata[variable]:
+ * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+ */
+ os_memcpy(pos, rsn->mgtk, rsn->mgtk_len);
+ pos += rsn->mgtk_len;
+ wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->mgtk_key_id, pos);
+ pos += WPA_KEY_RSC_LEN;
+ /* Use fixed GTKExpirationTime for now */
+ WPA_PUT_LE32(pos, 0xffffffff);
+ pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+ /*
+ * IGTKdata[variable]:
+ * Key ID[2], IPN[6], IGTK[variable]
+ */
+ if (rsn->igtk_len) {
+ WPA_PUT_LE16(pos, rsn->igtk_key_id);
+ pos += 2;
+ wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->igtk_key_id, pos);
+ pos += 6;
+ os_memcpy(pos, rsn->igtk, rsn->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
+
+skip_keys:
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
+ ampe_ie, 2 + len);
/* IE: MIC */
- mic_ie[0] = WLAN_EID_MIC;
- mic_ie[1] = AES_BLOCK_SIZE;
- wpabuf_put_data(buf, mic_ie, 2);
+ wpabuf_put_u8(buf, WLAN_EID_MIC);
+ wpabuf_put_u8(buf, AES_BLOCK_SIZE);
/* MIC field is output ciphertext */
/* encrypt after MIC */
- mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) +
- AES_BLOCK_SIZE);
+ mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE);
- if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3,
+ if (aes_siv_encrypt(sta->aek, sizeof(sta->aek), ampe_ie, 2 + len, 3,
aad, aad_len, mic_payload)) {
wpa_printf(MSG_ERROR, "protect frame: failed to encrypt");
ret = -ENOMEM;
- goto free;
}
-free:
os_free(ampe_ie);
- os_free(mic_ie);
return ret;
}
@@ -503,18 +631,39 @@ free:
int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *chosen_pmk,
const u8 *start, size_t elems_len)
{
int ret = 0;
struct ieee80211_ampe_ie *ampe;
- u8 null_nonce[32] = {};
+ u8 null_nonce[WPA_NONCE_LEN] = {};
u8 ampe_eid;
u8 ampe_ie_len;
- u8 *ampe_buf, *crypt = NULL;
+ u8 *ampe_buf, *crypt = NULL, *pos, *end;
size_t crypt_len;
const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
- (elems->mic - 2) - cat };
+ elems->mic ? (elems->mic - 2) - cat : 0 };
+ size_t key_len;
+
+ if (!sta->sae) {
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, NULL)) {
+ wpa_printf(MSG_INFO,
+ "Mesh RSN: SAE is not prepared yet");
+ return -1;
+ }
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ }
+
+ if (chosen_pmk &&
+ (!sta->sae ||
+ os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN) != 0)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
+ return -1;
+ }
if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
@@ -526,7 +675,7 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
return -1;
crypt_len = elems_len - (elems->mic - start);
- if (crypt_len < 2) {
+ if (crypt_len < 2 + AES_BLOCK_SIZE) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
return -1;
}
@@ -541,17 +690,22 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
os_memcpy(crypt, elems->mic, crypt_len);
- if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
+ if (aes_siv_decrypt(sta->aek, sizeof(sta->aek), crypt, crypt_len, 3,
aad, aad_len, ampe_buf)) {
wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
- ret = -1;
+ ret = -2;
goto free;
}
+ crypt_len -= AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Decrypted AMPE element",
+ ampe_buf, crypt_len);
+
ampe_eid = *ampe_buf++;
ampe_ie_len = *ampe_buf++;
if (ampe_eid != WLAN_EID_AMPE ||
+ (size_t) 2 + ampe_ie_len > crypt_len ||
ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
ret = -1;
@@ -559,17 +713,89 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
}
ampe = (struct ieee80211_ampe_ie *) ampe_buf;
- if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 &&
- os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) {
+ pos = (u8 *) (ampe + 1);
+ end = ampe_buf + ampe_ie_len;
+ if (os_memcmp(ampe->peer_nonce, null_nonce, WPA_NONCE_LEN) != 0 &&
+ os_memcmp(ampe->peer_nonce, sta->my_nonce, WPA_NONCE_LEN) != 0) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
ret = -1;
goto free;
}
os_memcpy(sta->peer_nonce, ampe->local_nonce,
sizeof(ampe->local_nonce));
- os_memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk));
- /* todo parse mgtk expiration */
+ /* TODO: Key Replay Counter[8] in Mesh Group Key Inform/Acknowledge
+ * frames */
+
+ /*
+ * GTKdata shall not be included in Mesh Peering Confirm. While the
+ * standard does not state the same about IGTKdata, that same constraint
+ * needs to apply for it. It makes no sense to include the keys in Mesh
+ * Peering Close frames either, so while the standard does not seem to
+ * have a shall statement for these, they are described without
+ * mentioning GTKdata.
+ *
+ * An earlier implementation used to add GTKdata to both Mesh Peering
+ * Open and Mesh Peering Confirm frames, so ignore the possibly present
+ * GTKdata frame without rejecting the frame as a backwards
+ * compatibility mechanism.
+ */
+ if (cat[1] != PLINK_OPEN) {
+ if (end > pos) {
+ wpa_hexdump_key(MSG_DEBUG,
+ "mesh: Ignore unexpected GTKdata(etc.) fields in the end of AMPE element in Mesh Peering Confirm/Close",
+ pos, end - pos);
+ }
+ goto free;
+ }
+
+ /*
+ * GTKdata[variable]:
+ * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+ */
+ sta->mgtk_key_id = 1; /* FIX: Where to get Key ID? */
+ key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->group_cipher);
+ if ((int) key_len + WPA_KEY_RSC_LEN + 4 > end - pos) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "mesh: Truncated AMPE element");
+ ret = -1;
+ goto free;
+ }
+ sta->mgtk_len = key_len;
+ os_memcpy(sta->mgtk, pos, sta->mgtk_len);
+ wpa_hexdump_key(MSG_DEBUG, "mesh: GTKdata - MGTK",
+ sta->mgtk, sta->mgtk_len);
+ pos += sta->mgtk_len;
+ wpa_hexdump(MSG_DEBUG, "mesh: GTKdata - MGTK - Key RSC",
+ pos, WPA_KEY_RSC_LEN);
+ os_memcpy(sta->mgtk_rsc, pos, sizeof(sta->mgtk_rsc));
+ pos += WPA_KEY_RSC_LEN;
+ wpa_printf(MSG_DEBUG,
+ "mesh: GTKdata - MGTK - GTKExpirationTime: %u seconds",
+ WPA_GET_LE32(pos));
+ pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+ /*
+ * IGTKdata[variable]:
+ * Key ID[2], IPN[6], IGTK[variable]
+ */
+ key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->mgmt_group_cipher);
+ if (end - pos >= (int) (2 + 6 + key_len)) {
+ sta->igtk_key_id = WPA_GET_LE16(pos);
+ wpa_printf(MSG_DEBUG, "mesh: IGTKdata - Key ID %u",
+ sta->igtk_key_id);
+ pos += 2;
+ os_memcpy(sta->igtk_rsc, pos, sizeof(sta->igtk_rsc));
+ wpa_hexdump(MSG_DEBUG, "mesh: IGTKdata - IPN",
+ sta->igtk_rsc, sizeof(sta->igtk_rsc));
+ pos += 6;
+ os_memcpy(sta->igtk, pos, key_len);
+ sta->igtk_len = key_len;
+ wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
+ sta->igtk, sta->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
+
free:
os_free(crypt);
return ret;
diff --git a/contrib/wpa/wpa_supplicant/mesh_rsn.h b/contrib/wpa/wpa_supplicant/mesh_rsn.h
index b1471b2..8775ced 100644
--- a/contrib/wpa/wpa_supplicant/mesh_rsn.h
+++ b/contrib/wpa/wpa_supplicant/mesh_rsn.h
@@ -12,7 +12,15 @@
struct mesh_rsn {
struct wpa_supplicant *wpa_s;
struct wpa_authenticator *auth;
- u8 mgtk[16];
+ unsigned int pairwise_cipher;
+ unsigned int group_cipher;
+ u8 mgtk[WPA_TK_MAX_LEN];
+ size_t mgtk_len;
+ u8 mgtk_key_id;
+ unsigned int mgmt_group_cipher;
+ u8 igtk_key_id;
+ u8 igtk[WPA_TK_MAX_LEN];
+ size_t igtk_len;
#ifdef CONFIG_SAE
struct wpabuf *sae_token;
int sae_group_index;
@@ -30,6 +38,7 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
const u8 *cat, struct wpabuf *buf);
int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *chosen_pmk,
const u8 *start, size_t elems_len);
void mesh_auth_timer(void *eloop_ctx, void *user_data);
diff --git a/contrib/wpa/wpa_supplicant/notify.c b/contrib/wpa/wpa_supplicant/notify.c
index 45d06bf..bedb74b 100644
--- a/contrib/wpa/wpa_supplicant/notify.c
+++ b/contrib/wpa/wpa_supplicant/notify.c
@@ -13,8 +13,8 @@
#include "config.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
+#include "binder/binder.h"
#include "dbus/dbus_common.h"
-#include "dbus/dbus_old.h"
#include "dbus/dbus_new.h"
#include "rsn_supp/wpa.h"
#include "fst/fst.h"
@@ -26,13 +26,19 @@
int wpas_notify_supplicant_initialized(struct wpa_global *global)
{
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
if (global->params.dbus_ctrl_interface) {
global->dbus = wpas_dbus_init(global);
if (global->dbus == NULL)
return -1;
}
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+
+#ifdef CONFIG_BINDER
+ global->binder = wpas_binder_init(global);
+ if (!global->binder)
+ return -1;
+#endif /* CONFIG_BINDER */
return 0;
}
@@ -40,10 +46,15 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global)
void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
{
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
if (global->dbus)
wpas_dbus_deinit(global->dbus);
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+
+#ifdef CONFIG_BINDER
+ if (global->binder)
+ wpas_binder_deinit(global->binder);
+#endif /* CONFIG_BINDER */
}
@@ -52,9 +63,6 @@ int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
if (wpa_s->p2p_mgmt)
return 0;
- if (wpas_dbus_register_iface(wpa_s))
- return -1;
-
if (wpas_dbus_register_interface(wpa_s))
return -1;
@@ -67,9 +75,6 @@ void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s)
if (wpa_s->p2p_mgmt)
return;
- /* unregister interface in old DBus ctrl iface */
- wpas_dbus_unregister_iface(wpa_s);
-
/* unregister interface in new DBus ctrl iface */
wpas_dbus_unregister_interface(wpa_s);
}
@@ -82,10 +87,6 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
if (wpa_s->p2p_mgmt)
return;
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_state_change(wpa_s, new_state,
- old_state);
-
/* notify the new DBus API */
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
@@ -128,6 +129,60 @@ void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
}
+void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AUTH_STATUS_CODE);
+}
+
+
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE);
+}
+
+
+void wpas_notify_roam_time(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ROAM_TIME);
+}
+
+
+void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ROAM_COMPLETE);
+}
+
+
+void wpas_notify_session_length(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SESSION_LENGTH);
+}
+
+
+void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSS_TM_STATUS);
+}
+
+
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_mgmt)
@@ -201,9 +256,6 @@ void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
if (wpa_s->p2p_mgmt)
return;
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_scanning(wpa_s);
-
/* notify the new DBus API */
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SCANNING);
}
@@ -223,9 +275,6 @@ void wpas_notify_scan_results(struct wpa_supplicant *wpa_s)
if (wpa_s->p2p_mgmt)
return;
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_scan_results(wpa_s);
-
wpas_wps_notify_scan_results(wpa_s);
}
@@ -237,8 +286,6 @@ void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
return;
#ifdef CONFIG_WPS
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
/* notify the new DBus API */
wpas_dbus_signal_wps_cred(wpa_s, cred);
#endif /* CONFIG_WPS */
@@ -647,13 +694,13 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, int network_id,
- int client)
+ struct wpa_ssid *ssid, int persistent,
+ int client, const u8 *ip)
{
/* Notify a group has been started */
wpas_dbus_register_p2p_group(wpa_s, ssid);
- wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id);
+ wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent, ip);
}
@@ -699,6 +746,9 @@ static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr);
#endif /* CONFIG_P2P */
+ /* Register the station */
+ wpas_dbus_register_sta(wpa_s, sta);
+
/* Notify listeners a new station has been authorized */
wpas_dbus_signal_sta_authorized(wpa_s, sta);
}
@@ -719,6 +769,9 @@ static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
/* Notify listeners a station has been deauthorized */
wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
+
+ /* Unregister the station */
+ wpas_dbus_unregister_sta(wpa_s, sta);
}
@@ -766,9 +819,6 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
"depth=%d %s", depth, altsubject[i]);
}
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
- cert_hash, cert);
/* notify the new DBus API */
wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject,
num_altsubject, cert_hash, cert);
@@ -795,6 +845,12 @@ void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
}
+void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code)
+{
+ wpa_msg(wpa_s, MSG_ERROR, WPA_EVENT_EAP_ERROR_CODE "%d", error_code);
+}
+
+
void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -829,3 +885,49 @@ void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_P2P */
}
+
+
+#ifdef CONFIG_MESH
+
+void wpas_notify_mesh_group_started(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_mesh_group_started(wpa_s, ssid);
+}
+
+
+void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s,
+ const u8 *meshid, u8 meshid_len,
+ int reason_code)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_mesh_group_removed(wpa_s, meshid, meshid_len,
+ reason_code);
+}
+
+
+void wpas_notify_mesh_peer_connected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_mesh_peer_connected(wpa_s, peer_addr);
+}
+
+
+void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int reason_code)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_mesh_peer_disconnected(wpa_s, peer_addr, reason_code);
+}
+
+#endif /* CONFIG_MESH */
diff --git a/contrib/wpa/wpa_supplicant/notify.h b/contrib/wpa/wpa_supplicant/notify.h
index d9f0f5a..65f513e 100644
--- a/contrib/wpa/wpa_supplicant/notify.h
+++ b/contrib/wpa/wpa_supplicant/notify.h
@@ -23,6 +23,12 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
enum wpa_states new_state,
enum wpa_states old_state);
void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s);
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s);
+void wpas_notify_roam_time(struct wpa_supplicant *wpa_s);
+void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s);
+void wpas_notify_session_length(struct wpa_supplicant *wpa_s);
+void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
@@ -112,8 +118,8 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
u16 config_methods,
unsigned int generated_pin);
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, int network_id,
- int client);
+ struct wpa_ssid *ssid, int persistent,
+ int client, const u8 *ip);
void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
const char *reason);
void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
@@ -133,6 +139,7 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s,
const u8 *ie, size_t ie_len, u32 ssi_signal);
void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
const char *parameter);
+void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code);
void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,
@@ -140,5 +147,14 @@ void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,
void wpas_notify_p2p_invitation_received(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *go_dev_addr,
const u8 *bssid, int id, int op_freq);
+void wpas_notify_mesh_group_started(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s,
+ const u8 *meshid, u8 meshid_len,
+ int reason_code);
+void wpas_notify_mesh_peer_connected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr);
+void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int reason_code);
#endif /* NOTIFY_H */
diff --git a/contrib/wpa/wpa_supplicant/offchannel.c b/contrib/wpa/wpa_supplicant/offchannel.c
index 63af83a..b74be7d 100644
--- a/contrib/wpa/wpa_supplicant/offchannel.c
+++ b/contrib/wpa/wpa_supplicant/offchannel.c
@@ -23,8 +23,29 @@ wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
{
struct wpa_supplicant *iface;
- if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
+ if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) {
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_mgmt && wpa_s != wpa_s->parent &&
+ wpa_s->parent->ap_iface &&
+ os_memcmp(wpa_s->parent->own_addr,
+ wpa_s->own_addr, ETH_ALEN) == 0 &&
+ wpabuf_len(wpa_s->pending_action_tx) >= 2 &&
+ *wpabuf_head_u8(wpa_s->pending_action_tx) !=
+ WLAN_ACTION_PUBLIC) {
+ /*
+ * When P2P Device interface has same MAC address as
+ * the GO interface, make sure non-Public Action frames
+ * are sent through the GO interface. The P2P Device
+ * interface can only send Public Action frames.
+ */
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use GO interface %s instead of interface %s for Action TX",
+ wpa_s->parent->ifname, wpa_s->ifname);
+ return wpa_s->parent;
+ }
+#endif /* CONFIG_P2P */
return wpa_s;
+ }
/*
* Try to find a group interface that matches with the source address.
@@ -118,8 +139,9 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
}
wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
- MACSTR " using interface %s",
- MAC2STR(wpa_s->pending_action_dst), iface->ifname);
+ MACSTR " using interface %s (pending_action_tx=%p)",
+ MAC2STR(wpa_s->pending_action_dst), iface->ifname,
+ wpa_s->pending_action_tx);
res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
wpa_s->pending_action_dst,
wpa_s->pending_action_src,
@@ -183,8 +205,12 @@ void offchannel_send_action_tx_status(
return;
}
- wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame");
-
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Delete matching pending action frame (dst="
+ MACSTR " pending_action_tx=%p)", MAC2STR(dst),
+ wpa_s->pending_action_tx);
+ wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+ wpa_s->pending_action_tx);
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
@@ -250,8 +276,11 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
if (wpa_s->pending_action_tx) {
wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
- "frame TX to " MACSTR,
- MAC2STR(wpa_s->pending_action_dst));
+ "frame TX to " MACSTR " (pending_action_tx=%p)",
+ MAC2STR(wpa_s->pending_action_dst),
+ wpa_s->pending_action_tx);
+ wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+ wpa_s->pending_action_tx);
wpabuf_free(wpa_s->pending_action_tx);
}
wpa_s->pending_action_tx_done = 0;
@@ -268,6 +297,12 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
wpa_s->pending_action_freq = freq;
wpa_s->pending_action_no_cck = no_cck;
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Stored pending action frame (dst=" MACSTR
+ " pending_action_tx=%p)",
+ MAC2STR(dst), wpa_s->pending_action_tx);
+ wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
+ wpa_s->pending_action_tx);
if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
struct wpa_supplicant *iface;
@@ -275,6 +310,8 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
iface = wpas_get_tx_interface(wpa_s, src);
wpa_s->action_tx_wait_time = wait_time;
+ if (wait_time)
+ wpa_s->action_tx_wait_time_used = 1;
ret = wpa_drv_send_action(
iface, wpa_s->pending_action_freq,
@@ -363,13 +400,14 @@ void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
- wpa_s->action_tx_wait_time)
+ (wpa_s->action_tx_wait_time || wpa_s->action_tx_wait_time_used))
wpa_drv_send_action_cancel_wait(wpa_s);
else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_drv_cancel_remain_on_channel(wpa_s);
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = 0;
}
+ wpa_s->action_tx_wait_time_used = 0;
}
@@ -428,6 +466,9 @@ const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s)
*/
void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
{
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Clear pending Action frame TX (pending_action_tx=%p",
+ wpa_s->pending_action_tx);
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
}
diff --git a/contrib/wpa/wpa_supplicant/op_classes.c b/contrib/wpa/wpa_supplicant/op_classes.c
new file mode 100644
index 0000000..947917b
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/op_classes.c
@@ -0,0 +1,387 @@
+/*
+ * Operating classes
+ * Copyright(c) 2015 Intel Deutschland GmbH
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+
+
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+ unsigned int *flags)
+{
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].chan == chan)
+ break;
+ }
+
+ if (i == mode->num_channels ||
+ (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
+ return NOT_ALLOWED;
+
+ if (flags)
+ *flags = mode->channels[i].flag;
+
+ if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
+static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+ size_t i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ /*
+ * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+ * so the center channel is 6 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 6 &&
+ channel <= center_channels[i] + 6)
+ return center_channels[i];
+ }
+
+ return 0;
+}
+
+
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_chan;
+ unsigned int i;
+ unsigned int no_ir = 0;
+
+ center_chan = get_center_80mhz(mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+
+ /* check all the channels are available */
+ for (i = 0; i < 4; i++) {
+ unsigned int flags;
+ u8 adj_chan = center_chan - 6 + i * 4;
+
+ if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
+ (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
+ (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
+ (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
+ return NOT_ALLOWED;
+
+ if (flags & HOSTAPD_CHAN_NO_IR)
+ no_ir = 1;
+ }
+
+ if (no_ir)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
+static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_channels[] = { 50, 114 };
+ unsigned int i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ /*
+ * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
+ * so the center channel is 14 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 14 &&
+ channel <= center_channels[i] + 14)
+ return center_channels[i];
+ }
+
+ return 0;
+}
+
+
+static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ u8 center_chan;
+ unsigned int i;
+ unsigned int no_ir = 0;
+
+ center_chan = get_center_160mhz(mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+
+ /* Check all the channels are available */
+ for (i = 0; i < 8; i++) {
+ unsigned int flags;
+ u8 adj_chan = center_chan - 14 + i * 4;
+
+ if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
+ (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
+ (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
+ (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
+ (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
+ (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
+ (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
+ (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
+ return NOT_ALLOWED;
+
+ if (flags & HOSTAPD_CHAN_NO_IR)
+ no_ir = 1;
+ }
+
+ if (no_ir)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
+ u8 bw)
+{
+ unsigned int flag = 0;
+ enum chan_allowed res, res2;
+
+ res2 = res = allow_channel(mode, channel, &flag);
+ if (bw == BW40MINUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+ return NOT_ALLOWED;
+ res2 = allow_channel(mode, channel - 4, NULL);
+ } else if (bw == BW40PLUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+ return NOT_ALLOWED;
+ res2 = allow_channel(mode, channel + 4, NULL);
+ } else if (bw == BW80) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 80 MHz specific version.
+ */
+ res2 = res = verify_80mhz(mode, channel);
+ } else if (bw == BW160) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 160 MHz specific version.
+ */
+ res2 = res = verify_160mhz(mode, channel);
+ } else if (bw == BW80P80) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 80 MHz specific version.
+ */
+ res2 = res = verify_80mhz(mode, channel);
+ }
+
+ if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if (res == NO_IR || res2 == NO_IR)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
+static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const struct oper_class_map *op_class)
+{
+ int chan;
+ size_t i;
+ struct hostapd_hw_modes *mode;
+ int found;
+ int z;
+ int freq2 = 0;
+ int freq5 = 0;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+ if (!mode)
+ return 0;
+
+ /* If we are configured to disable certain things, take that into
+ * account here. */
+ if (ssid->freq_list && ssid->freq_list[0]) {
+ for (z = 0; ; z++) {
+ int f = ssid->freq_list[z];
+
+ if (f == 0)
+ break; /* end of list */
+ if (f > 4000 && f < 6000)
+ freq5 = 1;
+ else if (f > 2400 && f < 2500)
+ freq2 = 1;
+ }
+ } else {
+ /* No frequencies specified, can use anything hardware supports.
+ */
+ freq2 = freq5 = 1;
+ }
+
+ if (op_class->op_class >= 115 && op_class->op_class <= 130 && !freq5)
+ return 0;
+ if (op_class->op_class >= 81 && op_class->op_class <= 84 && !freq2)
+ return 0;
+
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ switch (op_class->op_class) {
+ case 83:
+ case 84:
+ case 104:
+ case 105:
+ case 116:
+ case 117:
+ case 119:
+ case 120:
+ case 122:
+ case 123:
+ case 126:
+ case 127:
+ case 128:
+ case 129:
+ case 130:
+ /* Disable >= 40 MHz channels if HT is disabled */
+ return 0;
+ }
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
+#ifdef CONFIG_VHT_OVERRIDES
+ if (ssid->disable_vht) {
+ if (op_class->op_class >= 128 && op_class->op_class <= 130) {
+ /* Disable >= 80 MHz channels if VHT is disabled */
+ return 0;
+ }
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
+ if (op_class->op_class == 128) {
+ u8 channels[] = { 42, 58, 106, 122, 138, 155 };
+
+ for (i = 0; i < ARRAY_SIZE(channels); i++) {
+ if (verify_channel(mode, channels[i], op_class->bw) !=
+ NOT_ALLOWED)
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (op_class->op_class == 129) {
+ /* Check if either 160 MHz channels is allowed */
+ return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
+ }
+
+ if (op_class->op_class == 130) {
+ /* Need at least two non-contiguous 80 MHz segments */
+ found = 0;
+
+ if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
+ found++;
+ if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ found++;
+ if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ found++;
+ if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
+ found++;
+
+ if (found >= 2)
+ return 1;
+
+ return 0;
+ }
+
+ found = 0;
+ for (chan = op_class->min_chan; chan <= op_class->max_chan;
+ chan += op_class->inc) {
+ if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
+ found = 1;
+ break;
+ }
+ }
+
+ return found;
+}
+
+
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ int freq, u8 *pos, size_t len)
+{
+ struct wpabuf *buf;
+ u8 op, current, chan;
+ u8 *ie_len;
+ size_t res;
+
+ /*
+ * Assume 20 MHz channel for now.
+ * TODO: Use the secondary channel and VHT channel width that will be
+ * used after association.
+ */
+ if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+ &current, &chan) == NUM_HOSTAPD_MODES)
+ return 0;
+
+ /*
+ * Need 3 bytes for EID, length, and current operating class, plus
+ * 1 byte for every other supported operating class.
+ */
+ buf = wpabuf_alloc(global_op_class_size + 3);
+ if (!buf)
+ return 0;
+
+ wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
+ /* Will set the length later, putting a placeholder */
+ ie_len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, current);
+
+ for (op = 0; global_op_class[op].op_class; op++) {
+ if (wpas_op_class_supported(wpa_s, ssid, &global_op_class[op]))
+ wpabuf_put_u8(buf, global_op_class[op].op_class);
+ }
+
+ *ie_len = wpabuf_len(buf) - 2;
+ if (*ie_len < 2 || wpabuf_len(buf) > len) {
+ wpa_printf(MSG_ERROR,
+ "Failed to add supported operating classes IE");
+ res = 0;
+ } else {
+ os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
+ res = wpabuf_len(buf);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "Added supported operating classes IE", buf);
+ }
+
+ wpabuf_free(buf);
+ return res;
+}
diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.c b/contrib/wpa/wpa_supplicant/p2p_supplicant.c
index 78bdd08..e7c1f5d 100644
--- a/contrib/wpa/wpa_supplicant/p2p_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.c
@@ -53,6 +53,13 @@
*/
#define P2P_GO_FREQ_CHANGE_TIME 5
+/**
+ * Defines CSA parameters which are used when GO evacuates the no longer valid
+ * channel (and if the driver supports channel switch).
+ */
+#define P2P_GO_CSA_COUNT 7
+#define P2P_GO_CSA_BLOCK_TX 0
+
#ifndef P2P_MAX_CLIENT_IDLE
/*
* How many seconds to try to reconnect to the GO when connection in P2P client
@@ -117,6 +124,10 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
int go);
static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
const u8 *ssid, size_t ssid_len);
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+ int *force_freq, int *pref_freq, int go,
+ unsigned int *pref_freq_list,
+ unsigned int *num_pref_freq);
static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
const u8 *ssid, size_t ssid_len);
static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
@@ -296,7 +307,14 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
return;
}
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
+ params->only_new_results = 1;
+ }
ret = wpa_drv_scan(wpa_s, params);
+ if (ret == 0)
+ wpa_s->curr_scan_cookie = params->scan_cookie;
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
@@ -309,6 +327,7 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
wpa_s->p2p_scan_work = work;
}
@@ -340,6 +359,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
int social_channels_freq[] = { 2412, 2437, 2462, 60480 };
size_t ielen;
u8 *n, i;
+ unsigned int bands;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -369,28 +389,6 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
if (wps_ie == NULL)
goto fail;
- ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
- ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
- if (ies == NULL) {
- wpabuf_free(wps_ie);
- goto fail;
- }
- wpabuf_put_buf(ies, wps_ie);
- wpabuf_free(wps_ie);
-
- p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
-
- params->p2p_probe = 1;
- n = os_malloc(wpabuf_len(ies));
- if (n == NULL) {
- wpabuf_free(ies);
- goto fail;
- }
- os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
- params->extra_ies = n;
- params->extra_ies_len = wpabuf_len(ies);
- wpabuf_free(ies);
-
switch (type) {
case P2P_SCAN_SOCIAL:
params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1,
@@ -431,6 +429,29 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
break;
}
+ ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+ ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+ if (ies == NULL) {
+ wpabuf_free(wps_ie);
+ goto fail;
+ }
+ wpabuf_put_buf(ies, wps_ie);
+ wpabuf_free(wps_ie);
+
+ bands = wpas_get_bands(wpa_s, params->freqs);
+ p2p_scan_ie(wpa_s->global->p2p, ies, dev_id, bands);
+
+ params->p2p_probe = 1;
+ n = os_malloc(wpabuf_len(ies));
+ if (n == NULL) {
+ wpabuf_free(ies);
+ goto fail;
+ }
+ os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
+ params->extra_ies = n;
+ params->extra_ies_len = wpabuf_len(ies);
+ wpabuf_free(ies);
+
radio_remove_works(wpa_s, "p2p-scan", 0);
if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb,
params) < 0)
@@ -538,27 +559,39 @@ static unsigned int p2p_group_go_member_count(struct wpa_supplicant *wpa_s)
}
+static unsigned int p2p_is_active_persistent_group(struct wpa_supplicant *wpa_s)
+{
+ return !wpa_s->p2p_mgmt && wpa_s->current_ssid &&
+ !wpa_s->current_ssid->disabled &&
+ wpa_s->current_ssid->p2p_group &&
+ wpa_s->current_ssid->p2p_persistent_group;
+}
+
+
+static unsigned int p2p_is_active_persistent_go(struct wpa_supplicant *wpa_s)
+{
+ return p2p_is_active_persistent_group(wpa_s) &&
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO;
+}
+
+
/* Find an interface for a P2P group where we are the GO */
static struct wpa_supplicant *
wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
{
struct wpa_supplicant *save = NULL;
- struct wpa_ssid *s;
if (!wpa_s)
return NULL;
for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- for (s = wpa_s->conf->ssid; s; s = s->next) {
- if (s->disabled || !s->p2p_group ||
- s->mode != WPAS_MODE_P2P_GO)
- continue;
+ if (!p2p_is_active_persistent_go(wpa_s))
+ continue;
- /* Prefer a group with connected clients */
- if (p2p_get_group_num_members(wpa_s->p2p_group))
- return wpa_s;
- save = wpa_s;
- }
+ /* Prefer a group with connected clients */
+ if (p2p_get_group_num_members(wpa_s->p2p_group))
+ return wpa_s;
+ save = wpa_s;
}
/* No group with connected clients, so pick the one without (if any) */
@@ -566,29 +599,23 @@ wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
}
-/* Find an active P2P group where we are the GO */
-static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s,
- u8 *bssid)
+static unsigned int p2p_is_active_persistent_cli(struct wpa_supplicant *wpa_s)
{
- struct wpa_ssid *s, *empty = NULL;
+ return p2p_is_active_persistent_group(wpa_s) &&
+ wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
+}
- if (!wpa_s)
- return 0;
+/* Find an interface for a P2P group where we are the P2P Client */
+static struct wpa_supplicant *
+wpas_p2p_get_cli_group(struct wpa_supplicant *wpa_s)
+{
for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- for (s = wpa_s->conf->ssid; s; s = s->next) {
- if (s->disabled || !s->p2p_group ||
- s->mode != WPAS_MODE_P2P_GO)
- continue;
-
- os_memcpy(bssid, wpa_s->own_addr, ETH_ALEN);
- if (p2p_get_group_num_members(wpa_s->p2p_group))
- return s;
- empty = s;
- }
+ if (p2p_is_active_persistent_cli(wpa_s))
+ return wpa_s;
}
- return empty;
+ return NULL;
}
@@ -607,20 +634,34 @@ wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s)
}
-static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
+static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role,
+ unsigned int *force_freq,
+ unsigned int *pref_freq)
{
- struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s;
+ struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
u8 conncap = P2PS_SETUP_NONE;
unsigned int owned_members = 0;
- unsigned int owner = 0;
- unsigned int client = 0;
- struct wpa_supplicant *go_wpa_s;
+ struct wpa_supplicant *go_wpa_s, *cli_wpa_s;
struct wpa_ssid *persistent_go;
int p2p_no_group_iface;
+ unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
+ if (force_freq)
+ *force_freq = 0;
+ if (pref_freq)
+ *pref_freq = 0;
+
+ size = P2P_MAX_PREF_CHANNELS;
+ if (force_freq && pref_freq &&
+ !wpas_p2p_setup_freqs(wpa_s, 0, (int *) force_freq,
+ (int *) pref_freq, 0, pref_freq_list, &size))
+ wpas_p2p_set_own_freq_preference(wpa_s,
+ *force_freq ? *force_freq :
+ *pref_freq);
+
/*
* For non-concurrent capable devices:
* If persistent_go, then no new.
@@ -628,36 +669,21 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
* If client, then no GO.
*/
go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+ if (go_wpa_s)
+ owned_members = p2p_get_group_num_members(go_wpa_s->p2p_group);
persistent_go = wpas_p2p_get_persistent_go(wpa_s);
p2p_no_group_iface = !wpas_p2p_create_iface(wpa_s);
+ cli_wpa_s = wpas_p2p_get_cli_group(wpa_s);
- wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p",
- go_wpa_s, persistent_go);
-
- for (tmp_wpa_s = wpa_s->global->ifaces; tmp_wpa_s;
- tmp_wpa_s = tmp_wpa_s->next) {
- for (s = tmp_wpa_s->conf->ssid; s; s = s->next) {
- wpa_printf(MSG_DEBUG,
- "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
- tmp_wpa_s, s, s->disabled,
- s->p2p_group, s->mode);
- if (!s->disabled && s->p2p_group) {
- if (s->mode == WPAS_MODE_P2P_GO) {
- owned_members +=
- p2p_get_group_num_members(
- tmp_wpa_s->p2p_group);
- owner++;
- } else
- client++;
- }
- }
- }
+ wpa_printf(MSG_DEBUG,
+ "P2P: GO(iface)=%p members=%u CLI(iface)=%p persistent(ssid)=%p",
+ go_wpa_s, owned_members, cli_wpa_s, persistent_go);
/* If not concurrent, restrict our choices */
if (p2p_no_group_iface) {
wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface");
- if (client)
+ if (cli_wpa_s)
return P2PS_SETUP_NONE;
if (go_wpa_s) {
@@ -689,10 +715,20 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
/* If a required role has been specified, handle it here */
if (role && role != P2PS_SETUP_NEW) {
switch (incoming) {
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+ /*
+ * Peer has an active GO, so if the role allows it and
+ * we do not have any active roles, become client.
+ */
+ if ((role & P2PS_SETUP_CLIENT) && !go_wpa_s &&
+ !cli_wpa_s)
+ return P2PS_SETUP_CLIENT;
+
+ /* fall through */
+
case P2PS_SETUP_NONE:
case P2PS_SETUP_NEW:
- case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
- case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
conncap = role;
goto grp_owner;
@@ -701,7 +737,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
* Must be a complimentary role - cannot be a client to
* more than one peer.
*/
- if (incoming == role || client)
+ if (incoming == role || cli_wpa_s)
return P2PS_SETUP_NONE;
return P2PS_SETUP_CLIENT;
@@ -712,6 +748,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
conncap = P2PS_SETUP_GROUP_OWNER;
goto grp_owner;
}
+ /* fall through */
default:
return P2PS_SETUP_NONE;
@@ -727,7 +764,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
switch (incoming) {
case P2PS_SETUP_NONE:
case P2PS_SETUP_NEW:
- if (client)
+ if (cli_wpa_s)
conncap = P2PS_SETUP_GROUP_OWNER;
else if (!owned_members)
conncap = P2PS_SETUP_NEW;
@@ -742,13 +779,13 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
break;
case P2PS_SETUP_GROUP_OWNER:
- if (!client)
+ if (!cli_wpa_s)
conncap = P2PS_SETUP_CLIENT;
break;
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
- if (client)
+ if (cli_wpa_s)
conncap = P2PS_SETUP_GROUP_OWNER;
else {
u8 r;
@@ -770,17 +807,16 @@ grp_owner:
(!incoming && (conncap & P2PS_SETUP_NEW))) {
if (go_wpa_s && p2p_client_limit_reached(go_wpa_s->p2p_group))
conncap &= ~P2PS_SETUP_GROUP_OWNER;
- wpa_printf(MSG_DEBUG, "P2P: GOs:%d members:%d conncap:%d",
- owner, owned_members, conncap);
s = wpas_p2p_get_persistent_go(wpa_s);
-
- if (!s && !owner && p2p_no_group_iface) {
+ if (!s && !go_wpa_s && p2p_no_group_iface) {
p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->p2p_mgmt ?
+ wpa_s->parent->own_addr :
wpa_s->own_addr);
- } else if (!s && !owner) {
+ } else if (!s && !go_wpa_s) {
if (wpas_p2p_add_group_interface(wpa_s,
- WPA_IF_P2P_GO) < 0) {
+ WPA_IF_P2P_GROUP) < 0) {
wpa_printf(MSG_ERROR,
"P2P: Failed to allocate a new interface for the group");
return P2PS_SETUP_NONE;
@@ -850,7 +886,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
if (wpa_s->cross_connect_in_use) {
wpa_s->cross_connect_in_use = 0;
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
wpa_s->ifname, wpa_s->cross_connect_uplink);
}
@@ -881,7 +917,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
break;
}
if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_REMOVED "%s %s%s",
wpa_s->ifname, gtype, reason);
}
@@ -891,7 +927,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL) > 0) {
+ wpa_s->p2pdev, NULL) > 0) {
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
"timeout");
wpa_s->p2p_in_provisioning = 0;
@@ -926,6 +962,12 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
return 1;
}
+ /*
+ * The primary interface was used for P2P group operations, so
+ * need to reset its p2pdev.
+ */
+ wpa_s->p2pdev = wpa_s->parent;
+
if (!wpa_s->p2p_go_group_formation_completed) {
wpa_s->global->p2p_group_formation = NULL;
wpa_s->p2p_in_provisioning = 0;
@@ -938,6 +980,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
os_free(wpa_s->p2p_group_common_freqs);
wpa_s->p2p_group_common_freqs = NULL;
wpa_s->p2p_group_common_freqs_num = 0;
+ wpa_s->p2p_go_do_acs = 0;
wpa_s->waiting_presence_resp = 0;
@@ -1043,7 +1086,7 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
"go_dev_addr=" MACSTR,
MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
- return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ return !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP);
}
@@ -1101,7 +1144,8 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
s->auth_alg = WPA_AUTH_ALG_OPEN;
s->key_mgmt = WPA_KEY_MGMT_PSK;
s->proto = WPA_PROTO_RSN;
- s->pairwise_cipher = WPA_CIPHER_CCMP;
+ s->pbss = ssid->pbss;
+ s->pairwise_cipher = ssid->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
s->export_keys = 1;
if (ssid->passphrase) {
os_free(s->passphrase);
@@ -1241,7 +1285,7 @@ static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s,
* Include PSK/passphrase only in the control interface message and
* leave it out from the debug log entry.
*/
- wpa_msg_global_ctrl(wpa_s->parent, MSG_INFO,
+ wpa_msg_global_ctrl(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_STARTED
"%s %s ssid=\"%s\" freq=%d%s%s%s%s%s go_dev_addr="
MACSTR "%s%s",
@@ -1267,7 +1311,6 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
int client;
int persistent;
u8 go_dev_addr[ETH_ALEN];
- int network_id = -1;
/*
* This callback is likely called for the main interface. Update wpa_s
@@ -1279,12 +1322,16 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
if (wpa_s->p2p_go_group_formation_completed) {
wpa_s->global->p2p_group_formation = NULL;
wpa_s->p2p_in_provisioning = 0;
+ } else if (wpa_s->p2p_in_provisioning && !success) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "P2P: Stop provisioning state due to failure");
+ wpa_s->p2p_in_provisioning = 0;
}
wpa_s->p2p_in_invitation = 0;
wpa_s->group_formation_reported = 1;
if (!success) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
wpas_notify_p2p_group_formation_failure(wpa_s, "");
if (already_deleted)
@@ -1294,7 +1341,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
return;
}
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_SUCCESS);
ssid = wpa_s->current_ssid;
@@ -1342,16 +1389,15 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
}
if (persistent)
- network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
- ssid, go_dev_addr);
+ wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+ ssid, go_dev_addr);
else {
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
}
- if (network_id < 0 && ssid)
- network_id = ssid->id;
+
if (!client) {
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0, NULL);
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
}
}
@@ -1368,6 +1414,25 @@ struct send_action_work {
};
+static void wpas_p2p_free_send_action_work(struct wpa_supplicant *wpa_s)
+{
+ struct send_action_work *awork = wpa_s->p2p_send_action_work->ctx;
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Free Action frame radio work @%p (freq=%u dst="
+ MACSTR " src=" MACSTR " bssid=" MACSTR " wait_time=%u)",
+ wpa_s->p2p_send_action_work, awork->freq,
+ MAC2STR(awork->dst), MAC2STR(awork->src),
+ MAC2STR(awork->bssid), awork->wait_time);
+ wpa_hexdump(MSG_DEBUG, "P2P: Freeing pending Action frame",
+ awork->buf, awork->len);
+ os_free(awork);
+ wpa_s->p2p_send_action_work->ctx = NULL;
+ radio_work_done(wpa_s->p2p_send_action_work);
+ wpa_s->p2p_send_action_work = NULL;
+}
+
+
static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
void *timeout_ctx)
{
@@ -1377,9 +1442,7 @@ static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
return;
wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out");
- os_free(wpa_s->p2p_send_action_work->ctx);
- radio_work_done(wpa_s->p2p_send_action_work);
- wpa_s->p2p_send_action_work = NULL;
+ wpas_p2p_free_send_action_work(wpa_s);
}
@@ -1387,11 +1450,13 @@ static void wpas_p2p_action_tx_clear(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_send_action_work) {
struct send_action_work *awork;
+
awork = wpa_s->p2p_send_action_work->ctx;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Clear Action TX work @%p (wait_time=%u)",
+ wpa_s->p2p_send_action_work, awork->wait_time);
if (awork->wait_time == 0) {
- os_free(awork);
- radio_work_done(wpa_s->p2p_send_action_work);
- wpa_s->p2p_send_action_work = NULL;
+ wpas_p2p_free_send_action_work(wpa_s);
} else {
/*
* In theory, this should not be needed, but number of
@@ -1447,7 +1512,7 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
wpa_s->pending_pd_before_join = 0;
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
"during p2p_connect-auto");
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_FALLBACK_TO_GO_NEG
"reason=no-ACK-to-PD-Req");
wpas_p2p_fallback_to_go_neg(wpa_s, 0);
@@ -1520,20 +1585,27 @@ static int wpas_send_action_work(struct wpa_supplicant *wpa_s,
static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
- size_t len, unsigned int wait_time)
+ size_t len, unsigned int wait_time, int *scheduled)
{
struct wpa_supplicant *wpa_s = ctx;
int listen_freq = -1, send_freq = -1;
+ if (scheduled)
+ *scheduled = 0;
if (wpa_s->p2p_listen_work)
listen_freq = wpa_s->p2p_listen_work->freq;
if (wpa_s->p2p_send_action_work)
send_freq = wpa_s->p2p_send_action_work->freq;
if (listen_freq != (int) freq && send_freq != (int) freq) {
- wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)",
- listen_freq, send_freq);
- return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
- len, wait_time);
+ int res;
+
+ wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d freq=%u)",
+ listen_freq, send_freq, freq);
+ res = wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
+ len, wait_time);
+ if (res == 0 && scheduled)
+ *scheduled = 1;
+ return res;
}
wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX");
@@ -1585,16 +1657,16 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
wpa_supplicant_ap_deinit(wpa_s);
wpas_copy_go_neg_results(wpa_s, res);
if (res->wps_method == WPS_PBC) {
- wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
+ wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1, 0);
#ifdef CONFIG_WPS_NFC
} else if (res->wps_method == WPS_NFC) {
wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
res->peer_interface_addr,
- wpa_s->parent->p2p_oob_dev_pw,
- wpa_s->parent->p2p_oob_dev_pw_id, 1,
- wpa_s->parent->p2p_oob_dev_pw_id ==
+ wpa_s->p2pdev->p2p_oob_dev_pw,
+ wpa_s->p2pdev->p2p_oob_dev_pw_id, 1,
+ wpa_s->p2pdev->p2p_oob_dev_pw_id ==
DEV_PW_NFC_CONNECTION_HANDOVER ?
- wpa_s->parent->p2p_peer_oob_pubkey_hash :
+ wpa_s->p2pdev->p2p_peer_oob_pubkey_hash :
NULL,
NULL, 0, 0);
#endif /* CONFIG_WPS_NFC */
@@ -1620,7 +1692,7 @@ static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s,
if (!wpa_s->ap_iface)
return;
- persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+ persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, NULL, ssid->ssid,
ssid->ssid_len);
if (persistent == NULL)
return;
@@ -1650,14 +1722,23 @@ static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s,
static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s)
{
+ char buf[20 + P2P_MAX_CHANNELS * 6];
+ char *pos, *end;
unsigned int i;
+ int res;
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):",
- wpa_s->p2p_group_common_freqs_num);
+ pos = buf;
+ end = pos + sizeof(buf);
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ res = os_snprintf(pos, end - pos, " %d",
+ wpa_s->p2p_group_common_freqs[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
- for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++)
- wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d",
- i, wpa_s->p2p_group_common_freqs[i]);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies:%s", buf);
}
@@ -1685,8 +1766,8 @@ static void p2p_go_save_group_common_freqs(struct wpa_supplicant *wpa_s,
static void p2p_config_write(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_CONFIG_WRITE
- if (wpa_s->parent->conf->update_config &&
- wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ if (wpa_s->p2pdev->conf->update_config &&
+ wpa_config_write(wpa_s->p2pdev->confname, wpa_s->p2pdev->conf))
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
#endif /* CONFIG_NO_CONFIG_WRITE */
}
@@ -1697,7 +1778,15 @@ static void p2p_go_configured(void *ctx, void *data)
struct wpa_supplicant *wpa_s = ctx;
struct p2p_go_neg_results *params = data;
struct wpa_ssid *ssid;
- int network_id = -1;
+
+ wpa_s->ap_configured_cb = NULL;
+ wpa_s->ap_configured_cb_ctx = NULL;
+ wpa_s->ap_configured_cb_data = NULL;
+ if (!wpa_s->go_params) {
+ wpa_printf(MSG_ERROR,
+ "P2P: p2p_go_configured() called with wpa_s->go_params == NULL");
+ return;
+ }
p2p_go_save_group_common_freqs(wpa_s, params);
p2p_go_dump_common_freqs(wpa_s);
@@ -1715,8 +1804,8 @@ static void p2p_go_configured(void *ctx, void *data)
params->persistent_group, "");
wpa_s->group_formation_reported = 1;
- if (wpa_s->parent->p2ps_method_config_any) {
- if (is_zero_ether_addr(wpa_s->parent->p2ps_join_addr)) {
+ if (wpa_s->p2pdev->p2ps_method_config_any) {
+ if (is_zero_ether_addr(wpa_s->p2pdev->p2ps_join_addr)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2PS: Setting default PIN for ANY");
wpa_supplicant_ap_wps_pin(wpa_s, NULL,
@@ -1725,24 +1814,25 @@ static void p2p_go_configured(void *ctx, void *data)
} else {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2PS: Setting default PIN for " MACSTR,
- MAC2STR(wpa_s->parent->p2ps_join_addr));
+ MAC2STR(wpa_s->p2pdev->p2ps_join_addr));
wpa_supplicant_ap_wps_pin(
- wpa_s, wpa_s->parent->p2ps_join_addr,
+ wpa_s, wpa_s->p2pdev->p2ps_join_addr,
"12345670", NULL, 0, 0);
}
- wpa_s->parent->p2ps_method_config_any = 0;
+ wpa_s->p2pdev->p2ps_method_config_any = 0;
}
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
if (params->persistent_group) {
- network_id = wpas_p2p_store_persistent_group(
- wpa_s->parent, ssid,
+ wpas_p2p_store_persistent_group(
+ wpa_s->p2pdev, ssid,
wpa_s->global->p2p_dev_addr);
wpas_p2p_add_psk_list(wpa_s, ssid);
}
- if (network_id < 0)
- network_id = ssid->id;
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+
+ wpas_notify_p2p_group_started(wpa_s, ssid,
+ params->persistent_group, 0,
+ NULL);
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
@@ -1753,11 +1843,11 @@ static void p2p_go_configured(void *ctx, void *data)
wpa_s->p2p_go_group_formation_completed = 0;
wpa_s->global->p2p_group_formation = wpa_s;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
eloop_register_timeout(
wpa_s->p2p_first_connection_timeout, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
return;
@@ -1775,17 +1865,17 @@ static void p2p_go_configured(void *ctx, void *data)
params->peer_device_addr);
#ifdef CONFIG_WPS_NFC
} else if (params->wps_method == WPS_NFC) {
- if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ if (wpa_s->p2pdev->p2p_oob_dev_pw_id !=
DEV_PW_NFC_CONNECTION_HANDOVER &&
- !wpa_s->parent->p2p_oob_dev_pw) {
+ !wpa_s->p2pdev->p2p_oob_dev_pw) {
wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
return;
}
wpas_ap_wps_add_nfc_pw(
- wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
- wpa_s->parent->p2p_oob_dev_pw,
- wpa_s->parent->p2p_peer_oob_pk_hash_known ?
- wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+ wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id,
+ wpa_s->p2pdev->p2p_oob_dev_pw,
+ wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ?
+ wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL);
#endif /* CONFIG_WPS_NFC */
} else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
@@ -1822,12 +1912,15 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->p2p_group = 1;
- ssid->p2p_persistent_group = params->persistent_group;
+ ssid->p2p_persistent_group = !!params->persistent_group;
ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
ssid->ht40 = params->ht40;
ssid->vht = params->vht;
+ ssid->max_oper_chwidth = params->max_oper_chwidth;
+ ssid->vht_center_freq2 = params->vht_center_freq2;
+ ssid->he = params->he;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -1845,6 +1938,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
*/
ssid->pairwise_cipher = WPA_CIPHER_GCMP;
ssid->group_cipher = WPA_CIPHER_GCMP;
+ /* P2P GO in 60 GHz is always a PCP (PBSS) */
+ ssid->pbss = 1;
}
if (os_strlen(params->passphrase) > 0) {
ssid->passphrase = os_strdup(params->passphrase);
@@ -1861,7 +1956,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
else if (ssid->passphrase)
wpa_config_update_psk(ssid);
- ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
+ ssid->ap_max_inactivity = wpa_s->p2pdev->conf->p2p_go_max_inactivity;
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
@@ -1885,7 +1980,12 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
d = dst->conf;
s = src->conf;
-#define C(n) if (s->n) d->n = os_strdup(s->n)
+#define C(n) \
+do { \
+ if (s->n && !d->n) \
+ d->n = os_strdup(s->n); \
+} while (0)
+
C(device_name);
C(manufacturer);
C(model_name);
@@ -1913,11 +2013,19 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
d->disable_scan_offload = s->disable_scan_offload;
d->passive_scan = s->passive_scan;
- if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
+ if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
+ !d->wps_nfc_pw_from_config) {
+ wpabuf_free(d->wps_nfc_dh_privkey);
+ wpabuf_free(d->wps_nfc_dh_pubkey);
d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
}
d->p2p_cli_probe = s->p2p_cli_probe;
+ d->go_interworking = s->go_interworking;
+ d->go_access_network_type = s->go_access_network_type;
+ d->go_internet = s->go_internet;
+ d->go_venue_group = s->go_venue_group;
+ d->go_venue_type = s->go_venue_type;
}
@@ -1976,6 +2084,13 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
return -1;
}
+ if (wpa_s->conf->p2p_interface_random_mac_addr) {
+ random_mac_addr(wpa_s->pending_interface_addr);
+ wpa_printf(MSG_DEBUG, "P2P: Generate random MAC address " MACSTR
+ " for the group",
+ MAC2STR(wpa_s->pending_interface_addr));
+ }
+
if (force_ifname[0]) {
wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s",
force_ifname);
@@ -2054,6 +2169,29 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
wpas_p2p_clone_config(group_wpa_s, wpa_s);
+ if (wpa_s->conf->p2p_interface_random_mac_addr) {
+ if (wpa_drv_set_mac_addr(group_wpa_s,
+ wpa_s->pending_interface_addr) < 0) {
+ wpa_msg(group_wpa_s, MSG_INFO,
+ "Failed to set random MAC address");
+ wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s,
+ 0);
+ return NULL;
+ }
+
+ if (wpa_supplicant_update_mac_addr(group_wpa_s) < 0) {
+ wpa_msg(group_wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s,
+ 0);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Using random MAC address " MACSTR
+ " for the group",
+ MAC2STR(wpa_s->pending_interface_addr));
+ }
+
return group_wpa_s;
}
@@ -2071,7 +2209,7 @@ static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
int already_deleted)
{
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
if (wpa_s->global->p2p)
p2p_group_formation_failed(wpa_s->global->p2p);
wpas_group_formation_completed(wpa_s, 0, already_deleted);
@@ -2082,9 +2220,9 @@ static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure");
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
wpa_s->global->p2p_fail_on_wps_complete = 0;
}
@@ -2095,15 +2233,16 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
return;
/* Speed up group formation timeout since this cannot succeed */
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *group_wpa_s;
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_drv_cancel_remain_on_channel(wpa_s);
@@ -2129,6 +2268,8 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
res->ht40 = 1;
if (wpa_s->p2p_go_vht)
res->vht = 1;
+ res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
+ res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
"freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
@@ -2154,7 +2295,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
}
if (wpa_s->create_p2p_iface) {
- struct wpa_supplicant *group_wpa_s =
+ group_wpa_s =
wpas_p2p_init_group_interface(wpa_s, res->role_go);
if (group_wpa_s == NULL) {
wpas_p2p_remove_pending_group_interface(wpa_s);
@@ -2163,31 +2304,27 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpas_p2p_group_formation_failed(wpa_s, 1);
return;
}
- if (group_wpa_s != wpa_s) {
- os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
- sizeof(group_wpa_s->p2p_pin));
- group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
- }
os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
wpa_s->pending_interface_name[0] = '\0';
- group_wpa_s->p2p_in_provisioning = 1;
-
- if (res->role_go) {
- wpas_start_wps_go(group_wpa_s, res, 1);
- } else {
- os_get_reltime(&group_wpa_s->scan_min_time);
- wpas_start_wps_enrollee(group_wpa_s, res);
- }
} else {
- wpa_s->p2p_in_provisioning = 1;
- wpa_s->global->p2p_group_formation = wpa_s;
+ group_wpa_s = wpa_s->parent;
+ wpa_s->global->p2p_group_formation = group_wpa_s;
+ if (group_wpa_s != wpa_s)
+ wpas_p2p_clone_config(group_wpa_s, wpa_s);
+ }
- if (res->role_go) {
- wpas_start_wps_go(wpa_s, res, 1);
- } else {
- os_get_reltime(&wpa_s->scan_min_time);
- wpas_start_wps_enrollee(ctx, res);
- }
+ group_wpa_s->p2p_in_provisioning = 1;
+ group_wpa_s->p2pdev = wpa_s;
+ if (group_wpa_s != wpa_s) {
+ os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
+ sizeof(group_wpa_s->p2p_pin));
+ group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
+ }
+ if (res->role_go) {
+ wpas_start_wps_go(group_wpa_s, res, 1);
+ } else {
+ os_get_reltime(&group_wpa_s->scan_min_time);
+ wpas_start_wps_enrollee(group_wpa_s, res);
}
wpa_s->p2p_long_listen = 0;
@@ -2308,6 +2445,10 @@ static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
static void wpas_find_stopped(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
+
+ if (wpa_s->p2p_scan_work && wpas_abort_ongoing_scan(wpa_s) < 0)
+ wpa_printf(MSG_DEBUG, "P2P: Abort ongoing scan failed");
+
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
wpas_notify_p2p_find_stopped(wpa_s);
}
@@ -2521,7 +2662,13 @@ static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
params[sizeof(params) - 1] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY) {
- generated_pin = wps_generate_pin();
+ if (wps_generate_pin(&generated_pin) < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN");
+ wpas_notify_p2p_provision_discovery(
+ wpa_s, peer, 0 /* response */,
+ P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0);
+ return;
+ }
wpas_prov_disc_local_display(wpa_s, peer, params,
generated_pin);
} else if (config_methods & WPS_CONFIG_KEYPAD)
@@ -2566,7 +2713,13 @@ static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
if (config_methods & WPS_CONFIG_DISPLAY)
wpas_prov_disc_local_keypad(wpa_s, peer, params);
else if (config_methods & WPS_CONFIG_KEYPAD) {
- generated_pin = wps_generate_pin();
+ if (wps_generate_pin(&generated_pin) < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not generate PIN");
+ wpas_notify_p2p_provision_discovery(
+ wpa_s, peer, 0 /* response */,
+ P2P_PROV_DISC_INFO_UNAVAILABLE, 0, 0);
+ return;
+ }
wpas_prov_disc_local_display(wpa_s, peer, params,
generated_pin);
} else if (config_methods & WPS_CONFIG_PUSHBUTTON)
@@ -2589,7 +2742,7 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
if (wpa_s->p2p_fallback_to_go_neg) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
"failed - fall back to GO Negotiation");
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_FALLBACK_TO_GO_NEG
"reason=PD-failed");
wpas_p2p_fallback_to_go_neg(wpa_s, 0);
@@ -2685,6 +2838,29 @@ static int wpas_p2p_go_is_peer_freq(struct wpa_supplicant *wpa_s, int freq)
}
+static int wpas_sta_check_ecsa(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ int *ecsa_support = ctx;
+
+ *ecsa_support &= sta->ecsa_supported;
+
+ return 0;
+}
+
+
+/* Check if all the peers support eCSA */
+static int wpas_p2p_go_clients_support_ecsa(struct wpa_supplicant *wpa_s)
+{
+ int ecsa_support = 1;
+
+ ap_for_each_sta(wpa_s->ap_iface->bss[0], wpas_sta_check_ecsa,
+ &ecsa_support);
+
+ return ecsa_support;
+}
+
+
/**
* Pick the best frequency to use from all the currently used frequencies.
*/
@@ -2811,7 +2987,11 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
"invitation");
return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
}
- os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
+ if (wpa_s->p2p_mgmt)
+ os_memcpy(group_bssid, wpa_s->parent->own_addr,
+ ETH_ALEN);
+ else
+ os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
} else if (s->mode == WPAS_MODE_P2P_GO) {
*go = 1;
if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0)
@@ -2893,12 +3073,31 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
+ if (go) {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR
+ " persistent=%d freq=%d",
+ MAC2STR(sa), s->id, op_freq);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR
+ " persistent=%d",
+ MAC2STR(sa), s->id);
+ }
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR " go_dev_addr=" MACSTR
+ " bssid=" MACSTR " unknown-network",
+ MAC2STR(sa), MAC2STR(go_dev_addr),
+ MAC2STR(bssid));
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method, 0, op_freq,
ssid, ssid_len);
@@ -2999,7 +3198,7 @@ static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
!ssid->p2p_persistent_group)
return; /* Not operating as a GO in persistent group */
- ssid = wpas_p2p_get_persistent(wpa_s->parent, peer,
+ ssid = wpas_p2p_get_persistent(wpa_s->p2pdev, peer,
ssid->ssid, ssid->ssid_len);
wpas_remove_persistent_peer(wpa_s, ssid, peer, 1);
}
@@ -3027,9 +3226,37 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
status, MAC2STR(peer));
if (wpa_s->pending_invite_ssid_id == -1) {
+ struct wpa_supplicant *group_if =
+ wpa_s->global->p2p_invite_group;
+
if (status == P2P_SC_FAIL_UNKNOWN_GROUP)
wpas_remove_persistent_client(wpa_s, peer);
- return; /* Invitation to active group */
+
+ /*
+ * Invitation to an active group. If this is successful and we
+ * are the GO, set the client wait to postpone some concurrent
+ * operations and to allow provisioning and connection to happen
+ * more quickly.
+ */
+ if (status == P2P_SC_SUCCESS &&
+ group_if && group_if->current_ssid &&
+ group_if->current_ssid->mode == WPAS_MODE_P2P_GO) {
+ os_get_reltime(&wpa_s->global->p2p_go_wait_client);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (group_if->p2p_go_csa_on_inv) {
+ wpa_printf(MSG_DEBUG,
+ "Testing: force P2P GO CSA after invitation");
+ eloop_cancel_timeout(
+ wpas_p2p_reconsider_moving_go,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 0, 50000,
+ wpas_p2p_reconsider_moving_go,
+ wpa_s, NULL);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ }
+ return;
}
if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
@@ -3083,7 +3310,10 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
ssid->mode == WPAS_MODE_P2P_GO,
wpa_s->p2p_persistent_go_freq,
freq,
+ wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
+ wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
@@ -3169,25 +3399,6 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
}
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes,
- enum hostapd_hw_mode mode)
-{
- u16 i;
-
- for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
- return &modes[i];
- }
-
- return NULL;
-}
-
-
-enum chan_allowed {
- NOT_ALLOWED, NO_IR, ALLOWED
-};
-
static int has_channel(struct wpa_global *global,
struct hostapd_hw_modes *mode, u8 chan, int *flags)
{
@@ -3217,49 +3428,12 @@ static int has_channel(struct wpa_global *global,
}
-struct p2p_oper_class_map {
- enum hostapd_hw_mode mode;
- u8 op_class;
- u8 min_chan;
- u8 max_chan;
- u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160 } bw;
-};
-
-static const struct p2p_oper_class_map op_class[] = {
- { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
-#if 0 /* Do not enable HT40 on 2 GHz for now */
- { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
-#endif
- { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
- { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
-
- /*
- * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
- * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
- * 80 MHz, but currently use the following definition for simplicity
- * (these center frequencies are not actual channels, which makes
- * has_channel() fail). wpas_p2p_verify_80mhz() should take care of
- * removing invalid channels.
- */
- { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
- { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160 },
- { -1, 0, 0, 0, 0, BW20 }
-};
-
-
static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel)
{
u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
- unsigned int i;
+ size_t i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
@@ -3315,6 +3489,75 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
}
+static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ u8 center_channels[] = { 50, 114 };
+ unsigned int i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+ /*
+ * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
+ * so the center channel is 14 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 14 &&
+ channel <= center_channels[i] + 14)
+ return center_channels[i];
+
+ return 0;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel, u8 bw)
+{
+ u8 center_chan;
+ int i, flags;
+ enum chan_allowed res, ret = ALLOWED;
+
+ center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+ /* VHT 160 MHz uses DFS channels in most countries. */
+
+ /* Check all the channels are available */
+ for (i = 0; i < 8; i++) {
+ int adj_chan = center_chan - 14 + i * 4;
+
+ res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+ if (res == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if (res == NO_IR)
+ ret = NO_IR;
+
+ if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150))
+ return NOT_ALLOWED;
+ if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130))
+ return NOT_ALLOWED;
+ if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110))
+ return NOT_ALLOWED;
+ if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90))
+ return NOT_ALLOWED;
+ if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70))
+ return NOT_ALLOWED;
+ if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50))
+ return NOT_ALLOWED;
+ if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30))
+ return NOT_ALLOWED;
+ if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))
+ return NOT_ALLOWED;
+ }
+
+ return ret;
+}
+
+
static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel, u8 bw)
@@ -3333,6 +3576,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
} else if (bw == BW80) {
res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+ } else if (bw == BW160) {
+ res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3359,11 +3604,14 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
cla = cli_cla = 0;
- for (op = 0; op_class[op].op_class; op++) {
- const struct p2p_oper_class_map *o = &op_class[op];
+ for (op = 0; global_op_class[op].op_class; op++) {
+ const struct oper_class_map *o = &global_op_class[op];
u8 ch;
struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
+ if (o->p2p == NO_P2P_SUPP)
+ continue;
+
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
if (mode == NULL)
continue;
@@ -3418,10 +3666,13 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
int op;
enum chan_allowed ret;
- for (op = 0; op_class[op].op_class; op++) {
- const struct p2p_oper_class_map *o = &op_class[op];
+ for (op = 0; global_op_class[op].op_class; op++) {
+ const struct oper_class_map *o = &global_op_class[op];
u8 ch;
+ if (o->p2p == NO_P2P_SUPP)
+ continue;
+
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
if (o->mode != HOSTAPD_MODE_IEEE80211A ||
(o->bw != BW40PLUS && o->bw != BW40MINUS) ||
@@ -3446,6 +3697,15 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
}
+int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel)
+{
+ if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160))
+ return 0;
+ return wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+}
+
+
static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
size_t buf_len)
{
@@ -3577,6 +3837,7 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
return -1;
}
+ p2pdev_wpa_s->p2pdev = p2pdev_wpa_s;
wpa_s->pending_interface_name[0] = '\0';
return 0;
}
@@ -3638,11 +3899,12 @@ static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
static int wpas_get_go_info(void *ctx, u8 *intended_addr,
- u8 *ssid, size_t *ssid_len, int *group_iface)
+ u8 *ssid, size_t *ssid_len, int *group_iface,
+ unsigned int *freq)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *go;
struct wpa_ssid *s;
- u8 bssid[ETH_ALEN];
/*
* group_iface will be set to 1 only if a dedicated interface for P2P
@@ -3652,17 +3914,25 @@ static int wpas_get_go_info(void *ctx, u8 *intended_addr,
* that the pending interface should be used.
*/
*group_iface = 0;
- s = wpas_p2p_group_go_ssid(wpa_s, bssid);
- if (!s) {
+
+ if (freq)
+ *freq = 0;
+
+ go = wpas_p2p_get_go_group(wpa_s);
+ if (!go) {
s = wpas_p2p_get_persistent_go(wpa_s);
*group_iface = wpas_p2p_create_iface(wpa_s);
if (s)
- os_memcpy(bssid, s->bssid, ETH_ALEN);
+ os_memcpy(intended_addr, s->bssid, ETH_ALEN);
else
return 0;
+ } else {
+ s = go->current_ssid;
+ os_memcpy(intended_addr, go->own_addr, ETH_ALEN);
+ if (freq)
+ *freq = go->assoc_freq;
}
- os_memcpy(intended_addr, bssid, ETH_ALEN);
os_memcpy(ssid, s->ssid, s->ssid_len);
*ssid_len = s->ssid_len;
@@ -3688,6 +3958,10 @@ static int wpas_remove_stale_groups(void *ctx, const u8 *peer, const u8 *go,
/* Remove stale persistent group */
if (s->mode != WPAS_MODE_P2P_GO || s->num_p2p_clients <= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove stale persistent group id=%d",
+ s->id);
+ wpas_notify_persistent_group_removed(wpa_s, s);
wpa_config_remove_network(wpa_s->conf, s->id);
save_config = 1;
continue;
@@ -3750,11 +4024,13 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
const u8 *persist_ssid,
size_t persist_ssid_size, int response_done,
int prov_start, const char *session_info,
- const u8 *feat_cap, size_t feat_cap_len)
+ const u8 *feat_cap, size_t feat_cap_len,
+ unsigned int freq,
+ const u8 *group_ssid, size_t group_ssid_len)
{
struct wpa_supplicant *wpa_s = ctx;
u8 mac[ETH_ALEN];
- struct wpa_ssid *persistent_go, *stale, *s;
+ struct wpa_ssid *persistent_go, *stale, *s = NULL;
int save_config = 0;
struct wpa_supplicant *go_wpa_s;
char feat_cap_str[256];
@@ -3809,6 +4085,11 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
if (persistent_go && !persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s,
+ persistent_go);
wpa_config_remove_network(wpa_s->conf,
persistent_go->id);
}
@@ -3825,8 +4106,9 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
}
/* Clean up stale persistent groups with this device */
- s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
- persist_ssid_size);
+ if (persist_ssid && persist_ssid_size)
+ s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
+ persist_ssid_size);
if (persist_ssid && s && s->mode != WPAS_MODE_P2P_GO &&
is_zero_ether_addr(grp_mac)) {
@@ -3848,6 +4130,10 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
/* Remove stale persistent group */
if (stale->mode != WPAS_MODE_P2P_GO ||
stale->num_p2p_clients <= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove stale persistent group id=%d",
+ stale->id);
+ wpas_notify_persistent_group_removed(wpa_s, stale);
wpa_config_remove_network(wpa_s->conf, stale->id);
} else {
size_t i;
@@ -3880,6 +4166,11 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
if (persistent_go && s != persistent_go &&
!persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s,
+ persistent_go);
wpa_config_remove_network(wpa_s->conf,
persistent_go->id);
/* Save config */
@@ -3897,6 +4188,9 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
return;
}
+ wpa_s->global->pending_p2ps_group = 0;
+ wpa_s->global->pending_p2ps_group_freq = 0;
+
if (conncap == P2PS_SETUP_GROUP_OWNER) {
/*
* We need to copy the interface name. Simply saving a
@@ -3907,7 +4201,10 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
go_ifname[0] = '\0';
if (!go_wpa_s) {
- wpa_s->global->pending_p2ps_group = 1;
+ if (!response_done) {
+ wpa_s->global->pending_p2ps_group = 1;
+ wpa_s->global->pending_p2ps_group_freq = freq;
+ }
if (!wpas_p2p_create_iface(wpa_s))
os_memcpy(go_ifname, wpa_s->ifname,
@@ -3922,7 +4219,8 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
wpa_s, P2P_SC_FAIL_UNKNOWN_GROUP,
dev, adv_mac, ses_mac,
grp_mac, adv_id, ses_id, 0, 0,
- NULL, 0, 0, 0, NULL, NULL, 0);
+ NULL, 0, 0, 0, NULL, NULL, 0, 0,
+ NULL, 0);
return;
}
@@ -3930,13 +4228,14 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 0, 0, 0, 0, NULL,
persistent_go->mode ==
WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
0, 0);
} else if (response_done) {
- wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq,
+ 0, 0, 0, 0, 0);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -3985,20 +4284,32 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
if (persistent_go && !persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s, persistent_go);
wpa_config_remove_network(wpa_s->conf, persistent_go->id);
}
if (conncap == P2PS_SETUP_CLIENT) {
+ char ssid_hex[32 * 2 + 1];
+
+ if (group_ssid)
+ wpa_snprintf_hex(ssid_hex, sizeof(ssid_hex),
+ group_ssid, group_ssid_len);
+ else
+ ssid_hex[0] = '\0';
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_P2PS_PROVISION_DONE MACSTR
" status=%d conncap=%x"
" adv_id=%x adv_mac=" MACSTR
" session=%x mac=" MACSTR
- " dev_passwd_id=%d join=" MACSTR "%s",
+ " dev_passwd_id=%d join=" MACSTR "%s%s%s",
MAC2STR(dev), status, conncap,
adv_id, MAC2STR(adv_mac),
ses_id, MAC2STR(ses_mac),
- passwd_id, MAC2STR(grp_mac), feat_cap_str);
+ passwd_id, MAC2STR(grp_mac), feat_cap_str,
+ group_ssid ? " group_ssid=" : "", ssid_hex);
} else {
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_P2PS_PROVISION_DONE MACSTR
@@ -4025,10 +4336,13 @@ static int wpas_prov_disc_resp_cb(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *persistent_go;
+ unsigned int freq;
if (!wpa_s->global->pending_p2ps_group)
return 0;
+ freq = wpa_s->global->pending_p2ps_group_freq;
+ wpa_s->global->pending_p2ps_group_freq = 0;
wpa_s->global->pending_p2ps_group = 0;
if (wpas_p2p_get_go_group(wpa_s))
@@ -4037,11 +4351,11 @@ static int wpas_prov_disc_resp_cb(void *ctx)
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, NULL,
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
persistent_go->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
} else {
- wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0);
}
return 1;
@@ -4059,6 +4373,54 @@ static int wpas_p2p_get_pref_freq_list(void *ctx, int go,
}
+int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
+{
+ u8 addr[ETH_ALEN] = {0};
+
+ if (wpa_s->conf->p2p_device_random_mac_addr == 0)
+ return 0;
+
+ if (!wpa_s->conf->ssid) {
+ if (random_mac_addr(addr) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to generate random MAC address");
+ return -EINVAL;
+ }
+
+ /* Store generated MAC address. */
+ os_memcpy(wpa_s->conf->p2p_device_persistent_mac_addr, addr,
+ ETH_ALEN);
+ } else {
+ /* If there are existing saved groups, restore last MAC address.
+ * if there is no last used MAC address, the last one is
+ * factory MAC. */
+ if (is_zero_ether_addr(
+ wpa_s->conf->p2p_device_persistent_mac_addr))
+ return 0;
+ os_memcpy(addr, wpa_s->conf->p2p_device_persistent_mac_addr,
+ ETH_ALEN);
+ wpa_msg(wpa_s, MSG_DEBUG, "Restore last used MAC address.");
+ }
+
+ if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to set random MAC address");
+ return -EINVAL;
+ }
+
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return -EINVAL;
+ }
+
+ wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
+ MAC2STR(addr));
+
+ return 0;
+}
+
+
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
* @global: Pointer to global data from wpa_supplicant_init()
@@ -4079,6 +4441,12 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
if (global->p2p)
return 0;
+ if (wpas_p2p_mac_setup(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to initialize P2P random MAC address.");
+ return -1;
+ }
+
os_memset(&p2p, 0, sizeof(p2p));
p2p.cb_ctx = wpa_s;
p2p.debug_print = wpas_p2p_debug_print;
@@ -4143,7 +4511,10 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
* channel.
*/
if (p2p_config_get_random_social(&p2p, &p2p.reg_class,
- &p2p.channel) != 0) {
+ &p2p.channel,
+ &global->p2p_go_avoid_freq,
+ &global->p2p_disallow_freq) !=
+ 0) {
wpa_printf(MSG_INFO,
"P2P: No social channels supported by the driver - do not enable P2P");
return 0;
@@ -4168,10 +4539,14 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
* other preference is indicated.
*/
if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class,
- &p2p.op_channel) != 0) {
- wpa_printf(MSG_ERROR,
+ &p2p.op_channel, NULL,
+ NULL) != 0) {
+ wpa_printf(MSG_INFO,
"P2P: Failed to select random social channel as operation channel");
- return -1;
+ p2p.op_reg_class = 0;
+ p2p.op_channel = 0;
+ /* This will be overridden during group setup in
+ * p2p_prepare_channel(), so allow setup to continue. */
}
p2p.cfg_op_channel = 0;
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
@@ -4333,8 +4708,7 @@ static void wpas_p2p_deinit_global(struct wpa_global *global)
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
{
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
- wpa_s->conf->p2p_no_group_iface)
+ if (wpa_s->conf->p2p_no_group_iface)
return 0; /* separate interface disabled per configuration */
if (wpa_s->drv_flags &
(WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
@@ -4415,7 +4789,7 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
MAC2STR(wpa_s->pending_join_dev_addr));
return;
}
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
wpas_notify_p2p_group_formation_failure(wpa_s, "");
}
@@ -4551,7 +4925,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
if (join < 0) {
wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
"running a GO -> use GO Negotiation");
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_FALLBACK_TO_GO_NEG
"reason=peer-not-running-GO");
wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
@@ -4559,10 +4933,14 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->p2p_persistent_group, 0, 0, 0,
wpa_s->p2p_go_intent,
wpa_s->p2p_connect_freq,
+ wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_persistent_id,
wpa_s->p2p_pd_before_go_neg,
wpa_s->p2p_go_ht40,
- wpa_s->p2p_go_vht);
+ wpa_s->p2p_go_vht,
+ wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
+ NULL, 0);
return;
}
@@ -4570,7 +4948,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
"try to join the group", join ? "" :
" in older scan");
if (!join) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED);
wpa_s->p2p_fallback_to_go_neg = 1;
}
@@ -4608,8 +4986,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
wpa_s->p2p_join_ssid,
wpa_s->p2p_join_ssid_len);
- }
- if (!bss) {
+ } else if (!bss) {
wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
MACSTR, MAC2STR(wpa_s->pending_join_iface_addr));
bss = wpa_bss_get_bssid_latest(wpa_s,
@@ -4640,7 +5017,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
u16 method;
if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE
"reason=FREQ_CONFLICT");
wpas_notify_p2p_group_formation_failure(
@@ -4708,7 +5085,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
start:
/* Start join operation immediately */
- wpas_p2p_join_start(wpa_s, 0, NULL, 0);
+ wpas_p2p_join_start(wpa_s, 0, wpa_s->p2p_join_ssid,
+ wpa_s->p2p_join_ssid_len);
}
@@ -4720,6 +5098,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
struct wpabuf *wps_ie, *ies;
size_t ielen;
int freqs[2] = { 0, 0 };
+ unsigned int bands;
os_memset(&params, 0, sizeof(params));
@@ -4745,6 +5124,22 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
return;
}
+ if (!freq) {
+ int oper_freq;
+ /*
+ * If freq is not provided, check the operating freq of the GO
+ * and use a single channel scan on if possible.
+ */
+ oper_freq = p2p_get_oper_freq(wpa_s->global->p2p,
+ wpa_s->pending_join_iface_addr);
+ if (oper_freq > 0)
+ freq = oper_freq;
+ }
+ if (freq > 0) {
+ freqs[0] = freq;
+ params.freqs = freqs;
+ }
+
ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
if (ies == NULL) {
@@ -4755,26 +5150,17 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
wpabuf_put_buf(ies, wps_ie);
wpabuf_free(wps_ie);
- p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
+ bands = wpas_get_bands(wpa_s, freqs);
+ p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
params.p2p_probe = 1;
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
- if (!freq) {
- int oper_freq;
- /*
- * If freq is not provided, check the operating freq of the GO
- * and use a single channel scan on if possible.
- */
- oper_freq = p2p_get_oper_freq(wpa_s->global->p2p,
- wpa_s->pending_join_iface_addr);
- if (oper_freq > 0)
- freq = oper_freq;
- }
- if (freq > 0) {
- freqs[0] = freq;
- params.freqs = freqs;
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
+ params.only_new_results = 1;
}
/*
@@ -4786,6 +5172,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
}
wpabuf_free(ies);
@@ -4850,17 +5237,18 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
sizeof(group->p2p_pin));
group->p2p_wps_method = wpa_s->p2p_wps_method;
- } else {
- /*
- * Need to mark the current interface for p2p_group_formation
- * when a separate group interface is not used. This is needed
- * to allow p2p_cancel stop a pending p2p_connect-join.
- * wpas_p2p_init_group_interface() addresses this for the case
- * where a separate group interface is used.
- */
- wpa_s->global->p2p_group_formation = wpa_s;
}
+ /*
+ * Need to mark the current interface for p2p_group_formation
+ * when a separate group interface is not used. This is needed
+ * to allow p2p_cancel stop a pending p2p_connect-join.
+ * wpas_p2p_init_group_interface() addresses this for the case
+ * where a separate group interface is used.
+ */
+ if (group == wpa_s->parent)
+ wpa_s->global->p2p_group_formation = group;
+
group->p2p_in_provisioning = 1;
group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
@@ -4874,8 +5262,13 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
res.ssid_len = ssid_len;
os_memcpy(res.ssid, ssid, ssid_len);
} else {
- bss = wpa_bss_get_bssid_latest(wpa_s,
- wpa_s->pending_join_iface_addr);
+ if (ssid && ssid_len) {
+ bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
+ ssid, ssid_len);
+ } else {
+ bss = wpa_bss_get_bssid_latest(
+ wpa_s, wpa_s->pending_join_iface_addr);
+ }
if (bss) {
res.freq = bss->freq;
res.ssid_len = bss->ssid_len;
@@ -4883,6 +5276,11 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)",
bss->freq,
wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ } else if (ssid && ssid_len) {
+ res.ssid_len = ssid_len;
+ os_memcpy(res.ssid, ssid, ssid_len);
+ wpa_printf(MSG_DEBUG, "P2P: Join target GO (SSID %s)",
+ wpa_ssid_txt(ssid, ssid_len));
}
}
@@ -4947,7 +5345,8 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
if (!ret) {
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(freq)) {
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
/*
* If freq is a DFS channel and DFS is offloaded
* to the driver, allow P2P GO to use it.
@@ -5000,9 +5399,11 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
if (!res && max_pref_freq > 0) {
*num_pref_freq = max_pref_freq;
i = 0;
- while (wpas_p2p_disallowed_freq(wpa_s->global,
- pref_freq_list[i]) &&
- i < *num_pref_freq) {
+ while (i < *num_pref_freq &&
+ (!p2p_supported_freq(wpa_s->global->p2p,
+ pref_freq_list[i]) ||
+ wpas_p2p_disallowed_freq(wpa_s->global,
+ pref_freq_list[i]))) {
wpa_printf(MSG_DEBUG,
"P2P: preferred_freq_list[%d]=%d is disallowed",
i, pref_freq_list[i]);
@@ -5067,12 +5468,17 @@ exit_free:
* initiating Group Owner negotiation
* @go_intent: GO Intent or -1 to use default
* @freq: Frequency for the group or 0 for auto-selection
+ * @freq2: Center frequency of segment 1 for the GO operating in VHT 80P80 mode
* @persistent_id: Persistent group credentials to use for forcing GO
* parameters or -1 to generate new values (SSID/passphrase)
* @pd: Whether to send Provision Discovery prior to GO Negotiation as an
* interoperability workaround when initiating group formation
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
+ * @vht_chwidth: Channel width supported by GO operating with VHT support
+ * (VHT_CHANWIDTH_*).
+ * @group_ssid: Specific Group SSID for join or %NULL if not set
+ * @group_ssid_len: Length of @group_ssid in octets
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
@@ -5080,8 +5486,10 @@ exit_free:
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int auto_join, int join, int auth,
- int go_intent, int freq, int persistent_id, int pd,
- int ht40, int vht)
+ int go_intent, int freq, unsigned int vht_center_freq2,
+ int persistent_id, int pd, int ht40, int vht,
+ unsigned int vht_chwidth, int he, const u8 *group_ssid,
+ size_t group_ssid_len)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -5105,6 +5513,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->global->p2p_fail_on_wps_complete = 0;
wpa_s->global->pending_p2ps_group = 0;
+ wpa_s->global->pending_p2ps_group_freq = 0;
wpa_s->p2ps_method_config_any = 0;
if (go_intent < 0)
@@ -5122,17 +5531,24 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_pd_before_go_neg = !!pd;
wpa_s->p2p_go_ht40 = !!ht40;
wpa_s->p2p_go_vht = !!vht;
+ wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
+ wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
+ wpa_s->p2p_go_he = !!he;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
else if (wps_method == WPS_PIN_DISPLAY) {
- ret = wps_generate_pin();
+ if (wps_generate_pin((unsigned int *) &ret) < 0)
+ return -1;
res = os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin),
"%08d", ret);
if (os_snprintf_error(sizeof(wpa_s->p2p_pin), res))
wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0';
wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
wpa_s->p2p_pin);
+ } else if (wps_method == WPS_P2PS) {
+ /* Force the P2Ps default PIN to be used */
+ os_strlcpy(wpa_s->p2p_pin, "12345670", sizeof(wpa_s->p2p_pin));
} else
wpa_s->p2p_pin[0] = '\0';
@@ -5161,7 +5577,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
}
wpa_s->user_initiated_pd = 1;
if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
- auto_join, freq, NULL, 0) < 0)
+ auto_join, freq,
+ group_ssid, group_ssid_len) < 0)
return -1;
return ret;
}
@@ -5191,7 +5608,10 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
if_addr = wpa_s->pending_interface_addr;
} else {
- if_addr = wpa_s->own_addr;
+ if (wpa_s->p2p_mgmt)
+ if_addr = wpa_s->parent->own_addr;
+ else
+ if_addr = wpa_s->own_addr;
os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
}
@@ -5347,9 +5767,11 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
&size, pref_freq_list);
if (!res && size > 0) {
i = 0;
- while (wpas_p2p_disallowed_freq(wpa_s->global,
- pref_freq_list[i]) &&
- i < size) {
+ while (i < size &&
+ (!p2p_supported_freq(wpa_s->global->p2p,
+ pref_freq_list[i]) ||
+ wpas_p2p_disallowed_freq(wpa_s->global,
+ pref_freq_list[i]))) {
wpa_printf(MSG_DEBUG,
"P2P: preferred_freq_list[%d]=%d is disallowed",
i, pref_freq_list[i]);
@@ -5413,7 +5835,8 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(freq)) {
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
/*
* If freq is a DFS channel and DFS is offloaded to the
* driver, allow P2P GO to use it.
@@ -5451,30 +5874,6 @@ static void wpas_p2p_select_go_freq_no_pref(struct wpa_supplicant *wpa_s,
{
unsigned int i, r;
- /* first try some random selection of the social channels */
- if (os_get_random((u8 *) &r, sizeof(r)) < 0)
- return;
-
- for (i = 0; i < 3; i++) {
- params->freq = 2412 + ((r + i) % 3) * 25;
- if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
- goto out;
- }
-
- /* try all other channels in operating class 81 */
- for (i = 0; i < 11; i++) {
- params->freq = 2412 + i * 5;
-
- /* skip social channels; covered in the previous loop */
- if (params->freq == 2412 ||
- params->freq == 2437 ||
- params->freq == 2462)
- continue;
-
- if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
- goto out;
- }
-
/* try all channels in operating class 115 */
for (i = 0; i < 4; i++) {
params->freq = 5180 + i * 20;
@@ -5509,6 +5908,30 @@ static void wpas_p2p_select_go_freq_no_pref(struct wpa_supplicant *wpa_s,
goto out;
}
+ /* try some random selection of the social channels */
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return;
+
+ for (i = 0; i < 3; i++) {
+ params->freq = 2412 + ((r + i) % 3) * 25;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
+ goto out;
+ }
+
+ /* try all other channels in operating class 81 */
+ for (i = 0; i < 11; i++) {
+ params->freq = 2412 + i * 5;
+
+ /* skip social channels; covered in the previous loop */
+ if (params->freq == 2412 ||
+ params->freq == 2437 ||
+ params->freq == 2462)
+ continue;
+
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
+ goto out;
+ }
+
params->freq = 0;
wpa_printf(MSG_DEBUG, "P2P: No 2.4, 5, or 60 GHz channel allowed");
return;
@@ -5518,40 +5941,95 @@ out:
}
+static int wpas_same_band(int freq1, int freq2)
+{
+ enum hostapd_hw_mode mode1, mode2;
+ u8 chan1, chan2;
+
+ mode1 = ieee80211_freq_to_chan(freq1, &chan1);
+ mode2 = ieee80211_freq_to_chan(freq2, &chan2);
+ if (mode1 == NUM_HOSTAPD_MODES)
+ return 0;
+ return mode1 == mode2;
+}
+
+
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
- int freq, int ht40, int vht,
+ int freq, int vht_center_freq2, int ht40,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
unsigned int cand;
unsigned int num, i;
+ int ignore_no_freqs = 0;
+ int unused_channels = wpas_p2p_num_unused_channels(wpa_s) > 0;
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
params->ht40 = ht40;
params->vht = vht;
-
- if (wpa_s->p2p_group_common_freqs_num)
- wpa_printf(MSG_DEBUG, "P2P: %s called for an active GO",
- __func__);
+ params->he = he;
+ params->max_oper_chwidth = max_oper_chwidth;
+ params->vht_center_freq2 = vht_center_freq2;
freqs = os_calloc(wpa_s->num_multichan_concurrent,
sizeof(struct wpa_used_freq_data));
if (!freqs)
return -1;
- num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ num = get_shared_radio_freqs_data(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO &&
+ wpa_s->wpa_state == WPA_COMPLETED) {
+ wpa_printf(MSG_DEBUG, "P2P: %s called for an active GO",
+ __func__);
+
+ /*
+ * If the frequency selection is done for an active P2P GO that
+ * is not sharing a frequency, allow to select a new frequency
+ * even if there are no unused frequencies as we are about to
+ * move the P2P GO so its frequency can be re-used.
+ */
+ for (i = 0; i < num; i++) {
+ if (freqs[i].freq == wpa_s->current_ssid->frequency &&
+ freqs[i].flags == 0) {
+ ignore_no_freqs = 1;
+ break;
+ }
+ }
+ }
/* try using the forced freq */
if (freq) {
- if (!wpas_p2p_supported_freq_go(wpa_s, channels, freq)) {
+ if (wpas_p2p_disallowed_freq(wpa_s->global, freq) ||
+ !freq_included(wpa_s, channels, freq)) {
wpa_printf(MSG_DEBUG,
- "P2P: Forced GO freq %d MHz not accepted",
+ "P2P: Forced GO freq %d MHz disallowed",
freq);
goto fail;
}
+ if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
+ /*
+ * If freq is a DFS channel and DFS is offloaded
+ * to the driver, allow P2P GO to use it.
+ */
+ wpa_printf(MSG_DEBUG,
+ "P2P: %s: The forced channel for GO (%u MHz) requires DFS and DFS is offloaded",
+ __func__, freq);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "P2P: The forced channel for GO (%u MHz) is not supported for P2P uses",
+ freq);
+ goto fail;
+ }
+ }
for (i = 0; i < num; i++) {
if (freqs[i].freq == freq) {
@@ -5563,7 +6041,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
}
}
- if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ if (!ignore_no_freqs && !unused_channels) {
wpa_printf(MSG_DEBUG,
"P2P: Cannot force GO on freq (%d MHz) as all the channels are in use",
freq);
@@ -5578,12 +6056,13 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
}
/* consider using one of the shared frequencies */
- if (num) {
+ if (num &&
+ (!wpa_s->conf->p2p_ignore_shared_freq || !unused_channels)) {
cand = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
wpa_printf(MSG_DEBUG,
"P2P: Use shared freq (%d MHz) for GO",
- freq);
+ cand);
params->freq = cand;
goto success;
}
@@ -5594,14 +6073,14 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
freqs[i].freq)) {
wpa_printf(MSG_DEBUG,
"P2P: Use shared freq (%d MHz) for GO",
- freq);
+ freqs[i].freq);
params->freq = freqs[i].freq;
goto success;
}
}
}
- if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ if (!ignore_no_freqs && !unused_channels) {
wpa_printf(MSG_DEBUG,
"P2P: Cannot force GO on any of the channels we are already using");
goto fail;
@@ -5676,6 +6155,80 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
goto success;
}
+ /* Try using a channel that allows VHT to be used with 80 MHz */
+ if (wpa_s->hw.modes && wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ enum hostapd_hw_mode mode;
+ struct hostapd_hw_modes *hwmode;
+ u8 chan;
+
+ cand = wpa_s->p2p_group_common_freqs[i];
+ mode = ieee80211_freq_to_chan(cand, &chan);
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ mode);
+ if (!hwmode ||
+ wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW80) != ALLOWED)
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer and allowing VHT80",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
+ /* Try using a channel that allows HT to be used with 40 MHz on the same
+ * band so that CSA can be used */
+ if (wpa_s->current_ssid && wpa_s->hw.modes &&
+ wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ enum hostapd_hw_mode mode;
+ struct hostapd_hw_modes *hwmode;
+ u8 chan;
+
+ cand = wpa_s->p2p_group_common_freqs[i];
+ mode = ieee80211_freq_to_chan(cand, &chan);
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ mode);
+ if (!wpas_same_band(wpa_s->current_ssid->frequency,
+ cand) ||
+ !hwmode ||
+ (wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW40MINUS) != ALLOWED &&
+ wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW40PLUS) != ALLOWED))
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer, allowing HT40, and maintaining same band",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
+ /* Try using one of the group common freqs on the same band so that CSA
+ * can be used */
+ if (wpa_s->current_ssid && wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ cand = wpa_s->p2p_group_common_freqs[i];
+ if (!wpas_same_band(wpa_s->current_ssid->frequency,
+ cand))
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer and maintaining same band",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
/* Try using one of the group common freqs */
if (wpa_s->p2p_group_common_freqs) {
for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
@@ -5714,9 +6267,20 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
struct wpa_supplicant *group_wpa_s;
if (!wpas_p2p_create_iface(wpa_s)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
- "operations");
+ if (wpa_s->p2p_mgmt) {
+ /*
+ * We may be called on the p2p_dev interface which
+ * cannot be used for group operations, so always use
+ * the primary interface.
+ */
+ wpa_s->parent->p2pdev = wpa_s;
+ wpa_s = wpa_s->parent;
+ }
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Use primary interface for group operations");
wpa_s->p2p_first_connection_timeout = 0;
+ if (wpa_s != wpa_s->p2pdev)
+ wpas_p2p_clone_config(wpa_s, wpa_s->p2pdev);
return wpa_s;
}
@@ -5734,6 +6298,12 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
return NULL;
}
+ if (go && wpa_s->p2p_go_do_acs) {
+ group_wpa_s->p2p_go_do_acs = wpa_s->p2p_go_do_acs;
+ group_wpa_s->p2p_go_acs_band = wpa_s->p2p_go_acs_band;
+ wpa_s->p2p_go_do_acs = 0;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
group_wpa_s->ifname);
group_wpa_s->p2p_first_connection_timeout = 0;
@@ -5746,15 +6316,18 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
* @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
* @persistent_group: Whether to create a persistent group
* @freq: Frequency for the group or 0 to indicate no hardcoding
+ * @vht_center_freq2: segment_1 center frequency for GO operating in VHT 80P80
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
+ * @vht_chwidth: channel bandwidth for GO operating with VHT support
* Returns: 0 on success, -1 on failure
*
* This function creates a new P2P group with the local end as the Group Owner,
* i.e., without using Group Owner Negotiation.
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq, int ht40, int vht)
+ int freq, int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth, int he)
{
struct p2p_go_neg_results params;
@@ -5768,30 +6341,16 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
wpas_p2p_stop_find_oper(wpa_s);
- freq = wpas_p2p_select_go_freq(wpa_s, freq);
- if (freq < 0)
- return -1;
-
- if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, NULL))
- return -1;
- if (params.freq &&
- !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
- if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(params.freq)) {
- /*
- * If freq is a DFS channel and DFS is offloaded to the
- * driver, allow P2P GO to use it.
- */
- wpa_printf(MSG_DEBUG,
- "P2P: %s: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded to driver",
- __func__, params.freq);
- } else {
- wpa_printf(MSG_DEBUG,
- "P2P: The selected channel for GO (%u MHz) is not supported for P2P uses",
- params.freq);
+ if (!wpa_s->p2p_go_do_acs) {
+ freq = wpas_p2p_select_go_freq(wpa_s, freq);
+ if (freq < 0)
return -1;
- }
}
+
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
+ ht40, vht, max_oper_chwidth, he, NULL))
+ return -1;
+
p2p_go_params(wpa_s->global->p2p, &params);
params.persistent_group = persistent_group;
@@ -5826,8 +6385,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->proto = WPA_PROTO_RSN;
- ssid->pairwise_cipher = WPA_CIPHER_CCMP;
- ssid->group_cipher = WPA_CIPHER_CCMP;
+ ssid->pbss = params->pbss;
+ ssid->pairwise_cipher = params->pbss ? WPA_CIPHER_GCMP :
+ WPA_CIPHER_CCMP;
+ ssid->group_cipher = params->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->ssid = os_malloc(params->ssid_len);
if (ssid->ssid == NULL) {
@@ -5848,12 +6409,14 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
wpa_s->show_group_started = 1;
wpa_s->p2p_in_invitation = 1;
wpa_s->p2p_invite_go_freq = freq;
+ wpa_s->p2p_go_group_formation_completed = 0;
+ wpa_s->global->p2p_group_formation = wpa_s;
- eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev,
NULL);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
wpa_supplicant_select_network(wpa_s, ssid);
return 0;
@@ -5862,8 +6425,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int force_freq, int neg_freq, int ht40,
- int vht, const struct p2p_channels *channels,
+ int force_freq, int neg_freq,
+ int vht_center_freq2, int ht40,
+ int vht, int max_oper_chwidth, int he,
+ const struct p2p_channels *channels,
int connection_timeout, int force_scan)
{
struct p2p_go_neg_results params;
@@ -5878,7 +6443,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
"already running");
if (go == 0 &&
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL)) {
+ wpa_s->p2pdev, NULL)) {
/*
* This can happen if Invitation Response frame was lost
* and the peer (GO of a persistent group) tries to
@@ -5891,7 +6456,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
"P2P: Reschedule group formation timeout since peer is still trying to invite us");
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
return 0;
}
@@ -5937,7 +6502,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
- if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
+ ht40, vht, max_oper_chwidth, he, channels))
return -1;
params.role_go = 1;
@@ -6019,7 +6585,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct p2p_group *group;
struct p2p_group_config *cfg;
- if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+ !ssid->p2p_group)
return NULL;
cfg = os_zalloc(sizeof(*cfg));
@@ -6042,6 +6609,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
cfg->cb_ctx = wpa_s;
cfg->ie_update = wpas_p2p_ie_update;
cfg->idle_update = wpas_p2p_idle_update;
+ cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start)
+ != 0;
group = p2p_group_init(wpa_s->global->p2p, cfg);
if (group == NULL)
@@ -6073,7 +6642,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr);
}
- eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev,
NULL);
wpa_s->p2p_go_group_formation_completed = 1;
if (ssid && ssid->mode == WPAS_MODE_INFRA) {
@@ -6088,7 +6657,9 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
P2P_MAX_INITIAL_CONN_WAIT);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
+ /* Complete group formation on successful data connection. */
+ wpa_s->p2p_go_group_formation_completed = 0;
} else if (ssid) {
/*
* Use a separate timeout for initial data connection to
@@ -6100,7 +6671,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
P2P_MAX_INITIAL_CONN_WAIT_GO);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT_GO, 0,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
/*
* Complete group formation on first successful data connection
*/
@@ -6139,7 +6710,7 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
wpa_s->global->p2p_fail_on_wps_complete = 1;
eloop_deplete_timeout(0, 50000,
wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
}
@@ -6164,11 +6735,14 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
u16 config_methods;
wpa_s->global->pending_p2ps_group = 0;
+ wpa_s->global->pending_p2ps_group_freq = 0;
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->pending_pd_use = NORMAL_PD;
if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
p2ps_prov->conncap = p2ps_group_capability(
- wpa_s, P2PS_SETUP_NONE, p2ps_prov->role);
+ wpa_s, P2PS_SETUP_NONE, p2ps_prov->role,
+ &p2ps_prov->force_freq, &p2ps_prov->pref_freq);
+
wpa_printf(MSG_DEBUG,
"P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
__func__, p2ps_prov->conncap,
@@ -6229,7 +6803,12 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
if (!offchannel_pending_action_tx(wpa_s))
return;
- wpas_p2p_action_tx_clear(wpa_s);
+ if (wpa_s->p2p_send_action_work) {
+ wpas_p2p_free_send_action_work(wpa_s);
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ }
wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
"operation request");
@@ -6247,8 +6826,14 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
wpa_s->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
- wpa_s->p2p_in_provisioning)
+ wpa_s->p2p_in_provisioning) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Reject p2p_find operation%s%s",
+ (wpa_s->global->p2p_disabled || !wpa_s->global->p2p) ?
+ " (P2P disabled)" : "",
+ wpa_s->p2p_in_provisioning ?
+ " (p2p_in_provisioning)" : "");
return -1;
+ }
wpa_supplicant_cancel_sched_scan(wpa_s);
@@ -6320,6 +6905,12 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpa_s->p2p_lo_started) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Cannot start P2P listen, it is offloaded");
+ return -1;
+ }
+
wpa_supplicant_cancel_sched_scan(wpa_s);
wpas_p2p_clear_pending_action_tx(wpa_s);
@@ -6393,7 +6984,7 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
return 0;
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
- ie, ie_len, rx_freq)) {
+ ie, ie_len, rx_freq, wpa_s->p2p_lo_started)) {
case P2P_PREQ_NOT_P2P:
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
ssi_signal);
@@ -6425,12 +7016,15 @@ void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies)
{
+ unsigned int bands;
+
if (wpa_s->global->p2p_disabled)
return;
if (wpa_s->global->p2p == NULL)
return;
- p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
+ bands = wpas_get_bands(wpa_s, NULL);
+ p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
}
@@ -6460,7 +7054,8 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
/* Invite to reinvoke a persistent group */
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int ht40, int vht, int pref_freq)
+ int vht_center_freq2, int ht40, int vht, int max_chwidth,
+ int pref_freq, int he)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -6477,6 +7072,10 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
+ wpa_s->p2p_go_vht = !!vht;
+ wpa_s->p2p_go_he = !!he;
+ wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
+ wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -6493,7 +7092,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return -1;
}
bssid = wpa_s->pending_interface_addr;
- } else
+ } else if (wpa_s->p2p_mgmt)
+ bssid = wpa_s->parent->own_addr;
+ else
bssid = wpa_s->own_addr;
} else {
role = P2P_INVITE_ROLE_CLIENT;
@@ -6507,11 +7108,12 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
pref_freq_list, &size);
if (res)
return res;
- p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ p2p_set_own_pref_freq_list(wpa_s->global->p2p, pref_freq_list, size);
+
if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
no_pref_freq_given && pref_freq > 0 &&
wpa_s->num_multichan_concurrent > 1 &&
@@ -6549,6 +7151,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
wpa_s->p2p_persistent_go_freq = 0;
wpa_s->p2p_go_ht40 = 0;
wpa_s->p2p_go_vht = 0;
+ wpa_s->p2p_go_vht_center_freq2 = 0;
+ wpa_s->p2p_go_max_oper_chwidth = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -6568,7 +7172,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
wpa_s->global->p2p_invite_group = wpa_s;
persistent = ssid->p2p_persistent_group &&
- wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
+ wpas_p2p_get_persistent(wpa_s->p2pdev, peer_addr,
ssid->ssid, ssid->ssid_len);
if (ssid->mode == WPAS_MODE_P2P_GO) {
@@ -6591,7 +7195,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
(int) wpa_s->assoc_freq;
}
- wpa_s->parent->pending_invite_ssid_id = -1;
+ wpa_s->p2pdev->pending_invite_ssid_id = -1;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -6614,21 +7218,29 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
u8 go_dev_addr[ETH_ALEN];
- int network_id = -1;
int persistent;
int freq;
- u8 ip[3 * 4];
+ u8 ip[3 * 4], *ip_ptr = NULL;
char ip_addr[100];
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
if (!wpa_s->show_group_started || !ssid)
return;
wpa_s->show_group_started = 0;
+ if (!wpa_s->p2p_go_group_formation_completed &&
+ wpa_s->global->p2p_group_formation == wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Marking group formation completed on client on data connection");
+ wpa_s->p2p_go_group_formation_completed = 1;
+ wpa_s->global->p2p_group_formation = NULL;
+ wpa_s->p2p_in_provisioning = 0;
+ wpa_s->p2p_in_invitation = 0;
+ }
os_memset(go_dev_addr, 0, ETH_ALEN);
if (ssid->bssid_set)
@@ -6655,6 +7267,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
ip[8], ip[9], ip[10], ip[11]);
if (os_snprintf_error(sizeof(ip_addr), res))
ip_addr[0] = '\0';
+ ip_ptr = ip;
}
wpas_p2p_group_started(wpa_s, 0, ssid, freq,
@@ -6664,11 +7277,10 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
ip_addr);
if (persistent)
- network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
- ssid, go_dev_addr);
- if (network_id < 0)
- network_id = ssid->id;
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+ wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+ ssid, go_dev_addr);
+
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip_ptr);
}
@@ -7001,7 +7613,7 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
iface->cross_connect_enabled = 0;
iface->cross_connect_in_use = 0;
- wpa_msg_global(iface->parent, MSG_INFO,
+ wpa_msg_global(iface->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
iface->ifname,
iface->cross_connect_uplink);
@@ -7031,7 +7643,7 @@ static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
continue;
iface->cross_connect_in_use = 1;
- wpa_msg_global(iface->parent, MSG_INFO,
+ wpa_msg_global(iface->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
iface->ifname, iface->cross_connect_uplink);
}
@@ -7051,7 +7663,7 @@ static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
if (!iface->cross_connect_in_use)
continue;
- wpa_msg_global(iface->parent, MSG_INFO,
+ wpa_msg_global(iface->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
iface->ifname, iface->cross_connect_uplink);
iface->cross_connect_in_use = 0;
@@ -7114,7 +7726,7 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
break;
wpa_s->cross_connect_in_use = 1;
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
wpa_s->ifname, wpa_s->cross_connect_uplink);
break;
@@ -7130,8 +7742,8 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
"session overlap");
- if (wpa_s != wpa_s->parent)
- wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
+ if (wpa_s != wpa_s->p2pdev)
+ wpa_msg_ctrl(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_OVERLAP);
wpas_p2p_group_formation_failed(wpa_s, 0);
return 1;
}
@@ -7238,7 +7850,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
wpa_s->ifname);
found = 1;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
if (wpa_s->p2p_in_provisioning) {
wpas_group_formation_completed(wpa_s, 0, 0);
break;
@@ -7251,6 +7863,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
wpa_s->ifname);
found = 1;
wpas_p2p_group_formation_failed(wpa_s, 0);
+ break;
}
}
@@ -7367,7 +7980,7 @@ void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
{
if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL) > 0) {
+ wpa_s->p2pdev, NULL) > 0) {
/**
* Remove the network by scheduling the group formation
* timeout to happen immediately. The teardown code
@@ -7379,7 +7992,7 @@ void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
"P2P group network getting removed");
eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
+ wpa_s->p2pdev, NULL);
}
}
@@ -7423,7 +8036,7 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL) > 0) {
+ wpa_s->p2pdev, NULL) > 0) {
/*
* This can happen if WPS provisioning step is not terminated
* cleanly (e.g., P2P Client does not send WSC_Done). Since the
@@ -7479,10 +8092,13 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+ wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_persistent_id,
wpa_s->p2p_pd_before_go_neg,
wpa_s->p2p_go_ht40,
- wpa_s->p2p_go_vht);
+ wpa_s->p2p_go_vht,
+ wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he, NULL, 0);
return ret;
}
@@ -7500,7 +8116,7 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
"fallback to GO Negotiation");
- wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG
"reason=GO-not-found");
res = wpas_p2p_fallback_to_go_neg(wpa_s, 1);
@@ -7609,7 +8225,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
return;
}
- persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+ persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, NULL, ssid->ssid,
ssid->ssid_len);
if (!persistent) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not find persistent group information to store the new PSK");
@@ -7638,7 +8254,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
os_free(last);
}
- wpas_p2p_remove_psk_entry(wpa_s->parent, persistent,
+ wpas_p2p_remove_psk_entry(wpa_s->p2pdev, persistent,
p2p_dev_addr ? p2p_dev_addr : mac_addr,
p2p_dev_addr == NULL);
if (p2p_dev_addr) {
@@ -7650,8 +8266,8 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
}
dl_list_add(&persistent->psk_list, &p->list);
- if (wpa_s->parent->conf->update_config &&
- wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ if (wpa_s->p2pdev->conf->update_config &&
+ wpa_config_write(wpa_s->p2pdev->confname, wpa_s->p2pdev->conf))
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
}
@@ -7830,14 +8446,14 @@ int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Two 4-way handshake failures for a P2P group - go_dev_addr="
MACSTR, MAC2STR(go_dev_addr));
- persistent = wpas_p2p_get_persistent(wpa_s->parent, go_dev_addr,
+ persistent = wpas_p2p_get_persistent(wpa_s->p2pdev, go_dev_addr,
ssid->ssid,
ssid->ssid_len);
if (persistent == NULL || persistent->mode != WPAS_MODE_INFRA) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No matching persistent group stored");
goto disconnect;
}
- wpa_msg_global(wpa_s->parent, MSG_INFO,
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_PERSISTENT_PSK_FAIL "%d",
persistent->id);
disconnect:
@@ -8016,7 +8632,11 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
- params->go_freq, -1, 0, 1, 1);
+ params->go_freq, wpa_s->p2p_go_vht_center_freq2,
+ -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
+ params->go_ssid_len ? params->go_ssid : NULL,
+ params->go_ssid_len);
}
@@ -8043,17 +8663,17 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
return -1;
}
- if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ if (wpa_s->p2pdev->p2p_oob_dev_pw_id !=
DEV_PW_NFC_CONNECTION_HANDOVER &&
- !wpa_s->parent->p2p_oob_dev_pw) {
+ !wpa_s->p2pdev->p2p_oob_dev_pw) {
wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
return -1;
}
res = wpas_ap_wps_add_nfc_pw(
- wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
- wpa_s->parent->p2p_oob_dev_pw,
- wpa_s->parent->p2p_peer_oob_pk_hash_known ?
- wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+ wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id,
+ wpa_s->p2pdev->p2p_oob_dev_pw,
+ wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ?
+ wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL);
if (res)
return res;
@@ -8071,16 +8691,16 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
wpa_s->global->p2p_invite_group = wpa_s;
persistent = ssid->p2p_persistent_group &&
- wpas_p2p_get_persistent(wpa_s->parent,
+ wpas_p2p_get_persistent(wpa_s->p2pdev,
params->peer->p2p_device_addr,
ssid->ssid, ssid->ssid_len);
- wpa_s->parent->pending_invite_ssid_id = -1;
+ wpa_s->p2pdev->pending_invite_ssid_id = -1;
return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr,
P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr,
ssid->ssid, ssid->ssid_len, ssid->frequency,
wpa_s->global->p2p_dev_addr, persistent, 0,
- wpa_s->parent->p2p_oob_dev_pw_id);
+ wpa_s->p2pdev->p2p_oob_dev_pw_id);
}
@@ -8092,7 +8712,9 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
"connection handover");
return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
- forced_freq, -1, 0, 1, 1);
+ forced_freq, wpa_s->p2p_go_vht_center_freq2,
+ -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he, NULL, 0);
}
@@ -8106,7 +8728,9 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
"connection handover");
res = wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
- forced_freq, -1, 0, 1, 1);
+ forced_freq, wpa_s->p2p_go_vht_center_freq2,
+ -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he, NULL, 0);
if (res)
return res;
@@ -8397,7 +9021,9 @@ int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
}
if_addr = wpa_s->pending_interface_addr;
- } else
+ } else if (wpa_s->p2p_mgmt)
+ if_addr = wpa_s->parent->own_addr;
+ else
if_addr = wpa_s->own_addr;
wpa_s->p2p_nfc_tag_enabled = enabled;
@@ -8473,14 +9099,115 @@ static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s)
{
+ struct hostapd_config *conf;
+ struct p2p_go_neg_results params;
+ struct csa_settings csa_settings;
+ struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+ int old_freq = current_ssid->frequency;
+ int ret;
+
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
wpa_dbg(wpa_s, MSG_DEBUG, "CSA is not enabled");
return -1;
}
- /* TODO: Add CSA support */
- wpa_dbg(wpa_s, MSG_DEBUG, "Moving GO with CSA is not implemented");
- return -1;
+ /*
+ * TODO: This function may not always work correctly. For example,
+ * when we have a running GO and a BSS on a DFS channel.
+ */
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Failed to select new frequency for GO");
+ return -1;
+ }
+
+ if (current_ssid->frequency == params.freq) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Selected same frequency - not moving GO");
+ return 0;
+ }
+
+ conf = hostapd_config_defaults();
+ if (!conf) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Failed to allocate default config");
+ return -1;
+ }
+
+ current_ssid->frequency = params.freq;
+ if (wpa_supplicant_conf_ap_ht(wpa_s, current_ssid, conf)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Failed to create new GO config");
+ ret = -1;
+ goto out;
+ }
+
+ if (conf->hw_mode != wpa_s->ap_iface->current_mode->mode) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: CSA to a different band is not supported");
+ ret = -1;
+ goto out;
+ }
+
+ os_memset(&csa_settings, 0, sizeof(csa_settings));
+ csa_settings.cs_count = P2P_GO_CSA_COUNT;
+ csa_settings.block_tx = P2P_GO_CSA_BLOCK_TX;
+ csa_settings.freq_params.freq = params.freq;
+ csa_settings.freq_params.sec_channel_offset = conf->secondary_channel;
+ csa_settings.freq_params.ht_enabled = conf->ieee80211n;
+ csa_settings.freq_params.bandwidth = conf->secondary_channel ? 40 : 20;
+
+ if (conf->ieee80211ac) {
+ int freq1 = 0, freq2 = 0;
+ u8 chan, opclass;
+
+ if (ieee80211_freq_to_channel_ext(params.freq,
+ conf->secondary_channel,
+ conf->vht_oper_chwidth,
+ &opclass, &chan) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "P2P CSA: Bad freq");
+ ret = -1;
+ goto out;
+ }
+
+ if (conf->vht_oper_centr_freq_seg0_idx)
+ freq1 = ieee80211_chan_to_freq(
+ NULL, opclass,
+ conf->vht_oper_centr_freq_seg0_idx);
+
+ if (conf->vht_oper_centr_freq_seg1_idx)
+ freq2 = ieee80211_chan_to_freq(
+ NULL, opclass,
+ conf->vht_oper_centr_freq_seg1_idx);
+
+ if (freq1 < 0 || freq2 < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P CSA: Selected invalid VHT center freqs");
+ ret = -1;
+ goto out;
+ }
+
+ csa_settings.freq_params.vht_enabled = conf->ieee80211ac;
+ csa_settings.freq_params.center_freq1 = freq1;
+ csa_settings.freq_params.center_freq2 = freq2;
+
+ switch (conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ case VHT_CHANWIDTH_80P80MHZ:
+ csa_settings.freq_params.bandwidth = 80;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ csa_settings.freq_params.bandwidth = 160;
+ break;
+ }
+ }
+
+ ret = ap_switch_channel(wpa_s, &csa_settings);
+out:
+ current_ssid->frequency = old_freq;
+ hostapd_config_free(conf);
+ return ret;
}
@@ -8500,7 +9227,7 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
@@ -8537,6 +9264,13 @@ static void wpas_p2p_move_go(void *eloop_ctx, void *timeout_ctx)
wpas_p2p_go_update_common_freqs(wpa_s);
+ /* Do not move GO in the middle of a CSA */
+ if (hostapd_csa_in_progress(wpa_s->ap_iface)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: CSA is in progress - not moving GO");
+ return;
+ }
+
/*
* First, try a channel switch flow. If it is not supported or fails,
* take down the GO and bring it up again.
@@ -8584,16 +9318,20 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s,
unsigned int i, invalid_freq = 0, policy_move = 0, flags = 0;
unsigned int timeout;
int freq;
+ int dfs_offload;
wpas_p2p_go_update_common_freqs(wpa_s);
freq = wpa_s->current_ssid->frequency;
+ dfs_offload = (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
for (i = 0, invalid_freq = 0; i < num; i++) {
if (freqs[i].freq == freq) {
flags = freqs[i].flags;
/* The channel is invalid, must change it */
- if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+ if (!p2p_supported_freq_go(wpa_s->global->p2p, freq) &&
+ !dfs_offload) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P: Freq=%d MHz no longer valid for GO",
freq);
@@ -8603,7 +9341,7 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s,
/* Freq is not used by any other station interface */
continue;
} else if (!p2p_supported_freq(wpa_s->global->p2p,
- freqs[i].freq)) {
+ freqs[i].freq) && !dfs_offload) {
/* Freq is not valid for P2P use cases */
continue;
} else if (wpa_s->conf->p2p_go_freq_change_policy ==
@@ -8613,6 +9351,25 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s,
P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS &&
wpas_p2p_go_is_peer_freq(wpa_s, freqs[i].freq)) {
policy_move = 1;
+ } else if ((wpa_s->conf->p2p_go_freq_change_policy ==
+ P2P_GO_FREQ_MOVE_SCM_ECSA) &&
+ wpas_p2p_go_is_peer_freq(wpa_s, freqs[i].freq)) {
+ if (!p2p_get_group_num_members(wpa_s->p2p_group)) {
+ policy_move = 1;
+ } else if ((wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_AP_CSA) &&
+ wpas_p2p_go_clients_support_ecsa(wpa_s)) {
+ u8 chan;
+
+ /*
+ * We do not support CSA between bands, so move
+ * GO only within the same band.
+ */
+ if (wpa_s->ap_iface->current_mode->mode ==
+ ieee80211_freq_to_chan(freqs[i].freq,
+ &chan))
+ policy_move = 1;
+ }
}
}
@@ -8647,6 +9404,16 @@ static void wpas_p2p_consider_moving_one_go(struct wpa_supplicant *wpa_s,
return;
}
+ /*
+ * Do not consider moving GO if it is in the middle of a CSA. When the
+ * CSA is finished this flow should be retriggered.
+ */
+ if (hostapd_csa_in_progress(wpa_s->ap_iface)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Not initiating a GO frequency change - CSA is in progress");
+ return;
+ }
+
if (invalid_freq && !wpas_p2p_disallowed_freq(wpa_s->global, freq))
timeout = P2P_GO_FREQ_CHANGE_TIME;
else
@@ -8726,3 +9493,86 @@ void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
wpas_p2p_group_deinit(wpa_s);
}
+
+
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ u8 *device_types;
+ size_t dev_types_len;
+ struct wpabuf *buf;
+ int ret;
+
+ if (wpa_s->p2p_lo_started) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P Listen offload is already started");
+ return 0;
+ }
+
+ if (wpa_s->global->p2p == NULL ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "P2P: Listen offload not supported");
+ return -1;
+ }
+
+ if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_ERROR, "P2P: Input channel not supported: %u",
+ freq);
+ return -1;
+ }
+
+ /* Get device type */
+ dev_types_len = (wpa_s->conf->num_sec_device_types + 1) *
+ WPS_DEV_TYPE_LEN;
+ device_types = os_malloc(dev_types_len);
+ if (!device_types)
+ return -1;
+ os_memcpy(device_types, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN);
+ os_memcpy(&device_types[WPS_DEV_TYPE_LEN], wpa_s->conf->sec_device_type,
+ wpa_s->conf->num_sec_device_types * WPS_DEV_TYPE_LEN);
+
+ /* Get Probe Response IE(s) */
+ buf = p2p_build_probe_resp_template(p2p, freq);
+ if (!buf) {
+ os_free(device_types);
+ return -1;
+ }
+
+ ret = wpa_drv_p2p_lo_start(wpa_s, freq, period, interval, count,
+ device_types, dev_types_len,
+ wpabuf_mhead_u8(buf), wpabuf_len(buf));
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to start P2P listen offload");
+
+ os_free(device_types);
+ wpabuf_free(buf);
+
+ if (ret == 0) {
+ wpa_s->p2p_lo_started = 1;
+
+ /* Stop current P2P listen if any */
+ wpas_stop_listen(wpa_s);
+ }
+
+ return ret;
+}
+
+
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ int ret;
+
+ if (!wpa_s->p2p_lo_started)
+ return 0;
+
+ ret = wpa_drv_p2p_lo_stop(wpa_s);
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to stop P2P listen offload");
+
+ wpa_s->p2p_lo_started = 0;
+ return ret;
+}
diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.h b/contrib/wpa/wpa_supplicant/p2p_supplicant.h
index 56e6834..24ec2ca 100644
--- a/contrib/wpa/wpa_supplicant/p2p_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.h
@@ -34,17 +34,22 @@ struct wpa_supplicant * wpas_get_p2p_client_iface(struct wpa_supplicant *wpa_s,
const u8 *peer_dev_addr);
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
- int persistent_group, int auto_join, int join,
- int auth, int go_intent, int freq, int persistent_id,
- int pd, int ht40, int vht);
+ int persistent_group, int auto_join, int join, int auth,
+ int go_intent, int freq, unsigned int vht_center_freq2,
+ int persistent_id, int pd, int ht40, int vht,
+ unsigned int vht_chwidth, int he, const u8 *group_ssid,
+ size_t group_ssid_len);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq, int ht40, int vht);
+ int freq, int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth, int he);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int force_freq, int neg_freq, int ht40,
- int vht, const struct p2p_channels *channels,
+ int force_freq, int neg_freq,
+ int vht_center_freq2, int ht40,
+ int vht, int max_oper_chwidth, int he,
+ const struct p2p_channels *channels,
int connection_timeout, int force_scan);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
@@ -111,7 +116,8 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int ht40, int vht, int pref_freq);
+ int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth, int pref_freq, int he);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
@@ -140,6 +146,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel);
int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel);
unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
const u8 *p2p_dev_addr,
@@ -199,6 +207,11 @@ int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count);
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
+int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s);
#else /* CONFIG_P2P */
diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant_sd.c b/contrib/wpa/wpa_supplicant/p2p_supplicant_sd.c
index fc07b07..f8675e6 100644
--- a/contrib/wpa/wpa_supplicant/p2p_supplicant_sd.c
+++ b/contrib/wpa/wpa_supplicant/p2p_supplicant_sd.c
@@ -48,7 +48,7 @@ static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
u8 *spos_tmp;
/* Offset */
- if (*spos + 2 > end) {
+ if (end - *spos < 2) {
wpa_printf(MSG_DEBUG, "P2P: No room for full "
"DNS offset field");
return -1;
@@ -74,14 +74,14 @@ static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
return 0;
(*spos)++;
- if (*spos + len > end) {
+ if (len > end - *spos) {
wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
"sequence - no room for label with length "
"%u", len);
return -1;
}
- if (*upos + len + 2 > uend)
+ if (len + 2 > uend - *upos)
return -2;
os_memcpy(*upos, *spos, len);
@@ -722,11 +722,11 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
if (resp == NULL)
return;
- while (pos + 1 < end) {
+ while (end - pos > 1) {
wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end || slen < 2) {
+ if (slen > end - pos || slen < 2) {
wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
"length");
wpabuf_free(resp);
@@ -827,10 +827,10 @@ static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
u8 svc_len;
/* Sanity check fixed length+svc_str */
- if (pos + 6 >= tlv_end)
+ if (6 >= tlv_end - pos)
break;
svc_len = pos[6];
- if (pos + svc_len + 10 > tlv_end)
+ if (svc_len + 10 > tlv_end - pos)
break;
/* Advertisement ID */
@@ -917,13 +917,13 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
}
}
- while (pos < end) {
+ while (end - pos >= 2) {
u8 srv_proto, srv_trans_id, status;
wpa_printf(MSG_DEBUG, "P2P: Service Response TLV");
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end || slen < 3) {
+ if (slen > end - pos || slen < 3) {
wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
"length");
return;
diff --git a/contrib/wpa/wpa_supplicant/preauth_test.c b/contrib/wpa/wpa_supplicant/preauth_test.c
index f4bba98..f2fff55 100644
--- a/contrib/wpa/wpa_supplicant/preauth_test.c
+++ b/contrib/wpa/wpa_supplicant/preauth_test.c
@@ -143,16 +143,19 @@ static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
}
-static int wpa_supplicant_add_pmkid(void *wpa_s,
- const u8 *bssid, const u8 *pmkid)
+static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
+ const u8 *bssid, const u8 *pmkid,
+ const u8 *fils_cache_id,
+ const u8 *pmk, size_t pmk_len)
{
printf("%s - not implemented\n", __func__);
return -1;
}
-static int wpa_supplicant_remove_pmkid(void *wpa_s,
- const u8 *bssid, const u8 *pmkid)
+static int wpa_supplicant_remove_pmkid(void *wpa_s, void *network_ctx,
+ const u8 *bssid, const u8 *pmkid,
+ const u8 *fils_cache_id)
{
printf("%s - not implemented\n", __func__);
return -1;
@@ -344,8 +347,8 @@ int main(int argc, char *argv[])
if (preauth_test.auth_timed_out)
ret = -2;
else {
- ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0)
- ? 0 : -3;
+ ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0,
+ NULL, 0) ? 0 : -3;
}
test_eapol_clean(&wpa_s);
diff --git a/contrib/wpa/wpa_supplicant/rrm.c b/contrib/wpa/wpa_supplicant/rrm.c
new file mode 100644
index 0000000..cb3c6c9
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/rrm.c
@@ -0,0 +1,1575 @@
+/*
+ * wpa_supplicant - Radio Measurements
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "p2p_supplicant.h"
+
+
+static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
+{
+ struct rrm_data *rrm = data;
+
+ if (!rrm->notify_neighbor_rep) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Unexpected neighbor report timeout");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
+ rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
+
+ rrm->notify_neighbor_rep = NULL;
+ rrm->neighbor_rep_cb_ctx = NULL;
+}
+
+
+/*
+ * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
+ * @wpa_s: Pointer to wpa_supplicant
+ */
+void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->rrm.rrm_used = 0;
+
+ eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+ NULL);
+ if (wpa_s->rrm.notify_neighbor_rep)
+ wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+ wpa_s->rrm.next_neighbor_rep_token = 1;
+ wpas_clear_beacon_rep_data(wpa_s);
+}
+
+
+/*
+ * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
+ * @wpa_s: Pointer to wpa_supplicant
+ * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
+ * @report_len: Length of neighbor report buffer
+ */
+void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
+ const u8 *report, size_t report_len)
+{
+ struct wpabuf *neighbor_rep;
+
+ wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
+ if (report_len < 1)
+ return;
+
+ if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Discarding neighbor report with token %d (expected %d)",
+ report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
+ return;
+ }
+
+ eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+ NULL);
+
+ if (!wpa_s->rrm.notify_neighbor_rep) {
+ wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+ return;
+ }
+
+ /* skipping the first byte, which is only an id (dialog token) */
+ neighbor_rep = wpabuf_alloc(report_len - 1);
+ if (!neighbor_rep) {
+ wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+ return;
+ }
+ wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
+ wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+ report[0]);
+ wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
+ neighbor_rep);
+ wpa_s->rrm.notify_neighbor_rep = NULL;
+ wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
+}
+
+
+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+/* Workaround different, undefined for Windows, error codes used here */
+#define ENOTCONN -1
+#define EOPNOTSUPP -1
+#define ECANCELED -1
+#endif
+
+/* Measurement Request element + Location Subject + Maximum Age subelement */
+#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
+/* Measurement Request element + Location Civic Request */
+#define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
+
+
+/**
+ * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
+ * is sent in the request.
+ * @lci: if set, neighbor request will include LCI request
+ * @civic: if set, neighbor request will include civic location request
+ * @cb: Callback function to be called once the requested report arrives, or
+ * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
+ * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
+ * the requester's responsibility to free it.
+ * In the latter case NULL will be sent in 'neighbor_rep'.
+ * @cb_ctx: Context value to send the callback function
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ * In case there is a previous request which has not been answered yet, the
+ * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
+ * Request must contain a callback function.
+ */
+int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid_value *ssid,
+ int lci, int civic,
+ void (*cb)(void *ctx,
+ struct wpabuf *neighbor_rep),
+ void *cb_ctx)
+{
+ struct wpabuf *buf;
+ const u8 *rrm_ie;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+ return -ENOTCONN;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+ return -EOPNOTSUPP;
+ }
+
+ rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
+ !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: No network support for Neighbor Report.");
+ return -EOPNOTSUPP;
+ }
+
+ /* Refuse if there's a live request */
+ if (wpa_s->rrm.notify_neighbor_rep) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Currently handling previous Neighbor Report.");
+ return -EBUSY;
+ }
+
+ /* 3 = action category + action code + dialog token */
+ buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
+ (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
+ (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Failed to allocate Neighbor Report Request");
+ return -ENOMEM;
+ }
+
+ wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
+ (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+ wpa_s->rrm.next_neighbor_rep_token);
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
+ wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
+ if (ssid) {
+ wpabuf_put_u8(buf, WLAN_EID_SSID);
+ wpabuf_put_u8(buf, ssid->ssid_len);
+ wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
+ }
+
+ if (lci) {
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
+
+ /*
+ * Measurement token; nonzero number that is unique among the
+ * Measurement Request elements in a particular frame.
+ */
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+
+ /*
+ * Parallel, Enable, Request, and Report bits are 0, Duration is
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
+
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
+ /* Location Subject */
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+ /* Optional Subelements */
+ /*
+ * IEEE P802.11-REVmc/D5.0 Figure 9-170
+ * The Maximum Age subelement is required, otherwise the AP can
+ * send only data that was determined after receiving the
+ * request. Setting it here to unlimited age.
+ */
+ wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+ wpabuf_put_u8(buf, 2);
+ wpabuf_put_le16(buf, 0xffff);
+ }
+
+ if (civic) {
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
+
+ /*
+ * Measurement token; nonzero number that is unique among the
+ * Measurement Request elements in a particular frame.
+ */
+ wpabuf_put_u8(buf, 2); /* Measurement Token */
+
+ /*
+ * Parallel, Enable, Request, and Report bits are 0, Duration is
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ /* Measurement Type */
+ wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
+
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
+ * Location Civic request */
+ /* Location Subject */
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+ wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
+ /* Location Service Interval Units: Seconds */
+ wpabuf_put_u8(buf, 0);
+ /* Location Service Interval: 0 - Only one report is requested
+ */
+ wpabuf_put_le16(buf, 0);
+ /* No optional subelements */
+ }
+
+ wpa_s->rrm.next_neighbor_rep_token++;
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Failed to send Neighbor Report Request");
+ wpabuf_free(buf);
+ return -ECANCELED;
+ }
+
+ wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
+ wpa_s->rrm.notify_neighbor_rep = cb;
+ eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
+ wpas_rrm_neighbor_rep_timeout_handler,
+ &wpa_s->rrm, NULL);
+
+ wpabuf_free(buf);
+ return 0;
+}
+
+
+static int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type,
+ const u8 *data, size_t data_len)
+{
+ if (wpabuf_resize(buf, 5 + data_len))
+ return -1;
+
+ wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(*buf, 3 + data_len);
+ wpabuf_put_u8(*buf, token);
+ wpabuf_put_u8(*buf, mode);
+ wpabuf_put_u8(*buf, type);
+
+ if (data_len)
+ wpabuf_put_data(*buf, data, data_len);
+
+ return 0;
+}
+
+
+static int
+wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
+ const struct rrm_measurement_request_element *req,
+ struct wpabuf **buf)
+{
+ u8 subject;
+ u16 max_age = 0;
+ struct os_reltime t, diff;
+ unsigned long diff_l;
+ const u8 *subelem;
+ const u8 *request = req->variable;
+ size_t len = req->len - 3;
+
+ if (len < 1)
+ return -1;
+
+ if (!wpa_s->lci)
+ goto reject;
+
+ subject = *request++;
+ len--;
+
+ wpa_printf(MSG_DEBUG, "Measurement request location subject=%u",
+ subject);
+
+ if (subject != LOCATION_SUBJECT_REMOTE) {
+ wpa_printf(MSG_INFO,
+ "Not building LCI report - bad location subject");
+ return 0;
+ }
+
+ /* Subelements are formatted exactly like elements */
+ wpa_hexdump(MSG_DEBUG, "LCI request subelements", request, len);
+ subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
+ if (subelem && subelem[1] == 2)
+ max_age = WPA_GET_LE16(subelem + 2);
+
+ if (os_get_reltime(&t))
+ goto reject;
+
+ os_reltime_sub(&t, &wpa_s->lci_time, &diff);
+ /* LCI age is calculated in 10th of a second units. */
+ diff_l = diff.sec * 10 + diff.usec / 100000;
+
+ if (max_age != 0xffff && max_age < diff_l)
+ goto reject;
+
+ if (wpas_rrm_report_elem(buf, req->token,
+ MEASUREMENT_REPORT_MODE_ACCEPT, req->type,
+ wpabuf_head_u8(wpa_s->lci),
+ wpabuf_len(wpa_s->lci)) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to add LCI report element");
+ return -1;
+ }
+
+ return 0;
+
+reject:
+ if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
+ wpas_rrm_report_elem(buf, req->token,
+ MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
+ req->type, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t len)
+{
+ struct wpabuf *report = wpabuf_alloc(len + 3);
+
+ if (!report)
+ return;
+
+ wpabuf_put_u8(report, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(report, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
+ wpabuf_put_u8(report, wpa_s->rrm.token);
+
+ wpabuf_put_data(report, data, len);
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(report), wpabuf_len(report), 0)) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Radio measurement report failed: Sending Action frame failed");
+ }
+
+ wpabuf_free(report);
+}
+
+
+static int wpas_rrm_beacon_rep_update_last_frame(u8 *pos, size_t len)
+{
+ struct rrm_measurement_report_element *msr_rep;
+ u8 *end = pos + len;
+ u8 *msr_rep_end;
+ struct rrm_measurement_beacon_report *rep = NULL;
+ u8 *subelem;
+
+ /* Find the last beacon report element */
+ while (end - pos >= (int) sizeof(*msr_rep)) {
+ msr_rep = (struct rrm_measurement_report_element *) pos;
+ msr_rep_end = pos + msr_rep->len + 2;
+
+ if (msr_rep->eid != WLAN_EID_MEASURE_REPORT ||
+ msr_rep_end > end) {
+ /* Should not happen. This indicates a bug. */
+ wpa_printf(MSG_ERROR,
+ "RRM: non-measurement report element in measurement report frame");
+ return -1;
+ }
+
+ if (msr_rep->type == MEASURE_TYPE_BEACON)
+ rep = (struct rrm_measurement_beacon_report *)
+ msr_rep->variable;
+
+ pos += pos[1] + 2;
+ }
+
+ if (!rep)
+ return 0;
+
+ subelem = rep->variable;
+ while (subelem + 2 < msr_rep_end &&
+ subelem[0] != WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION)
+ subelem += 2 + subelem[1];
+
+ if (subelem + 2 < msr_rep_end &&
+ subelem[0] == WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION &&
+ subelem[1] == 1 &&
+ subelem + BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN <= end)
+ subelem[2] = 1;
+
+ return 0;
+}
+
+
+static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s,
+ struct wpabuf *buf)
+{
+ int len = wpabuf_len(buf);
+ u8 *pos = wpabuf_mhead_u8(buf), *next = pos;
+
+#define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3)
+
+ while (len) {
+ int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len;
+
+ if (send_len == len)
+ wpas_rrm_beacon_rep_update_last_frame(pos, len);
+
+ if (send_len == len ||
+ (send_len + next[1] + 2) > MPDU_REPORT_LEN) {
+ wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len);
+ len -= send_len;
+ pos = next;
+ }
+
+ if (len)
+ next += next[1] + 2;
+ }
+#undef MPDU_REPORT_LEN
+}
+
+
+static int wpas_add_channel(u8 op_class, u8 chan, u8 num_primary_channels,
+ int *freqs)
+{
+ size_t i;
+
+ for (i = 0; i < num_primary_channels; i++) {
+ u8 primary_chan = chan - (2 * num_primary_channels - 2) + i * 4;
+
+ freqs[i] = ieee80211_chan_to_freq(NULL, op_class, primary_chan);
+ /* ieee80211_chan_to_freq() is not really meant for this
+ * conversion of 20 MHz primary channel numbers for wider VHT
+ * channels, so handle those as special cases here for now. */
+ if (freqs[i] < 0 &&
+ (op_class == 128 || op_class == 129 || op_class == 130))
+ freqs[i] = 5000 + 5 * primary_chan;
+ if (freqs[i] < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon Report: Invalid channel %u",
+ chan);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int * wpas_add_channels(const struct oper_class_map *op,
+ struct hostapd_hw_modes *mode, int active,
+ const u8 *channels, const u8 size)
+{
+ int *freqs, *next_freq;
+ u8 num_primary_channels, i;
+ u8 num_chans;
+
+ num_chans = channels ? size :
+ (op->max_chan - op->min_chan) / op->inc + 1;
+
+ if (op->bw == BW80 || op->bw == BW80P80)
+ num_primary_channels = 4;
+ else if (op->bw == BW160)
+ num_primary_channels = 8;
+ else
+ num_primary_channels = 1;
+
+ /* one extra place for the zero-terminator */
+ freqs = os_calloc(num_chans * num_primary_channels + 1, sizeof(*freqs));
+ if (!freqs) {
+ wpa_printf(MSG_ERROR,
+ "Beacon Report: Failed to allocate freqs array");
+ return NULL;
+ }
+
+ next_freq = freqs;
+ for (i = 0; i < num_chans; i++) {
+ u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
+ enum chan_allowed res = verify_channel(mode, chan, op->bw);
+
+ if (res == NOT_ALLOWED || (res == NO_IR && active))
+ continue;
+
+ if (wpas_add_channel(op->op_class, chan, num_primary_channels,
+ next_freq) < 0) {
+ os_free(freqs);
+ return NULL;
+ }
+
+ next_freq += num_primary_channels;
+ }
+
+ if (!freqs[0]) {
+ os_free(freqs);
+ return NULL;
+ }
+
+ return freqs;
+}
+
+
+static int * wpas_op_class_freqs(const struct oper_class_map *op,
+ struct hostapd_hw_modes *mode, int active)
+{
+ u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 };
+ u8 channels_160mhz[] = { 50, 114 };
+
+ /*
+ * When adding all channels in the operating class, 80 + 80 MHz
+ * operating classes are like 80 MHz channels because we add all valid
+ * channels anyway.
+ */
+ if (op->bw == BW80 || op->bw == BW80P80)
+ return wpas_add_channels(op, mode, active, channels_80mhz,
+ ARRAY_SIZE(channels_80mhz));
+
+ if (op->bw == BW160)
+ return wpas_add_channels(op, mode, active, channels_160mhz,
+ ARRAY_SIZE(channels_160mhz));
+
+ return wpas_add_channels(op, mode, active, NULL, 0);
+}
+
+
+static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active,
+ const char *country, const u8 *subelems,
+ size_t len)
+{
+ int *freqs = NULL, *new_freqs;
+ const u8 *end = subelems + len;
+
+ while (end - subelems > 2) {
+ const struct oper_class_map *op;
+ const u8 *ap_chan_elem, *pos;
+ u8 left;
+ struct hostapd_hw_modes *mode;
+
+ ap_chan_elem = get_ie(subelems, end - subelems,
+ WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL);
+ if (!ap_chan_elem)
+ break;
+ pos = ap_chan_elem + 2;
+ left = ap_chan_elem[1];
+ if (left < 1)
+ break;
+ subelems = ap_chan_elem + 2 + left;
+
+ op = get_oper_class(country, *pos);
+ if (!op) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: unknown operating class in AP Channel Report subelement %u",
+ *pos);
+ goto out;
+ }
+ pos++;
+ left--;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ if (!mode)
+ continue;
+
+ /*
+ * For 80 + 80 MHz operating classes, this AP Channel Report
+ * element should be followed by another element specifying
+ * the second 80 MHz channel. For now just add this 80 MHz
+ * channel, the second 80 MHz channel will be added when the
+ * next element is parsed.
+ * TODO: Verify that this AP Channel Report element is followed
+ * by a corresponding AP Channel Report element as specified in
+ * IEEE Std 802.11-2016, 11.11.9.1.
+ */
+ new_freqs = wpas_add_channels(op, mode, active, pos, left);
+ if (new_freqs)
+ int_array_concat(&freqs, new_freqs);
+
+ os_free(new_freqs);
+ }
+
+ return freqs;
+out:
+ os_free(freqs);
+ return NULL;
+}
+
+
+static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s,
+ u8 op_class, u8 chan, int active,
+ const u8 *subelems, size_t len)
+{
+ int *freqs = NULL, *ext_freqs = NULL;
+ struct hostapd_hw_modes *mode;
+ const char *country = NULL;
+ const struct oper_class_map *op;
+ const u8 *elem;
+
+ if (!wpa_s->current_bss)
+ return NULL;
+ elem = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+ if (elem && elem[1] >= 2)
+ country = (const char *) (elem + 2);
+
+ op = get_oper_class(country, op_class);
+ if (!op) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: invalid operating class %d",
+ op_class);
+ return NULL;
+ }
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ if (!mode)
+ return NULL;
+
+ switch (chan) {
+ case 0:
+ freqs = wpas_op_class_freqs(op, mode, active);
+ if (!freqs)
+ return NULL;
+ break;
+ case 255:
+ /* freqs will be added from AP channel subelements */
+ break;
+ default:
+ freqs = wpas_add_channels(op, mode, active, &chan, 1);
+ if (!freqs)
+ return NULL;
+ break;
+ }
+
+ ext_freqs = wpas_channel_report_freqs(wpa_s, active, country, subelems,
+ len);
+ if (ext_freqs) {
+ int_array_concat(&freqs, ext_freqs);
+ os_free(ext_freqs);
+ int_array_sort_unique(freqs);
+ }
+
+ return freqs;
+}
+
+
+static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type)
+{
+ const u8 *ie;
+ int sec_chan = 0, vht = 0;
+ struct ieee80211_ht_operation *ht_oper = NULL;
+ struct ieee80211_vht_operation *vht_oper = NULL;
+ u8 seg0, seg1;
+
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= sizeof(struct ieee80211_ht_operation)) {
+ u8 sec_chan_offset;
+
+ ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+ sec_chan_offset = ht_oper->ht_param &
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ if (sec_chan_offset == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ sec_chan = 1;
+ else if (sec_chan_offset ==
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ sec_chan = -1;
+ }
+
+ ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
+ if (ie && ie[1] >= sizeof(struct ieee80211_vht_operation)) {
+ vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
+
+ switch (vht_oper->vht_op_info_chwidth) {
+ case 1:
+ seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx;
+ seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx;
+ if (seg1 && abs(seg1 - seg0) == 8)
+ vht = VHT_CHANWIDTH_160MHZ;
+ else if (seg1)
+ vht = VHT_CHANWIDTH_80P80MHZ;
+ else
+ vht = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 2:
+ vht = VHT_CHANWIDTH_160MHZ;
+ break;
+ case 3:
+ vht = VHT_CHANWIDTH_80P80MHZ;
+ break;
+ default:
+ vht = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+ }
+
+ if (ieee80211_freq_to_channel_ext(freq, sec_chan, vht, op_class,
+ chan) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "Cannot determine operating class and channel");
+ return -1;
+ }
+
+ *phy_type = ieee80211_get_phy_type(freq, ht_oper != NULL,
+ vht_oper != NULL);
+ if (*phy_type == PHY_TYPE_UNSPECIFIED) {
+ wpa_printf(MSG_DEBUG, "Cannot determine phy type");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
+ enum beacon_report_detail detail,
+ struct wpa_bss *bss, u8 *buf,
+ size_t buf_len, u8 **ies_buf,
+ size_t *ie_len, int add_fixed)
+{
+ u8 *ies = *ies_buf;
+ size_t ies_len = *ie_len;
+ u8 *pos = buf;
+ int rem_len;
+
+ rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) -
+ sizeof(struct rrm_measurement_report_element) - 2 -
+ REPORTED_FRAME_BODY_SUBELEM_LEN;
+
+ if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon Request: Invalid reporting detail: %d",
+ detail);
+ return -1;
+ }
+
+ if (detail == BEACON_REPORT_DETAIL_NONE)
+ return 0;
+
+ /*
+ * Minimal frame body subelement size: EID(1) + length(1) + TSF(8) +
+ * beacon interval(2) + capabilities(2) = 14 bytes
+ */
+ if (add_fixed && buf_len < 14)
+ return -1;
+
+ *pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY;
+ /* The length will be filled later */
+ pos++;
+
+ if (add_fixed) {
+ WPA_PUT_LE64(pos, bss->tsf);
+ pos += sizeof(bss->tsf);
+ WPA_PUT_LE16(pos, bss->beacon_int);
+ pos += 2;
+ WPA_PUT_LE16(pos, bss->caps);
+ pos += 2;
+ }
+
+ rem_len -= pos - buf;
+
+ /*
+ * According to IEEE Std 802.11-2016, 9.4.2.22.7, if the reported frame
+ * body subelement causes the element to exceed the maximum element
+ * size, the subelement is truncated so that the last IE is a complete
+ * IE. So even when required to report all IEs, add elements one after
+ * the other and stop once there is no more room in the measurement
+ * element.
+ */
+ while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) {
+ if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
+ (eids && bitfield_is_set(eids, ies[0]))) {
+ u8 elen = ies[1];
+
+ if (2 + elen > buf + buf_len - pos ||
+ 2 + elen > rem_len)
+ break;
+
+ *pos++ = ies[0];
+ *pos++ = elen;
+ os_memcpy(pos, ies + 2, elen);
+ pos += elen;
+ rem_len -= 2 + elen;
+ }
+
+ ies_len -= 2 + ies[1];
+ ies += 2 + ies[1];
+ }
+
+ *ie_len = ies_len;
+ *ies_buf = ies;
+
+ /* Now the length is known */
+ buf[1] = pos - buf - 2;
+ return pos - buf;
+}
+
+
+static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
+ struct wpa_bss *bss,
+ struct wpabuf **wpa_buf,
+ struct rrm_measurement_beacon_report *rep,
+ u8 **ie, size_t *ie_len, u8 idx)
+{
+ int ret;
+ u8 *buf, *pos;
+ u32 subelems_len = REPORTED_FRAME_BODY_SUBELEM_LEN +
+ (data->last_indication ?
+ BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN : 0);
+
+ /* Maximum element length: Beacon Report element + Reported Frame Body
+ * subelement + all IEs of the reported Beacon frame + Reported Frame
+ * Body Fragment ID subelement */
+ buf = os_malloc(sizeof(*rep) + 14 + *ie_len + subelems_len);
+ if (!buf)
+ return -1;
+
+ os_memcpy(buf, rep, sizeof(*rep));
+
+ ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
+ bss, buf + sizeof(*rep),
+ 14 + *ie_len, ie, ie_len,
+ idx == 0);
+ if (ret < 0)
+ goto out;
+
+ pos = buf + ret + sizeof(*rep);
+ pos[0] = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID;
+ pos[1] = 2;
+
+ /*
+ * Only one Beacon Report Measurement is supported at a time, so
+ * the Beacon Report ID can always be set to 1.
+ */
+ pos[2] = 1;
+
+ /* Fragment ID Number (bits 0..6) and More Frame Body Fragments (bit 7)
+ */
+ pos[3] = idx;
+ if (data->report_detail != BEACON_REPORT_DETAIL_NONE && *ie_len)
+ pos[3] |= REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+ else
+ pos[3] &= ~REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+
+ pos += REPORTED_FRAME_BODY_SUBELEM_LEN;
+
+ if (data->last_indication) {
+ pos[0] = WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION;
+ pos[1] = 1;
+
+ /* This field will be updated later if this is the last frame */
+ pos[2] = 0;
+ }
+
+ ret = wpas_rrm_report_elem(wpa_buf, data->token,
+ MEASUREMENT_REPORT_MODE_ACCEPT,
+ MEASURE_TYPE_BEACON, buf,
+ ret + sizeof(*rep) + subelems_len);
+out:
+ os_free(buf);
+ return ret;
+}
+
+
+static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
+ struct wpabuf **wpa_buf, struct wpa_bss *bss,
+ u64 start, u64 parent_tsf)
+{
+ struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+ u8 *ies = (u8 *) (bss + 1);
+ u8 *pos = ies;
+ size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ struct rrm_measurement_beacon_report rep;
+ u8 idx = 0;
+
+ if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 &&
+ os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0)
+ return 0;
+
+ if (data->ssid_len &&
+ (data->ssid_len != bss->ssid_len ||
+ os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0))
+ return 0;
+
+ if (wpas_get_op_chan_phy(bss->freq, ies, ies_len, &rep.op_class,
+ &rep.channel, &rep.report_info) < 0)
+ return 0;
+
+ rep.start_time = host_to_le64(start);
+ rep.duration = host_to_le16(data->scan_params.duration);
+ rep.rcpi = rssi_to_rcpi(bss->level);
+ rep.rsni = 255; /* 255 indicates that RSNI is not available */
+ os_memcpy(rep.bssid, bss->bssid, ETH_ALEN);
+ rep.antenna_id = 0; /* unknown */
+ rep.parent_tsf = host_to_le32(parent_tsf);
+
+ do {
+ int ret;
+
+ ret = wpas_add_beacon_rep_elem(data, bss, wpa_buf, &rep,
+ &pos, &ies_len, idx++);
+ if (ret)
+ return ret;
+ } while (data->report_detail != BEACON_REPORT_DETAIL_NONE &&
+ ies_len >= 2);
+
+ return 0;
+}
+
+
+static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s,
+ struct wpabuf **buf)
+{
+ return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
+ MEASUREMENT_REPORT_MODE_ACCEPT,
+ MEASURE_TYPE_BEACON, NULL, 0);
+}
+
+
+static void wpas_beacon_rep_table(struct wpa_supplicant *wpa_s,
+ struct wpabuf **buf)
+{
+ size_t i;
+
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (wpas_add_beacon_rep(wpa_s, buf, wpa_s->last_scan_res[i],
+ 0, 0) < 0)
+ break;
+ }
+
+ if (!(*buf))
+ wpas_beacon_rep_no_results(wpa_s, buf);
+
+ wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", *buf);
+}
+
+
+void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s)
+{
+ if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr)) {
+ struct wpabuf *buf = NULL;
+
+ if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token,
+ MEASUREMENT_REPORT_MODE_REJECT_REFUSED,
+ MEASURE_TYPE_BEACON, NULL, 0)) {
+ wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
+ wpabuf_free(buf);
+ return;
+ }
+
+ wpas_rrm_send_msr_report(wpa_s, buf);
+ wpabuf_free(buf);
+ }
+
+ wpas_clear_beacon_rep_data(wpa_s);
+}
+
+
+static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpa_driver_scan_params *params =
+ &wpa_s->beacon_rep_data.scan_params;
+ u16 prev_duration = params->duration;
+
+ if (!wpa_s->current_bss)
+ return;
+
+ if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) &&
+ params->duration) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Cannot set scan duration due to missing driver support");
+ params->duration = 0;
+ }
+ os_get_reltime(&wpa_s->beacon_rep_scan);
+ if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) ||
+ wpa_supplicant_trigger_scan(wpa_s, params))
+ wpas_rrm_refuse_request(wpa_s);
+ params->duration = prev_duration;
+}
+
+
+static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s,
+ struct beacon_rep_data *data,
+ u8 sid, u8 slen, const u8 *subelem)
+{
+ u8 report_info, i;
+
+ switch (sid) {
+ case WLAN_BEACON_REQUEST_SUBELEM_SSID:
+ if (!slen) {
+ wpa_printf(MSG_DEBUG,
+ "SSID subelement with zero length - wildcard SSID");
+ break;
+ }
+
+ if (slen > SSID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid SSID subelement length: %u", slen);
+ return -1;
+ }
+
+ data->ssid_len = slen;
+ os_memcpy(data->ssid, subelem, data->ssid_len);
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_INFO:
+ if (slen != 2) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid reporting information subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ report_info = subelem[0];
+ if (report_info != 0) {
+ wpa_printf(MSG_DEBUG,
+ "reporting information=%u is not supported",
+ report_info);
+ return 0;
+ }
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_DETAIL:
+ if (slen != 1) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid reporting detail subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ data->report_detail = subelem[0];
+ if (data->report_detail >
+ BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
+ wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u",
+ subelem[0]);
+ return -1;
+ }
+
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_REQUEST:
+ if (data->report_detail !=
+ BEACON_REPORT_DETAIL_REQUESTED_ONLY) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: request subelement is present but report detail is %u",
+ data->report_detail);
+ return -1;
+ }
+
+ if (!slen) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid request subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ if (data->eids) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon Request: Request subelement appears more than once");
+ return -1;
+ }
+
+ data->eids = bitfield_alloc(255);
+ if (!data->eids) {
+ wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap");
+ return -1;
+ }
+
+ for (i = 0; i < slen; i++)
+ bitfield_set(data->eids, subelem[i]);
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL:
+ /* Skip - it will be processed when freqs are added */
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION:
+ if (slen != 1) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: Invalid last indication request subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ data->last_indication = subelem[0];
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: Unknown subelement id %u", sid);
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Returns 0 if the next element can be processed, 1 if some operation was
+ * triggered, and -1 if processing failed (i.e., the element is in invalid
+ * format or an internal error occurred).
+ */
+static int
+wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s,
+ u8 elem_token, int duration_mandatory,
+ const struct rrm_measurement_beacon_request *req,
+ size_t len, struct wpabuf **buf)
+{
+ struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+ struct wpa_driver_scan_params *params = &data->scan_params;
+ const u8 *subelems;
+ size_t elems_len;
+ u16 rand_interval;
+ u32 interval_usec;
+ u32 _rand;
+ int ret = 0, res;
+ u8 reject_mode;
+
+ if (len < sizeof(*req))
+ return -1;
+
+ if (req->mode != BEACON_REPORT_MODE_PASSIVE &&
+ req->mode != BEACON_REPORT_MODE_ACTIVE &&
+ req->mode != BEACON_REPORT_MODE_TABLE)
+ return 0;
+
+ subelems = req->variable;
+ elems_len = len - sizeof(*req);
+ rand_interval = le_to_host16(req->rand_interval);
+
+ os_free(params->freqs);
+ os_memset(params, 0, sizeof(*params));
+
+ data->token = elem_token;
+
+ /* default reporting detail is all fixed length fields and all
+ * elements */
+ data->report_detail = BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS;
+ os_memcpy(data->bssid, req->bssid, ETH_ALEN);
+
+ while (elems_len >= 2) {
+ if (subelems[1] > elems_len - 2) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon Request: Truncated subelement");
+ ret = -1;
+ goto out;
+ }
+
+ res = wpas_rm_handle_beacon_req_subelem(
+ wpa_s, data, subelems[0], subelems[1], &subelems[2]);
+ if (res < 0) {
+ ret = res;
+ goto out;
+ } else if (!res) {
+ reject_mode = MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE;
+ goto out_reject;
+ }
+
+ elems_len -= 2 + subelems[1];
+ subelems += 2 + subelems[1];
+ }
+
+ if (req->mode == BEACON_REPORT_MODE_TABLE) {
+ wpas_beacon_rep_table(wpa_s, buf);
+ goto out;
+ }
+
+ params->freqs = wpas_beacon_request_freqs(
+ wpa_s, req->oper_class, req->channel,
+ req->mode == BEACON_REPORT_MODE_ACTIVE,
+ req->variable, len - sizeof(*req));
+ if (!params->freqs) {
+ wpa_printf(MSG_DEBUG, "Beacon request: No valid channels");
+ reject_mode = MEASUREMENT_REPORT_MODE_REJECT_REFUSED;
+ goto out_reject;
+ }
+
+ params->duration = le_to_host16(req->duration);
+ params->duration_mandatory = duration_mandatory;
+ if (!params->duration) {
+ wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0");
+ ret = -1;
+ goto out;
+ }
+
+ params->only_new_results = 1;
+
+ if (req->mode == BEACON_REPORT_MODE_ACTIVE) {
+ params->ssids[params->num_ssids].ssid = data->ssid;
+ params->ssids[params->num_ssids++].ssid_len = data->ssid_len;
+ }
+
+ if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+ _rand = os_random();
+ interval_usec = (_rand % (rand_interval + 1)) * 1024;
+ eloop_register_timeout(0, interval_usec, wpas_rrm_scan_timeout, wpa_s,
+ NULL);
+ return 1;
+out_reject:
+ if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
+ wpas_rrm_report_elem(buf, elem_token, reject_mode,
+ MEASURE_TYPE_BEACON, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+ ret = -1;
+ }
+out:
+ wpas_clear_beacon_rep_data(wpa_s);
+ return ret;
+}
+
+
+static int
+wpas_rrm_handle_msr_req_element(
+ struct wpa_supplicant *wpa_s,
+ const struct rrm_measurement_request_element *req,
+ struct wpabuf **buf)
+{
+ int duration_mandatory;
+
+ wpa_printf(MSG_DEBUG, "Measurement request type %d token %d",
+ req->type, req->token);
+
+ if (req->mode & MEASUREMENT_REQUEST_MODE_ENABLE) {
+ /* Enable bit is not supported for now */
+ wpa_printf(MSG_DEBUG, "RRM: Enable bit not supported, ignore");
+ return 0;
+ }
+
+ if ((req->mode & MEASUREMENT_REQUEST_MODE_PARALLEL) &&
+ req->type > MEASURE_TYPE_RPI_HIST) {
+ /* Parallel measurements are not supported for now */
+ wpa_printf(MSG_DEBUG,
+ "RRM: Parallel measurements are not supported, reject");
+ goto reject;
+ }
+
+ duration_mandatory =
+ !!(req->mode & MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY);
+
+ switch (req->type) {
+ case MEASURE_TYPE_LCI:
+ return wpas_rrm_build_lci_report(wpa_s, req, buf);
+ case MEASURE_TYPE_BEACON:
+ if (duration_mandatory &&
+ !(wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Driver does not support dwell time configuration - reject beacon report with mandatory duration");
+ goto reject;
+ }
+ return wpas_rm_handle_beacon_req(wpa_s, req->token,
+ duration_mandatory,
+ (const void *) req->variable,
+ req->len - 3, buf);
+ default:
+ wpa_printf(MSG_INFO,
+ "RRM: Unsupported radio measurement type %u",
+ req->type);
+ break;
+ }
+
+reject:
+ if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
+ wpas_rrm_report_elem(buf, req->token,
+ MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
+ req->type, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static struct wpabuf *
+wpas_rrm_process_msr_req_elems(struct wpa_supplicant *wpa_s, const u8 *pos,
+ size_t len)
+{
+ struct wpabuf *buf = NULL;
+
+ while (len) {
+ const struct rrm_measurement_request_element *req;
+ int res;
+
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "RRM: Truncated element");
+ goto out;
+ }
+
+ req = (const struct rrm_measurement_request_element *) pos;
+ if (req->eid != WLAN_EID_MEASURE_REQUEST) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Expected Measurement Request element, but EID is %u",
+ req->eid);
+ goto out;
+ }
+
+ if (req->len < 3) {
+ wpa_printf(MSG_DEBUG, "RRM: Element length too short");
+ goto out;
+ }
+
+ if (req->len > len - 2) {
+ wpa_printf(MSG_DEBUG, "RRM: Element length too long");
+ goto out;
+ }
+
+ res = wpas_rrm_handle_msr_req_element(wpa_s, req, &buf);
+ if (res < 0)
+ goto out;
+
+ pos += req->len + 2;
+ len -= req->len + 2;
+ }
+
+ return buf;
+
+out:
+ wpabuf_free(buf);
+ return NULL;
+}
+
+
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *dst,
+ const u8 *frame, size_t len)
+{
+ struct wpabuf *report;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring radio measurement request: Not associated");
+ return;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring radio measurement request: Not RRM network");
+ return;
+ }
+
+ if (len < 3) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring too short radio measurement request");
+ return;
+ }
+
+ wpa_s->rrm.token = *frame;
+ os_memcpy(wpa_s->rrm.dst_addr, dst, ETH_ALEN);
+
+ /* Number of repetitions is not supported */
+
+ report = wpas_rrm_process_msr_req_elems(wpa_s, frame + 3, len - 3);
+ if (!report)
+ return;
+
+ wpas_rrm_send_msr_report(wpa_s, report);
+ wpabuf_free(report);
+}
+
+
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len,
+ int rssi)
+{
+ struct wpabuf *buf;
+ const struct rrm_link_measurement_request *req;
+ struct rrm_link_measurement_report report;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring link measurement request. Not associated");
+ return;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring link measurement request. Not RRM network");
+ return;
+ }
+
+ if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
+ wpa_printf(MSG_INFO,
+ "RRM: Measurement report failed. TX power insertion not supported");
+ return;
+ }
+
+ req = (const struct rrm_link_measurement_request *) frame;
+ if (len < sizeof(*req)) {
+ wpa_printf(MSG_INFO,
+ "RRM: Link measurement report failed. Request too short");
+ return;
+ }
+
+ os_memset(&report, 0, sizeof(report));
+ report.dialog_token = req->dialog_token;
+ report.tpc.eid = WLAN_EID_TPC_REPORT;
+ report.tpc.len = 2;
+ /* Note: The driver is expected to update report.tpc.tx_power and
+ * report.tpc.link_margin subfields when sending out this frame.
+ * Similarly, the driver would need to update report.rx_ant_id and
+ * report.tx_ant_id subfields. */
+ report.rsni = 255; /* 255 indicates that RSNI is not available */
+ report.rcpi = rssi_to_rcpi(rssi);
+
+ /* action_category + action_code */
+ buf = wpabuf_alloc(2 + sizeof(report));
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Link measurement report failed. Buffer allocation failed");
+ return;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
+ wpabuf_put_data(buf, &report, sizeof(report));
+ wpa_hexdump_buf(MSG_DEBUG, "RRM: Link measurement report", buf);
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0)) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Link measurement report failed. Send action failed");
+ }
+ wpabuf_free(buf);
+}
+
+
+int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res,
+ struct scan_info *info)
+{
+ size_t i = 0;
+ struct wpabuf *buf = NULL;
+
+ if (!wpa_s->beacon_rep_data.token)
+ return 0;
+
+ if (!wpa_s->current_bss)
+ goto out;
+
+ /* If the measurement was aborted, don't report partial results */
+ if (info->aborted)
+ goto out;
+
+ wpa_printf(MSG_DEBUG, "RRM: TSF BSSID: " MACSTR " current BSS: " MACSTR,
+ MAC2STR(info->scan_start_tsf_bssid),
+ MAC2STR(wpa_s->current_bss->bssid));
+ if ((wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) &&
+ os_memcmp(info->scan_start_tsf_bssid, wpa_s->current_bss->bssid,
+ ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Ignore scan results due to mismatching TSF BSSID");
+ goto out;
+ }
+
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_bss *bss =
+ wpa_bss_get_bssid(wpa_s, scan_res->res[i]->bssid);
+
+ if (!bss)
+ continue;
+
+ if ((wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) &&
+ os_memcmp(scan_res->res[i]->tsf_bssid,
+ wpa_s->current_bss->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Ignore scan result for " MACSTR
+ " due to mismatching TSF BSSID" MACSTR,
+ MAC2STR(scan_res->res[i]->bssid),
+ MAC2STR(scan_res->res[i]->tsf_bssid));
+ continue;
+ }
+
+ /*
+ * Don't report results that were not received during the
+ * current measurement.
+ */
+ if (!(wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT)) {
+ struct os_reltime update_time, diff;
+
+ /* For now, allow 8 ms older results due to some
+ * unknown issue with cfg80211 BSS table updates during
+ * a scan with the current BSS.
+ * TODO: Fix this more properly to avoid having to have
+ * this type of hacks in place. */
+ calculate_update_time(&scan_res->fetch_time,
+ scan_res->res[i]->age,
+ &update_time);
+ os_reltime_sub(&wpa_s->beacon_rep_scan,
+ &update_time, &diff);
+ if (os_reltime_before(&update_time,
+ &wpa_s->beacon_rep_scan) &&
+ (diff.sec || diff.usec >= 8000)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Ignore scan result for " MACSTR
+ " due to old update (age(ms) %u, calculated age %u.%06u seconds)",
+ MAC2STR(scan_res->res[i]->bssid),
+ scan_res->res[i]->age,
+ (unsigned int) diff.sec,
+ (unsigned int) diff.usec);
+ continue;
+ }
+ } else if (info->scan_start_tsf >
+ scan_res->res[i]->parent_tsf) {
+ continue;
+ }
+
+ if (wpas_add_beacon_rep(wpa_s, &buf, bss, info->scan_start_tsf,
+ scan_res->res[i]->parent_tsf) < 0)
+ break;
+ }
+
+ if (!buf && wpas_beacon_rep_no_results(wpa_s, &buf))
+ goto out;
+
+ wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", buf);
+
+ wpas_rrm_send_msr_report(wpa_s, buf);
+ wpabuf_free(buf);
+
+out:
+ wpas_clear_beacon_rep_data(wpa_s);
+ return 1;
+}
+
+
+void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s)
+{
+ struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+
+ eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL);
+ bitfield_free(data->eids);
+ os_free(data->scan_params.freqs);
+ os_memset(data, 0, sizeof(*data));
+}
diff --git a/contrib/wpa/wpa_supplicant/scan.c b/contrib/wpa/wpa_supplicant/scan.c
index d7049a1..7abb028 100644
--- a/contrib/wpa/wpa_supplicant/scan.c
+++ b/contrib/wpa/wpa_supplicant/scan.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Scanning
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -36,8 +36,7 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
if (wpa_s->current_ssid == NULL) {
wpa_s->current_ssid = ssid;
- if (wpa_s->current_ssid != NULL)
- wpas_notify_network_changed(wpa_s);
+ wpas_notify_network_changed(wpa_s);
}
wpa_supplicant_initiate_eapol(wpa_s);
wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
@@ -60,10 +59,7 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
wps = 1;
*req_type = wpas_wps_get_req_type(ssid);
- if (!ssid->eap.phase1)
- continue;
-
- if (os_strstr(ssid->eap.phase1, "pbc=1"))
+ if (ssid->eap.phase1 && os_strstr(ssid->eap.phase1, "pbc=1"))
return 2;
}
@@ -121,9 +117,19 @@ int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ int min_temp_disabled = 0;
+
while (ssid) {
- if (!wpas_network_disabled(wpa_s, ssid))
- break;
+ if (!wpas_network_disabled(wpa_s, ssid)) {
+ int temp_disabled = wpas_temp_disabled(wpa_s, ssid);
+
+ if (temp_disabled <= 0)
+ break;
+
+ if (!min_temp_disabled ||
+ temp_disabled < min_temp_disabled)
+ min_temp_disabled = temp_disabled;
+ }
ssid = ssid->next;
}
@@ -132,7 +138,7 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached "
"end of scan list - go back to beginning");
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ wpa_supplicant_req_scan(wpa_s, min_temp_disabled, 0);
return;
}
if (ssid->next) {
@@ -166,6 +172,8 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for a scan");
+ wpa_scan_free_params(params);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
radio_work_done(work);
return;
}
@@ -178,10 +186,22 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
params->only_new_results = 1;
}
ret = wpa_drv_scan(wpa_s, params);
+ /*
+ * Store the obtained vendor scan cookie (if any) in wpa_s context.
+ * The current design is to allow only one scan request on each
+ * interface, hence having this scan cookie stored in wpa_s context is
+ * fine for now.
+ *
+ * Revisit this logic if concurrent scan operations per interface
+ * is supported.
+ */
+ if (ret == 0)
+ wpa_s->curr_scan_cookie = params->scan_cookie;
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
- int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ;
+ int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
+ !wpa_s->beacon_rep_data.token;
if (wpa_s->disconnected)
retry = 0;
@@ -199,7 +219,14 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
/* Restore scan_req since we will try to scan again */
wpa_s->scan_req = wpa_s->last_scan_req;
wpa_supplicant_req_scan(wpa_s, 1, 0);
+ } else if (wpa_s->scan_res_handler) {
+ /* Clear the scan_res_handler */
+ wpa_s->scan_res_handler = NULL;
}
+
+ if (wpa_s->beacon_rep_data.token)
+ wpas_rrm_refuse_request(wpa_s);
+
return;
}
@@ -229,12 +256,11 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
}
ctx = wpa_scan_clone_params(params);
- if (ctx == NULL)
- return -1;
-
- if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+ if (!ctx ||
+ radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
{
wpa_scan_free_params(ctx);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
return -1;
}
@@ -266,14 +292,14 @@ wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
}
-int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- int interval)
+static int
+wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
{
int ret;
wpa_supplicant_notify_scanning(wpa_s, 1);
- ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
+ ret = wpa_drv_sched_scan(wpa_s, params);
if (ret)
wpa_supplicant_notify_scanning(wpa_s, 0);
else
@@ -283,7 +309,7 @@ int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
}
-int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
{
int ret;
@@ -429,6 +455,68 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_MBO
+static void wpas_fils_req_param_add_max_channel(struct wpa_supplicant *wpa_s,
+ struct wpabuf **ie)
+{
+ if (wpabuf_resize(ie, 5)) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate space for FILS Request Parameters element");
+ return;
+ }
+
+ /* FILS Request Parameters element */
+ wpabuf_put_u8(*ie, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(*ie, 3); /* FILS Request attribute length */
+ wpabuf_put_u8(*ie, WLAN_EID_EXT_FILS_REQ_PARAMS);
+ /* Parameter control bitmap */
+ wpabuf_put_u8(*ie, 0);
+ /* Max Channel Time field - contains the value of MaxChannelTime
+ * parameter of the MLME-SCAN.request primitive represented in units of
+ * TUs, as an unsigned integer. A Max Channel Time field value of 255
+ * is used to indicate any duration of more than 254 TUs, or an
+ * unspecified or unknown duration. (IEEE Std 802.11ai-2016, 9.4.2.178)
+ */
+ wpabuf_put_u8(*ie, 255);
+}
+#endif /* CONFIG_MBO */
+
+
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *default_ies = NULL;
+ u8 ext_capab[18];
+ int ext_capab_len;
+ enum wpa_driver_if_type type = WPA_IF_STATION;
+
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+ type = WPA_IF_P2P_CLIENT;
+#endif /* CONFIG_P2P */
+
+ wpa_drv_get_ext_capa(wpa_s, type);
+
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
+ sizeof(ext_capab));
+ if (ext_capab_len > 0 &&
+ wpabuf_resize(&default_ies, ext_capab_len) == 0)
+ wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
+
+#ifdef CONFIG_MBO
+ if (wpa_s->enable_oce & OCE_STA)
+ wpas_fils_req_param_add_max_channel(wpa_s, &default_ies);
+ /* Send MBO and OCE capabilities */
+ if (wpabuf_resize(&default_ies, 12) == 0)
+ wpas_mbo_scan_ie(wpa_s, default_ies);
+#endif /* CONFIG_MBO */
+
+ if (default_ies)
+ wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
+ wpabuf_len(default_ies));
+ wpabuf_free(default_ies);
+}
+
+
static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
{
struct wpabuf *extra_ie = NULL;
@@ -439,6 +527,13 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+#endif /* CONFIG_P2P */
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
sizeof(ext_capab));
if (ext_capab_len > 0 &&
@@ -451,6 +546,11 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
wpas_add_interworking_elements(wpa_s, extra_ie);
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_MBO
+ if (wpa_s->enable_oce & OCE_STA)
+ wpas_fils_req_param_add_max_channel(wpa_s, &extra_ie);
+#endif /* CONFIG_MBO */
+
#ifdef CONFIG_WPS
wps = wpas_wps_in_use(wpa_s, &req_type);
@@ -481,8 +581,8 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
- if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
- wpas_hs20_add_indication(extra_ie, -1);
+ if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 9) == 0)
+ wpas_hs20_add_indication(extra_ie, -1, 0);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
@@ -491,6 +591,19 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
wpabuf_put_buf(extra_ie, wpa_s->fst_ies);
#endif /* CONFIG_FST */
+#ifdef CONFIG_MBO
+ /* Send MBO and OCE capabilities */
+ if (wpabuf_resize(&extra_ie, 12) == 0)
+ wpas_mbo_scan_ie(wpa_s, extra_ie);
+#endif /* CONFIG_MBO */
+
+ if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) {
+ struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ];
+
+ if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0)
+ wpabuf_put_buf(extra_ie, buf);
+ }
+
return extra_ie;
}
@@ -522,21 +635,6 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_P2P */
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes,
- enum hostapd_hw_mode mode)
-{
- u16 i;
-
- for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
- return &modes[i];
- }
-
- return NULL;
-}
-
-
static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
enum hostapd_hw_mode band,
struct wpa_driver_scan_params *params)
@@ -579,6 +677,87 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
}
+static void wpa_add_scan_ssid(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ size_t max_ssids, const u8 *ssid, size_t ssid_len)
+{
+ unsigned int j;
+
+ for (j = 0; j < params->num_ssids; j++) {
+ if (params->ssids[j].ssid_len == ssid_len &&
+ params->ssids[j].ssid &&
+ os_memcmp(params->ssids[j].ssid, ssid, ssid_len) == 0)
+ return; /* already in the list */
+ }
+
+ if (params->num_ssids + 1 > max_ssids) {
+ wpa_printf(MSG_DEBUG, "Over max scan SSIDs for manual request");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s",
+ wpa_ssid_txt(ssid, ssid_len));
+
+ params->ssids[params->num_ssids].ssid = ssid;
+ params->ssids[params->num_ssids].ssid_len = ssid_len;
+ params->num_ssids++;
+}
+
+
+static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ struct wpa_ssid *ssid, size_t max_ssids)
+{
+#ifdef CONFIG_OWE
+ struct wpa_bss *bss;
+
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+ return;
+
+ wpa_printf(MSG_DEBUG, "OWE: Look for transition mode AP. ssid=%s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ const u8 *owe, *pos, *end;
+ const u8 *owe_ssid;
+ size_t owe_ssid_len;
+
+ if (bss->ssid_len != ssid->ssid_len ||
+ os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) != 0)
+ continue;
+
+ owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+ if (!owe || owe[1] < 4)
+ continue;
+
+ pos = owe + 6;
+ end = owe + 2 + owe[1];
+
+ /* Must include BSSID and ssid_len */
+ if (end - pos < ETH_ALEN + 1)
+ return;
+
+ /* Skip BSSID */
+ pos += ETH_ALEN;
+ owe_ssid_len = *pos++;
+ owe_ssid = pos;
+
+ if ((size_t) (end - pos) < owe_ssid_len ||
+ owe_ssid_len > SSID_MAX_LEN)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "OWE: scan_ssids: transition mode OWE ssid=%s",
+ wpa_ssid_txt(owe_ssid, owe_ssid_len));
+
+ wpa_add_scan_ssid(wpa_s, params, max_ssids,
+ owe_ssid, owe_ssid_len);
+ return;
+ }
+#endif /* CONFIG_OWE */
+}
+
+
static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params,
size_t max_ssids)
@@ -586,34 +765,24 @@ static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
unsigned int i;
struct wpa_ssid *ssid;
- for (i = 0; i < wpa_s->scan_id_count; i++) {
- unsigned int j;
+ /*
+ * For devices with max_ssids greater than 1, leave the last slot empty
+ * for adding the wildcard scan entry.
+ */
+ max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
+ for (i = 0; i < wpa_s->scan_id_count; i++) {
ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]);
- if (!ssid || !ssid->scan_ssid)
+ if (!ssid)
continue;
-
- for (j = 0; j < params->num_ssids; j++) {
- if (params->ssids[j].ssid_len == ssid->ssid_len &&
- params->ssids[j].ssid &&
- os_memcmp(params->ssids[j].ssid, ssid->ssid,
- ssid->ssid_len) == 0)
- break;
- }
- if (j < params->num_ssids)
- continue; /* already in the list */
-
- if (params->num_ssids + 1 > max_ssids) {
- wpa_printf(MSG_DEBUG,
- "Over max scan SSIDs for manual request");
- break;
- }
-
- wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- params->ssids[params->num_ssids].ssid = ssid->ssid;
- params->ssids[params->num_ssids].ssid_len = ssid->ssid_len;
- params->num_ssids++;
+ if (ssid->scan_ssid)
+ wpa_add_scan_ssid(wpa_s, params, max_ssids,
+ ssid->ssid, ssid->ssid_len);
+ /*
+ * Also add the SSID of the OWE BSS, to allow discovery of
+ * transition mode APs more quickly.
+ */
+ wpa_add_owe_scan_ssid(wpa_s, params, ssid, max_ssids);
}
wpa_s->scan_id_count = 0;
@@ -662,10 +831,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
size_t max_ssids;
int connect_without_scan = 0;
- if (wpa_s->pno || wpa_s->pno_sched_pending) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
- return;
- }
+ wpa_s->ignore_post_flush_scan_res = 0;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
@@ -727,6 +893,21 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
return;
}
+ /*
+ * Don't cancel the scan based on ongoing PNO; defer it. Some scans are
+ * used for changing modes inside wpa_supplicant (roaming,
+ * auto-reconnect, etc). Discarding the scan might hurt these processes.
+ * The normal use case for PNO is to suspend the host immediately after
+ * starting PNO, so the periodic 100 ms attempts to run the scan do not
+ * normally happen in practice multiple times, i.e., this is simply
+ * restarting scanning once the host is woken up and PNO stopped.
+ */
+ if (wpa_s->pno || wpa_s->pno_sched_pending) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress");
+ wpa_supplicant_req_scan(wpa_s, 0, 100000);
+ return;
+ }
+
if (wpa_s->conf->ap_scan == 2)
max_ssids = 1;
else {
@@ -840,12 +1021,10 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
* slot for the zero-terminator.
*/
params.freqs = os_malloc(sizeof(int) * 2);
- if (params.freqs == NULL) {
- wpa_dbg(wpa_s, MSG_ERROR, "Memory allocation failed");
- return;
+ if (params.freqs) {
+ params.freqs[0] = wpa_s->assoc_freq;
+ params.freqs[1] = 0;
}
- params.freqs[0] = wpa_s->assoc_freq;
- params.freqs[1] = 0;
/*
* Reset the reattach flag so that we fall back to full scan if
@@ -870,6 +1049,17 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
if (params.num_ssids + 1 >= max_ssids)
break;
}
+
+ if (!wpas_network_disabled(wpa_s, ssid)) {
+ /*
+ * Also add the SSID of the OWE BSS, to allow
+ * discovery of transition mode APs more
+ * quickly.
+ */
+ wpa_add_owe_scan_ssid(wpa_s, &params, ssid,
+ max_ssids);
+ }
+
ssid = ssid->next;
if (ssid == start)
break;
@@ -956,6 +1146,13 @@ ssid_list_set:
wpa_s->manual_scan_freqs = NULL;
}
+ if (params.freqs == NULL && wpa_s->select_network_scan_freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Limit select_network scan to specified channels");
+ params.freqs = wpa_s->select_network_scan_freqs;
+ wpa_s->select_network_scan_freqs = NULL;
+ }
+
if (params.freqs == NULL && wpa_s->next_scan_freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
"generated frequency list");
@@ -990,6 +1187,11 @@ ssid_list_set:
}
}
+#ifdef CONFIG_MBO
+ if (wpa_s->enable_oce & OCE_STA)
+ params.oce_scan = 1;
+#endif /* CONFIG_MBO */
+
params.filter_ssids = wpa_supplicant_build_filter_ssids(
wpa_s->conf, &params.num_filter_ssids);
if (extra_ie) {
@@ -1008,7 +1210,8 @@ ssid_list_set:
}
#endif /* CONFIG_P2P */
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_scan) {
params.mac_addr = wpa_s->mac_addr_scan;
@@ -1016,6 +1219,27 @@ ssid_list_set:
}
}
+ if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
+ struct wpa_bss *bss;
+
+ params.bssid = wpa_s->next_scan_bssid;
+ bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
+ if (bss && bss->ssid_len && params.num_ssids == 1 &&
+ params.ssids[0].ssid_len == 0) {
+ params.ssids[0].ssid = bss->ssid;
+ params.ssids[0].ssid_len = bss->ssid_len;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Scan a previously specified BSSID " MACSTR
+ " and SSID %s",
+ MAC2STR(params.bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Scan a previously specified BSSID " MACSTR,
+ MAC2STR(params.bssid));
+ }
+ }
+
scan_params = &params;
scan:
@@ -1076,6 +1300,8 @@ scan:
#ifdef CONFIG_INTERWORKING
wpa_s->interworking_fast_assoc_tried = 0;
#endif /* CONFIG_INTERWORKING */
+ if (params.bssid)
+ os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
}
}
@@ -1163,6 +1389,26 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
}
+static void
+wpa_scan_set_relative_rssi_params(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
+{
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI) ||
+ wpa_s->srp.relative_rssi_set == 0)
+ return;
+
+ params->relative_rssi_set = 1;
+ params->relative_rssi = wpa_s->srp.relative_rssi;
+
+ if (wpa_s->srp.relative_adjust_rssi == 0)
+ return;
+
+ params->relative_adjust_band = wpa_s->srp.relative_adjust_band;
+ params->relative_adjust_rssi = wpa_s->srp.relative_adjust_rssi;
+}
+
+
/**
* wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
* @wpa_s: Pointer to wpa_supplicant data
@@ -1182,6 +1428,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
unsigned int max_sched_scan_ssids;
int wildcard = 0;
int need_ssids;
+ struct sched_scan_plan scan_plan;
if (!wpa_s->sched_scan_supported)
return -1;
@@ -1193,6 +1440,8 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
return -1;
+ wpa_s->sched_scan_stop_req = 0;
+
if (wpa_s->sched_scanning) {
wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
return 0;
@@ -1271,11 +1520,6 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
if (!ssid || !wpa_s->prev_sched_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
- if (wpa_s->conf->sched_scan_interval)
- wpa_s->sched_scan_interval =
- wpa_s->conf->sched_scan_interval;
- if (wpa_s->sched_scan_interval == 0)
- wpa_s->sched_scan_interval = 10;
wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
wpa_s->first_sched_scan = 1;
ssid = wpa_s->conf->ssid;
@@ -1357,22 +1601,70 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
int_array_concat(&params.freqs, wpa_s->conf->freq_list);
}
+#ifdef CONFIG_MBO
+ if (wpa_s->enable_oce & OCE_STA)
+ params.oce_scan = 1;
+#endif /* CONFIG_MBO */
+
scan_params = &params;
scan:
+ wpa_s->sched_scan_timed_out = 0;
+
+ /*
+ * We cannot support multiple scan plans if the scan request includes
+ * too many SSID's, so in this case use only the last scan plan and make
+ * it run infinitely. It will be stopped by the timeout.
+ */
+ if (wpa_s->sched_scan_plans_num == 1 ||
+ (wpa_s->sched_scan_plans_num && !ssid && wpa_s->first_sched_scan)) {
+ params.sched_scan_plans = wpa_s->sched_scan_plans;
+ params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
+ } else if (wpa_s->sched_scan_plans_num > 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Too many SSIDs. Default to using single scheduled_scan plan");
+ params.sched_scan_plans =
+ &wpa_s->sched_scan_plans[wpa_s->sched_scan_plans_num -
+ 1];
+ params.sched_scan_plans_num = 1;
+ } else {
+ if (wpa_s->conf->sched_scan_interval)
+ scan_plan.interval = wpa_s->conf->sched_scan_interval;
+ else
+ scan_plan.interval = 10;
+
+ if (scan_plan.interval > wpa_s->max_sched_scan_plan_interval) {
+ wpa_printf(MSG_WARNING,
+ "Scan interval too long(%u), use the maximum allowed(%u)",
+ scan_plan.interval,
+ wpa_s->max_sched_scan_plan_interval);
+ scan_plan.interval =
+ wpa_s->max_sched_scan_plan_interval;
+ }
+
+ scan_plan.iterations = 0;
+ params.sched_scan_plans = &scan_plan;
+ params.sched_scan_plans_num = 1;
+ }
+
+ params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay;
+
if (ssid || !wpa_s->first_sched_scan) {
wpa_dbg(wpa_s, MSG_DEBUG,
- "Starting sched scan: interval %d timeout %d",
- wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+ "Starting sched scan after %u seconds: interval %u timeout %d",
+ params.sched_scan_start_delay,
+ params.sched_scan_plans[0].interval,
+ wpa_s->sched_scan_timeout);
} else {
wpa_dbg(wpa_s, MSG_DEBUG,
- "Starting sched scan: interval %d (no timeout)",
- wpa_s->sched_scan_interval);
+ "Starting sched scan after %u seconds (no timeout)",
+ params.sched_scan_start_delay);
}
wpa_setband_scan_freqs(wpa_s, scan_params);
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_sched_scan) {
params.mac_addr = wpa_s->mac_addr_sched_scan;
@@ -1381,8 +1673,9 @@ scan:
}
}
- ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
- wpa_s->sched_scan_interval);
+ wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
+
+ ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
if (ret) {
@@ -1400,9 +1693,12 @@ scan:
wpa_s, NULL);
wpa_s->first_sched_scan = 0;
wpa_s->sched_scan_timeout /= 2;
- wpa_s->sched_scan_interval *= 2;
- if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) {
- wpa_s->sched_scan_interval = 10;
+ params.sched_scan_plans[0].interval *= 2;
+ if ((unsigned int) wpa_s->sched_scan_timeout <
+ params.sched_scan_plans[0].interval ||
+ params.sched_scan_plans[0].interval >
+ wpa_s->max_sched_scan_plan_interval) {
+ params.sched_scan_plans[0].interval = 10;
wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
}
}
@@ -1457,6 +1753,9 @@ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
if (!wpa_s->sched_scanning)
return;
+ if (wpa_s->sched_scanning)
+ wpa_s->sched_scan_stop_req = 1;
+
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
wpa_supplicant_stop_sched_scan(wpa_s);
@@ -1516,20 +1815,13 @@ static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
*/
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
{
- const u8 *end, *pos;
+ size_t ie_len = res->ie_len;
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
+ /* Use the Beacon frame IEs if res->ie_len is not available */
+ if (!ie_len)
+ ie_len = res->beacon_ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
+ return get_ie((const u8 *) (res + 1), ie_len, ie);
}
@@ -1550,8 +1842,8 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
pos = (const u8 *) (res + 1);
end = pos + res->ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1587,8 +1879,8 @@ const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
pos += res->ie_len;
end = pos + res->beacon_ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1623,8 +1915,8 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
pos = (const u8 *) (res + 1);
end = pos + res->ie_len;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
+ while (end - pos > 1) {
+ if (2 + pos[1] > end - pos)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
vendor_type == WPA_GET_BE32(&pos[2]))
@@ -1646,10 +1938,12 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
* This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
* rule of thumb is that any SNR above 20 is good." This one
* http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
- * recommends 25 as a minimum SNR for 54 Mbps data rate. 30 is chosen here as a
- * conservative value.
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
+ * scan_est_throughput() allow even smaller SNR values for the maximum rates
+ * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
+ * somewhat conservative value here.
*/
-#define GREAT_SNR 30
+#define GREAT_SNR 25
#define IS_5GHZ(n) (n > 4000)
@@ -1697,10 +1991,13 @@ static int wpa_scan_result_compar(const void *a, const void *b)
}
/* if SNR is close, decide by max rate or frequency band */
+ if (snr_a && snr_b && abs(snr_b - snr_a) < 7) {
+ if (wa->est_throughput != wb->est_throughput)
+ return (int) wb->est_throughput -
+ (int) wa->est_throughput;
+ }
if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
(wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
- if (wa->est_throughput != wb->est_throughput)
- return wb->est_throughput - wa->est_throughput;
if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
return IS_5GHZ(wa->freq) ? -1 : 1;
}
@@ -1832,8 +2129,8 @@ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
}
-static void filter_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *res)
+void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res)
{
size_t i, j;
@@ -1860,13 +2157,13 @@ static void filter_scan_res(struct wpa_supplicant *wpa_s,
/*
* Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurments. These values were
+ * measurements, but no noise floor measurements. These values were
* measured in an office environment with many APs.
*/
#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
-static void scan_snr(struct wpa_scan_res *res)
+void scan_snr(struct wpa_scan_res *res)
{
if (res->flags & WPA_SCAN_NOISE_INVALID) {
res->noise = IS_5GHZ(res->freq) ?
@@ -1950,8 +2247,8 @@ static unsigned int max_vht80_rate(int snr)
}
-static void scan_est_throughput(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
{
enum local_hw_capab capab = wpa_s->hw_capab;
int rate; /* max legacy rate in 500 kb/s units */
@@ -2088,10 +2385,22 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_WPS */
- qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
- compar);
+ if (scan_res->res) {
+ qsort(scan_res->res, scan_res->num,
+ sizeof(struct wpa_scan_res *), compar);
+ }
dump_scan_res(scan_res);
+ if (wpa_s->ignore_post_flush_scan_res) {
+ /* FLUSH command aborted an ongoing scan and these are the
+ * results from the aborted scan. Do not process the results to
+ * maintain flushed state. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Do not update BSS table based on pending post-FLUSH scan results");
+ wpa_s->ignore_post_flush_scan_res = 0;
+ return scan_res;
+ }
+
wpa_bss_update_start(wpa_s);
for (i = 0; i < scan_res->num; i++)
wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
@@ -2148,6 +2457,9 @@ void scan_only_handler(struct wpa_supplicant *wpa_s,
wpa_s->scan_work = NULL;
radio_work_done(work);
}
+
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
}
@@ -2170,11 +2482,10 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
for (i = 0; i < src->num_ssids; i++) {
if (src->ssids[i].ssid) {
- n = os_malloc(src->ssids[i].ssid_len);
+ n = os_memdup(src->ssids[i].ssid,
+ src->ssids[i].ssid_len);
if (n == NULL)
goto failed;
- os_memcpy(n, src->ssids[i].ssid,
- src->ssids[i].ssid_len);
params->ssids[i].ssid = n;
params->ssids[i].ssid_len = src->ssids[i].ssid_len;
}
@@ -2182,30 +2493,26 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->num_ssids = src->num_ssids;
if (src->extra_ies) {
- n = os_malloc(src->extra_ies_len);
+ n = os_memdup(src->extra_ies, src->extra_ies_len);
if (n == NULL)
goto failed;
- os_memcpy(n, src->extra_ies, src->extra_ies_len);
params->extra_ies = n;
params->extra_ies_len = src->extra_ies_len;
}
if (src->freqs) {
int len = int_array_len(src->freqs);
- params->freqs = os_malloc((len + 1) * sizeof(int));
+ params->freqs = os_memdup(src->freqs, (len + 1) * sizeof(int));
if (params->freqs == NULL)
goto failed;
- os_memcpy(params->freqs, src->freqs, (len + 1) * sizeof(int));
}
if (src->filter_ssids) {
- params->filter_ssids = os_malloc(sizeof(*params->filter_ssids) *
+ params->filter_ssids = os_memdup(src->filter_ssids,
+ sizeof(*params->filter_ssids) *
src->num_filter_ssids);
if (params->filter_ssids == NULL)
goto failed;
- os_memcpy(params->filter_ssids, src->filter_ssids,
- sizeof(*params->filter_ssids) *
- src->num_filter_ssids);
params->num_filter_ssids = src->num_filter_ssids;
}
@@ -2213,6 +2520,20 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->p2p_probe = src->p2p_probe;
params->only_new_results = src->only_new_results;
params->low_priority = src->low_priority;
+ params->duration = src->duration;
+ params->duration_mandatory = src->duration_mandatory;
+ params->oce_scan = src->oce_scan;
+
+ if (src->sched_scan_plans_num > 0) {
+ params->sched_scan_plans =
+ os_memdup(src->sched_scan_plans,
+ sizeof(*src->sched_scan_plans) *
+ src->sched_scan_plans_num);
+ if (!params->sched_scan_plans)
+ goto failed;
+
+ params->sched_scan_plans_num = src->sched_scan_plans_num;
+ }
if (src->mac_addr_rand) {
params->mac_addr_rand = src->mac_addr_rand;
@@ -2231,6 +2552,20 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->mac_addr_mask = mac_addr + ETH_ALEN;
}
}
+
+ if (src->bssid) {
+ u8 *bssid;
+
+ bssid = os_memdup(src->bssid, ETH_ALEN);
+ if (!bssid)
+ goto failed;
+ params->bssid = bssid;
+ }
+
+ params->relative_rssi_set = src->relative_rssi_set;
+ params->relative_rssi = src->relative_rssi;
+ params->relative_adjust_band = src->relative_adjust_band;
+ params->relative_adjust_rssi = src->relative_adjust_rssi;
return params;
failed:
@@ -2251,6 +2586,7 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
os_free((u8 *) params->extra_ies);
os_free(params->freqs);
os_free(params->filter_ssids);
+ os_free(params->sched_scan_plans);
/*
* Note: params->mac_addr_mask points to same memory allocation and
@@ -2258,25 +2594,36 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
*/
os_free((u8 *) params->mac_addr);
+ os_free((u8 *) params->bssid);
+
os_free(params);
}
int wpas_start_pno(struct wpa_supplicant *wpa_s)
{
- int ret, interval, prio;
+ int ret, prio;
size_t i, num_ssid, num_match_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
+ struct sched_scan_plan scan_plan;
+ unsigned int max_sched_scan_ssids;
if (!wpa_s->sched_scan_supported)
return -1;
+ if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
+ max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
+ else
+ max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
+ if (max_sched_scan_ssids < 1)
+ return -1;
+
if (wpa_s->pno || wpa_s->pno_sched_pending)
return 0;
if ((wpa_s->wpa_state > WPA_SCANNING) &&
- (wpa_s->wpa_state <= WPA_COMPLETED)) {
+ (wpa_s->wpa_state < WPA_COMPLETED)) {
wpa_printf(MSG_ERROR, "PNO: In assoc process");
return -EAGAIN;
}
@@ -2292,6 +2639,13 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
}
}
+ if (wpa_s->sched_scan_stop_req) {
+ wpa_printf(MSG_DEBUG,
+ "Schedule PNO after previous sched scan has stopped");
+ wpa_s->pno_sched_pending = 1;
+ return 0;
+ }
+
os_memset(&params, 0, sizeof(params));
num_ssid = num_match_ssid = 0;
@@ -2315,10 +2669,10 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
num_ssid++;
}
- if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+ if (num_ssid > max_sched_scan_ssids) {
wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
- "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
- num_ssid = WPAS_MAX_SCAN_SSIDS;
+ "%u", max_sched_scan_ssids, (unsigned int) num_ssid);
+ num_ssid = max_sched_scan_ssids;
}
if (num_match_ssid > wpa_s->max_match_sets) {
@@ -2361,15 +2715,30 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->filter_rssi)
params.filter_rssi = wpa_s->conf->filter_rssi;
- interval = wpa_s->conf->sched_scan_interval ?
- wpa_s->conf->sched_scan_interval : 10;
+ if (wpa_s->sched_scan_plans_num) {
+ params.sched_scan_plans = wpa_s->sched_scan_plans;
+ params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
+ } else {
+ /* Set one scan plan that will run infinitely */
+ if (wpa_s->conf->sched_scan_interval)
+ scan_plan.interval = wpa_s->conf->sched_scan_interval;
+ else
+ scan_plan.interval = 10;
+
+ scan_plan.iterations = 0;
+ params.sched_scan_plans = &scan_plan;
+ params.sched_scan_plans_num = 1;
+ }
+
+ params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay;
if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels");
params.freqs = wpa_s->manual_sched_scan_freqs;
}
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_pno) {
params.mac_addr = wpa_s->mac_addr_pno;
@@ -2377,7 +2746,9 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
}
}
- ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
+ wpa_scan_set_relative_rssi_params(wpa_s, &params);
+
+ ret = wpa_supplicant_start_sched_scan(wpa_s, &params);
os_free(params.filter_ssids);
if (ret == 0)
wpa_s->pno = 1;
@@ -2395,6 +2766,7 @@ int wpas_stop_pno(struct wpa_supplicant *wpa_s)
return 0;
ret = wpa_supplicant_stop_sched_scan(wpa_s);
+ wpa_s->sched_scan_stop_req = 1;
wpa_s->pno = 0;
wpa_s->pno_sched_pending = 0;
@@ -2435,6 +2807,13 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
{
u8 *tmp = NULL;
+ if ((wpa_s->mac_addr_rand_supported & type) != type ) {
+ wpa_printf(MSG_INFO,
+ "scan: MAC randomization type %u != supported=%u",
+ type, wpa_s->mac_addr_rand_supported);
+ return -1;
+ }
+
wpas_mac_addr_rand_scan_clear(wpa_s, type);
if (addr) {
@@ -2462,3 +2841,162 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
wpa_s->mac_addr_rand_enable |= type;
return 0;
}
+
+
+int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_radio_work *work;
+ struct wpa_radio *radio = wpa_s->radio;
+
+ dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
+ if (work->wpa_s != wpa_s || !work->started ||
+ (os_strcmp(work->type, "scan") != 0 &&
+ os_strcmp(work->type, "p2p-scan") != 0))
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan");
+ return wpa_drv_abort_scan(wpa_s, wpa_s->curr_scan_cookie);
+ }
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "No ongoing scan/p2p-scan found to abort");
+ return -1;
+}
+
+
+int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct sched_scan_plan *scan_plans = NULL;
+ const char *token, *context = NULL;
+ unsigned int num = 0;
+
+ if (!cmd)
+ return -1;
+
+ if (!cmd[0]) {
+ wpa_printf(MSG_DEBUG, "Clear sched scan plans");
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = NULL;
+ wpa_s->sched_scan_plans_num = 0;
+ return 0;
+ }
+
+ while ((token = cstr_token(cmd, " ", &context))) {
+ int ret;
+ struct sched_scan_plan *scan_plan, *n;
+
+ n = os_realloc_array(scan_plans, num + 1, sizeof(*scan_plans));
+ if (!n)
+ goto fail;
+
+ scan_plans = n;
+ scan_plan = &scan_plans[num];
+ num++;
+
+ ret = sscanf(token, "%u:%u", &scan_plan->interval,
+ &scan_plan->iterations);
+ if (ret <= 0 || ret > 2 || !scan_plan->interval) {
+ wpa_printf(MSG_ERROR,
+ "Invalid sched scan plan input: %s", token);
+ goto fail;
+ }
+
+ if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) {
+ wpa_printf(MSG_WARNING,
+ "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)",
+ num, scan_plan->interval,
+ wpa_s->max_sched_scan_plan_interval);
+ scan_plan->interval =
+ wpa_s->max_sched_scan_plan_interval;
+ }
+
+ if (ret == 1) {
+ scan_plan->iterations = 0;
+ break;
+ }
+
+ if (!scan_plan->iterations) {
+ wpa_printf(MSG_ERROR,
+ "scan plan %u: Number of iterations cannot be zero",
+ num);
+ goto fail;
+ }
+
+ if (scan_plan->iterations >
+ wpa_s->max_sched_scan_plan_iterations) {
+ wpa_printf(MSG_WARNING,
+ "scan plan %u: Too many iterations(%u), use the maximum allowed(%u)",
+ num, scan_plan->iterations,
+ wpa_s->max_sched_scan_plan_iterations);
+ scan_plan->iterations =
+ wpa_s->max_sched_scan_plan_iterations;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "scan plan %u: interval=%u iterations=%u",
+ num, scan_plan->interval, scan_plan->iterations);
+ }
+
+ if (!scan_plans) {
+ wpa_printf(MSG_ERROR, "Invalid scan plans entry");
+ goto fail;
+ }
+
+ if (cstr_token(cmd, " ", &context) || scan_plans[num - 1].iterations) {
+ wpa_printf(MSG_ERROR,
+ "All scan plans but the last must specify a number of iterations");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "scan plan %u (last plan): interval=%u",
+ num, scan_plans[num - 1].interval);
+
+ if (num > wpa_s->max_sched_scan_plans) {
+ wpa_printf(MSG_WARNING,
+ "Too many scheduled scan plans (only %u supported)",
+ wpa_s->max_sched_scan_plans);
+ wpa_printf(MSG_WARNING,
+ "Use only the first %u scan plans, and the last one (in infinite loop)",
+ wpa_s->max_sched_scan_plans - 1);
+ os_memcpy(&scan_plans[wpa_s->max_sched_scan_plans - 1],
+ &scan_plans[num - 1], sizeof(*scan_plans));
+ num = wpa_s->max_sched_scan_plans;
+ }
+
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = scan_plans;
+ wpa_s->sched_scan_plans_num = num;
+
+ return 0;
+
+fail:
+ os_free(scan_plans);
+ wpa_printf(MSG_ERROR, "invalid scan plans list");
+ return -1;
+}
+
+
+/**
+ * wpas_scan_reset_sched_scan - Reset sched_scan state
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel a running scheduled scan and to reset an
+ * internal scan state to continue with a regular scan on the following
+ * wpa_supplicant_req_scan() calls.
+ */
+void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->normal_scans = 0;
+ if (wpa_s->sched_scanning) {
+ wpa_s->sched_scan_timed_out = 0;
+ wpa_s->prev_sched_ssid = NULL;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ }
+}
+
+
+void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ /* simulate timeout to restart the sched scan */
+ wpa_s->sched_scan_timed_out = 1;
+ wpa_s->prev_sched_ssid = NULL;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+}
diff --git a/contrib/wpa/wpa_supplicant/scan.h b/contrib/wpa/wpa_supplicant/scan.h
index 7650f5a..2aa0a8b 100644
--- a/contrib/wpa/wpa_supplicant/scan.h
+++ b/contrib/wpa/wpa_supplicant/scan.h
@@ -39,20 +39,25 @@ void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec);
void scan_only_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
int wpas_scan_scheduled(struct wpa_supplicant *wpa_s);
-int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- int interval);
-int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s);
struct wpa_driver_scan_params *
wpa_scan_clone_params(const struct wpa_driver_scan_params *src);
void wpa_scan_free_params(struct wpa_driver_scan_params *params);
int wpas_start_pno(struct wpa_supplicant *wpa_s);
int wpas_stop_pno(struct wpa_supplicant *wpa_s);
+void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s);
+void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s);
void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
unsigned int type);
int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
const u8 *mask);
+int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
+void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res);
+void scan_snr(struct wpa_scan_res *res);
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res);
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
#endif /* SCAN_H */
diff --git a/contrib/wpa/wpa_supplicant/sme.c b/contrib/wpa/wpa_supplicant/sme.c
index f2e5a43..17a984d 100644
--- a/contrib/wpa/wpa_supplicant/sme.c
+++ b/contrib/wpa/wpa_supplicant/sme.c
@@ -12,9 +12,11 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
#include "common/sae.h"
+#include "common/dpp.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
#include "config.h"
@@ -56,7 +58,7 @@ static int index_within_array(const int *array, int idx)
static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
{
int *groups = wpa_s->conf->sae_groups;
- int default_groups[] = { 19, 20, 21, 25, 26, 0 };
+ int default_groups[] = { 19, 20, 21, 0 };
if (!groups || groups[0] <= 0)
groups = default_groups;
@@ -72,7 +74,7 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
wpa_s->sme.sae.group);
- return 0;
+ return 0;
}
wpa_s->sme.sae_group_index++;
}
@@ -83,43 +85,77 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- const u8 *bssid)
+ const u8 *bssid, int external,
+ int reuse)
{
struct wpabuf *buf;
size_t len;
+ const char *password;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->sae_commit_override) {
+ wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
+ buf = wpabuf_alloc(4 + wpabuf_len(wpa_s->sae_commit_override));
+ if (!buf)
+ return NULL;
+ if (!external) {
+ wpabuf_put_le16(buf, 1); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ }
+ wpabuf_put_buf(buf, wpa_s->sae_commit_override);
+ return buf;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
- if (ssid->passphrase == NULL) {
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+ if (!password) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
}
+ if (reuse && wpa_s->sme.sae.tmp &&
+ os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Reuse previously generated PWE on a retry with the same AP");
+ goto reuse_data;
+ }
if (sme_set_sae_group(wpa_s) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
return NULL;
}
if (sae_prepare_commit(wpa_s->own_addr, bssid,
- (u8 *) ssid->passphrase,
- os_strlen(ssid->passphrase),
+ (u8 *) password, os_strlen(password),
+ ssid->sae_password_id,
&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
}
+ if (wpa_s->sme.sae.tmp)
+ os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
+reuse_data:
len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+ if (ssid->sae_password_id)
+ len += 4 + os_strlen(ssid->sae_password_id);
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
if (buf == NULL)
return NULL;
-
- wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
- sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
+ if (!external) {
+ wpabuf_put_le16(buf, 1); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ }
+ sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
+ ssid->sae_password_id);
return buf;
}
-static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s,
+ int external)
{
struct wpabuf *buf;
@@ -127,8 +163,10 @@ static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
if (buf == NULL)
return NULL;
- wpabuf_put_le16(buf, 2); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (!external) {
+ wpabuf_put_le16(buf, 2); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ }
sae_write_confirm(&wpa_s->sme.sae, buf);
return buf;
@@ -161,9 +199,10 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
return;
}
- if (!(wpa_s->drv_rrm_flags &
- WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
- !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) {
+ if (!((wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
+ (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
+ !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) {
wpa_printf(MSG_DEBUG,
"RRM: Insufficient RRM support in driver - do not use RRM");
return;
@@ -186,6 +225,13 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+ *pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
+
+ if (wpa_s->lci)
+ pos[1] |= WLAN_RRM_CAPS_LCI_MEASUREMENT;
+
wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
wpa_s->rrm.rrm_used = 1;
}
@@ -200,14 +246,19 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211R
const u8 *ie;
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
const u8 *md = NULL;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
int i, bssid_changed;
struct wpabuf *resp = NULL;
u8 ext_capab[18];
int ext_capab_len;
int skip_auth;
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+#ifdef CONFIG_MBO
+ const u8 *mbo_ie;
+#endif /* CONFIG_MBO */
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -265,6 +316,12 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (!rsn) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE enabled, but target BSS does not advertise RSN");
+#ifdef CONFIG_DPP
+ } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ (ied.key_mgmt & WPA_KEY_MGMT_DPP)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Prefer DPP over SAE when both are enabled");
+#endif /* CONFIG_DPP */
} else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
wpa_key_mgmt_sae(ied.key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
@@ -293,13 +350,20 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
+ const u8 *cache_id = NULL;
+
try_opportunistic = (ssid->proactive_key_caching < 0 ?
wpa_s->conf->okc :
ssid->proactive_key_caching) &&
(ssid->proto & WPA_PROTO_RSN);
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(ssid->key_mgmt))
+ cache_id = wpa_bss_get_fils_cache_id(bss);
+#endif /* CONFIG_FILS */
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
wpa_s->current_ssid,
- try_opportunistic) == 0)
+ try_opportunistic, cache_id,
+ 0) == 0)
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -310,6 +374,20 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpas_connect_work_done(wpa_s);
return;
}
+#ifdef CONFIG_HS20
+ } else if (wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
+ /* No PMKSA caching, but otherwise similar to RSN/WPA */
+ wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+ if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
+ wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
+ "key management and encryption suites");
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+#endif /* CONFIG_HS20 */
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
/*
@@ -349,17 +427,45 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_s->sme.assoc_req_ie_len = 0;
}
+ /* In case the WPA vendor IE is used, it should be placed after all the
+ * non-vendor IEs, as the lower layer expects the IEs to be ordered as
+ * defined in the standard. Store the WPA IE so it can later be
+ * inserted at the correct location.
+ */
+ wpa_ie = NULL;
+ wpa_ie_len = 0;
+ if (wpa_s->wpa_proto == WPA_PROTO_WPA) {
+ wpa_ie = os_memdup(wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ if (wpa_ie) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Storing WPA IE");
+
+ wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ wpa_s->sme.assoc_req_ie_len = 0;
+ } else {
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed copy WPA IE");
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+ }
+
#ifdef CONFIG_IEEE80211R
ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
md = ie + 2;
wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
+ if (md && (!wpa_key_mgmt_ft(ssid->key_mgmt) ||
+ !wpa_key_mgmt_ft(wpa_s->key_mgmt)))
+ md = NULL;
if (md) {
/* Prepare for the next transition */
wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
}
- if (md && wpa_key_mgmt_ft(ssid->key_mgmt)) {
+ if (md) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x",
+ md[0], md[1]);
+
if (wpa_s->sme.assoc_req_ie_len + 5 <
sizeof(wpa_s->sme.assoc_req_ie)) {
struct rsn_mdie *mdie;
@@ -374,7 +480,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
wpa_s->sme.assoc_req_ie_len += 5;
}
- if (wpa_s->sme.ft_used &&
+ if (wpa_s->sme.prev_bssid_set && wpa_s->sme.ft_used &&
os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
wpa_sm_has_ptk(wpa_s->wpa)) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
@@ -416,28 +522,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_P2P */
-#ifdef CONFIG_HS20
- if (is_hs20_network(wpa_s, ssid, bss)) {
- struct wpabuf *hs20;
- hs20 = wpabuf_alloc(20);
- if (hs20) {
- int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
- size_t len;
-
- wpas_hs20_add_indication(hs20, pps_mo_id);
- len = sizeof(wpa_s->sme.assoc_req_ie) -
- wpa_s->sme.assoc_req_ie_len;
- if (wpabuf_len(hs20) <= len) {
- os_memcpy(wpa_s->sme.assoc_req_ie +
- wpa_s->sme.assoc_req_ie_len,
- wpabuf_head(hs20), wpabuf_len(hs20));
- wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
- }
- wpabuf_free(hs20);
- }
- }
-#endif /* CONFIG_HS20 */
-
#ifdef CONFIG_FST
if (wpa_s->fst_ies) {
int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
@@ -453,6 +537,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_FST */
+ sme_auth_handle_rrm(wpa_s, bss);
+
+ wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
+ wpa_s, ssid, bss->freq,
+ wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
+
+ if (params.p2p)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
sizeof(ext_capab));
if (ext_capab_len > 0) {
@@ -466,6 +562,51 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memcpy(pos, ext_capab, ext_capab_len);
}
+#ifdef CONFIG_HS20
+ if (is_hs20_network(wpa_s, ssid, bss)) {
+ struct wpabuf *hs20;
+
+ hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
+ if (hs20) {
+ int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
+ size_t len;
+
+ wpas_hs20_add_indication(hs20, pps_mo_id,
+ get_hs20_version(bss));
+ wpas_hs20_add_roam_cons_sel(hs20, ssid);
+ len = sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len;
+ if (wpabuf_len(hs20) <= len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(hs20), wpabuf_len(hs20));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
+ }
+ wpabuf_free(hs20);
+ }
+ }
+#endif /* CONFIG_HS20 */
+
+ if (wpa_ie) {
+ size_t len;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Reinsert WPA IE");
+
+ len = sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len;
+
+ if (len > wpa_ie_len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ wpa_ie, wpa_ie_len);
+ wpa_s->sme.assoc_req_ie_len += wpa_ie_len;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Failed to add WPA IE");
+ }
+
+ os_free(wpa_ie);
+ }
+
if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
size_t len;
@@ -480,14 +621,32 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
}
- sme_auth_handle_rrm(wpa_s, bss);
+#ifdef CONFIG_MBO
+ mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+ if (mbo_ie) {
+ int len;
+
+ len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len,
+ !!mbo_attr_from_mbo_ie(mbo_ie,
+ OCE_ATTR_ID_CAPA_IND));
+ if (len >= 0)
+ wpa_s->sme.assoc_req_ie_len += len;
+ }
+#endif /* CONFIG_MBO */
#ifdef CONFIG_SAE
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
- pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0)
- {
+ pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0,
+ NULL,
+ wpa_s->key_mgmt == WPA_KEY_MGMT_FT_SAE ?
+ WPA_KEY_MGMT_FT_SAE :
+ WPA_KEY_MGMT_SAE) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG,
"PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
+ wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
params.auth_alg = WPA_AUTH_ALG_OPEN;
wpa_s->sme.sae_pmksa_caching = 1;
}
@@ -495,19 +654,106 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) {
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
- bss->bssid);
+ bss->bssid, 0,
+ start == 2);
else
- resp = sme_auth_build_sae_confirm(wpa_s);
+ resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
wpas_connection_failed(wpa_s, bss->bssid);
return;
}
- params.sae_data = wpabuf_head(resp);
- params.sae_data_len = wpabuf_len(resp);
+ params.auth_data = wpabuf_head(resp);
+ params.auth_data_len = wpabuf_len(resp);
wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
}
#endif /* CONFIG_SAE */
+ old_ssid = wpa_s->current_ssid;
+ wpa_s->current_ssid = ssid;
+ wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+ wpa_supplicant_initiate_eapol(wpa_s);
+
+#ifdef CONFIG_FILS
+ /* TODO: FILS operations can in some cases be done between different
+ * network_ctx (i.e., same credentials can be used with multiple
+ * networks). */
+ if (params.auth_alg == WPA_AUTH_ALG_OPEN &&
+ wpa_key_mgmt_fils(ssid->key_mgmt)) {
+ const u8 *indic;
+ u16 fils_info;
+ const u8 *realm, *username, *rrk;
+ size_t realm_len, username_len, rrk_len;
+ u16 next_seq_num;
+
+ /*
+ * Check FILS Indication element (FILS Information field) bits
+ * indicating supported authentication algorithms against local
+ * configuration (ssid->fils_dh_group). Try to use FILS
+ * authentication only if the AP supports the combination in the
+ * network profile. */
+ indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+ if (!indic || indic[1] < 2) {
+ wpa_printf(MSG_DEBUG, "SME: " MACSTR
+ " does not include FILS Indication element - cannot use FILS authentication with it",
+ MAC2STR(bss->bssid));
+ goto no_fils;
+ }
+
+ fils_info = WPA_GET_LE16(indic + 2);
+ if (ssid->fils_dh_group == 0 && !(fils_info & BIT(9))) {
+ wpa_printf(MSG_DEBUG, "SME: " MACSTR
+ " does not support FILS SK without PFS - cannot use FILS authentication with it",
+ MAC2STR(bss->bssid));
+ goto no_fils;
+ }
+ if (ssid->fils_dh_group != 0 && !(fils_info & BIT(10))) {
+ wpa_printf(MSG_DEBUG, "SME: " MACSTR
+ " does not support FILS SK with PFS - cannot use FILS authentication with it",
+ MAC2STR(bss->bssid));
+ goto no_fils;
+ }
+
+ if (wpa_s->last_con_fail_realm &&
+ eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
+ &username, &username_len,
+ &realm, &realm_len, &next_seq_num,
+ &rrk, &rrk_len) == 0 &&
+ realm && realm_len == wpa_s->last_con_fail_realm_len &&
+ os_memcmp(realm, wpa_s->last_con_fail_realm,
+ realm_len) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "SME: FILS authentication for this realm failed last time - try to regenerate ERP key hierarchy");
+ goto no_fils;
+ }
+
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ ssid, 0,
+ wpa_bss_get_fils_cache_id(bss),
+ 0) == 0)
+ wpa_printf(MSG_DEBUG,
+ "SME: Try to use FILS with PMKSA caching");
+ resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md);
+ if (resp) {
+ int auth_alg;
+
+ if (ssid->fils_dh_group)
+ wpa_printf(MSG_DEBUG,
+ "SME: Try to use FILS SK authentication with PFS (DH Group %u)",
+ ssid->fils_dh_group);
+ else
+ wpa_printf(MSG_DEBUG,
+ "SME: Try to use FILS SK authentication without PFS");
+ auth_alg = ssid->fils_dh_group ?
+ WPA_AUTH_ALG_FILS_SK_PFS : WPA_AUTH_ALG_FILS;
+ params.auth_alg = auth_alg;
+ params.auth_data = wpabuf_head(resp);
+ params.auth_data_len = wpabuf_len(resp);
+ wpa_s->sme.auth_alg = auth_alg;
+ }
+ }
+no_fils:
+#endif /* CONFIG_FILS */
+
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_cancel_scan(wpa_s);
@@ -515,15 +761,16 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
+ eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
wpa_clear_keys(wpa_s, bss->bssid);
wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
- old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = ssid;
- wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
- wpa_supplicant_initiate_eapol(wpa_s);
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
+#ifdef CONFIG_HS20
+ hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+
#ifdef CONFIG_P2P
/*
* If multi-channel concurrency is not supported, check for any
@@ -605,6 +852,10 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
return;
}
+ /* Starting new connection, so clear the possibly used WPA IE from the
+ * previous association. */
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
@@ -632,6 +883,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
radio_remove_works(wpa_s, "sme-connect", 0);
}
+ wpas_abort_ongoing_scan(wpa_s);
+
cwork = os_zalloc(sizeof(*cwork));
if (cwork == NULL)
return;
@@ -653,8 +906,150 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_SAE
+static int sme_external_auth_build_buf(struct wpabuf *buf,
+ struct wpabuf *params,
+ const u8 *sa, const u8 *da,
+ u16 auth_transaction, u16 seq_num)
+{
+ struct ieee80211_mgmt *resp;
+
+ resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.auth.variable));
+
+ resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+ os_memcpy(resp->da, da, ETH_ALEN);
+ os_memcpy(resp->sa, sa, ETH_ALEN);
+ os_memcpy(resp->bssid, da, ETH_ALEN);
+ resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
+ resp->seq_ctrl = host_to_le16(seq_num << 4);
+ resp->u.auth.auth_transaction = host_to_le16(auth_transaction);
+ resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+ if (params)
+ wpabuf_put_buf(buf, params);
+
+ return 0;
+}
+
+
+static void sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
+ const u8 *bssid,
+ struct wpa_ssid *ssid)
+{
+ struct wpabuf *resp, *buf;
+
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0);
+ if (!resp)
+ return;
+
+ wpa_s->sme.sae.state = SAE_COMMITTED;
+ buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp));
+ if (!buf) {
+ wpabuf_free(resp);
+ return;
+ }
+
+ wpa_s->sme.seq_num++;
+ sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
+ bssid, 1, wpa_s->sme.seq_num);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ wpabuf_free(resp);
+ wpabuf_free(buf);
+}
+
+
+static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s,
+ u16 status)
+{
+ struct external_auth params;
+
+ os_memset(&params, 0, sizeof(params));
+ params.status = status;
+ params.ssid = wpa_s->sme.ext_auth.ssid;
+ params.ssid_len = wpa_s->sme.ext_auth.ssid_len;
+ params.bssid = wpa_s->sme.ext_auth.bssid;
+ wpa_drv_send_external_auth_status(wpa_s, &params);
+}
+
+
+static void sme_handle_external_auth_start(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ struct wpa_ssid *ssid;
+ size_t ssid_str_len = data->external_auth.ssid_len;
+ const u8 *ssid_str = data->external_auth.ssid;
+
+ /* Get the SSID conf from the ssid string obtained */
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid_str_len == ssid->ssid_len &&
+ os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)))
+ break;
+ }
+ if (ssid)
+ sme_external_auth_send_sae_commit(wpa_s,
+ data->external_auth.bssid,
+ ssid);
+ else
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
+}
+
+
+static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
+ const u8 *da)
+{
+ struct wpabuf *resp, *buf;
+
+ resp = sme_auth_build_sae_confirm(wpa_s, 1);
+ if (!resp) {
+ wpa_printf(MSG_DEBUG, "SAE: Confirm message buf alloc failure");
+ return;
+ }
+
+ wpa_s->sme.sae.state = SAE_CONFIRMED;
+ buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp));
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure");
+ wpabuf_free(resp);
+ return;
+ }
+ wpa_s->sme.seq_num++;
+ sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
+ da, 2, wpa_s->sme.seq_num);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ wpabuf_free(resp);
+ wpabuf_free(buf);
+}
+
+
+void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ if (RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) !=
+ RSN_AUTH_KEY_MGMT_SAE)
+ return;
+
+ if (data->external_auth.action == EXT_AUTH_START) {
+ os_memcpy(&wpa_s->sme.ext_auth, data,
+ sizeof(struct external_auth));
+ wpa_s->sme.seq_num = 0;
+ wpa_s->sme.sae.state = SAE_NOTHING;
+ wpa_s->sme.sae.send_confirm = 0;
+ wpa_s->sme.sae_group_index = 0;
+ sme_handle_external_auth_start(wpa_s, data);
+ } else if (data->external_auth.action == EXT_AUTH_ABORT) {
+ /* Report failure to driver for the wrong trigger */
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
+ }
+}
+
+
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
- u16 status_code, const u8 *data, size_t len)
+ u16 status_code, const u8 *data, size_t len,
+ int external, const u8 *sa)
{
int *groups;
@@ -664,8 +1059,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
if (auth_transaction == 1 &&
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
wpa_s->sme.sae.state == SAE_COMMITTED &&
- wpa_s->current_bss && wpa_s->current_ssid) {
- int default_groups[] = { 19, 20, 21, 25, 26, 0 };
+ (external || wpa_s->current_bss) && wpa_s->current_ssid) {
+ int default_groups[] = { 19, 20, 21, 0 };
u16 group;
groups = wpa_s->conf->sae_groups;
@@ -691,25 +1086,45 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
wpabuf_free(wpa_s->sme.sae_token);
wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
len - sizeof(le16));
- sme_send_authentication(wpa_s, wpa_s->current_bss,
- wpa_s->current_ssid, 1);
+ if (!external)
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 2);
+ else
+ sme_external_auth_send_sae_commit(
+ wpa_s, wpa_s->sme.ext_auth.bssid,
+ wpa_s->current_ssid);
return 0;
}
if (auth_transaction == 1 &&
status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
wpa_s->sme.sae.state == SAE_COMMITTED &&
- wpa_s->current_bss && wpa_s->current_ssid) {
+ (external || wpa_s->current_bss) && wpa_s->current_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
wpa_s->sme.sae_group_index++;
if (sme_set_sae_group(wpa_s) < 0)
return -1; /* no other groups enabled */
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
- sme_send_authentication(wpa_s, wpa_s->current_bss,
- wpa_s->current_ssid, 1);
+ if (!external)
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 1);
+ else
+ sme_external_auth_send_sae_commit(
+ wpa_s, wpa_s->sme.ext_auth.bssid,
+ wpa_s->current_ssid);
return 0;
}
+ if (auth_transaction == 1 &&
+ status_code == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
+ const u8 *bssid = sa ? sa : wpa_s->pending_bssid;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER MACSTR,
+ MAC2STR(bssid));
+ return -1;
+ }
+
if (status_code != WLAN_STATUS_SUCCESS)
return -1;
@@ -719,7 +1134,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
groups = wpa_s->conf->sae_groups;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
- if (wpa_s->current_bss == NULL ||
+ if ((!external && wpa_s->current_bss == NULL) ||
wpa_s->current_ssid == NULL)
return -1;
if (wpa_s->sme.sae.state != SAE_COMMITTED)
@@ -744,8 +1159,11 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
wpabuf_free(wpa_s->sme.sae_token);
wpa_s->sme.sae_token = NULL;
- sme_send_authentication(wpa_s, wpa_s->current_bss,
- wpa_s->current_ssid, 0);
+ if (!external)
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 0);
+ else
+ sme_external_auth_send_sae_confirm(wpa_s, sa);
return 0;
} else if (auth_transaction == 2) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
@@ -755,11 +1173,60 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1;
wpa_s->sme.sae.state = SAE_ACCEPTED;
sae_clear_temp_data(&wpa_s->sme.sae);
+
+ if (external) {
+ /* Report success to driver */
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_SUCCESS);
+ }
+
return 1;
}
return -1;
}
+
+
+void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+ const u8 *auth_frame, size_t len)
+{
+ const struct ieee80211_mgmt *header;
+ size_t auth_length;
+
+ header = (const struct ieee80211_mgmt *) auth_frame;
+ auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
+
+ if (len < auth_length) {
+ /* Notify failure to the driver */
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return;
+ }
+
+ if (le_to_host16(header->u.auth.auth_alg) == WLAN_AUTH_SAE) {
+ int res;
+
+ res = sme_sae_auth(
+ wpa_s, le_to_host16(header->u.auth.auth_transaction),
+ le_to_host16(header->u.auth.status_code),
+ header->u.auth.variable,
+ len - auth_length, 1, header->sa);
+ if (res < 0) {
+ /* Notify failure to the driver */
+ sme_send_external_auth_status(
+ wpa_s, WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return;
+ }
+ if (res != 1)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "SME: SAE completed - setting PMK for 4-way handshake");
+ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+ wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+ }
+}
+
#endif /* CONFIG_SAE */
@@ -800,7 +1267,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
int res;
res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
data->auth.status_code, data->auth.ies,
- data->auth.ies_len);
+ data->auth.ies_len, 0, NULL);
if (res < 0) {
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
@@ -812,7 +1279,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
"4-way handshake");
wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
- wpa_s->pending_bssid);
+ wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
}
#endif /* CONFIG_SAE */
@@ -828,12 +1295,19 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
}
}
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AUTH_REJECT MACSTR
- " auth_type=%u auth_transaction=%u status_code=%u ie=%s",
+ " auth_type=%u auth_transaction=%u status_code=%u%s%s",
MAC2STR(data->auth.peer), data->auth.auth_type,
data->auth.auth_transaction, data->auth.status_code,
- ie_txt);
+ ie_txt ? " ie=" : "",
+ ie_txt ? ie_txt : "");
os_free(ie_txt);
+#ifdef CONFIG_FILS
+ if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
+ wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS)
+ fils_connection_failure(wpa_s);
+#endif /* CONFIG_FILS */
+
if (data->auth.status_code !=
WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
wpa_s->sme.auth_alg == data->auth.auth_type ||
@@ -869,9 +1343,17 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
#ifdef CONFIG_IEEE80211R
if (data->auth.auth_type == WLAN_AUTH_FT) {
+ const u8 *ric_ies = NULL;
+ size_t ric_ies_len = 0;
+
+ if (wpa_s->ric_ies) {
+ ric_ies = wpabuf_head(wpa_s->ric_ies);
+ ric_ies_len = wpabuf_len(wpa_s->ric_ies);
+ }
if (wpa_ft_process_response(wpa_s->wpa, data->auth.ies,
data->auth.ies_len, 0,
- data->auth.peer, NULL, 0) < 0) {
+ data->auth.peer,
+ ric_ies, ric_ies_len) < 0) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: FT Authentication response processing failed");
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
@@ -886,16 +1368,73 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_FILS
+ if (data->auth.auth_type == WLAN_AUTH_FILS_SK ||
+ data->auth.auth_type == WLAN_AUTH_FILS_SK_PFS) {
+ u16 expect_auth_type;
+
+ expect_auth_type = wpa_s->sme.auth_alg ==
+ WPA_AUTH_ALG_FILS_SK_PFS ? WLAN_AUTH_FILS_SK_PFS :
+ WLAN_AUTH_FILS_SK;
+ if (data->auth.auth_type != expect_auth_type) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: FILS Authentication response used different auth alg (%u; expected %u)",
+ data->auth.auth_type, expect_auth_type);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
+ MACSTR
+ " reason=%d locally_generated=1",
+ MAC2STR(wpa_s->pending_bssid),
+ WLAN_REASON_DEAUTH_LEAVING);
+ wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ return;
+ }
+
+ if (fils_process_auth(wpa_s->wpa, wpa_s->pending_bssid,
+ data->auth.ies, data->auth.ies_len) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: FILS Authentication response processing failed");
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
+ MACSTR
+ " reason=%d locally_generated=1",
+ MAC2STR(wpa_s->pending_bssid),
+ WLAN_REASON_DEAUTH_LEAVING);
+ wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ return;
+ }
+ }
+#endif /* CONFIG_FILS */
+
sme_associate(wpa_s, ssid->mode, data->auth.peer,
data->auth.auth_type);
}
+#ifdef CONFIG_IEEE80211R
+static void remove_ie(u8 *buf, size_t *len, u8 eid)
+{
+ u8 *pos, *next, *end;
+
+ pos = (u8 *) get_ie(buf, *len, eid);
+ if (pos) {
+ next = pos + 2 + pos[1];
+ end = buf + *len;
+ *len -= 2 + pos[1];
+ os_memmove(pos, next, end - next);
+ }
+}
+#endif /* CONFIG_IEEE80211R */
+
+
void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
const u8 *bssid, u16 auth_type)
{
struct wpa_driver_associate_params params;
struct ieee802_11_elems elems;
+#ifdef CONFIG_FILS
+ u8 nonces[2 * FILS_NONCE_LEN];
+#endif /* CONFIG_FILS */
#ifdef CONFIG_HT_OVERRIDES
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
@@ -906,6 +1445,184 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
#endif /* CONFIG_VHT_OVERRIDES */
os_memset(&params, 0, sizeof(params));
+
+#ifdef CONFIG_FILS
+ if (auth_type == WLAN_AUTH_FILS_SK ||
+ auth_type == WLAN_AUTH_FILS_SK_PFS) {
+ struct wpabuf *buf;
+ const u8 *snonce, *anonce;
+ const unsigned int max_hlp = 20;
+ struct wpabuf *hlp[max_hlp];
+ unsigned int i, num_hlp = 0;
+ struct fils_hlp_req *req;
+
+ dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
+ list) {
+ hlp[num_hlp] = wpabuf_alloc(2 * ETH_ALEN + 6 +
+ wpabuf_len(req->pkt));
+ if (!hlp[num_hlp])
+ break;
+ wpabuf_put_data(hlp[num_hlp], req->dst, ETH_ALEN);
+ wpabuf_put_data(hlp[num_hlp], wpa_s->own_addr,
+ ETH_ALEN);
+ wpabuf_put_data(hlp[num_hlp],
+ "\xaa\xaa\x03\x00\x00\x00", 6);
+ wpabuf_put_buf(hlp[num_hlp], req->pkt);
+ num_hlp++;
+ if (num_hlp >= max_hlp)
+ break;
+ }
+
+ buf = fils_build_assoc_req(wpa_s->wpa, &params.fils_kek,
+ &params.fils_kek_len, &snonce,
+ &anonce,
+ (const struct wpabuf **) hlp,
+ num_hlp);
+ for (i = 0; i < num_hlp; i++)
+ wpabuf_free(hlp[i]);
+ if (!buf)
+ return;
+ wpa_hexdump(MSG_DEBUG, "FILS: assoc_req before FILS elements",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) {
+ /* Remove RSNE and MDE to allow them to be overridden
+ * with FILS+FT specific values from
+ * fils_build_assoc_req(). */
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RSN);
+ wpa_hexdump(MSG_DEBUG,
+ "FILS: assoc_req after RSNE removal",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_MOBILITY_DOMAIN);
+ wpa_hexdump(MSG_DEBUG,
+ "FILS: assoc_req after MDE removal",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ }
+#endif /* CONFIG_IEEE80211R */
+ /* TODO: Make wpa_s->sme.assoc_req_ie use dynamic allocation */
+ if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(buf) >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Not enough buffer room for own AssocReq elements");
+ wpabuf_free(buf);
+ return;
+ }
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf);
+ wpabuf_free(buf);
+ wpa_hexdump(MSG_DEBUG, "FILS: assoc_req after FILS elements",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+
+ os_memcpy(nonces, snonce, FILS_NONCE_LEN);
+ os_memcpy(nonces + FILS_NONCE_LEN, anonce, FILS_NONCE_LEN);
+ params.fils_nonces = nonces;
+ params.fils_nonces_len = sizeof(nonces);
+ }
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+#ifdef CONFIG_TESTING_OPTIONS
+ if (get_ie_ext(wpa_s->sme.assoc_req_ie, wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_EXT_OWE_DH_PARAM)) {
+ wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (auth_type == WLAN_AUTH_OPEN &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
+ struct wpabuf *owe_ie;
+ u16 group;
+
+ if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) {
+ group = wpa_s->current_ssid->owe_group;
+ } else if (wpa_s->assoc_status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ if (wpa_s->last_owe_group == 19)
+ group = 20;
+ else if (wpa_s->last_owe_group == 20)
+ group = 21;
+ else
+ group = OWE_DH_GROUP;
+ } else {
+ group = OWE_DH_GROUP;
+ }
+
+ wpa_s->last_owe_group = group;
+ wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
+ owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
+ if (!owe_ie) {
+ wpa_printf(MSG_ERROR,
+ "OWE: Failed to build IE for Association Request frame");
+ return;
+ }
+ if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(owe_ie) >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_printf(MSG_ERROR,
+ "OWE: Not enough buffer room for own Association Request frame elements");
+ wpabuf_free(owe_ie);
+ return;
+ }
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(owe_ie), wpabuf_len(owe_ie));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(owe_ie);
+ wpabuf_free(owe_ie);
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid &&
+ wpa_s->current_ssid->dpp_netaccesskey) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ dpp_pfs_free(wpa_s->dpp_pfs);
+ wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len);
+ if (!wpa_s->dpp_pfs) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
+ /* Try to continue without PFS */
+ goto pfs_fail;
+ }
+ if (wpa_s->sme.assoc_req_ie_len +
+ wpabuf_len(wpa_s->dpp_pfs->ie) >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Not enough buffer room for own Association Request frame elements");
+ dpp_pfs_free(wpa_s->dpp_pfs);
+ wpa_s->dpp_pfs = NULL;
+ goto pfs_fail;
+ }
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(wpa_s->dpp_pfs->ie),
+ wpabuf_len(wpa_s->dpp_pfs->ie));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
+ }
+pfs_fail:
+#endif /* CONFIG_DPP2 */
+
+ if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) {
+ size_t multi_ap_ie_len;
+
+ multi_ap_ie_len = add_multi_ap_ie(
+ wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len,
+ MULTI_AP_BACKHAUL_STA);
+ if (multi_ap_ie_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "Multi-AP: Failed to build Multi-AP IE");
+ return;
+ }
+ wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
+ }
+
params.bssid = bssid;
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
@@ -915,8 +1632,11 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
wpa_s->sme.assoc_req_ie : NULL;
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ wpa_hexdump(MSG_DEBUG, "SME: Association Request IEs",
+ params.wpa_ie, params.wpa_ie_len);
params.pairwise_suite = wpa_s->pairwise_cipher;
params.group_suite = wpa_s->group_cipher;
+ params.mgmt_group_suite = wpa_s->mgmt_group_cipher;
params.key_mgmt_suite = wpa_s->key_mgmt;
params.wpa_proto = wpa_s->wpa_proto;
#ifdef CONFIG_HT_OVERRIDES
@@ -934,9 +1654,85 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
#endif /* CONFIG_VHT_OVERRIDES */
#ifdef CONFIG_IEEE80211R
- if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
+ if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
+ get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
+ WLAN_EID_RIC_DATA)) {
+ /* There seems to be a pretty inconvenient bug in the Linux
+ * kernel IE splitting functionality when RIC is used. For now,
+ * skip correct behavior in IE construction here (i.e., drop the
+ * additional non-FT-specific IEs) to avoid kernel issues. This
+ * is fine since RIC is used only for testing purposes in the
+ * current implementation. */
+ wpa_printf(MSG_INFO,
+ "SME: Linux kernel workaround - do not try to include additional IEs with RIC");
params.wpa_ie = wpa_s->sme.ft_ies;
params.wpa_ie_len = wpa_s->sme.ft_ies_len;
+ } else if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
+ const u8 *rm_en, *pos, *end;
+ size_t rm_en_len = 0;
+ u8 *rm_en_dup = NULL, *wpos;
+
+ /* Remove RSNE, MDE, FTE to allow them to be overridden with
+ * FT specific values */
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RSN);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_MOBILITY_DOMAIN);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_FAST_BSS_TRANSITION);
+ rm_en = get_ie(wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ if (rm_en) {
+ /* Need to remove RM Enabled Capabilities element as
+ * well temporarily, so that it can be placed between
+ * RSNE and MDE. */
+ rm_en_len = 2 + rm_en[1];
+ rm_en_dup = os_memdup(rm_en, rm_en_len);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Association Request IEs after FT IE removal",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ if (wpa_s->sme.assoc_req_ie_len + wpa_s->sme.ft_ies_len +
+ rm_en_len > sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_printf(MSG_ERROR,
+ "SME: Not enough buffer room for FT IEs in Association Request frame");
+ os_free(rm_en_dup);
+ return;
+ }
+
+ os_memmove(wpa_s->sme.assoc_req_ie + wpa_s->sme.ft_ies_len +
+ rm_en_len,
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ pos = wpa_s->sme.ft_ies;
+ end = pos + wpa_s->sme.ft_ies_len;
+ wpos = wpa_s->sme.assoc_req_ie;
+ if (*pos == WLAN_EID_RSN) {
+ os_memcpy(wpos, pos, 2 + pos[1]);
+ wpos += 2 + pos[1];
+ pos += 2 + pos[1];
+ }
+ if (rm_en_dup) {
+ os_memcpy(wpos, rm_en_dup, rm_en_len);
+ wpos += rm_en_len;
+ os_free(rm_en_dup);
+ }
+ os_memcpy(wpos, pos, end - pos);
+ wpa_s->sme.assoc_req_ie_len += wpa_s->sme.ft_ies_len +
+ rm_en_len;
+ params.wpa_ie = wpa_s->sme.assoc_req_ie;
+ params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Association Request IEs after FT override",
+ params.wpa_ie, params.wpa_ie_len);
}
#endif /* CONFIG_IEEE80211R */
params.mode = mode;
@@ -975,8 +1771,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
params.p2p = 1;
- if (wpa_s->parent->set_sta_uapsd)
- params.uapsd = wpa_s->parent->sta_uapsd;
+ if (wpa_s->p2pdev->set_sta_uapsd)
+ params.uapsd = wpa_s->p2pdev->sta_uapsd;
else
params.uapsd = -1;
@@ -991,6 +1787,14 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
eloop_register_timeout(SME_ASSOC_TIMEOUT, 0, sme_assoc_timer, wpa_s,
NULL);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
+ wpa_s->last_assoc_req_wpa_ie = NULL;
+ if (params.wpa_ie)
+ wpa_s->last_assoc_req_wpa_ie =
+ wpabuf_alloc_copy(params.wpa_ie, params.wpa_ie_len);
+#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1009,10 +1813,9 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN);
wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len);
os_free(wpa_s->sme.ft_ies);
- wpa_s->sme.ft_ies = os_malloc(ies_len);
+ wpa_s->sme.ft_ies = os_memdup(ies, ies_len);
if (wpa_s->sme.ft_ies == NULL)
return -1;
- os_memcpy(wpa_s->sme.ft_ies, ies, ies_len);
wpa_s->sme.ft_ies_len = ies_len;
return 0;
}
@@ -1179,20 +1982,17 @@ void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
sae_clear_data(&wpa_s->sme.sae);
#endif /* CONFIG_SAE */
#ifdef CONFIG_IEEE80211R
- if (wpa_s->sme.ft_ies)
+ if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used)
sme_update_ft_ies(wpa_s, NULL, NULL, 0);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ sme_stop_sa_query(wpa_s);
+#endif /* CONFIG_IEEE80211W */
}
void sme_deinit(struct wpa_supplicant *wpa_s)
{
- os_free(wpa_s->sme.ft_ies);
- wpa_s->sme.ft_ies = NULL;
- wpa_s->sme.ft_ies_len = 0;
-#ifdef CONFIG_IEEE80211W
- sme_stop_sa_query(wpa_s);
-#endif /* CONFIG_IEEE80211W */
sme_clear_on_disassoc(wpa_s);
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
@@ -1320,21 +2120,6 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
}
-static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes,
- enum hostapd_hw_mode mode)
-{
- u16 i;
-
- for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
- return &modes[i];
- }
-
- return NULL;
-}
-
-
static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
@@ -1501,6 +2286,7 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
static const unsigned int sa_query_max_timeout = 1000;
static const unsigned int sa_query_retry_timeout = 201;
+static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */
static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
{
@@ -1524,7 +2310,9 @@ static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
const u8 *trans_id)
{
- u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN];
+ u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN];
+ u8 req_len = 2 + WLAN_SA_QUERY_TR_ID_LEN;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to "
MACSTR, MAC2STR(wpa_s->bssid));
wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID",
@@ -1532,9 +2320,27 @@ static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
req[0] = WLAN_ACTION_SA_QUERY;
req[1] = WLAN_SA_QUERY_REQUEST;
os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Request frame");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, req + req_len) < 0)
+ return;
+
+ req_len += OCV_OCI_EXTENDED_LEN;
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
- req, sizeof(req), 0) < 0)
+ req, req_len, 0) < 0)
wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query "
"Request");
}
@@ -1553,8 +2359,10 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
wpa_s->sme.sa_query_count + 1,
WLAN_SA_QUERY_TR_ID_LEN);
- if (nbuf == NULL)
+ if (nbuf == NULL) {
+ sme_stop_sa_query(wpa_s);
return;
+ }
if (wpa_s->sme.sa_query_count == 0) {
/* Starting a new SA Query procedure */
os_get_reltime(&wpa_s->sme.sa_query_start);
@@ -1565,6 +2373,7 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
+ sme_stop_sa_query(wpa_s);
return;
}
@@ -1588,6 +2397,8 @@ static void sme_start_sa_query(struct wpa_supplicant *wpa_s)
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->sme.sa_query_trans_id)
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Stop SA Query");
eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
os_free(wpa_s->sme.sa_query_trans_id);
wpa_s->sme.sa_query_trans_id = NULL;
@@ -1626,15 +2437,74 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
}
-void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
- const u8 *data, size_t len)
+void sme_event_ch_switch(struct wpa_supplicant *wpa_s)
+{
+ unsigned int usec;
+ u32 _rand;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ !wpa_sm_ocv_enabled(wpa_s->wpa))
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Channel switch completed - trigger new SA Query to verify new operating channel");
+ sme_stop_sa_query(wpa_s);
+
+ if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+ _rand = os_random();
+ usec = _rand % (sa_query_ch_switch_max_delay + 1);
+ eloop_register_timeout(0, usec, sme_sa_query_timer, wpa_s, NULL);
+}
+
+
+static void sme_process_sa_query_request(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data,
+ size_t len)
+{
+ u8 resp[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN];
+ u8 resp_len = 2 + WLAN_SA_QUERY_TR_ID_LEN;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Response to "
+ MACSTR, MAC2STR(wpa_s->bssid));
+
+ resp[0] = WLAN_ACTION_SA_QUERY;
+ resp[1] = WLAN_SA_QUERY_RESPONSE;
+ os_memcpy(resp + 2, data + 1, WLAN_SA_QUERY_TR_ID_LEN);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Response frame");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0)
+ return;
+
+ resp_len += OCV_OCI_EXTENDED_LEN;
+ }
+#endif /* CONFIG_OCV */
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ resp, resp_len, 0) < 0)
+ wpa_msg(wpa_s, MSG_INFO,
+ "SME: Failed to send SA Query Response");
+}
+
+
+static void sme_process_sa_query_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data,
+ size_t len)
{
int i;
- if (wpa_s->sme.sa_query_trans_id == NULL ||
- len < 1 + WLAN_SA_QUERY_TR_ID_LEN ||
- data[0] != WLAN_SA_QUERY_RESPONSE)
+ if (!wpa_s->sme.sa_query_trans_id)
return;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query response from "
MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
@@ -1659,4 +2529,48 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
sme_stop_sa_query(wpa_s);
}
+
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+ const u8 *data, size_t len)
+{
+ if (len < 1 + WLAN_SA_QUERY_TR_ID_LEN)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query frame from "
+ MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct ieee802_11_elems elems;
+ struct wpa_channel_info ci;
+
+ if (ieee802_11_parse_elems(data + 1 + WLAN_SA_QUERY_TR_ID_LEN,
+ len - 1 - WLAN_SA_QUERY_TR_ID_LEN,
+ &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "SA Query: Failed to parse elements");
+ return;
+ }
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in SA Query Action frame");
+ return;
+ }
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ if (data[0] == WLAN_SA_QUERY_REQUEST)
+ sme_process_sa_query_request(wpa_s, sa, data, len);
+ else if (data[0] == WLAN_SA_QUERY_RESPONSE)
+ sme_process_sa_query_response(wpa_s, sa, data, len);
+}
+
#endif /* CONFIG_IEEE80211W */
diff --git a/contrib/wpa/wpa_supplicant/sme.h b/contrib/wpa/wpa_supplicant/sme.h
index fd5c3b4..1a7f9e8 100644
--- a/contrib/wpa/wpa_supplicant/sme.h
+++ b/contrib/wpa/wpa_supplicant/sme.h
@@ -28,6 +28,7 @@ void sme_event_disassoc(struct wpa_supplicant *wpa_s,
struct disassoc_info *info);
void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *da, u16 reason_code);
+void sme_event_ch_switch(struct wpa_supplicant *wpa_s);
void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *data, size_t len);
void sme_state_changed(struct wpa_supplicant *wpa_s);
@@ -38,6 +39,10 @@ void sme_deinit(struct wpa_supplicant *wpa_s);
int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
+void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data);
+void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+ const u8 *auth_frame, size_t len);
#else /* CONFIG_SME */
@@ -85,6 +90,10 @@ static inline void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s,
{
}
+static inline void sme_event_ch_switch(struct wpa_supplicant *wpa_s)
+{
+}
+
static inline void sme_state_changed(struct wpa_supplicant *wpa_s)
{
}
@@ -113,6 +122,16 @@ static inline void sme_sched_obss_scan(struct wpa_supplicant *wpa_s,
{
}
+static inline void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+}
+
+static inline void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+ const u8 *auth_frame, size_t len)
+{
+}
+
#endif /* CONFIG_SME */
#endif /* SME_H */
diff --git a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
new file mode 100644
index 0000000..03ac507
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -0,0 +1,15 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and nl80211 driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+Before=network.target
+Wants=network.target
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service
diff --git a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
new file mode 100644
index 0000000..c8a744d
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -0,0 +1,15 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and wired driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+Before=network.target
+Wants=network.target
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service
diff --git a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
new file mode 100644
index 0000000..7788b38
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -0,0 +1,15 @@
+[Unit]
+Description=WPA supplicant daemon (interface-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+Before=network.target
+Wants=network.target
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant@%i.service
diff --git a/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.in b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.in
new file mode 100644
index 0000000..75a37a8
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/systemd/wpa_supplicant.service.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant
+Before=network.target
+Wants=network.target
+
+[Service]
+Type=dbus
+BusName=fi.w1.wpa_supplicant1
+ExecStart=@BINDIR@/wpa_supplicant -u
+
+[Install]
+WantedBy=multi-user.target
+Alias=dbus-fi.w1.wpa_supplicant1.service
diff --git a/contrib/wpa/wpa_supplicant/tests/link_test.c b/contrib/wpa/wpa_supplicant/tests/link_test.c
deleted file mode 100644
index 3bfbed5..0000000
--- a/contrib/wpa/wpa_supplicant/tests/link_test.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Dummy functions to allow link_test to be linked. The need for these
- * functions should be removed to allow IEEE 802.1X/EAPOL authenticator to
- * be built outside hostapd.
- */
-
-#include "includes.h"
-
-#include "common.h"
-
-
-struct hostapd_data;
-struct sta_info;
-struct rsn_pmksa_cache_entry;
-struct eapol_state_machine;
-struct hostapd_eap_user;
-struct hostapd_bss_config;
-struct hostapd_vlan;
-
-
-struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
-{
- return NULL;
-}
-
-
-int ap_for_each_sta(struct hostapd_data *hapd,
- int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
- void *ctx),
- void *ctx)
-{
- return 0;
-}
-
-
-void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
- u32 session_timeout)
-{
-}
-
-
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
- int old_vlanid)
-{
- return 0;
-}
-
-
-void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
- int success)
-{
-}
-
-
-void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
- u8 *buf, size_t len)
-{
-}
-
-
-void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
-{
-}
-
-
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
- struct eapol_state_machine *eapol)
-{
-}
-
-
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
- size_t identity_len, int phase2)
-{
- return NULL;
-}
-
-
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
-{
- return NULL;
-}
diff --git a/contrib/wpa/wpa_supplicant/tests/test_eap_sim_common.c b/contrib/wpa/wpa_supplicant/tests/test_eap_sim_common.c
deleted file mode 100644
index f60b182..0000000
--- a/contrib/wpa/wpa_supplicant/tests/test_eap_sim_common.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Test program for EAP-SIM PRF
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "eap_common/eap_sim_common.c"
-
-
-static int test_eap_sim_prf(void)
-{
- /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
- u8 xkey[] = {
- 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
- 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
- 0xeb, 0x5a, 0x38, 0xb6
- };
- u8 w[] = {
- 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
- 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
- 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
- 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
- 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
- };
- u8 buf[40];
-
- printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
- eap_sim_prf(xkey, buf, sizeof(buf));
- if (memcmp(w, buf, sizeof(w)) != 0) {
- printf("eap_sim_prf failed\n");
- return 1;
- }
-
- return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
- int errors = 0;
-
- errors += test_eap_sim_prf();
-
- return errors;
-}
diff --git a/contrib/wpa/wpa_supplicant/tests/test_wpa.c b/contrib/wpa/wpa_supplicant/tests/test_wpa.c
deleted file mode 100644
index 39971f2..0000000
--- a/contrib/wpa/wpa_supplicant/tests/test_wpa.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Test program for combined WPA authenticator/supplicant
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "../config.h"
-#include "rsn_supp/wpa.h"
-#include "rsn_supp/wpa_ie.h"
-#include "ap/wpa_auth.h"
-
-
-struct wpa {
- u8 auth_addr[ETH_ALEN];
- u8 supp_addr[ETH_ALEN];
- u8 psk[PMK_LEN];
-
- /* from authenticator */
- u8 auth_eapol_dst[ETH_ALEN];
- u8 *auth_eapol;
- size_t auth_eapol_len;
-
- /* from supplicant */
- u8 *supp_eapol;
- size_t supp_eapol_len;
-
- struct wpa_sm *supp;
- struct wpa_authenticator *auth_group;
- struct wpa_state_machine *auth;
-
- struct wpa_ssid ssid;
- u8 supp_ie[80];
- size_t supp_ie_len;
-};
-
-
-static int supp_get_bssid(void *ctx, u8 *bssid)
-{
- struct wpa *wpa = ctx;
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
- os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
- return 0;
-}
-
-
-static void supp_set_state(void *ctx, enum wpa_states state)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
-}
-
-
-static void auth_eapol_rx(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
- wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
- wpa->supp_eapol_len);
-}
-
-
-static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
- size_t len)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
- "len=%lu)",
- __func__, MAC2STR(dest), proto, (unsigned long) len);
-
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = os_malloc(len);
- if (wpa->supp_eapol == NULL)
- return -1;
- os_memcpy(wpa->supp_eapol, buf, len);
- wpa->supp_eapol_len = len;
- eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
-
- return 0;
-}
-
-
-static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
- u16 data_len, size_t *msg_len, void **data_pos)
-{
- struct ieee802_1x_hdr *hdr;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
- __func__, type, data_len);
-
- *msg_len = sizeof(*hdr) + data_len;
- hdr = os_malloc(*msg_len);
- if (hdr == NULL)
- return NULL;
-
- hdr->version = 2;
- hdr->type = type;
- hdr->length = host_to_be16(data_len);
-
- if (data)
- os_memcpy(hdr + 1, data, data_len);
- else
- os_memset(hdr + 1, 0, data_len);
-
- if (data_pos)
- *data_pos = hdr + 1;
-
- return (u8 *) hdr;
-}
-
-
-static int supp_get_beacon_ie(void *ctx)
-{
- struct wpa *wpa = ctx;
- const u8 *ie;
- size_t ielen;
-
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-
- ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
- if (ie == NULL || ielen < 1)
- return -1;
- if (ie[0] == WLAN_EID_RSN)
- return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
- return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
-}
-
-
-static int supp_set_key(void *ctx, enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
- "set_tx=%d)",
- __func__, alg, MAC2STR(addr), key_idx, set_tx);
- wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
- wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
- return 0;
-}
-
-
-static int supp_mlme_setprotection(void *ctx, const u8 *addr,
- int protection_type, int key_type)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
- "key_type=%d)",
- __func__, MAC2STR(addr), protection_type, key_type);
- return 0;
-}
-
-
-static void supp_cancel_auth_timeout(void *ctx)
-{
- wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-}
-
-
-static int supp_init(struct wpa *wpa)
-{
- struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
- if (ctx == NULL)
- return -1;
-
- ctx->ctx = wpa;
- ctx->msg_ctx = wpa;
- ctx->set_state = supp_set_state;
- ctx->get_bssid = supp_get_bssid;
- ctx->ether_send = supp_ether_send;
- ctx->get_beacon_ie = supp_get_beacon_ie;
- ctx->alloc_eapol = supp_alloc_eapol;
- ctx->set_key = supp_set_key;
- ctx->mlme_setprotection = supp_mlme_setprotection;
- ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
- wpa->supp = wpa_sm_init(ctx);
- if (wpa->supp == NULL) {
- wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
- return -1;
- }
-
- wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
- wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
- wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN);
-
- wpa->supp_ie_len = sizeof(wpa->supp_ie);
- if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
- &wpa->supp_ie_len) < 0) {
- wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
- " failed");
- return -1;
- }
-
- wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
-
- return 0;
-}
-
-
-static void auth_logger(void *ctx, const u8 *addr, logger_level level,
- const char *txt)
-{
- if (addr)
- wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
- MAC2STR(addr), txt);
- else
- wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
-}
-
-
-static void supp_eapol_rx(void *eloop_data, void *user_ctx)
-{
- struct wpa *wpa = eloop_data;
-
- wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
- wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
- wpa->auth_eapol_len);
-}
-
-
-static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
- size_t data_len, int encrypt)
-{
- struct wpa *wpa = ctx;
-
- wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
- "encrypt=%d)",
- __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
-
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = os_malloc(data_len);
- if (wpa->auth_eapol == NULL)
- return -1;
- os_memcpy(wpa->auth_eapol_dst, addr, ETH_ALEN);
- os_memcpy(wpa->auth_eapol, data, data_len);
- wpa->auth_eapol_len = data_len;
- eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
-
- return 0;
-}
-
-
-static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
-{
- struct wpa *wpa = ctx;
- wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
- __func__, MAC2STR(addr), prev_psk);
- if (prev_psk)
- return NULL;
- return wpa->psk;
-}
-
-
-static int auth_init_group(struct wpa *wpa)
-{
- struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
-
- wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
-
- os_memset(&conf, 0, sizeof(conf));
- conf.wpa = 2;
- conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- conf.wpa_pairwise = WPA_CIPHER_CCMP;
- conf.rsn_pairwise = WPA_CIPHER_CCMP;
- conf.wpa_group = WPA_CIPHER_CCMP;
- conf.eapol_version = 2;
-
- os_memset(&cb, 0, sizeof(cb));
- cb.ctx = wpa;
- cb.logger = auth_logger;
- cb.send_eapol = auth_send_eapol;
- cb.get_psk = auth_get_psk;
-
- wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb);
- if (wpa->auth_group == NULL) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
- return -1;
- }
-
- return 0;
-}
-
-
-static int auth_init(struct wpa *wpa)
-{
- wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL);
- if (wpa->auth == NULL) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
- return -1;
- }
-
- if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
- wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) {
- wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
- return -1;
- }
-
- wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
-
- wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
-
- return 0;
-}
-
-
-static void deinit(struct wpa *wpa)
-{
- wpa_auth_sta_deinit(wpa->auth);
- wpa_sm_deinit(wpa->supp);
- wpa_deinit(wpa->auth_group);
- os_free(wpa->auth_eapol);
- wpa->auth_eapol = NULL;
- os_free(wpa->supp_eapol);
- wpa->supp_eapol = NULL;
-}
-
-
-int main(int argc, char *argv[])
-{
- struct wpa wpa;
-
- if (os_program_init())
- return -1;
-
- os_memset(&wpa, 0, sizeof(wpa));
- os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
- os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
- os_memset(wpa.psk, 0x44, PMK_LEN);
-
- wpa_debug_level = 0;
- wpa_debug_show_keys = 1;
-
- if (eloop_init()) {
- wpa_printf(MSG_ERROR, "Failed to initialize event loop");
- return -1;
- }
-
- if (auth_init_group(&wpa) < 0)
- return -1;
-
- if (supp_init(&wpa) < 0)
- return -1;
-
- if (auth_init(&wpa) < 0)
- return -1;
-
- wpa_printf(MSG_DEBUG, "Starting eloop");
- eloop_run();
- wpa_printf(MSG_DEBUG, "eloop done");
-
- deinit(&wpa);
-
- eloop_destroy();
-
- os_program_deinit();
-
- return 0;
-}
diff --git a/contrib/wpa/wpa_supplicant/utils/log2pcap.py b/contrib/wpa/wpa_supplicant/utils/log2pcap.py
index 65e2fa1..141aecb 100755
--- a/contrib/wpa/wpa_supplicant/utils/log2pcap.py
+++ b/contrib/wpa/wpa_supplicant/utils/log2pcap.py
@@ -28,7 +28,7 @@ if __name__ == "__main__":
input = sys.argv[1]
pcap = sys.argv[2]
except IndexError:
- print "Usage: %s <log file> <pcap file>" % sys.argv[0]
+ print("Usage: %s <log file> <pcap file>" % sys.argv[0])
sys.exit(2)
input_file = open(input, 'r')
diff --git a/contrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj b/contrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
new file mode 100644
index 0000000..af7b3fe
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
@@ -0,0 +1,473 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="eapol_test"
+ ProjectGUID="{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}"
+ RootNamespace="eapol_test"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\crypto\aes-cbc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-ctr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-eax.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-encblock.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-omac1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-unwrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-wrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\base64.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\blacklist.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\bss.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\chap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config_file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\crypto_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface_named_pipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_aka.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_gtc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_leap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_methods.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_otp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_peap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_peap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\eap_register.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_sim.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_sim_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tnc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_ttls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\eapol_test.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\eloop_win.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\fips_prf_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\ip_addr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\ms_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\notify.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\pcsc_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\peerkey.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\preauth.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\radius\radius.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\radius\radius_client.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\scan.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-prf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\tls_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\tncc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\common\wpa_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpa_debug.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa_ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_supplicant.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpabuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpas_glue.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/contrib/wpa/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj b/contrib/wpa/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj
new file mode 100644
index 0000000..e79fc0f
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="win_if_list"
+ ProjectGUID="{9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}"
+ RootNamespace="win_if_list"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\src\utils;C:\dev\WpdPack\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wpcap.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\src\utils;C:\dev\WpdPack\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wpcap.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\win_if_list.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/contrib/wpa/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj b/contrib/wpa/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj
new file mode 100644
index 0000000..d2de768
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="wpa_cli"
+ ProjectGUID="{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}"
+ RootNamespace="wpa_cli"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\utils"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\utils"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_cli.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\common\wpa_ctrl.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/contrib/wpa/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj b/contrib/wpa/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
new file mode 100644
index 0000000..97aa2c5
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="wpa_passphrase"
+ ProjectGUID="{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}"
+ RootNamespace="wpa_passphrase"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\utils;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\utils;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5-internal.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-internal.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-prf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_passphrase.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant.sln b/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant.sln
new file mode 100644
index 0000000..df89e31
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant.sln
@@ -0,0 +1,52 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_supplicant", "wpa_supplicant\wpa_supplicant.vcproj", "{8BCFDA77-AEDC-4168-8897-5B73105BBB87}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_cli", "wpa_cli\wpa_cli.vcproj", "{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpasvc", "wpasvc\wpasvc.vcproj", "{E2A4A85F-CA77-406D-8ABF-63EF94545ACC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_passphrase", "wpa_passphrase\wpa_passphrase.vcproj", "{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_if_list", "win_if_list\win_if_list.vcproj", "{9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eapol_test", "eapol_test\eapol_test.vcproj", "{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}"
+EndProject
+Global
+ GlobalSection(DPCodeReviewSolutionGUID) = preSolution
+ DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000}
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.Build.0 = Debug|Win32
+ {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.ActiveCfg = Release|Win32
+ {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.Build.0 = Release|Win32
+ {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.Build.0 = Debug|Win32
+ {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.ActiveCfg = Release|Win32
+ {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.Build.0 = Release|Win32
+ {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.Build.0 = Debug|Win32
+ {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.ActiveCfg = Release|Win32
+ {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.Build.0 = Release|Win32
+ {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.Build.0 = Debug|Win32
+ {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.ActiveCfg = Release|Win32
+ {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.Build.0 = Release|Win32
+ {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.Build.0 = Debug|Win32
+ {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.ActiveCfg = Release|Win32
+ {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.Build.0 = Release|Win32
+ {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.Build.0 = Debug|Win32
+ {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Release|Win32.ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj b/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
new file mode 100644
index 0000000..51acab9
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
@@ -0,0 +1,461 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="wpa_supplicant"
+ ProjectGUID="{8BCFDA77-AEDC-4168-8897-5B73105BBB87}"
+ RootNamespace="wpa_supplicant"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\crypto\aes-cbc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-ctr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-eax.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-encblock.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-omac1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-unwrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-wrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\base64.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\blacklist.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\bss.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\chap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config_file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\crypto_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface_named_pipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_ndis.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_ndis_.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\drivers.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_gtc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_leap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_methods.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_otp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_peap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_peap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\eap_register.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tnc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_ttls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\eloop_win.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\ms_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\ndis_events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\notify.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\pcsc_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\peerkey.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\preauth.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\scan.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-prf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\tls_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\tncc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\common\wpa_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpa_debug.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa_ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_supplicant.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpabuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpas_glue.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/contrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj b/contrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
new file mode 100644
index 0000000..6fd8af8
--- /dev/null
+++ b/contrib/wpa/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
@@ -0,0 +1,461 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="wpasvc"
+ ProjectGUID="{E2A4A85F-CA77-406D-8ABF-63EF94545ACC}"
+ RootNamespace="wpasvc"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\crypto\aes-cbc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-ctr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-eax.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-encblock.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-omac1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-unwrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\aes-wrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\base64.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\blacklist.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\bss.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\chap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config_winreg.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\crypto_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface_named_pipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_ndis.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_ndis_.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\drivers.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_gtc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_leap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_methods.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_otp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_peap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_peap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\eap_register.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tnc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_ttls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\eloop_win.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\main_winsvc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\ms_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\ndis_events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\notify.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\pcsc_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\peerkey.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\preauth.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\scan.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-pbkdf2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-prf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1-tlsprf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\tls_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\tncc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\common\wpa_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpa_debug.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa_ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_supplicant.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpabuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpas_glue.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/contrib/wpa/wpa_supplicant/wifi_display.c b/contrib/wpa/wpa_supplicant/wifi_display.c
index c363b21..c94e461 100644
--- a/contrib/wpa/wpa_supplicant/wifi_display.c
+++ b/contrib/wpa/wpa_supplicant/wifi_display.c
@@ -86,6 +86,7 @@ static int wifi_display_update_wfd_ie(struct wpa_global *global)
p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
p2p_set_wfd_ie_go_neg(global->p2p, NULL);
p2p_set_wfd_dev_info(global->p2p, NULL);
+ p2p_set_wfd_r2_dev_info(global->p2p, NULL);
p2p_set_wfd_assoc_bssid(global->p2p, NULL);
p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
return 0;
@@ -93,6 +94,8 @@ static int wifi_display_update_wfd_ie(struct wpa_global *global)
p2p_set_wfd_dev_info(global->p2p,
global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+ p2p_set_wfd_r2_dev_info(
+ global->p2p, global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]);
p2p_set_wfd_assoc_bssid(
global->p2p,
global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
@@ -133,6 +136,11 @@ static int wifi_display_update_wfd_ie(struct wpa_global *global)
if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
len += wpabuf_len(global->wfd_subelem[
WFD_SUBELEM_DEVICE_INFO]);
+
+ if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_R2_DEVICE_INFO]);
+
if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
len += wpabuf_len(global->wfd_subelem[
WFD_SUBELEM_ASSOCIATED_BSSID]);
@@ -151,6 +159,11 @@ static int wifi_display_update_wfd_ie(struct wpa_global *global)
if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
wpabuf_put_buf(buf,
global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+
+ if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]);
+
if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
wpabuf_put_buf(buf, global->wfd_subelem[
WFD_SUBELEM_ASSOCIATED_BSSID]);
diff --git a/contrib/wpa/wpa_supplicant/wmm_ac.c b/contrib/wpa/wpa_supplicant/wmm_ac.c
index 5625d36..38800cc 100644
--- a/contrib/wpa/wpa_supplicant/wmm_ac.c
+++ b/contrib/wpa/wpa_supplicant/wmm_ac.c
@@ -87,13 +87,10 @@ static int wmm_ac_add_ts(struct wpa_supplicant *wpa_s, const u8 *addr,
}
/* copy tspec */
- _tspec = os_malloc(sizeof(*_tspec));
+ _tspec = os_memdup(tspec, sizeof(*_tspec));
if (!_tspec)
return -1;
- /* store the admitted TSPEC */
- os_memcpy(_tspec, tspec, sizeof(*_tspec));
-
if (dir != WMM_AC_DIR_DOWNLINK) {
ret = wpa_drv_add_ts(wpa_s, tsid, addr, up, admitted_time);
wpa_printf(MSG_DEBUG,
@@ -474,13 +471,8 @@ static int wmm_ac_init(struct wpa_supplicant *wpa_s, const u8 *ies,
return -1;
}
- if (!ies) {
- wpa_printf(MSG_ERROR, "WMM AC: Missing IEs");
- return -1;
- }
-
- if (!(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
- wpa_printf(MSG_DEBUG, "WMM AC: Missing U-APSD configuration");
+ if (!ies || !(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
+ /* WMM AC not in use for this connection */
return -1;
}
@@ -525,7 +517,7 @@ static void wmm_ac_deinit(struct wpa_supplicant *wpa_s)
for (i = 0; i < WMM_AC_NUM; i++)
wmm_ac_del_ts(wpa_s, i, TS_DIR_IDX_ALL);
- /* delete pending add_ts requset */
+ /* delete pending add_ts request */
wmm_ac_del_req(wpa_s, 1);
os_free(wpa_s->wmm_ac_assoc_info);
diff --git a/contrib/wpa/wpa_supplicant/wmm_ac.h b/contrib/wpa/wpa_supplicant/wmm_ac.h
index 5171b16..0d15ad0 100644
--- a/contrib/wpa/wpa_supplicant/wmm_ac.h
+++ b/contrib/wpa/wpa_supplicant/wmm_ac.h
@@ -88,7 +88,7 @@ enum ts_dir_idx {
*/
struct wmm_ac_addts_request {
/*
- * dialog token - Used to link the recived ADDTS response with this
+ * dialog token - Used to link the received ADDTS response with this
* saved ADDTS request when ADDTS response is being handled
*/
u8 dialog_token;
diff --git a/contrib/wpa/wpa_supplicant/wnm_sta.c b/contrib/wpa/wpa_supplicant/wnm_sta.c
index d88c863..22a2136 100644
--- a/contrib/wpa/wpa_supplicant/wnm_sta.c
+++ b/contrib/wpa/wpa_supplicant/wnm_sta.c
@@ -12,18 +12,22 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/ocv.h"
#include "rsn_supp/wpa.h"
+#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "scan.h"
#include "ctrl_iface.h"
#include "bss.h"
#include "wnm_sta.h"
+#include "notify.h"
#include "hs20_supplicant.h"
#define MAX_TFS_IE_LEN 1024
#define WNM_MAX_NEIGHBOR_REPORT 10
+#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
/* get the TFS IE from driver */
static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
@@ -37,12 +41,14 @@ static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
/* set the TFS IE to driver */
static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
- const u8 *addr, u8 *buf, u16 *buf_len,
+ const u8 *addr, const u8 *buf, u16 buf_len,
enum wnm_oper oper)
{
+ u16 len = buf_len;
+
wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
- return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
+ return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len);
}
@@ -54,8 +60,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
int res;
size_t len;
struct wnm_sleep_element *wnmsleep_ie;
- u8 *wnmtfs_ie;
- u8 wnmsleep_ie_len;
+ u8 *wnmtfs_ie, *oci_ie;
+ u8 wnmsleep_ie_len, oci_ie_len;
u16 wnmtfs_ie_len; /* possibly multiple IE(s) */
enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
WNM_SLEEP_TFS_REQ_IE_NONE;
@@ -81,12 +87,11 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
/* TFS IE(s) */
if (tfs_req) {
wnmtfs_ie_len = wpabuf_len(tfs_req);
- wnmtfs_ie = os_malloc(wnmtfs_ie_len);
+ wnmtfs_ie = os_memdup(wpabuf_head(tfs_req), wnmtfs_ie_len);
if (wnmtfs_ie == NULL) {
os_free(wnmsleep_ie);
return -1;
}
- os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len);
} else {
wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
if (wnmtfs_ie == NULL) {
@@ -103,7 +108,41 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
(u8 *) wnmtfs_ie, wnmtfs_ie_len);
- mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
+ oci_ie = NULL;
+ oci_ie_len = 0;
+#ifdef CONFIG_OCV
+ if (action == WNM_SLEEP_MODE_EXIT && wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ os_free(oci_ie);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len +
+ oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Request action frame");
@@ -128,8 +167,16 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
}
+#ifdef CONFIG_OCV
+ /* copy OCV OCI here */
+ if (oci_ie_len > 0) {
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
+ wnmsleep_ie_len + wnmtfs_ie_len, oci_ie, oci_ie_len);
+ }
+#endif /* CONFIG_OCV */
+
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
- wnmtfs_ie_len;
+ wnmtfs_ie_len + oci_ie_len;
res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
@@ -142,6 +189,7 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
os_free(wnmsleep_ie);
os_free(wnmtfs_ie);
+ os_free(oci_ie);
os_free(mgmt);
return res;
@@ -149,8 +197,8 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
- u8 *tfsresp_ie_start,
- u8 *tfsresp_ie_end)
+ const u8 *tfsresp_ie_start,
+ const u8 *tfsresp_ie_end)
{
wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
wpa_s->bssid, NULL, NULL);
@@ -166,7 +214,7 @@ static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
/* pass the TFS Resp IE(s) to driver for processing */
if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
tfsresp_ie_start,
- &tfsresp_ie_len,
+ tfsresp_ie_len,
WNM_SLEEP_TFS_RESP_IE_SET))
wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
}
@@ -195,8 +243,8 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
return;
}
- while (ptr + 1 < end) {
- if (ptr + 2 + ptr[1] > end) {
+ while (end - ptr > 1) {
+ if (2 + ptr[1] > end - ptr) {
wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
"length");
if (end > ptr) {
@@ -247,12 +295,16 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
* Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
* WNM-Sleep Mode IE | TFS Response IE
*/
- u8 *pos = (u8 *) frm; /* point to payload after the action field */
+ const u8 *pos = frm; /* point to payload after the action field */
u16 key_len_total;
struct wnm_sleep_element *wnmsleep_ie = NULL;
/* multiple TFS Resp IE (assuming consecutive) */
- u8 *tfsresp_ie_start = NULL;
- u8 *tfsresp_ie_end = NULL;
+ const u8 *tfsresp_ie_start = NULL;
+ const u8 *tfsresp_ie_end = NULL;
+#ifdef CONFIG_OCV
+ const u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
+#endif /* CONFIG_OCV */
size_t left;
if (!wpa_s->wnmsleep_used) {
@@ -273,19 +325,25 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
return;
}
pos += 3 + key_len_total;
- while (pos - frm < len) {
+ while (pos - frm + 1 < len) {
u8 ie_len = *(pos + 1);
- if (pos + 2 + ie_len > frm + len) {
+ if (2 + ie_len > frm + len - pos) {
wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
break;
}
wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
- if (*pos == WLAN_EID_WNMSLEEP)
+ if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4)
wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_RESP) {
if (!tfsresp_ie_start)
tfsresp_ie_start = pos;
tfsresp_ie_end = pos;
+#ifdef CONFIG_OCV
+ } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
+ pos[2] == WLAN_EID_EXT_OCV_OCI) {
+ oci_ie = pos + 3;
+ oci_ie_len = ie_len - 1;
+#endif /* CONFIG_OCV */
} else
wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
pos += ie_len + 2;
@@ -296,6 +354,26 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
return;
}
+#ifdef CONFIG_OCV
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
+ wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
+ return;
+ }
+
+ if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
wpa_s->wnmsleep_used = 0;
if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -335,6 +413,9 @@ void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
wpa_s->wnm_num_neighbor_report = 0;
os_free(wpa_s->wnm_neighbor_report_elements);
wpa_s->wnm_neighbor_report_elements = NULL;
+
+ wpabuf_free(wpa_s->coloc_intf_elems);
+ wpa_s->coloc_intf_elems = NULL;
}
@@ -429,6 +510,7 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
{
struct wpa_bss *bss = wpa_s->current_bss;
const char *country = NULL;
+ int freq;
if (bss) {
const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
@@ -437,7 +519,21 @@ static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
country = (const char *) (elem + 2);
}
- return ieee80211_chan_to_freq(country, op_class, chan);
+ freq = ieee80211_chan_to_freq(country, op_class, chan);
+ if (freq <= 0 && op_class == 0) {
+ /*
+ * Some APs do not advertise correct operating class
+ * information. Try to determine the most likely operating
+ * frequency based on the channel number.
+ */
+ if (chan >= 1 && chan <= 13)
+ freq = 2407 + chan * 5;
+ else if (chan == 14)
+ freq = 2484;
+ else if (chan >= 36 && chan <= 169)
+ freq = 5000 + chan * 5;
+ }
+ return freq;
}
@@ -483,20 +579,140 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
}
+static void wnm_clear_acceptable(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++)
+ wpa_s->wnm_neighbor_report_elements[i].acceptable = 0;
+}
+
+
+static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+ struct neighbor_report *nei;
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ if (nei->acceptable)
+ return wpa_bss_get_bssid(wpa_s, nei->bssid);
+ }
+
+ return NULL;
+}
+
+
+#ifdef CONFIG_MBO
static struct wpa_bss *
-compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
+get_mbo_transition_candidate(struct wpa_supplicant *wpa_s,
+ enum mbo_transition_reject_reason *reason)
{
+ struct wpa_bss *target = NULL;
+ struct wpa_bss_trans_info params;
+ struct wpa_bss_candidate_info *info = NULL;
+ struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements;
+ u8 *first_candidate_bssid = NULL, *pos;
+ unsigned int i;
+
+ params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason;
+ params.n_candidates = 0;
+ params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN);
+ if (!params.bssid)
+ return NULL;
+
+ pos = params.bssid;
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) {
+ if (nei->is_first)
+ first_candidate_bssid = nei->bssid;
+ if (!nei->acceptable)
+ continue;
+ os_memcpy(pos, nei->bssid, ETH_ALEN);
+ pos += ETH_ALEN;
+ params.n_candidates++;
+ }
+
+ if (!params.n_candidates)
+ goto end;
+
+ info = wpa_drv_get_bss_trans_status(wpa_s, &params);
+ if (!info) {
+ /* If failed to get candidate BSS transition status from driver,
+ * get the first acceptable candidate from wpa_supplicant.
+ */
+ target = wpa_bss_get_bssid(wpa_s, params.bssid);
+ goto end;
+ }
+
+ /* Get the first acceptable candidate from driver */
+ for (i = 0; i < info->num; i++) {
+ if (info->candidates[i].is_accept) {
+ target = wpa_bss_get_bssid(wpa_s,
+ info->candidates[i].bssid);
+ goto end;
+ }
+ }
+
+ /* If Disassociation Imminent is set and driver rejects all the
+ * candidate select first acceptable candidate which has
+ * rssi > disassoc_imminent_rssi_threshold
+ */
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ for (i = 0; i < info->num; i++) {
+ target = wpa_bss_get_bssid(wpa_s,
+ info->candidates[i].bssid);
+ if (target &&
+ (target->level <
+ wpa_s->conf->disassoc_imminent_rssi_threshold))
+ continue;
+ goto end;
+ }
+ }
+
+ /* While sending BTM reject use reason code of the first candidate
+ * received in BTM request frame
+ */
+ if (reason) {
+ for (i = 0; i < info->num; i++) {
+ if (first_candidate_bssid &&
+ os_memcmp(first_candidate_bssid,
+ info->candidates[i].bssid, ETH_ALEN) == 0)
+ {
+ *reason = info->candidates[i].reject_reason;
+ break;
+ }
+ }
+ }
+
+ target = NULL;
+
+end:
+ os_free(params.bssid);
+ if (info) {
+ os_free(info->candidates);
+ os_free(info);
+ }
+ return target;
+}
+#endif /* CONFIG_MBO */
+
+static struct wpa_bss *
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs,
+ enum mbo_transition_reject_reason *reason)
+{
u8 i;
struct wpa_bss *bss = wpa_s->current_bss;
struct wpa_bss *target;
if (!bss)
- return 0;
+ return NULL;
wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
MAC2STR(wpa_s->bssid), bss->level);
+ wnm_clear_acceptable(wpa_s);
+
for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
struct neighbor_report *nei;
@@ -517,6 +733,19 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
continue;
}
+ if (age_secs) {
+ struct os_reltime now;
+
+ if (os_get_reltime(&now) == 0 &&
+ os_reltime_expired(&now, &target->last_update,
+ age_secs)) {
+ wpa_printf(MSG_DEBUG,
+ "Candidate BSS is more than %ld seconds old",
+ age_secs);
+ continue;
+ }
+ }
+
if (bss->ssid_len != target->ssid_len ||
os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
/*
@@ -531,6 +760,25 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
continue;
}
+ if (wpa_s->current_ssid &&
+ !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
+ 1, 0)) {
+ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+ " (pref %d) does not match the current network profile",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1);
+ continue;
+ }
+
+ if (wpa_is_bss_tmp_disallowed(wpa_s, target)) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Candidate BSS " MACSTR
+ " retry delay is not over yet",
+ MAC2STR(nei->bssid));
+ continue;
+ }
+
if (target->level < bss->level && target->level < -80) {
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
" (pref %d) does not have sufficient signal level (%d)",
@@ -541,71 +789,320 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
continue;
}
+ nei->acceptable = 1;
+ }
+
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_trans_reason_present)
+ target = get_mbo_transition_candidate(wpa_s, reason);
+ else
+ target = get_first_acceptable(wpa_s);
+#else /* CONFIG_MBO */
+ target = get_first_acceptable(wpa_s);
+#endif /* CONFIG_MBO */
+
+ if (target) {
wpa_printf(MSG_DEBUG,
"WNM: Found an acceptable preferred transition candidate BSS "
MACSTR " (RSSI %d)",
- MAC2STR(nei->bssid), target->level);
- return target;
+ MAC2STR(target->bssid), target->level);
}
- return NULL;
+ return target;
+}
+
+
+static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
+{
+ const u8 *ie_a, *ie_b;
+
+ if (!a || !b)
+ return 0;
+
+ ie_a = wpa_bss_get_ie(a, eid);
+ ie_b = wpa_bss_get_ie(b, eid);
+
+ if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
+ return 0;
+
+ return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
+}
+
+
+static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ u32 info = 0;
+
+ info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
+
+ /*
+ * Leave the security and key scope bits unset to indicate that the
+ * security information is not available.
+ */
+
+ if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+ if (bss->caps & WLAN_CAPABILITY_QOS)
+ info |= NEI_REP_BSSID_INFO_QOS;
+ if (bss->caps & WLAN_CAPABILITY_APSD)
+ info |= NEI_REP_BSSID_INFO_APSD;
+ if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
+ info |= NEI_REP_BSSID_INFO_RM;
+ if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
+ info |= NEI_REP_BSSID_INFO_DELAYED_BA;
+ if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
+ info |= NEI_REP_BSSID_INFO_IMM_BA;
+ if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
+ info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
+ if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
+ info |= NEI_REP_BSSID_INFO_HT;
+
+ return info;
+}
+
+
+static int wnm_add_nei_rep(struct wpabuf **buf, const u8 *bssid,
+ u32 bss_info, u8 op_class, u8 chan, u8 phy_type,
+ u8 pref)
+{
+ if (wpabuf_len(*buf) + 18 >
+ IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: No room in frame for Neighbor Report element");
+ return -1;
+ }
+
+ if (wpabuf_resize(buf, 18) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Failed to allocate memory for Neighbor Report element");
+ return -1;
+ }
+
+ wpabuf_put_u8(*buf, WLAN_EID_NEIGHBOR_REPORT);
+ /* length: 13 for basic neighbor report + 3 for preference subelement */
+ wpabuf_put_u8(*buf, 16);
+ wpabuf_put_data(*buf, bssid, ETH_ALEN);
+ wpabuf_put_le32(*buf, bss_info);
+ wpabuf_put_u8(*buf, op_class);
+ wpabuf_put_u8(*buf, chan);
+ wpabuf_put_u8(*buf, phy_type);
+ wpabuf_put_u8(*buf, WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE);
+ wpabuf_put_u8(*buf, 1);
+ wpabuf_put_u8(*buf, pref);
+ return 0;
+}
+
+
+static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpabuf **buf,
+ u8 pref)
+{
+ const u8 *ie;
+ u8 op_class, chan;
+ int sec_chan = 0, vht = 0;
+ enum phy_type phy_type;
+ u32 info;
+ struct ieee80211_ht_operation *ht_oper = NULL;
+ struct ieee80211_vht_operation *vht_oper = NULL;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2) {
+ ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+
+ if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ sec_chan = 1;
+ else if (ht_oper->ht_param &
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ sec_chan = -1;
+ }
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION);
+ if (ie && ie[1] >= 1) {
+ vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
+
+ if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ ||
+ vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ ||
+ vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ vht = vht_oper->vht_op_info_chwidth;
+ }
+
+ if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class,
+ &chan) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Cannot determine operating class and channel");
+ return -2;
+ }
+
+ phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL),
+ (vht_oper != NULL));
+ if (phy_type == PHY_TYPE_UNSPECIFIED) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Cannot determine BSS phy type for Neighbor Report");
+ return -2;
+ }
+
+ info = wnm_get_bss_info(wpa_s, bss);
+
+ return wnm_add_nei_rep(buf, bss->bssid, info, op_class, chan, phy_type,
+ pref);
+}
+
+
+static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf)
+{
+ unsigned int i, pref = 255;
+ struct os_reltime now;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (!ssid)
+ return;
+
+ /*
+ * TODO: Define when scan results are no longer valid for the candidate
+ * list.
+ */
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &wpa_s->last_scan, 10))
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "WNM: Add candidate list to BSS Transition Management Response frame");
+ for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
+ struct wpa_bss *bss = wpa_s->last_scan_res[i];
+ int res;
+
+ if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) {
+ res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--);
+ if (res == -2)
+ continue; /* could not build entry for BSS */
+ if (res < 0)
+ break; /* no more room for candidates */
+ if (pref == 1)
+ break;
+ }
+ }
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "WNM: BSS Transition Management Response candidate list",
+ *buf);
}
+#define BTM_RESP_MIN_SIZE 5 + ETH_ALEN
+
static void wnm_send_bss_transition_mgmt_resp(
struct wpa_supplicant *wpa_s, u8 dialog_token,
- enum bss_trans_mgmt_status_code status, u8 delay,
- const u8 *target_bssid)
+ enum bss_trans_mgmt_status_code status,
+ enum mbo_transition_reject_reason reason,
+ u8 delay, const u8 *target_bssid)
{
- u8 buf[1000], *pos;
- struct ieee80211_mgmt *mgmt;
- size_t len;
+ struct wpabuf *buf;
int res;
- wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
- "to " MACSTR " dialog_token=%u status=%u delay=%d",
- MAC2STR(wpa_s->bssid), dialog_token, status, delay);
+ wpa_printf(MSG_DEBUG,
+ "WNM: Send BSS Transition Management Response to " MACSTR
+ " dialog_token=%u status=%u reason=%u delay=%d",
+ MAC2STR(wpa_s->bssid), dialog_token, status, reason, delay);
if (!wpa_s->current_bss) {
wpa_printf(MSG_DEBUG,
"WNM: Current BSS not known - drop response");
return;
}
- mgmt = (struct ieee80211_mgmt *) buf;
- os_memset(&buf, 0, sizeof(buf));
- os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
- os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
- os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
- mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- mgmt->u.action.category = WLAN_ACTION_WNM;
- mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
- mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
- mgmt->u.action.u.bss_tm_resp.status_code = status;
- mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
- pos = mgmt->u.action.u.bss_tm_resp.variable;
+ buf = wpabuf_alloc(BTM_RESP_MIN_SIZE);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Failed to allocate memory for BTM response");
+ return;
+ }
+
+ wpa_s->bss_tm_status = status;
+ wpas_notify_bss_tm_status(wpa_s);
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP);
+ wpabuf_put_u8(buf, dialog_token);
+ wpabuf_put_u8(buf, status);
+ wpabuf_put_u8(buf, delay);
if (target_bssid) {
- os_memcpy(pos, target_bssid, ETH_ALEN);
- pos += ETH_ALEN;
+ wpabuf_put_data(buf, target_bssid, ETH_ALEN);
} else if (status == WNM_BSS_TM_ACCEPT) {
/*
* P802.11-REVmc clarifies that the Target BSSID field is always
* present when status code is zero, so use a fake value here if
* no BSSID is yet known.
*/
- os_memset(pos, 0, ETH_ALEN);
- pos += ETH_ALEN;
+ wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN);
}
- len = pos - (u8 *) &mgmt->u.action.category;
+ if (status == WNM_BSS_TM_ACCEPT)
+ wnm_add_cand_list(wpa_s, &buf);
+
+#ifdef CONFIG_MBO
+ if (status != WNM_BSS_TM_ACCEPT &&
+ wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) {
+ u8 mbo[10];
+ size_t ret;
+
+ ret = wpas_mbo_ie_bss_trans_reject(wpa_s, mbo, sizeof(mbo),
+ reason);
+ if (ret) {
+ if (wpabuf_resize(&buf, ret) < 0) {
+ wpabuf_free(buf);
+ wpa_printf(MSG_DEBUG,
+ "WNM: Failed to allocate memory for MBO IE");
+ return;
+ }
+
+ wpabuf_put_data(buf, mbo, ret);
+ }
+ }
+#endif /* CONFIG_MBO */
res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
- &mgmt->u.action.category, len, 0);
+ wpabuf_head_u8(buf), wpabuf_len(buf), 0);
if (res < 0) {
wpa_printf(MSG_DEBUG,
"WNM: Failed to send BSS Transition Management Response");
}
+
+ wpabuf_free(buf);
+}
+
+
+static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid,
+ int after_new_scan)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Transition to BSS " MACSTR
+ " based on BSS Transition Management Request (old BSSID "
+ MACSTR " after_new_scan=%d)",
+ MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan);
+
+ /* Send the BSS Management Response - Accept */
+ if (wpa_s->wnm_reply) {
+ wpa_s->wnm_reply = 0;
+ wpa_printf(MSG_DEBUG,
+ "WNM: Sending successful BSS Transition Management Response");
+ wnm_send_bss_transition_mgmt_resp(
+ wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT,
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
+ bss->bssid);
+ }
+
+ if (bss == wpa_s->current_bss) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Already associated with the preferred candidate");
+ wnm_deallocate_memory(wpa_s);
+ return;
+ }
+
+ wpa_s->reassociate = 1;
+ wpa_printf(MSG_DEBUG, "WNM: Issuing connect");
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ wnm_deallocate_memory(wpa_s);
}
@@ -614,10 +1111,14 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
struct wpa_bss *bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
+ enum mbo_transition_reject_reason reason =
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
if (!wpa_s->wnm_neighbor_report_elements)
return 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Process scan results for BSS Transition Management");
if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
&wpa_s->scan_trigger_time)) {
wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
@@ -633,7 +1134,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
}
/* Compare the Neighbor Report and scan results */
- bss = compare_scan_neighbor_results(wpa_s);
+ bss = compare_scan_neighbor_results(wpa_s, 0, &reason);
if (!bss) {
wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
@@ -641,24 +1142,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
}
/* Associate to the network */
- /* Send the BSS Management Response - Accept */
- if (wpa_s->wnm_reply) {
- wpa_s->wnm_reply = 0;
- wnm_send_bss_transition_mgmt_resp(wpa_s,
- wpa_s->wnm_dialog_token,
- WNM_BSS_TM_ACCEPT,
- 0, bss->bssid);
- }
-
- if (bss == wpa_s->current_bss) {
- wpa_printf(MSG_DEBUG,
- "WNM: Already associated with the preferred candidate");
- return 1;
- }
-
- wpa_s->reassociate = 1;
- wpa_supplicant_connect(wpa_s, bss, ssid);
- wnm_deallocate_memory(wpa_s);
+ wnm_bss_tm_connect(wpa_s, bss, ssid, 1);
return 1;
send_bss_resp_fail:
@@ -671,7 +1155,7 @@ send_bss_resp_fail:
wpa_s->wnm_reply = 0;
wnm_send_bss_transition_mgmt_resp(wpa_s,
wpa_s->wnm_dialog_token,
- status, 0, NULL);
+ status, reason, 0, NULL);
}
wnm_deallocate_memory(wpa_s);
@@ -799,16 +1283,97 @@ static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
}
+static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_scan_results *scan_res;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ u8 i, found = 0;
+ size_t j;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Fetch current scan results from the driver for checking transition candidates");
+ scan_res = wpa_drv_get_scan_results2(wpa_s);
+ if (!scan_res) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results");
+ return 0;
+ }
+
+ if (scan_res->fetch_time.sec == 0)
+ os_get_reltime(&scan_res->fetch_time);
+
+ filter_scan_res(wpa_s, scan_res);
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ if (nei->preference_present && nei->preference == 0)
+ continue;
+
+ for (j = 0; j < scan_res->num; j++) {
+ struct wpa_scan_res *res;
+ const u8 *ssid_ie;
+
+ res = scan_res->res[j];
+ if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 ||
+ res->age > WNM_SCAN_RESULT_AGE * 1000)
+ continue;
+ bss = wpa_s->current_bss;
+ ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
+ if (bss && ssid_ie &&
+ (bss->ssid_len != ssid_ie[1] ||
+ os_memcmp(bss->ssid, ssid_ie + 2,
+ bss->ssid_len) != 0))
+ continue;
+
+ /* Potential candidate found */
+ found = 1;
+ scan_snr(res);
+ scan_est_throughput(wpa_s, res);
+ wpa_bss_update_scan_res(wpa_s, res,
+ &scan_res->fetch_time);
+ }
+ }
+
+ wpa_scan_results_free(scan_res);
+ if (!found) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: No transition candidate matches existing scan results");
+ return 0;
+ }
+
+ bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE, NULL);
+ if (!bss) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Comparison of scan results against transition candidates did not find matches");
+ return 0;
+ }
+
+ /* Associate to the network */
+ wnm_bss_tm_connect(wpa_s, bss, ssid, 0);
+ return 1;
+}
+
+
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
const u8 *pos, const u8 *end,
int reply)
{
unsigned int beacon_int;
u8 valid_int;
+#ifdef CONFIG_MBO
+ const u8 *vendor;
+#endif /* CONFIG_MBO */
- if (pos + 5 > end)
+ if (end - pos < 5)
return;
+#ifdef CONFIG_MBO
+ wpa_s->wnm_mbo_trans_reason_present = 0;
+ wpa_s->wnm_mbo_transition_reason = 0;
+#endif /* CONFIG_MBO */
+
if (wpa_s->current_bss)
beacon_int = wpa_s->current_bss->beacon_int;
else
@@ -826,10 +1391,23 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
wpa_s->wnm_dissoc_timer, valid_int);
+#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS)
+ if (wpa_s->reject_btm_req_reason) {
+ wpa_printf(MSG_INFO,
+ "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d",
+ wpa_s->reject_btm_req_reason);
+ wnm_send_bss_transition_mgmt_resp(
+ wpa_s, wpa_s->wnm_dialog_token,
+ wpa_s->reject_btm_req_reason,
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
+ return;
+ }
+#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */
+
pos += 5;
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
- if (pos + 12 > end) {
+ if (end - pos < 12) {
wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
return;
}
@@ -840,7 +1418,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
char url[256];
- if (pos + 1 > end || pos + 1 + pos[0] > end) {
+ if (end - pos < 1 || 1 + pos[0] > end - pos) {
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
"Management Request (URL)");
return;
@@ -865,6 +1443,12 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
}
}
+#ifdef CONFIG_MBO
+ vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
+ if (vendor)
+ wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
+#endif /* CONFIG_MBO */
+
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
unsigned int valid_ms;
@@ -876,7 +1460,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
if (wpa_s->wnm_neighbor_report_elements == NULL)
return;
- while (pos + 2 <= end &&
+ while (end - pos >= 2 &&
wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
{
u8 tag = *pos++;
@@ -884,7 +1468,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
tag);
- if (pos + len > end) {
+ if (len > end - pos) {
wpa_printf(MSG_DEBUG, "WNM: Truncated request");
return;
}
@@ -893,11 +1477,32 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
rep = &wpa_s->wnm_neighbor_report_elements[
wpa_s->wnm_num_neighbor_report];
wnm_parse_neighbor_report(wpa_s, pos, len, rep);
+ wpa_s->wnm_num_neighbor_report++;
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_trans_reason_present &&
+ wpa_s->wnm_num_neighbor_report == 1) {
+ rep->is_first = 1;
+ wpa_printf(MSG_DEBUG,
+ "WNM: First transition candidate is "
+ MACSTR, MAC2STR(rep->bssid));
+ }
+#endif /* CONFIG_MBO */
}
pos += len;
- wpa_s->wnm_num_neighbor_report++;
}
+
+ if (!wpa_s->wnm_num_neighbor_report) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Candidate list included bit is set, but no candidates found");
+ wnm_send_bss_transition_mgmt_resp(
+ wpa_s, wpa_s->wnm_dialog_token,
+ WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
+ NULL);
+ return;
+ }
+
wnm_sort_cand_list(wpa_s);
wnm_dump_cand_list(wpa_s);
valid_ms = valid_int * beacon_int * 128 / 125;
@@ -911,6 +1516,20 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
wpa_s->wnm_cand_valid_until.usec %= 1000000;
os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
+ /*
+ * Fetch the latest scan results from the kernel and check for
+ * candidates based on those results first. This can help in
+ * finding more up-to-date information should the driver has
+ * done some internal scanning operations after the last scan
+ * result update in wpa_supplicant.
+ */
+ if (wnm_fetch_scan_results(wpa_s) > 0)
+ return;
+
+ /*
+ * Try to use previously received scan results, if they are
+ * recent enough to use for a connection.
+ */
if (wpa_s->last_scan_res_used > 0) {
struct os_reltime now;
@@ -926,6 +1545,14 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
}
wnm_set_scan_freqs(wpa_s);
+ if (wpa_s->wnm_num_neighbor_report == 1) {
+ os_memcpy(wpa_s->next_scan_bssid,
+ wpa_s->wnm_neighbor_report_elements[0].bssid,
+ ETH_ALEN);
+ wpa_printf(MSG_DEBUG,
+ "WNM: Scan only for a specific BSSID since there is only a single candidate "
+ MACSTR, MAC2STR(wpa_s->next_scan_bssid));
+ }
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else if (reply) {
enum bss_trans_mgmt_status_code status;
@@ -935,44 +1562,65 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
status = WNM_BSS_TM_REJECT_UNSPECIFIED;
}
- wnm_send_bss_transition_mgmt_resp(wpa_s,
- wpa_s->wnm_dialog_token,
- status, 0, NULL);
+ wnm_send_bss_transition_mgmt_resp(
+ wpa_s, wpa_s->wnm_dialog_token, status,
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
}
}
+#define BTM_QUERY_MIN_SIZE 4
+
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
- u8 query_reason)
+ u8 query_reason,
+ const char *btm_candidates,
+ int cand_list)
{
- u8 buf[1000], *pos;
- struct ieee80211_mgmt *mgmt;
- size_t len;
+ struct wpabuf *buf;
int ret;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
- MACSTR " query_reason=%u",
- MAC2STR(wpa_s->bssid), query_reason);
+ MACSTR " query_reason=%u%s",
+ MAC2STR(wpa_s->bssid), query_reason,
+ cand_list ? " candidate list" : "");
- mgmt = (struct ieee80211_mgmt *) buf;
- os_memset(&buf, 0, sizeof(buf));
- os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
- os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
- os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
- mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- mgmt->u.action.category = WLAN_ACTION_WNM;
- mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
- mgmt->u.action.u.bss_tm_query.dialog_token = 1;
- mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
- pos = mgmt->u.action.u.bss_tm_query.variable;
+ buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE);
+ if (!buf)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, query_reason);
+
+ if (cand_list)
+ wnm_add_cand_list(wpa_s, &buf);
+
+ if (btm_candidates) {
+ const size_t max_len = 1000;
+
+ ret = wpabuf_resize(&buf, max_len);
+ if (ret < 0) {
+ wpabuf_free(buf);
+ return ret;
+ }
- len = pos - (u8 *) &mgmt->u.action.category;
+ ret = ieee802_11_parse_candidate_list(btm_candidates,
+ wpabuf_put(buf, 0),
+ max_len);
+ if (ret < 0) {
+ wpabuf_free(buf);
+ return ret;
+ }
+
+ wpabuf_put(buf, ret);
+ }
ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
- &mgmt->u.action.category, len, 0);
+ wpabuf_head_u8(buf), wpabuf_len(buf), 0);
+ wpabuf_free(buf);
return ret;
}
@@ -987,7 +1635,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
pos = data;
end = data + len;
- while (pos + 1 < end) {
+ while (end - pos > 1) {
ie = *pos++;
ie_len = *pos++;
wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
@@ -1025,7 +1673,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
url = NULL;
osu_method = 1;
} else {
- if (pos + url_len + 1 > ie_end) {
+ if (url_len + 1 > ie_end - pos) {
wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
url_len,
(int) (ie_end - pos));
@@ -1064,7 +1712,7 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
"Imminent - Reason Code %u "
"Re-Auth Delay %u URL Length %u",
code, reauth_delay, url_len);
- if (pos + url_len > ie_end)
+ if (url_len > ie_end - pos)
break;
url = os_malloc(url_len + 1);
if (url == NULL)
@@ -1077,6 +1725,32 @@ static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
pos = next;
continue;
}
+
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
+ WPA_GET_BE24(pos) == OUI_WFA &&
+ pos[3] == HS20_WNM_T_C_ACCEPTANCE) {
+ const u8 *ie_end;
+ u8 url_len;
+ char *url;
+
+ ie_end = pos + ie_len;
+ pos += 4;
+ url_len = *pos++;
+ wpa_printf(MSG_DEBUG,
+ "WNM: HS 2.0 Terms and Conditions Acceptance (URL Length %u)",
+ url_len);
+ if (url_len > ie_end - pos)
+ break;
+ url = os_malloc(url_len + 1);
+ if (!url)
+ break;
+ os_memcpy(url, pos, url_len);
+ url[url_len] = '\0';
+ hs20_rx_t_c_acceptance(wpa_s, url);
+ os_free(url);
+ pos = next;
+ continue;
+ }
#endif /* CONFIG_HS20 */
pos = next;
@@ -1124,6 +1798,46 @@ static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s,
}
+static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *frm,
+ int len)
+{
+ u8 dialog_token, req_info, auto_report, timeout;
+
+ if (!wpa_s->conf->coloc_intf_reporting)
+ return;
+
+ /* Dialog Token [1] | Request Info [1] */
+
+ if (len < 2)
+ return;
+ dialog_token = frm[0];
+ req_info = frm[1];
+ auto_report = req_info & 0x03;
+ timeout = req_info >> 2;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")",
+ dialog_token, auto_report, timeout, MAC2STR(sa));
+
+ if (dialog_token == 0)
+ return; /* only nonzero values are used for request */
+
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Collocated Interference Request frame not from current AP - ignore it");
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u",
+ dialog_token, auto_report, timeout);
+ wpa_s->coloc_intf_dialog_token = dialog_token;
+ wpa_s->coloc_intf_auto_report = auto_report;
+ wpa_s->coloc_intf_timeout = timeout;
+}
+
+
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -1157,8 +1871,75 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
case WNM_NOTIFICATION_REQ:
ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
break;
+ case WNM_COLLOCATED_INTERFERENCE_REQ:
+ ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos,
+ end - pos);
+ break;
default:
wpa_printf(MSG_ERROR, "WNM: Unknown request");
break;
}
}
+
+
+int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
+ const struct wpabuf *elems)
+{
+ struct wpabuf *buf;
+ int ret;
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to "
+ MACSTR " (dialog token %u)",
+ MAC2STR(wpa_s->bssid), dialog_token);
+
+ buf = wpabuf_alloc(3 + wpabuf_len(elems));
+ if (!buf)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT);
+ wpabuf_put_u8(buf, dialog_token);
+ wpabuf_put_buf(buf, elems);
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head_u8(buf), wpabuf_len(buf), 0);
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
+ struct wpabuf *elems)
+{
+ wpabuf_free(wpa_s->coloc_intf_elems);
+ if (elems && wpabuf_len(elems) == 0) {
+ wpabuf_free(elems);
+ elems = NULL;
+ }
+ wpa_s->coloc_intf_elems = elems;
+
+ if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems &&
+ wpa_s->coloc_intf_dialog_token &&
+ (wpa_s->coloc_intf_auto_report == 1 ||
+ wpa_s->coloc_intf_auto_report == 3)) {
+ /* TODO: Check that there has not been less than
+ * wpa_s->coloc_intf_timeout * 200 TU from the last report.
+ */
+ wnm_send_coloc_intf_report(wpa_s,
+ wpa_s->coloc_intf_dialog_token,
+ wpa_s->coloc_intf_elems);
+ }
+}
+
+
+void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+ wpa_s->coloc_intf_dialog_token = 0;
+ wpa_s->coloc_intf_auto_report = 0;
+#endif /* CONFIG_WNM */
+}
diff --git a/contrib/wpa/wpa_supplicant/wnm_sta.h b/contrib/wpa/wpa_supplicant/wnm_sta.h
index 8de4348..29625f8 100644
--- a/contrib/wpa/wpa_supplicant/wnm_sta.h
+++ b/contrib/wpa/wpa_supplicant/wnm_sta.h
@@ -43,6 +43,10 @@ struct neighbor_report {
unsigned int rm_capab_present:1;
unsigned int bearing_present:1;
unsigned int bss_term_present:1;
+ unsigned int acceptable:1;
+#ifdef CONFIG_MBO
+ unsigned int is_first:1;
+#endif /* CONFIG_MBO */
struct measurement_pilot *meas_pilot;
struct multiple_bssid *mul_bssid;
int freq;
@@ -56,13 +60,21 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len);
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
- u8 query_reason);
+ u8 query_reason,
+ const char *btm_candidates,
+ int cand_list);
+
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
+ const struct wpabuf *elems);
+void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
+ struct wpabuf *elems);
#ifdef CONFIG_WNM
int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
+void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s);
#else /* CONFIG_WNM */
@@ -72,6 +84,10 @@ static inline int wnm_scan_process(struct wpa_supplicant *wpa_s,
return 0;
}
+static inline void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
+{
+}
+
#endif /* CONFIG_WNM */
#endif /* WNM_STA_H */
diff --git a/contrib/wpa/wpa_supplicant/wpa_cli.c b/contrib/wpa/wpa_supplicant/wpa_cli.c
index 7ddae3d..695fcbe 100644
--- a/contrib/wpa/wpa_supplicant/wpa_cli.c
+++ b/contrib/wpa/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,7 @@
#include <dirent.h>
#endif /* CONFIG_CTRL_IFACE_UNIX */
+#include "common/cli.h"
#include "common/wpa_ctrl.h"
#include "utils/common.h"
#include "utils/eloop.h"
@@ -28,43 +29,13 @@
static const char *const wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
-
-
-static const char *const wpa_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const wpa_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-" notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-" notice, this list of conditions and the following disclaimer in the\n"
-" documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-" names of its contributors may be used to endorse or promote products\n"
-" derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
+"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors";
+
+#define VENDOR_ELEM_FRAME_ID \
+ " 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \
+ "3: Beacon (GO), 4: PD Req, 5: PD Resp, 6: GO Neg Req, " \
+ "7: GO Neg Resp, 8: GO Neg Conf, 9: Inv Req, 10: Inv Resp, " \
+ "11: Assoc Req (P2P), 12: Assoc Resp (P2P)"
static struct wpa_ctrl *ctrl_conn;
static struct wpa_ctrl *mon_conn;
@@ -78,22 +49,22 @@ static int wpa_cli_last_id = 0;
static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
static const char *client_socket_dir = NULL;
static char *ctrl_ifname = NULL;
+static const char *global = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
static int ping_interval = 5;
static int interactive = 0;
static char *ifname_prefix = NULL;
-struct cli_txt_entry {
- struct dl_list list;
- char *txt;
-};
-
static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(creds); /* struct cli_txt_entry */
+#ifdef CONFIG_AP
+static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
+#endif /* CONFIG_AP */
static void print_help(const char *cmd);
@@ -101,7 +72,10 @@ static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
static void wpa_cli_close_connection(void);
static char * wpa_cli_get_default_ifname(void);
static char ** wpa_list_cmd_list(void);
+static void update_creds(struct wpa_ctrl *ctrl);
static void update_networks(struct wpa_ctrl *ctrl);
+static void update_stations(struct wpa_ctrl *ctrl);
+static void update_ifnames(struct wpa_ctrl *ctrl);
static void usage(void)
@@ -124,168 +98,6 @@ static void usage(void)
}
-static void cli_txt_list_free(struct cli_txt_entry *e)
-{
- dl_list_del(&e->list);
- os_free(e->txt);
- os_free(e);
-}
-
-
-static void cli_txt_list_flush(struct dl_list *list)
-{
- struct cli_txt_entry *e;
- while ((e = dl_list_first(list, struct cli_txt_entry, list)))
- cli_txt_list_free(e);
-}
-
-
-static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
- const char *txt)
-{
- struct cli_txt_entry *e;
- dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
- if (os_strcmp(e->txt, txt) == 0)
- return e;
- }
- return NULL;
-}
-
-
-static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
-{
- struct cli_txt_entry *e;
- e = cli_txt_list_get(txt_list, txt);
- if (e)
- cli_txt_list_free(e);
-}
-
-
-static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
-{
- u8 addr[ETH_ALEN];
- char buf[18];
- if (hwaddr_aton(txt, addr) < 0)
- return;
- os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
- cli_txt_list_del(txt_list, buf);
-}
-
-
-#ifdef CONFIG_P2P
-static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
- int separator)
-{
- const char *end;
- char *buf;
- end = os_strchr(txt, separator);
- if (end == NULL)
- end = txt + os_strlen(txt);
- buf = dup_binstr(txt, end - txt);
- if (buf == NULL)
- return;
- cli_txt_list_del(txt_list, buf);
- os_free(buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
-{
- struct cli_txt_entry *e;
- e = cli_txt_list_get(txt_list, txt);
- if (e)
- return 0;
- e = os_zalloc(sizeof(*e));
- if (e == NULL)
- return -1;
- e->txt = os_strdup(txt);
- if (e->txt == NULL) {
- os_free(e);
- return -1;
- }
- dl_list_add(txt_list, &e->list);
- return 0;
-}
-
-
-#ifdef CONFIG_P2P
-static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
-{
- u8 addr[ETH_ALEN];
- char buf[18];
- if (hwaddr_aton(txt, addr) < 0)
- return -1;
- os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
- return cli_txt_list_add(txt_list, buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
- int separator)
-{
- const char *end;
- char *buf;
- int ret;
- end = os_strchr(txt, separator);
- if (end == NULL)
- end = txt + os_strlen(txt);
- buf = dup_binstr(txt, end - txt);
- if (buf == NULL)
- return -1;
- ret = cli_txt_list_add(txt_list, buf);
- os_free(buf);
- return ret;
-}
-
-
-static char ** cli_txt_list_array(struct dl_list *txt_list)
-{
- unsigned int i, count = dl_list_len(txt_list);
- char **res;
- struct cli_txt_entry *e;
-
- res = os_calloc(count + 1, sizeof(char *));
- if (res == NULL)
- return NULL;
-
- i = 0;
- dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
- res[i] = os_strdup(e->txt);
- if (res[i] == NULL)
- break;
- i++;
- }
-
- return res;
-}
-
-
-static int get_cmd_arg_num(const char *str, int pos)
-{
- int arg = 0, i;
-
- for (i = 0; i <= pos; i++) {
- if (str[i] != ' ') {
- arg++;
- while (i <= pos && str[i] != ' ')
- i++;
- }
- }
-
- if (arg > 0)
- arg--;
- return arg;
-}
-
-
-static int str_starts(const char *src, const char *match)
-{
- return os_strncmp(src, match, os_strlen(match)) == 0;
-}
-
-
static int wpa_cli_show_event(const char *event)
{
const char *start;
@@ -410,7 +222,7 @@ static void wpa_cli_msg_cb(char *msg, size_t len)
}
-static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
{
char buf[4096];
size_t len;
@@ -446,42 +258,12 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
}
-static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
+static int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
{
return _wpa_ctrl_command(ctrl, cmd, 1);
}
-static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
- char *argv[])
-{
- int i, res;
- char *pos, *end;
-
- pos = buf;
- end = buf + buflen;
-
- res = os_snprintf(pos, end - pos, "%s", cmd);
- if (os_snprintf_error(end - pos, res))
- goto fail;
- pos += res;
-
- for (i = 0; i < argc; i++) {
- res = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (os_snprintf_error(end - pos, res))
- goto fail;
- pos += res;
- }
-
- buf[buflen - 1] = '\0';
- return 0;
-
-fail:
- printf("Too long command\n");
- return -1;
-}
-
-
static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
int argc, char *argv[])
{
@@ -557,6 +339,39 @@ static int wpa_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
}
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+
+static int wpa_cli_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PMKSA_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PMKSA_ADD", 8, argc, argv);
+}
+
+
+#ifdef CONFIG_MESH
+
+static int wpa_cli_mesh_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PMKSA_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_mesh_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PMKSA_ADD", 4, argc, argv);
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
print_help(argc > 0 ? argv[0] : NULL);
@@ -581,7 +396,7 @@ static char ** wpa_cli_complete_help(const char *str, int pos)
static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
+ printf("%s\n\n%s\n", wpa_cli_version, cli_full_license);
return 0;
}
@@ -663,11 +478,13 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
#endif /* CONFIG_P2P */
"country", "bss_max_count", "bss_expiration_age",
"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
- "max_num_sta", "disassoc_low_ack",
+ "max_num_sta", "disassoc_low_ack", "ap_isolate",
#ifdef CONFIG_HS20
"hs20",
#endif /* CONFIG_HS20 */
"interworking", "hessid", "access_network_type", "pbc_in_m1",
+ "go_interworking", "go_access_network_type", "go_internet",
+ "go_venue_group", "go_venue_type",
"autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey",
"wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend",
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
@@ -677,7 +494,11 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
- "reassoc_same_bss_optim", "wps_priority"
+ "reassoc_same_bss_optim", "wps_priority",
+#ifdef CONFIG_TESTING_OPTIONS
+ "ignore_auth_resp",
+#endif /* CONFIG_TESTING_OPTIONS */
+ "relative_rssi", "relative_band_adjust",
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -705,6 +526,13 @@ static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
@@ -747,15 +575,18 @@ static char ** wpa_cli_complete_get(const char *str, int pos)
#endif /* CONFIG_P2P */
"bss_max_count", "bss_expiration_age",
"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
- "max_num_sta", "disassoc_low_ack",
+ "max_num_sta", "disassoc_low_ack", "ap_isolate",
#ifdef CONFIG_HS20
"hs20",
#endif /* CONFIG_HS20 */
"interworking", "access_network_type", "pbc_in_m1", "autoscan",
+ "go_interworking", "go_access_network_type", "go_internet",
+ "go_venue_group", "go_venue_type",
"wps_nfc_dev_pw_id", "ext_password_backend",
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
"dtim_period", "beacon_int", "ignore_old_scan_res",
"scan_cur_freq", "sched_scan_interval",
+ "sched_scan_start_delay",
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
@@ -855,13 +686,6 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
-{
- return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
-}
-
-
static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
@@ -1381,6 +1205,39 @@ static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_psk_passphrase(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i, ret;
+
+ if (argc < 2) {
+ printf("Invalid PSK_PASSPHRASE command: needs two arguments (network id and PSK/passphrase)\n");
+ return -1;
+ }
+
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PSK_PASSPHRASE-%s:%s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(end - pos, ret)) {
+ printf("Too long PSK_PASSPHRASE command.\n");
+ return -1;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (os_snprintf_error(end - pos, ret)) {
+ printf("Too long PSK_PASSPHRASE command.\n");
+ return -1;
+ }
+ pos += ret;
+ }
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1548,14 +1405,17 @@ static const char *network_fields[] = {
"ssid", "scan_ssid", "bssid", "bssid_blacklist",
"bssid_whitelist", "psk", "proto", "key_mgmt",
"bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
- "freq_list",
+ "freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1",
+ "vht_center_freq2", "ht",
#ifdef IEEE8021X_EAPOL
"eap", "identity", "anonymous_identity", "password", "ca_cert",
"ca_path", "client_cert", "private_key", "private_key_passwd",
"dh_file", "subject_match", "altsubject_match",
+ "check_cert_subject",
"domain_suffix_match", "domain_match", "ca_cert2", "ca_path2",
"client_cert2", "private_key2", "private_key2_passwd",
"dh_file2", "subject_match2", "altsubject_match2",
+ "check_cert_subject2",
"domain_suffix_match2", "domain_match2", "phase1", "phase2",
"pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id",
"pin2", "engine2_id", "key2_id", "cert2_id", "ca_cert2_id",
@@ -1568,7 +1428,7 @@ static const char *network_fields[] = {
"eap_workaround", "pac_file", "fragment_size", "ocsp",
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_MESH
- "mode", "no_auto_peer",
+ "mode", "no_auto_peer", "mesh_rssi_threshold",
#else /* CONFIG_MESH */
"mode",
#endif /* CONFIG_MESH */
@@ -1576,7 +1436,7 @@ static const char *network_fields[] = {
#ifdef CONFIG_IEEE80211W
"ieee80211w",
#endif /* CONFIG_IEEE80211W */
- "peerkey", "mixed_cell", "frequency", "fixed_freq",
+ "mixed_cell", "frequency", "fixed_freq",
#ifdef CONFIG_MESH
"mesh_basic_rates", "dot11MeshMaxRetries",
"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
@@ -1589,7 +1449,7 @@ static const char *network_fields[] = {
#ifdef CONFIG_HT_OVERRIDES
"disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc",
"ht40_intolerant", "disable_max_amsdu", "ampdu_factor",
- "ampdu_density", "ht_mcs",
+ "ampdu_density", "ht_mcs", "rx_stbc", "tx_stbc",
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
"disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1",
@@ -1602,11 +1462,16 @@ static const char *network_fields[] = {
"ap_max_inactivity", "dtim_period", "beacon_int",
#ifdef CONFIG_MACSEC
"macsec_policy",
+ "macsec_integ_only",
+ "macsec_replay_protect",
+ "macsec_replay_window",
+ "macsec_port",
+ "mka_priority",
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
"update_identifier",
#endif /* CONFIG_HS20 */
- "mac_addr"
+ "mac_addr", "pbss", "wps_disabled"
};
@@ -1695,14 +1560,56 @@ static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- return wpa_ctrl_command(ctrl, "ADD_CRED");
+ int res = wpa_ctrl_command(ctrl, "ADD_CRED");
+ if (interactive)
+ update_creds(ctrl);
+ return res;
}
static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
+ int res = wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
+ if (interactive)
+ update_creds(ctrl);
+ return res;
+}
+
+
+static const char * const cred_fields[] = {
+ "temporary", "priority", "sp_priority", "pcsc", "eap",
+ "update_identifier", "min_dl_bandwidth_home", "min_ul_bandwidth_home",
+ "min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming", "max_bss_load",
+ "req_conn_capab", "ocsp", "sim_num", "realm", "username", "password",
+ "ca_cert", "client_cert", "private_key", "private_key_passwd", "imsi",
+ "milenage", "domain_suffix_match", "domain", "phase1", "phase2",
+ "roaming_consortium", "required_roaming_consortium", "excluded_ssid",
+ "roaming_partner", "provisioning_sp"
+};
+
+
+static char ** wpa_cli_complete_cred(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ int i, num_fields = ARRAY_SIZE(cred_fields);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&creds);
+ break;
+ case 2:
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(cred_fields[i]);
+ if (res[i] == NULL)
+ break;
+ }
+ }
+ return res;
}
@@ -1764,6 +1671,13 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_abort_scan(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ABORT_SCAN");
+}
+
+
static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
@@ -1804,6 +1718,48 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
}
+static char ** wpa_cli_complete_get_capability(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ "eap", "pairwise", "group", "group_mgmt", "key_mgmt",
+ "proto", "auth_alg", "modes", "channels", "freq",
+#ifdef CONFIG_TDLS
+ "tdls",
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_ERP
+ "erp",
+#endif /* CONFIG_ERP */
+#ifdef CONFIG_FIPS
+ "fips",
+#endif /* CONFIG_FIPS */
+#ifdef CONFIG_ACS
+ "acs",
+#endif /* CONFIG_ACS */
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+ char **res = NULL;
+
+ if (arg == 1) {
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(fields[i]);
+ if (res[i] == NULL)
+ return res;
+ }
+ }
+ if (arg == 2) {
+ res = os_calloc(1 + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ res[0] = os_strdup("strict");
+ }
+ return res;
+}
+
+
static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
printf("Available interfaces:\n");
@@ -1866,14 +1822,15 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
/*
* INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
- * <driver_param>TAB<bridge_name>[TAB<create>]
+ * <driver_param>TAB<bridge_name>[TAB<create>[TAB<type>]]
*/
res = os_snprintf(cmd, sizeof(cmd),
- "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s",
+ "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
argv[0],
argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
- argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "");
+ argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "",
+ argc > 7 ? argv[7] : "");
if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
@@ -1902,8 +1859,23 @@ static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
- char *addr, size_t addr_len)
+static char ** wpa_cli_complete_sta(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
+ char *addr, size_t addr_len, int print)
{
char buf[4096], *pos;
size_t len;
@@ -1913,6 +1885,12 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
printf("Not connected to hostapd - command dropped.\n");
return -1;
}
+ if (ifname_prefix) {
+ os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
+ ifname_prefix, cmd);
+ buf[sizeof(buf) - 1] = '\0';
+ cmd = buf;
+ }
len = sizeof(buf) - 1;
ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
wpa_cli_msg_cb);
@@ -1925,9 +1903,11 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
}
buf[len] = '\0';
- if (os_memcmp(buf, "FAIL", 4) == 0)
+ if (os_memcmp(buf, "FAIL", 4) == 0 ||
+ os_memcmp(buf, "UNKNOWN COMMAND", 15) == 0)
return -1;
- printf("%s", buf);
+ if (print)
+ printf("%s", buf);
pos = buf;
while (*pos != '\0' && *pos != '\n')
@@ -1942,16 +1922,33 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char addr[32], cmd[64];
- if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
return 0;
do {
os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
- } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
return -1;
}
+static int wpa_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char addr[32], cmd[64];
+
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
+ return 0;
+ do {
+ if (os_strcmp(addr, "") != 0)
+ printf("%s\n", addr);
+ os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
+
+ return 0;
+}
+
+
static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1959,12 +1956,43 @@ static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
}
+static char ** wpa_cli_complete_deauthenticate(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
}
+
+static char ** wpa_cli_complete_disassociate(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2022,6 +2050,20 @@ static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
}
+
+static int wpa_cli_cmd_mesh_peer_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PEER_REMOVE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_peer_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv);
+}
+
#endif /* CONFIG_MESH */
@@ -2141,6 +2183,13 @@ static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_p2p_group_member(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_MEMBER", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2315,7 +2364,7 @@ static char ** wpa_cli_complete_p2p_peer(const char *str, int pos)
}
-static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
+static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, const char *cmd,
char *addr, size_t addr_len,
int discovered)
{
@@ -2479,6 +2528,28 @@ static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc,
#endif /* CONFIG_P2P */
+
+static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "VENDOR_ELEM_ADD", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_vendor_elem_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "VENDOR_ELEM_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_vendor_elem_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv);
+}
+
+
#ifdef CONFIG_WIFI_DISPLAY
static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
@@ -2719,6 +2790,13 @@ static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_signal_monitor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "SIGNAL_MONITOR", 0, argc, argv);
+}
+
+
static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2823,6 +2901,122 @@ static int wpa_cli_cmd_get_pref_freq_list(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv);
+}
+
+
+#ifdef CONFIG_DPP
+
+static int wpa_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN");
+}
+
+
+static int wpa_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
+}
+
+#endif /* CONFIG_DPP */
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2880,6 +3074,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "get", wpa_cli_cmd_get, wpa_cli_complete_get,
cli_cmd_flag_none,
"<name> = get information" },
+ { "driver_flags", wpa_cli_cmd_driver_flags, NULL,
+ cli_cmd_flag_none,
+ "= list driver flags" },
{ "logon", wpa_cli_cmd_logon, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logon" },
@@ -2892,6 +3089,22 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL,
cli_cmd_flag_none,
"= flush PMKSA cache entries" },
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ { "pmksa_get", wpa_cli_cmd_pmksa_get, NULL,
+ cli_cmd_flag_none,
+ "<network_id> = fetch all stored PMKSA cache entries" },
+ { "pmksa_add", wpa_cli_cmd_pmksa_add, NULL,
+ cli_cmd_flag_sensitive,
+ "<network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds> <expiration in seconds> <akmp> <opportunistic> = store PMKSA cache entry from external storage" },
+#ifdef CONFIG_MESH
+ { "mesh_pmksa_get", wpa_cli_mesh_cmd_pmksa_get, NULL,
+ cli_cmd_flag_none,
+ "<peer MAC address | any> = fetch all stored mesh PMKSA cache entries" },
+ { "mesh_pmksa_add", wpa_cli_mesh_cmd_pmksa_add, NULL,
+ cli_cmd_flag_sensitive,
+ "<BSSID> <PMKID> <PMK> <expiration in seconds> = store mesh PMKSA cache entry from external storage" },
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
{ "reassociate", wpa_cli_cmd_reassociate, NULL,
cli_cmd_flag_none,
"= force reassociation" },
@@ -2901,30 +3114,33 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = force preauthentication" },
- { "identity", wpa_cli_cmd_identity, NULL,
+ { "identity", wpa_cli_cmd_identity, wpa_cli_complete_network_id,
cli_cmd_flag_none,
"<network id> <identity> = configure identity for an SSID" },
- { "password", wpa_cli_cmd_password, NULL,
+ { "password", wpa_cli_cmd_password, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <password> = configure password for an SSID" },
- { "new_password", wpa_cli_cmd_new_password, NULL,
- cli_cmd_flag_sensitive,
+ { "new_password", wpa_cli_cmd_new_password,
+ wpa_cli_complete_network_id, cli_cmd_flag_sensitive,
"<network id> <password> = change password for an SSID" },
- { "pin", wpa_cli_cmd_pin, NULL,
+ { "pin", wpa_cli_cmd_pin, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <pin> = configure pin for an SSID" },
- { "otp", wpa_cli_cmd_otp, NULL,
+ { "otp", wpa_cli_cmd_otp, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <password> = configure one-time-password for an SSID"
},
- { "passphrase", wpa_cli_cmd_passphrase, NULL,
+ { "psk_passphrase", wpa_cli_cmd_psk_passphrase,
+ wpa_cli_complete_network_id, cli_cmd_flag_sensitive,
+ "<network id> <PSK/passphrase> = configure PSK/passphrase for an SSID" },
+ { "passphrase", wpa_cli_cmd_passphrase, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
" for an SSID" },
- { "sim", wpa_cli_cmd_sim, NULL,
+ { "sim", wpa_cli_cmd_sim, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <pin> = report SIM operation result" },
- { "bssid", wpa_cli_cmd_bssid, NULL,
+ { "bssid", wpa_cli_cmd_bssid, wpa_cli_complete_network_id,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
{ "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
@@ -2978,10 +3194,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "remove_cred", wpa_cli_cmd_remove_cred, NULL,
cli_cmd_flag_none,
"<cred id> = remove a credential" },
- { "set_cred", wpa_cli_cmd_set_cred, NULL,
+ { "set_cred", wpa_cli_cmd_set_cred, wpa_cli_complete_cred,
cli_cmd_flag_sensitive,
"<cred id> <variable> <value> = set credential variables" },
- { "get_cred", wpa_cli_cmd_get_cred, NULL,
+ { "get_cred", wpa_cli_cmd_get_cred, wpa_cli_complete_cred,
cli_cmd_flag_none,
"<cred id> <variable> = get credential variables" },
{ "save_config", wpa_cli_cmd_save_config, NULL,
@@ -3001,11 +3217,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "scan_results", wpa_cli_cmd_scan_results, NULL,
cli_cmd_flag_none,
"= get latest scan results" },
+ { "abort_scan", wpa_cli_cmd_abort_scan, NULL,
+ cli_cmd_flag_none,
+ "= request ongoing scan to be aborted" },
{ "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<<idx> | <bssid>> = get detailed scan result info" },
- { "get_capability", wpa_cli_cmd_get_capability, NULL,
- cli_cmd_flag_none,
+ { "get_capability", wpa_cli_cmd_get_capability,
+ wpa_cli_complete_get_capability, cli_cmd_flag_none,
"<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
"= get capabilities" },
{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
@@ -3017,8 +3236,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "interface_add", wpa_cli_cmd_interface_add, NULL,
cli_cmd_flag_none,
"<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
- " <bridge_name> = adds new interface, all parameters but <ifname>\n"
- " are optional" },
+ " <bridge_name> <create> <type> = adds new interface, all "
+ "parameters but\n"
+ " <ifname> are optional. Supported types are station ('sta') and "
+ "AP ('ap')" },
{ "interface_remove", wpa_cli_cmd_interface_remove, NULL,
cli_cmd_flag_none,
"<ifname> = removes the interface" },
@@ -3040,9 +3261,6 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "bss_flush", wpa_cli_cmd_bss_flush, NULL,
cli_cmd_flag_none,
"<value> = set BSS flush age (0 by default)" },
- { "stkstart", wpa_cli_cmd_stkstart, NULL,
- cli_cmd_flag_none,
- "<addr> = request STK negotiation with <addr>" },
{ "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = request over-the-DS FT with <addr>" },
@@ -3118,17 +3336,20 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
#ifdef CONFIG_AP
- { "sta", wpa_cli_cmd_sta, NULL,
+ { "sta", wpa_cli_cmd_sta, wpa_cli_complete_sta,
cli_cmd_flag_none,
"<addr> = get information about an associated station (AP)" },
{ "all_sta", wpa_cli_cmd_all_sta, NULL,
cli_cmd_flag_none,
"= get information about all associated stations (AP)" },
- { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
+ { "list_sta", wpa_cli_cmd_list_sta, NULL,
cli_cmd_flag_none,
+ "= list all stations (AP)" },
+ { "deauthenticate", wpa_cli_cmd_deauthenticate,
+ wpa_cli_complete_deauthenticate, cli_cmd_flag_none,
"<addr> = deauthenticate a station" },
- { "disassociate", wpa_cli_cmd_disassociate, NULL,
- cli_cmd_flag_none,
+ { "disassociate", wpa_cli_cmd_disassociate,
+ wpa_cli_complete_disassociate, cli_cmd_flag_none,
"<addr> = disassociate a station" },
{ "chan_switch", wpa_cli_cmd_chanswitch, NULL,
cli_cmd_flag_none,
@@ -3157,6 +3378,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
cli_cmd_flag_none,
"<ifname> = Remove mesh group interface" },
+ { "mesh_peer_remove", wpa_cli_cmd_mesh_peer_remove, NULL,
+ cli_cmd_flag_none,
+ "<addr> = Remove a mesh peer" },
+ { "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL,
+ cli_cmd_flag_none,
+ "<addr> [duration=<seconds>] = Add a mesh peer" },
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
@@ -3180,6 +3407,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
"<ifname> = remove P2P group interface (terminate group if GO)" },
{ "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
"[ht40] = add a new P2P group (local end as GO)" },
+ { "p2p_group_member", wpa_cli_cmd_p2p_group_member, NULL,
+ cli_cmd_flag_none,
+ "<dev_addr> = Get peer interface address on local GO using peer Device Address" },
{ "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <method> = request provisioning discovery" },
@@ -3249,6 +3479,18 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<address|iface=address> = remove a peer from all groups" },
#endif /* CONFIG_P2P */
+ { "vendor_elem_add", wpa_cli_cmd_vendor_elem_add, NULL,
+ cli_cmd_flag_none,
+ "<frame id> <hexdump of elem(s)> = add vendor specific IEs to frame(s)\n"
+ VENDOR_ELEM_FRAME_ID },
+ { "vendor_elem_get", wpa_cli_cmd_vendor_elem_get, NULL,
+ cli_cmd_flag_none,
+ "<frame id> = get vendor specific IE(s) to frame(s)\n"
+ VENDOR_ELEM_FRAME_ID },
+ { "vendor_elem_remove", wpa_cli_cmd_vendor_elem_remove, NULL,
+ cli_cmd_flag_none,
+ "<frame id> <hexdump of elem(s)> = remove vendor specific IE(s) in frame(s)\n"
+ VENDOR_ELEM_FRAME_ID },
#ifdef CONFIG_WIFI_DISPLAY
{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
cli_cmd_flag_none,
@@ -3336,6 +3578,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "signal_poll", wpa_cli_cmd_signal_poll, NULL,
cli_cmd_flag_none,
"= get signal parameters" },
+ { "signal_monitor", wpa_cli_cmd_signal_monitor, NULL,
+ cli_cmd_flag_none,
+ "= set signal monitor parameters" },
{ "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
cli_cmd_flag_none,
"= get TX/RX packet counters" },
@@ -3350,7 +3595,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
"<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
{ "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none,
- "<query reason> = Send BSS Transition Management Query" },
+ "<query reason> [list]"
+ " [neighbor=<BSSID>,<BSSID information>,<operating class>,<channel number>,<PHY type>[,<hexdump of optional subelements>]"
+ " = Send BSS Transition Management Query" },
#endif /* CONFIG_WNM */
{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
"<params..> = Sent unprocessed command" },
@@ -3367,8 +3614,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
},
{ "neighbor_rep_request",
wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
- "[ssid=<SSID>] = Trigger request to AP for neighboring AP report "
- "(with optional given SSID, default: current SSID)"
+ "[ssid=<SSID>] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)"
},
{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
"= flush ERP keys" },
@@ -3380,6 +3626,53 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL,
cli_cmd_flag_none,
"<interface type> = retrieve preferred freq list for the specified interface type" },
+ { "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL,
+ cli_cmd_flag_none,
+ "<freq> <period> <interval> <count> = start P2P listen offload" },
+ { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL,
+ cli_cmd_flag_none,
+ "= stop P2P listen offload" },
+#ifdef CONFIG_DPP
+ { "dpp_qr_code", wpa_cli_cmd_dpp_qr_code, NULL, cli_cmd_flag_none,
+ "report a scanned DPP URI from a QR Code" },
+ { "dpp_bootstrap_gen", wpa_cli_cmd_dpp_bootstrap_gen, NULL,
+ cli_cmd_flag_sensitive,
+ "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
+ { "dpp_bootstrap_remove", wpa_cli_cmd_dpp_bootstrap_remove, NULL,
+ cli_cmd_flag_none,
+ "*|<id> = remove DPP bootstrap information" },
+ { "dpp_bootstrap_get_uri", wpa_cli_cmd_dpp_bootstrap_get_uri, NULL,
+ cli_cmd_flag_none,
+ "<id> = get DPP bootstrap URI" },
+ { "dpp_bootstrap_info", wpa_cli_cmd_dpp_bootstrap_info, NULL,
+ cli_cmd_flag_none,
+ "<id> = show DPP bootstrap information" },
+ { "dpp_auth_init", wpa_cli_cmd_dpp_auth_init, NULL, cli_cmd_flag_none,
+ "peer=<id> [own=<id>] = initiate DPP bootstrapping" },
+ { "dpp_listen", wpa_cli_cmd_dpp_listen, NULL, cli_cmd_flag_none,
+ "<freq in MHz> = start DPP listen" },
+ { "dpp_stop_listen", wpa_cli_cmd_dpp_stop_listen, NULL,
+ cli_cmd_flag_none,
+ "= stop DPP listen" },
+ { "dpp_configurator_add", wpa_cli_cmd_dpp_configurator_add, NULL,
+ cli_cmd_flag_sensitive,
+ "[curve=..] [key=..] = add DPP configurator" },
+ { "dpp_configurator_remove", wpa_cli_cmd_dpp_configurator_remove, NULL,
+ cli_cmd_flag_none,
+ "*|<id> = remove DPP configurator" },
+ { "dpp_configurator_get_key", wpa_cli_cmd_dpp_configurator_get_key,
+ NULL, cli_cmd_flag_none,
+ "<id> = Get DPP configurator's private key" },
+ { "dpp_configurator_sign", wpa_cli_cmd_dpp_configurator_sign, NULL,
+ cli_cmd_flag_none,
+ "conf=<role> configurator=<id> = generate self DPP configuration" },
+ { "dpp_pkex_add", wpa_cli_cmd_dpp_pkex_add, NULL,
+ cli_cmd_flag_sensitive,
+ "add PKEX code" },
+ { "dpp_pkex_remove", wpa_cli_cmd_dpp_pkex_remove, NULL,
+ cli_cmd_flag_none,
+ "*|<id> = remove DPP pkex information" },
+#endif /* CONFIG_DPP */
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -3578,12 +3871,6 @@ static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static int str_match(const char *a, const char *b)
-{
- return os_strncmp(a, b, os_strlen(b)) == 0;
-}
-
-
static int wpa_cli_exec(const char *program, const char *arg1,
const char *arg2)
{
@@ -3591,6 +3878,10 @@ static int wpa_cli_exec(const char *program, const char *arg1,
size_t len;
int res;
+ /* If no interface is specified, set the global */
+ if (!arg1)
+ arg1 = "global";
+
len = os_strlen(arg1) + os_strlen(arg2) + 2;
arg = os_malloc(len);
if (arg == NULL)
@@ -3635,7 +3926,7 @@ static void wpa_cli_action_process(const char *msg)
pos = prev;
}
- if (str_match(pos, WPA_EVENT_CONNECTED)) {
+ if (str_starts(pos, WPA_EVENT_CONNECTED)) {
int new_id = -1;
os_unsetenv("WPA_ID");
os_unsetenv("WPA_ID_STR");
@@ -3671,44 +3962,54 @@ static void wpa_cli_action_process(const char *msg)
wpa_cli_last_id = new_id;
wpa_cli_exec(action_file, ifname, "CONNECTED");
}
- } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
+ } else if (str_starts(pos, WPA_EVENT_DISCONNECTED)) {
if (wpa_cli_connected) {
wpa_cli_connected = 0;
wpa_cli_exec(action_file, ifname, "DISCONNECTED");
}
- } else if (str_match(pos, MESH_GROUP_STARTED)) {
+ } else if (str_starts(pos, AP_EVENT_ENABLED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_starts(pos, AP_EVENT_DISABLED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_GROUP_REMOVED)) {
+ } else if (str_starts(pos, MESH_GROUP_STARTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_PEER_CONNECTED)) {
+ } else if (str_starts(pos, MESH_GROUP_REMOVED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
+ } else if (str_starts(pos, MESH_PEER_CONNECTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+ } else if (str_starts(pos, MESH_PEER_DISCONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_starts(pos, P2P_EVENT_GROUP_STARTED)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, P2P_EVENT_GROUP_REMOVED)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+ } else if (str_starts(pos, P2P_EVENT_GO_NEG_FAILURE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+ } else if (str_starts(pos, WPS_EVENT_SUCCESS)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+ } else if (str_starts(pos, WPS_EVENT_ACTIVE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+ } else if (str_starts(pos, WPS_EVENT_TIMEOUT)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+ } else if (str_starts(pos, WPS_EVENT_FAIL)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPS_EVENT_FAIL)) {
+ } else if (str_starts(pos, AP_STA_CONNECTED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, AP_STA_CONNECTED)) {
+ } else if (str_starts(pos, AP_STA_DISCONNECTED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, AP_STA_DISCONNECTED)) {
+ } else if (str_starts(pos, ESS_DISASSOC_IMMINENT)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+ } else if (str_starts(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
+ } else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
+ } else if (str_starts(pos, HS20_T_C_ACCEPTANCE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
+ } else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
}
@@ -3723,16 +4024,53 @@ static void wpa_cli_action_cb(char *msg, size_t len)
#endif /* CONFIG_ANSI_C_EXTRA */
+static int wpa_cli_open_global_ctrl(void)
+{
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ ctrl_conn = wpa_ctrl_open(NULL);
+#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ ctrl_conn = wpa_ctrl_open(global);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ if (!ctrl_conn) {
+ fprintf(stderr,
+ "Failed to connect to wpa_supplicant global interface: %s error: %s\n",
+ global, strerror(errno));
+ return -1;
+ }
+
+ if (interactive) {
+ update_ifnames(ctrl_conn);
+ mon_conn = wpa_ctrl_open(global);
+ if (mon_conn) {
+ if (wpa_ctrl_attach(mon_conn) == 0) {
+ wpa_cli_attached = 1;
+ eloop_register_read_sock(
+ wpa_ctrl_get_fd(mon_conn),
+ wpa_cli_mon_receive,
+ NULL, NULL);
+ } else {
+ printf("Failed to open monitor connection through global control interface\n");
+ }
+ }
+ update_stations(ctrl_conn);
+ }
+
+ return 0;
+}
+
+
static void wpa_cli_reconnect(void)
{
wpa_cli_close_connection();
- if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
+ if ((global && wpa_cli_open_global_ctrl() < 0) ||
+ (!global && wpa_cli_open_connection(ctrl_ifname, 1) < 0))
return;
if (interactive) {
edit_clear_line();
printf("\rConnection to wpa_supplicant re-established\n");
edit_redraw();
+ update_stations(ctrl_conn);
}
}
@@ -3818,7 +4156,7 @@ static int check_terminating(const char *msg)
pos = msg;
}
- if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+ if (str_starts(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
edit_clear_line();
printf("\rConnection to wpa_supplicant lost - trying to "
"reconnect\n");
@@ -3869,37 +4207,6 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
}
}
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
-{
- char *pos;
- int argc = 0;
-
- pos = cmd;
- for (;;) {
- while (*pos == ' ')
- pos++;
- if (*pos == '\0')
- break;
- argv[argc] = pos;
- argc++;
- if (argc == max_args)
- break;
- if (*pos == '"') {
- char *pos2 = os_strrchr(pos, '"');
- if (pos2)
- pos = pos2 + 1;
- }
- while (*pos != '\0' && *pos != ' ')
- pos++;
- if (*pos == ' ')
- *pos++ = '\0';
- }
-
- return argc;
-}
-
static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
{
@@ -3986,7 +4293,7 @@ static void update_bssid_list(struct wpa_ctrl *ctrl)
char buf[4096];
size_t len = sizeof(buf);
int ret;
- char *cmd = "BSS RANGE=ALL MASK=0x2";
+ const char *cmd = "BSS RANGE=ALL MASK=0x2";
char *pos, *end;
if (ctrl == NULL)
@@ -4017,7 +4324,7 @@ static void update_ifnames(struct wpa_ctrl *ctrl)
char buf[4096];
size_t len = sizeof(buf);
int ret;
- char *cmd = "INTERFACES";
+ const char *cmd = "INTERFACES";
char *pos, *end;
char txt[200];
@@ -4044,12 +4351,44 @@ static void update_ifnames(struct wpa_ctrl *ctrl)
}
+static void update_creds(struct wpa_ctrl *ctrl)
+{
+ char buf[4096];
+ size_t len = sizeof(buf);
+ int ret;
+ const char *cmd = "LIST_CREDS";
+ char *pos, *end;
+ int header = 1;
+
+ cli_txt_list_flush(&creds);
+
+ if (ctrl == NULL)
+ return;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+ if (ret < 0)
+ return;
+ buf[len] = '\0';
+
+ pos = buf;
+ while (pos) {
+ end = os_strchr(pos, '\n');
+ if (end == NULL)
+ break;
+ *end = '\0';
+ if (!header)
+ cli_txt_list_add_word(&creds, pos, '\t');
+ header = 0;
+ pos = end + 1;
+ }
+}
+
+
static void update_networks(struct wpa_ctrl *ctrl)
{
char buf[4096];
size_t len = sizeof(buf);
int ret;
- char *cmd = "LIST_NETWORKS";
+ const char *cmd = "LIST_NETWORKS";
char *pos, *end;
int header = 1;
@@ -4076,6 +4415,27 @@ static void update_networks(struct wpa_ctrl *ctrl)
}
+static void update_stations(struct wpa_ctrl *ctrl)
+{
+#ifdef CONFIG_AP
+ char addr[32], cmd[64];
+
+ if (!ctrl || !interactive)
+ return;
+
+ cli_txt_list_flush(&stations);
+
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
+ return;
+ do {
+ if (os_strcmp(addr, "") != 0)
+ cli_txt_list_add(&stations, addr);
+ os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
+#endif /* CONFIG_AP */
+}
+
+
static void try_connection(void *eloop_ctx, void *timeout_ctx)
{
if (ctrl_conn)
@@ -4084,7 +4444,7 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx)
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
- if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
+ if (wpa_cli_open_connection(ctrl_ifname, 1)) {
if (!warning_displayed) {
printf("Could not connect to wpa_supplicant: "
"%s - re-trying\n",
@@ -4096,7 +4456,9 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx)
}
update_bssid_list(ctrl_conn);
+ update_creds(ctrl_conn);
update_networks(ctrl_conn);
+ update_stations(ctrl_conn);
if (warning_displayed)
printf("Connection established.\n");
@@ -4118,6 +4480,7 @@ static void wpa_cli_interactive(void)
cli_txt_list_flush(&p2p_groups);
cli_txt_list_flush(&bsses);
cli_txt_list_flush(&ifnames);
+ cli_txt_list_flush(&creds);
cli_txt_list_flush(&networks);
if (edit_started)
edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
@@ -4259,7 +4622,6 @@ int main(int argc, char *argv[])
int c;
int daemonize = 0;
int ret = 0;
- const char *global = NULL;
if (os_program_init())
return -1;
@@ -4309,42 +4671,13 @@ int main(int argc, char *argv[])
interactive = (argc == optind) && (action_file == NULL);
if (interactive)
- printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
+ printf("%s\n\n%s\n\n", wpa_cli_version, cli_license);
if (eloop_init())
return -1;
- if (global) {
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
- ctrl_conn = wpa_ctrl_open(NULL);
-#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
- ctrl_conn = wpa_ctrl_open(global);
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
- if (ctrl_conn == NULL) {
- fprintf(stderr, "Failed to connect to wpa_supplicant "
- "global interface: %s error: %s\n",
- global, strerror(errno));
- return -1;
- }
-
- if (interactive) {
- update_ifnames(ctrl_conn);
- mon_conn = wpa_ctrl_open(global);
- if (mon_conn) {
- if (wpa_ctrl_attach(mon_conn) == 0) {
- wpa_cli_attached = 1;
- eloop_register_read_sock(
- wpa_ctrl_get_fd(mon_conn),
- wpa_cli_mon_receive,
- NULL, NULL);
- } else {
- printf("Failed to open monitor "
- "connection through global "
- "control interface\n");
- }
- }
- }
- }
+ if (global && wpa_cli_open_global_ctrl() < 0)
+ return -1;
eloop_register_signal_terminate(wpa_cli_terminate, NULL);
@@ -4373,7 +4706,7 @@ int main(int argc, char *argv[])
}
}
- if (daemonize && os_daemonize(pid_file))
+ if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
return -1;
if (action_file)
diff --git a/contrib/wpa/wpa_supplicant/wpa_passphrase.c b/contrib/wpa/wpa_supplicant/wpa_passphrase.c
index 9b568f0..adca1cc 100644
--- a/contrib/wpa/wpa_supplicant/wpa_passphrase.c
+++ b/contrib/wpa/wpa_supplicant/wpa_passphrase.c
@@ -17,6 +17,7 @@ int main(int argc, char *argv[])
unsigned char psk[32];
int i;
char *ssid, *passphrase, buf[64], *pos;
+ size_t len;
if (argc < 2) {
printf("usage: wpa_passphrase <ssid> [passphrase]\n"
@@ -47,10 +48,15 @@ int main(int argc, char *argv[])
passphrase = buf;
}
- if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) {
+ len = os_strlen(passphrase);
+ if (len < 8 || len > 63) {
printf("Passphrase must be 8..63 characters\n");
return 1;
}
+ if (has_ctrl_char((u8 *) passphrase, len)) {
+ printf("Invalid passphrase character\n");
+ return 1;
+ }
pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
diff --git a/contrib/wpa/wpa_supplicant/wpa_priv.c b/contrib/wpa/wpa_supplicant/wpa_priv.c
index 850ec40..b3ad45e 100644
--- a/contrib/wpa/wpa_supplicant/wpa_priv.c
+++ b/contrib/wpa/wpa_supplicant/wpa_priv.c
@@ -21,6 +21,7 @@
#include "common/privsep_commands.h"
#include "common/ieee802_11_defs.h"
+#define WPA_PRIV_MAX_L2 3
struct wpa_priv_interface {
struct wpa_priv_interface *next;
@@ -29,21 +30,34 @@ struct wpa_priv_interface {
char *sock_name;
int fd;
+ void *ctx;
+
const struct wpa_driver_ops *driver;
void *drv_priv;
void *drv_global_priv;
struct sockaddr_un drv_addr;
+ socklen_t drv_addr_len;
int wpas_registered;
- /* TODO: add support for multiple l2 connections */
- struct l2_packet_data *l2;
- struct sockaddr_un l2_addr;
+ struct l2_packet_data *l2[WPA_PRIV_MAX_L2];
+ struct sockaddr_un l2_addr[WPA_PRIV_MAX_L2];
+ socklen_t l2_addr_len[WPA_PRIV_MAX_L2];
+ struct wpa_priv_l2 {
+ struct wpa_priv_interface *parent;
+ int idx;
+ } l2_ctx[WPA_PRIV_MAX_L2];
+};
+
+struct wpa_priv_global {
+ struct wpa_priv_interface *interfaces;
};
static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
+ int i;
+
if (iface->drv_priv) {
wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance");
if (iface->driver->deinit)
@@ -56,16 +70,19 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
iface->wpas_registered = 0;
}
- if (iface->l2) {
- wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
- "instance");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
+ if (iface->l2[i]) {
+ wpa_printf(MSG_DEBUG,
+ "Cleaning up forgotten l2_packet instance");
+ l2_packet_deinit(iface->l2[i]);
+ iface->l2[i] = NULL;
+ }
}
if (iface->driver->init2) {
if (iface->driver->global_init) {
- iface->drv_global_priv = iface->driver->global_init();
+ iface->drv_global_priv =
+ iface->driver->global_init(iface->ctx);
if (!iface->drv_global_priv) {
wpa_printf(MSG_INFO,
"Failed to initialize driver global context");
@@ -89,7 +106,8 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface "
"'%s'", iface->driver_name, iface->ifname);
- os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr));
+ os_memcpy(&iface->drv_addr, from, fromlen);
+ iface->drv_addr_len = fromlen;
iface->wpas_registered = 1;
if (iface->driver->set_param &&
@@ -116,18 +134,43 @@ static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface,
static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
- char *buf, size_t len)
+ void *buf, size_t len)
{
struct wpa_driver_scan_params params;
+ struct privsep_cmd_scan *scan;
+ unsigned int i;
+ int freqs[PRIVSEP_MAX_SCAN_FREQS + 1];
if (iface->drv_priv == NULL)
return;
+ if (len < sizeof(*scan)) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request");
+ return;
+ }
+
+ scan = buf;
+
os_memset(&params, 0, sizeof(params));
- if (len) {
- params.ssids[0].ssid = (u8 *) buf;
- params.ssids[0].ssid_len = len;
- params.num_ssids = 1;
+ if (scan->num_ssids > WPAS_MAX_SCAN_SSIDS) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request (num_ssids)");
+ return;
+ }
+ params.num_ssids = scan->num_ssids;
+ for (i = 0; i < scan->num_ssids; i++) {
+ params.ssids[i].ssid = scan->ssids[i];
+ params.ssids[i].ssid_len = scan->ssid_lens[i];
+ }
+
+ if (scan->num_freqs > PRIVSEP_MAX_SCAN_FREQS) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request (num_freqs)");
+ return;
+ }
+ if (scan->num_freqs) {
+ for (i = 0; i < scan->num_freqs; i++)
+ freqs[i] = scan->freqs[i];
+ freqs[i] = 0;
+ params.freqs = freqs;
}
if (iface->driver->scan2)
@@ -136,7 +179,8 @@ static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
struct wpa_scan_results *res;
u8 *buf = NULL, *pos, *end;
@@ -158,7 +202,7 @@ static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
for (i = 0; i < res->num; i++) {
struct wpa_scan_res *r = res->res[i];
- val = sizeof(*r) + r->ie_len;
+ val = sizeof(*r) + r->ie_len + r->beacon_ie_len;
if (end - pos < (int) sizeof(int) + val)
break;
os_memcpy(pos, &val, sizeof(int));
@@ -167,8 +211,7 @@ static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
pos += val;
}
- sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from,
- sizeof(*from));
+ sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, fromlen);
os_free(buf);
wpa_scan_results_free(res);
@@ -177,21 +220,21 @@ static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
fail:
os_free(buf);
wpa_scan_results_free(res);
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
if (iface->drv_priv == NULL)
return;
if (iface->driver->get_scan_results2)
- wpa_priv_get_scan_results2(iface, from);
+ wpa_priv_get_scan_results2(iface, from, fromlen);
else
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from,
- sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
@@ -211,7 +254,7 @@ static void wpa_priv_cmd_authenticate(struct wpa_priv_interface *iface,
}
auth = buf;
- if (sizeof(*auth) + auth->ie_len + auth->sae_data_len > len) {
+ if (sizeof(*auth) + auth->ie_len + auth->auth_data_len > len) {
wpa_printf(MSG_DEBUG, "Authentication request overflow");
return;
}
@@ -237,9 +280,9 @@ static void wpa_priv_cmd_authenticate(struct wpa_priv_interface *iface,
params.ie = (u8 *) (auth + 1);
params.ie_len = auth->ie_len;
}
- if (auth->sae_data_len) {
- params.sae_data = ((u8 *) (auth + 1)) + auth->ie_len;
- params.sae_data_len = auth->sae_data_len;
+ if (auth->auth_data_len) {
+ params.auth_data = ((u8 *) (auth + 1)) + auth->ie_len;
+ params.auth_data_len = auth->auth_data_len;
}
res = iface->driver->authenticate(iface->drv_priv, &params);
@@ -296,7 +339,7 @@ static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface,
static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
u8 bssid[ETH_ALEN];
@@ -308,16 +351,16 @@ static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
goto fail;
sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
u8 ssid[sizeof(int) + SSID_MAX_LEN];
int res;
@@ -328,17 +371,18 @@ static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
if (iface->driver->get_ssid == NULL)
goto fail;
+ os_memset(ssid, 0, sizeof(ssid));
res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
if (res < 0 || res > SSID_MAX_LEN)
goto fail;
os_memcpy(ssid, &res, sizeof(int));
sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
@@ -371,7 +415,7 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface,
static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
struct wpa_driver_capa capa;
@@ -387,18 +431,19 @@ static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
capa.extended_capa_mask = NULL;
capa.extended_capa_len = 0;
sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
- struct wpa_priv_interface *iface = ctx;
+ struct wpa_priv_l2 *l2_ctx = ctx;
+ struct wpa_priv_interface *iface = l2_ctx->parent;
struct msghdr msg;
struct iovec io[2];
@@ -410,8 +455,8 @@ static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
msg.msg_iovlen = 2;
- msg.msg_name = &iface->l2_addr;
- msg.msg_namelen = sizeof(iface->l2_addr);
+ msg.msg_name = &iface->l2_addr[l2_ctx->idx];
+ msg.msg_namelen = iface->l2_addr_len[l2_ctx->idx];
if (sendmsg(iface->fd, &msg, 0) < 0) {
wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno));
@@ -419,14 +464,23 @@ static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
}
+static int wpa_priv_allowed_l2_proto(u16 proto)
+{
+ return proto == ETH_P_EAPOL || proto == ETH_P_RSN_PREAUTH ||
+ proto == ETH_P_80211_ENCAP;
+}
+
+
static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
struct sockaddr_un *from,
+ socklen_t fromlen,
void *buf, size_t len)
{
int *reg_cmd = buf;
u8 own_addr[ETH_ALEN];
int res;
u16 proto;
+ int idx;
if (len != 2 * sizeof(int)) {
wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu",
@@ -435,50 +489,69 @@ static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
}
proto = reg_cmd[0];
- if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH &&
- proto != ETH_P_80211_ENCAP) {
+ if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet connection for "
"ethertype 0x%x", proto);
return;
}
- if (iface->l2) {
- wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
- "instance");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (!iface->l2[idx])
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG, "No free l2_packet connection found");
+ return;
}
- os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr));
+ os_memcpy(&iface->l2_addr[idx], from, fromlen);
+ iface->l2_addr_len[idx] = fromlen;
- iface->l2 = l2_packet_init(iface->ifname, NULL, proto,
- wpa_priv_l2_rx, iface, reg_cmd[1]);
- if (iface->l2 == NULL) {
+ iface->l2_ctx[idx].idx = idx;
+ iface->l2_ctx[idx].parent = iface;
+ iface->l2[idx] = l2_packet_init(iface->ifname, NULL, proto,
+ wpa_priv_l2_rx, &iface->l2_ctx[idx],
+ reg_cmd[1]);
+ if (!iface->l2[idx]) {
wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet "
"instance for protocol %d", proto);
return;
}
- if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) {
+ if (l2_packet_get_own_addr(iface->l2[idx], own_addr) < 0) {
wpa_printf(MSG_DEBUG, "Failed to get own address from "
"l2_packet");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ l2_packet_deinit(iface->l2[idx]);
+ iface->l2[idx] = NULL;
return;
}
res = sendto(iface->fd, own_addr, ETH_ALEN, 0,
- (struct sockaddr *) from, sizeof(*from));
- wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res);
+ (struct sockaddr *) from, fromlen);
+ wpa_printf(MSG_DEBUG, "L2 registration[idx=%d]: res=%d", idx, res);
}
static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
- if (iface->l2) {
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ int idx;
+
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2_addr_len[idx] == fromlen &&
+ os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG,
+ "No registered l2_packet socket found for unregister request");
+ return;
+ }
+
+ if (iface->l2[idx]) {
+ l2_packet_deinit(iface->l2[idx]);
+ iface->l2[idx] = NULL;
}
}
@@ -486,20 +559,36 @@ static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface,
struct sockaddr_un *from)
{
- if (iface->l2)
- l2_packet_notify_auth_start(iface->l2);
+ int idx;
+
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2[idx])
+ l2_packet_notify_auth_start(iface->l2[idx]);
+ }
}
static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
- struct sockaddr_un *from,
+ struct sockaddr_un *from, socklen_t fromlen,
void *buf, size_t len)
{
u8 *dst_addr;
u16 proto;
int res;
+ int idx;
- if (iface->l2 == NULL)
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2_addr_len[idx] == fromlen &&
+ os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG,
+ "No registered l2_packet socket found for send request");
+ return;
+ }
+
+ if (iface->l2[idx] == NULL)
return;
if (len < ETH_ALEN + 2) {
@@ -511,15 +600,15 @@ static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
dst_addr = buf;
os_memcpy(&proto, buf + ETH_ALEN, 2);
- if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
+ if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
"0x%x", proto);
return;
}
- res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2,
- len - ETH_ALEN - 2);
- wpa_printf(MSG_DEBUG, "L2 send: res=%d", res);
+ res = l2_packet_send(iface->l2[idx], dst_addr, proto,
+ buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+ wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
}
@@ -564,7 +653,7 @@ static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
switch (cmd) {
case PRIVSEP_CMD_REGISTER:
- wpa_priv_cmd_register(iface, &from);
+ wpa_priv_cmd_register(iface, &from, fromlen);
break;
case PRIVSEP_CMD_UNREGISTER:
wpa_priv_cmd_unregister(iface, &from);
@@ -573,34 +662,35 @@ static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
wpa_priv_cmd_scan(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_SCAN_RESULTS:
- wpa_priv_cmd_get_scan_results(iface, &from);
+ wpa_priv_cmd_get_scan_results(iface, &from, fromlen);
break;
case PRIVSEP_CMD_ASSOCIATE:
wpa_priv_cmd_associate(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_BSSID:
- wpa_priv_cmd_get_bssid(iface, &from);
+ wpa_priv_cmd_get_bssid(iface, &from, fromlen);
break;
case PRIVSEP_CMD_GET_SSID:
- wpa_priv_cmd_get_ssid(iface, &from);
+ wpa_priv_cmd_get_ssid(iface, &from, fromlen);
break;
case PRIVSEP_CMD_SET_KEY:
wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_CAPA:
- wpa_priv_cmd_get_capa(iface, &from);
+ wpa_priv_cmd_get_capa(iface, &from, fromlen);
break;
case PRIVSEP_CMD_L2_REGISTER:
- wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len);
+ wpa_priv_cmd_l2_register(iface, &from, fromlen,
+ cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_L2_UNREGISTER:
- wpa_priv_cmd_l2_unregister(iface, &from);
+ wpa_priv_cmd_l2_unregister(iface, &from, fromlen);
break;
case PRIVSEP_CMD_L2_NOTIFY_AUTH_START:
wpa_priv_cmd_l2_notify_auth_start(iface, &from);
break;
case PRIVSEP_CMD_L2_SEND:
- wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len);
+ wpa_priv_cmd_l2_send(iface, &from, fromlen, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_SET_COUNTRY:
pos = cmd_buf;
@@ -618,8 +708,14 @@ static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
{
- if (iface->drv_priv && iface->driver->deinit)
- iface->driver->deinit(iface->drv_priv);
+ int i;
+
+ if (iface->drv_priv) {
+ if (iface->driver->deinit)
+ iface->driver->deinit(iface->drv_priv);
+ if (iface->drv_global_priv)
+ iface->driver->global_deinit(iface->drv_global_priv);
+ }
if (iface->fd >= 0) {
eloop_unregister_read_sock(iface->fd);
@@ -627,8 +723,10 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
unlink(iface->sock_name);
}
- if (iface->l2)
- l2_packet_deinit(iface->l2);
+ for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
+ if (iface->l2[i])
+ l2_packet_deinit(iface->l2[i]);
+ }
os_free(iface->ifname);
os_free(iface->driver_name);
@@ -638,7 +736,7 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
static struct wpa_priv_interface *
-wpa_priv_interface_init(const char *dir, const char *params)
+wpa_priv_interface_init(void *ctx, const char *dir, const char *params)
{
struct wpa_priv_interface *iface;
char *pos;
@@ -654,6 +752,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
if (iface == NULL)
return NULL;
iface->fd = -1;
+ iface->ctx = ctx;
len = pos - params;
iface->driver_name = dup_binstr(params, len);
@@ -769,7 +868,7 @@ static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event,
msg.msg_iov = io;
msg.msg_iovlen = data ? 2 : 1;
msg.msg_name = &iface->drv_addr;
- msg.msg_namelen = sizeof(iface->drv_addr);
+ msg.msg_namelen = iface->drv_addr_len;
if (sendmsg(iface->fd, &msg, 0) < 0) {
wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
@@ -788,7 +887,7 @@ static void wpa_priv_send_auth(struct wpa_priv_interface *iface,
struct privsep_event_auth *auth;
u8 *buf, *pos;
- buf = os_malloc(buflen);
+ buf = os_zalloc(buflen);
if (buf == NULL)
return;
@@ -982,12 +1081,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
&data->pmkid_candidate,
sizeof(struct pmkid_candidate));
break;
- case EVENT_STKSTART:
- if (data == NULL)
- return;
- wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART,
- &data->stkstart.peer, ETH_ALEN);
- break;
case EVENT_FT_RESPONSE:
wpa_priv_send_ft_response(iface, data);
break;
@@ -1002,6 +1095,37 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct wpa_priv_global *global = ctx;
+ struct wpa_priv_interface *iface;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ for (iface = global->interfaces; iface; iface = iface->next) {
+ if (os_strcmp(iface->ifname, data->interface_status.ifname) ==
+ 0)
+ break;
+ }
+ if (iface && iface->driver->get_ifindex) {
+ unsigned int ifindex;
+
+ ifindex = iface->driver->get_ifindex(iface->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_printf(MSG_DEBUG,
+ "%s: interface status ifindex %d mismatch (%d)",
+ iface->ifname, ifindex,
+ data->interface_status.ifindex);
+ return;
+ }
+ }
+ if (iface)
+ wpa_supplicant_event(iface, event, data);
+}
+
+
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1022,7 +1146,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
msg.msg_iov = io;
msg.msg_iovlen = 3;
msg.msg_name = &iface->drv_addr;
- msg.msg_namelen = sizeof(iface->drv_addr);
+ msg.msg_namelen = iface->drv_addr_len;
if (sendmsg(iface->fd, &msg, 0) < 0)
wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
@@ -1060,7 +1184,7 @@ static void wpa_priv_fd_workaround(void)
static void usage(void)
{
printf("wpa_priv v" VERSION_STR "\n"
- "Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> and "
+ "Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and "
"contributors\n"
"\n"
"usage:\n"
@@ -1077,13 +1201,17 @@ int main(int argc, char *argv[])
char *pid_file = NULL;
int daemonize = 0;
char *ctrl_dir = "/var/run/wpa_priv";
- struct wpa_priv_interface *interfaces = NULL, *iface;
+ struct wpa_priv_global global;
+ struct wpa_priv_interface *iface;
if (os_program_init())
return -1;
wpa_priv_fd_workaround();
+ os_memset(&global, 0, sizeof(global));
+ global.interfaces = NULL;
+
for (;;) {
c = getopt(argc, argv, "Bc:dP:");
if (c < 0)
@@ -1121,14 +1249,14 @@ int main(int argc, char *argv[])
for (i = optind; i < argc; i++) {
wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]);
- iface = wpa_priv_interface_init(ctrl_dir, argv[i]);
+ iface = wpa_priv_interface_init(&global, ctrl_dir, argv[i]);
if (iface == NULL)
goto out;
- iface->next = interfaces;
- interfaces = iface;
+ iface->next = global.interfaces;
+ global.interfaces = iface;
}
- if (daemonize && os_daemonize(pid_file))
+ if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
goto out;
eloop_register_signal_terminate(wpa_priv_terminate, NULL);
@@ -1137,7 +1265,7 @@ int main(int argc, char *argv[])
ret = 0;
out:
- iface = interfaces;
+ iface = global.interfaces;
while (iface) {
struct wpa_priv_interface *prev = iface;
iface = iface->next;
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.c b/contrib/wpa/wpa_supplicant/wpa_supplicant.c
index ef55fdc..96a3691 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,10 @@
*/
#include "includes.h"
+#ifdef CONFIG_MATCH_IFACE
+#include <net/if.h>
+#include <fnmatch.h>
+#endif /* CONFIG_MATCH_IFACE */
#include "common.h"
#include "crypto/random.h"
@@ -34,6 +38,8 @@
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
+#include "common/gas_server.h"
+#include "common/dpp.h"
#include "p2p/p2p.h"
#include "fst/fst.h"
#include "blacklist.h"
@@ -55,10 +61,15 @@
#include "wnm_sta.h"
#include "wpas_kay.h"
#include "mesh.h"
+#include "dpp_supplicant.h"
+#ifdef CONFIG_MESH
+#include "ap/ap_config.h"
+#include "ap/hostapd.h"
+#endif /* CONFIG_MESH */
const char *const wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors";
const char *const wpa_supplicant_license =
"This software may be distributed under the terms of the BSD license.\n"
@@ -108,6 +119,13 @@ const char *const wpa_supplicant_full_license5 =
"\n";
#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+
+
/* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
@@ -188,7 +206,9 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
const u8 *bssid = wpa_s->bssid;
- if (is_zero_ether_addr(bssid))
+ if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+ wpa_s->wpa_state == WPA_ASSOCIATING))
bssid = wpa_s->pending_bssid;
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(bssid));
@@ -224,10 +244,30 @@ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
"%d usec", sec, usec);
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+ wpa_s->last_auth_timeout_sec = sec;
eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
}
+/*
+ * wpas_auth_timeout_restart - Restart and change timeout for authentication
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec_diff: difference in seconds applied to original timeout value
+ */
+void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff)
+{
+ int new_sec = wpa_s->last_auth_timeout_sec + sec_diff;
+
+ if (eloop_is_timeout_registered(wpa_supplicant_timeout, wpa_s, NULL)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Authentication timeout restart: %d sec", new_sec);
+ eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+ eloop_register_timeout(new_sec, 0, wpa_supplicant_timeout,
+ wpa_s, NULL);
+ }
+}
+
+
/**
* wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
* @wpa_s: Pointer to wpa_supplicant data
@@ -241,6 +281,9 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
wpa_blacklist_del(wpa_s, wpa_s->bssid);
+ os_free(wpa_s->last_con_fail_realm);
+ wpa_s->last_con_fail_realm = NULL;
+ wpa_s->last_con_fail_realm_len = 0;
}
@@ -323,7 +366,12 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
- ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#ifdef CONFIG_MACSEC
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
+ ieee802_1x_create_preshared_mka(wpa_s, ssid);
+ else
+ ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* CONFIG_MACSEC */
#endif /* IEEE8021X_EAPOL */
}
@@ -397,6 +445,32 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
}
+void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss_tmp_disallowed *bss, *prev;
+
+ dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
+ struct wpa_bss_tmp_disallowed, list) {
+ eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
+ dl_list_del(&bss->list);
+ os_free(bss);
+ }
+}
+
+
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
+{
+ struct fils_hlp_req *req;
+
+ while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
+ list)) != NULL) {
+ dl_list_del(&req->list);
+ wpabuf_free(req->pkt);
+ os_free(req);
+ }
+}
+
+
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
int i;
@@ -416,6 +490,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_TESTING_OPTIONS
l2_packet_deinit(wpa_s->l2_test);
wpa_s->l2_test = NULL;
+ os_free(wpa_s->get_pref_freq_list_override);
+ wpa_s->get_pref_freq_list_override = NULL;
+ wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
+ wpa_s->last_assoc_req_wpa_ie = NULL;
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
@@ -430,6 +508,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
os_free(wpa_s->confanother);
wpa_s->confanother = NULL;
+ os_free(wpa_s->last_con_fail_realm);
+ wpa_s->last_con_fail_realm = NULL;
+ wpa_s->last_con_fail_realm_len = 0;
+
wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
@@ -488,6 +570,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
os_free(wpa_s->manual_scan_freqs);
wpa_s->manual_scan_freqs = NULL;
+ os_free(wpa_s->select_network_scan_freqs);
+ wpa_s->select_network_scan_freqs = NULL;
os_free(wpa_s->manual_sched_scan_freqs);
wpa_s->manual_sched_scan_freqs = NULL;
@@ -506,6 +590,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
radio_remove_works(wpa_s, "gas-query", 0);
gas_query_deinit(wpa_s->gas);
wpa_s->gas = NULL;
+ gas_server_deinit(wpa_s->gas_server);
+ wpa_s->gas_server = NULL;
free_hw_features(wpa_s);
@@ -536,6 +622,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->last_scan_res = NULL;
#ifdef CONFIG_HS20
+ if (wpa_s->drv_priv)
+ wpa_drv_configure_frame_filters(wpa_s, 0);
hs20_deinit(wpa_s);
#endif /* CONFIG_HS20 */
@@ -545,6 +633,49 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
}
wmm_ac_notify_disassoc(wpa_s);
+
+ wpa_s->sched_scan_plans_num = 0;
+ os_free(wpa_s->sched_scan_plans);
+ wpa_s->sched_scan_plans = NULL;
+
+#ifdef CONFIG_MBO
+ wpa_s->non_pref_chan_num = 0;
+ os_free(wpa_s->non_pref_chan);
+ wpa_s->non_pref_chan = NULL;
+#endif /* CONFIG_MBO */
+
+ free_bss_tmp_disallowed(wpa_s);
+
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = NULL;
+ wpas_clear_beacon_rep_data(wpa_s);
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+ {
+ struct external_pmksa_cache *entry;
+
+ while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+ struct external_pmksa_cache,
+ list)) != NULL) {
+ dl_list_del(&entry->list);
+ os_free(entry->pmksa_cache);
+ os_free(entry);
+ }
+ }
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+ wpas_flush_fils_hlp_req(wpa_s);
+
+ wpabuf_free(wpa_s->ric_ies);
+ wpa_s->ric_ies = NULL;
+
+#ifdef CONFIG_DPP
+ wpas_dpp_deinit(wpa_s);
+ dpp_global_deinit(wpa_s->dpp);
+ wpa_s->dpp = NULL;
+#endif /* CONFIG_DPP */
}
@@ -718,6 +849,23 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_supplicant_state_txt(wpa_s->wpa_state),
wpa_supplicant_state_txt(state));
+ if (state == WPA_COMPLETED &&
+ os_reltime_initialized(&wpa_s->roam_start)) {
+ os_reltime_age(&wpa_s->roam_start, &wpa_s->roam_time);
+ wpa_s->roam_start.sec = 0;
+ wpa_s->roam_start.usec = 0;
+ wpas_notify_auth_changed(wpa_s);
+ wpas_notify_roam_time(wpa_s);
+ wpas_notify_roam_complete(wpa_s);
+ } else if (state == WPA_DISCONNECTED &&
+ os_reltime_initialized(&wpa_s->roam_start)) {
+ wpa_s->roam_start.sec = 0;
+ wpa_s->roam_start.usec = 0;
+ wpa_s->roam_time.sec = 0;
+ wpa_s->roam_time.usec = 0;
+ wpas_notify_roam_complete(wpa_s);
+ }
+
if (state == WPA_INTERFACE_DISABLED) {
/* Assure normal scan when interface is restored */
wpa_s->normal_scans = 0;
@@ -758,12 +906,24 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
if (state == WPA_COMPLETED && wpa_s->new_connection) {
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int fils_hlp_sent = 0;
+
+#ifdef CONFIG_SME
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ wpa_auth_alg_fils(wpa_s->sme.auth_alg))
+ fils_hlp_sent = 1;
+#endif /* CONFIG_SME */
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ wpa_auth_alg_fils(wpa_s->auth_alg))
+ fils_hlp_sent = 1;
+
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
- MACSTR " completed [id=%d id_str=%s]",
+ MACSTR " completed [id=%d id_str=%s%s]",
MAC2STR(wpa_s->bssid),
ssid ? ssid->id : -1,
- ssid && ssid->id_str ? ssid->id_str : "");
+ ssid && ssid->id_str ? ssid->id_str : "",
+ fils_hlp_sent ? " FILS_HLP_SENT" : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
wpas_clear_temp_disabled(wpa_s, ssid, 1);
wpa_blacklist_clear(wpa_s);
@@ -778,6 +938,11 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpas_p2p_completed(wpa_s);
sme_sched_obss_scan(wpa_s, 1);
+
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ if (!fils_hlp_sent && ssid && ssid->eap.erp)
+ wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -796,7 +961,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
- if (state == WPA_AUTHENTICATING)
+ if (state > WPA_SCANNING)
wpa_supplicant_stop_autoscan(wpa_s);
if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
@@ -892,7 +1057,13 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
"file '%s' - exiting", wpa_s->confname);
return -1;
}
- wpa_config_read(wpa_s->confanother, conf);
+ if (wpa_s->confanother &&
+ !wpa_config_read(wpa_s->confanother, conf)) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to parse the configuration file '%s' - exiting",
+ wpa_s->confanother);
+ return -1;
+ }
conf->changed_parameters = (unsigned int) -1;
@@ -918,7 +1089,9 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
* TODO: should notify EAPOL SM about changes in opensc_engine_path,
* pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
*/
- if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+ if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
/*
* Clear forced success to clear EAP state for next
* authentication.
@@ -963,6 +1136,11 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
wpa_supplicant_terminate_proc(global);
}
}
+
+ if (wpa_debug_reopen_file() < 0) {
+ /* Ignore errors since we cannot really do much to fix this */
+ wpa_printf(MSG_DEBUG, "Could not reopen debug log file");
+ }
}
@@ -1014,6 +1192,18 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
}
+static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
+ int freq)
+{
+ if (!ie->has_group)
+ ie->group_cipher = wpa_default_rsn_cipher(freq);
+ if (!ie->has_pairwise)
+ ie->pairwise_cipher = wpa_default_rsn_cipher(freq);
+ return (ie->group_cipher & ssid->group_cipher) &&
+ (ie->pairwise_cipher & ssid->pairwise_cipher);
+}
+
+
/**
* wpa_supplicant_set_suites - Set authentication and encryption parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -1045,8 +1235,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
- (ie.group_cipher & ssid->group_cipher) &&
- (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ matching_ciphers(ssid, &ie, bss->freq) &&
(ie.key_mgmt & ssid->key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
proto = WPA_PROTO_RSN;
@@ -1058,14 +1247,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
proto = WPA_PROTO_WPA;
#ifdef CONFIG_HS20
- } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN)) {
+ } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN) &&
+ wpa_parse_wpa_ie(bss_osen, 2 + bss_osen[1], &ie) == 0 &&
+ (ie.group_cipher & ssid->group_cipher) &&
+ (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ (ie.key_mgmt & ssid->key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN");
- /* TODO: parse OSEN element */
- os_memset(&ie, 0, sizeof(ie));
- ie.group_cipher = WPA_CIPHER_CCMP;
- ie.pairwise_cipher = WPA_CIPHER_CCMP;
- ie.key_mgmt = WPA_KEY_MGMT_OSEN;
proto = WPA_PROTO_OSEN;
+ } else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) &&
+ wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
+ (ie.group_cipher & ssid->group_cipher) &&
+ (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ (ie.key_mgmt & ssid->key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using OSEN (within RSN)");
+ proto = WPA_PROTO_RSN;
#endif /* CONFIG_HS20 */
} else if (bss) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
@@ -1117,10 +1312,35 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ie.pairwise_cipher = ssid->pairwise_cipher;
ie.key_mgmt = ssid->key_mgmt;
#ifdef CONFIG_IEEE80211W
- ie.mgmt_group_cipher =
- ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
- WPA_CIPHER_AES_128_CMAC : 0;
+ ie.mgmt_group_cipher = 0;
+ if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (ssid->group_mgmt_cipher &
+ WPA_CIPHER_BIP_GMAC_256)
+ ie.mgmt_group_cipher =
+ WPA_CIPHER_BIP_GMAC_256;
+ else if (ssid->group_mgmt_cipher &
+ WPA_CIPHER_BIP_CMAC_256)
+ ie.mgmt_group_cipher =
+ WPA_CIPHER_BIP_CMAC_256;
+ else if (ssid->group_mgmt_cipher &
+ WPA_CIPHER_BIP_GMAC_128)
+ ie.mgmt_group_cipher =
+ WPA_CIPHER_BIP_GMAC_128;
+ else
+ ie.mgmt_group_cipher =
+ WPA_CIPHER_AES_128_CMAC;
+ }
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OWE
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !ssid->owe_only &&
+ !bss_wpa && !bss_rsn && !bss_osen) {
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_s->wpa_proto = 0;
+ *wpa_ie_len = 0;
+ return 0;
+ }
+#endif /* CONFIG_OWE */
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
"based on configuration");
} else
@@ -1150,7 +1370,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
return -1;
}
+#ifdef CONFIG_NO_WPA
+ wpa_s->group_cipher = WPA_CIPHER_NONE;
+ wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+#else /* CONFIG_NO_WPA */
sel = ie.group_cipher & ssid->group_cipher;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP group 0x%x network profile group 0x%x; available group 0x%x",
+ ie.group_cipher, ssid->group_cipher, sel);
wpa_s->group_cipher = wpa_pick_group_cipher(sel);
if (wpa_s->group_cipher < 0) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
@@ -1161,6 +1388,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_cipher_txt(wpa_s->group_cipher));
sel = ie.pairwise_cipher & ssid->pairwise_cipher;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP pairwise 0x%x network profile pairwise 0x%x; available pairwise 0x%x",
+ ie.pairwise_cipher, ssid->pairwise_cipher, sel);
wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
if (wpa_s->pairwise_cipher < 0) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
@@ -1169,13 +1399,32 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
wpa_cipher_txt(wpa_s->pairwise_cipher));
+#endif /* CONFIG_NO_WPA */
sel = ie.key_mgmt & ssid->key_mgmt;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
+ ie.key_mgmt, ssid->key_mgmt, sel);
#ifdef CONFIG_SAE
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
if (0) {
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SHA384
+ } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using KEY_MGMT FT/802.1X-SHA384");
+ if (pmksa_cache_get_current(wpa_s->wpa)) {
+ /* PMKSA caching with FT is not fully functional, so
+ * disable the case for now. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: Disable PMKSA caching for FT/802.1X connection");
+ pmksa_cache_clear_current(wpa_s->wpa);
+ }
+#endif /* CONFIG_SHA384 */
+#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SUITEB192
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
@@ -1188,22 +1437,52 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT 802.1X with Suite B");
#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_FILS
+#ifdef CONFIG_IEEE80211R
+ } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
+ } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
+#endif /* CONFIG_IEEE80211R */
+ } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
+ } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
+#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
- } else if (sel & WPA_KEY_MGMT_FT_PSK) {
- wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
+ if (pmksa_cache_get_current(wpa_s->wpa)) {
+ /* PMKSA caching with FT is not fully functional, so
+ * disable the case for now. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: Disable PMKSA caching for FT/802.1X connection");
+ pmksa_cache_clear_current(wpa_s->wpa);
+ }
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_DPP
+ } else if (sel & WPA_KEY_MGMT_DPP) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
+#endif /* CONFIG_DPP */
#ifdef CONFIG_SAE
- } else if (sel & WPA_KEY_MGMT_SAE) {
- wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
- wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
} else if (sel & WPA_KEY_MGMT_FT_SAE) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+ } else if (sel & WPA_KEY_MGMT_SAE) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+ } else if (sel & WPA_KEY_MGMT_FT_PSK) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
+#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -1228,6 +1507,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_OWE
+ } else if (sel & WPA_KEY_MGMT_OWE) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE");
+#endif /* CONFIG_OWE */
} else {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
"authenticated key management type");
@@ -1241,9 +1525,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211W
sel = ie.mgmt_group_cipher;
+ if (ssid->group_mgmt_cipher)
+ sel &= ssid->group_mgmt_cipher;
if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
!(ie.capabilities & WPA_CAPABILITY_MFPC))
sel = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
+ ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
if (sel & WPA_CIPHER_AES_128_CMAC) {
wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
@@ -1269,34 +1558,56 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
wpas_get_ssid_pmf(wpa_s, ssid));
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
+#endif /* CONFIG_OCV */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
return -1;
}
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
+ if (0) {
+#ifdef CONFIG_DPP
+ } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
+ /* Use PMK from DPP network introduction (PMKSA entry) */
+ wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+#endif /* CONFIG_DPP */
+ } else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
int psk_set = 0;
+ int sae_only;
- if (ssid->psk_set) {
- wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
+ sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256)) == 0;
+
+ if (ssid->psk_set && !sae_only) {
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
+ ssid->psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
+ NULL);
psk_set = 1;
}
+
+ if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ (ssid->sae_password || ssid->passphrase))
+ psk_set = 1;
+
#ifndef CONFIG_NO_PBKDF2
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
- ssid->passphrase) {
+ ssid->passphrase && !sae_only) {
u8 psk[PMK_LEN];
pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
4096, psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL);
psk_set = 1;
os_memset(psk, 0, sizeof(psk));
}
#endif /* CONFIG_NO_PBKDF2 */
#ifdef CONFIG_EXT_PASSWORD
- if (ssid->ext_psk) {
+ if (ssid->ext_psk && !sae_only) {
struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
ssid->ext_psk);
char pw_str[64 + 1];
@@ -1328,7 +1639,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
"external passphrase)",
psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
+ NULL);
psk_set = 1;
os_memset(psk, 0, sizeof(psk));
} else
@@ -1341,7 +1653,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ext_password_free(pw);
return -1;
}
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "PSK (from external PSK)",
+ psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
+ NULL);
psk_set = 1;
os_memset(psk, 0, sizeof(psk));
} else {
@@ -1360,8 +1676,15 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (!psk_set) {
wpa_msg(wpa_s, MSG_INFO,
"No PSK available for association");
+ wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
return -1;
}
+#ifdef CONFIG_OWE
+ } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
+ /* OWE Diffie-Hellman exchange in (Re)Association
+ * Request/Response frames set the PMK, so do not override it
+ * here. */
+#endif /* CONFIG_OWE */
} else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
@@ -1377,6 +1700,10 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
case 0: /* Bits 0-7 */
break;
case 1: /* Bits 8-15 */
+ if (wpa_s->conf->coloc_intf_reporting) {
+ /* Bit 13 - Collocated Interference Reporting */
+ *pos |= 0x20;
+ }
break;
case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM
@@ -1395,7 +1722,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
break;
case 4: /* Bits 32-39 */
#ifdef CONFIG_INTERWORKING
- if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING)
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)
*pos |= 0x01; /* Bit 32 - QoS Map */
#endif /* CONFIG_INTERWORKING */
break;
@@ -1404,9 +1731,26 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
if (wpa_s->conf->hs20)
*pos |= 0x40; /* Bit 46 - WNM-Notification */
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_MBO */
break;
case 6: /* Bits 48-55 */
break;
+ case 7: /* Bits 56-63 */
+ break;
+ case 8: /* Bits 64-71 */
+ if (wpa_s->conf->ftm_responder)
+ *pos |= 0x40; /* Bit 70 - FTM responder */
+ if (wpa_s->conf->ftm_initiator)
+ *pos |= 0x80; /* Bit 71 - FTM initiator */
+ break;
+ case 9: /* Bits 72-79 */
+#ifdef CONFIG_FILS
+ if (!wpa_s->disable_fils)
+ *pos |= 0x01;
+#endif /* CONFIG_FILS */
+ break;
}
}
@@ -1414,7 +1758,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
{
u8 *pos = buf;
- u8 len = 6, i;
+ u8 len = 10, i;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
@@ -1586,6 +1930,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_connect_work *cwork;
int rand_style;
+ wpa_s->own_disconnect_req = 0;
+
+ /*
+ * If we are starting a new connection, any previously pending EAPOL
+ * RX cannot be valid anymore.
+ */
+ wpabuf_free(wpa_s->pending_eapol_rx);
+ wpa_s->pending_eapol_rx = NULL;
+
if (ssid->mac_addr == -1)
rand_style = wpa_s->conf->mac_addr;
else
@@ -1593,18 +1946,27 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
+ wpa_s->reassoc_same_ess = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ wpa_s->testing_resend_assoc = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->last_ssid == ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+ wpa_s->reassoc_same_ess = 1;
if (wpa_s->current_bss && wpa_s->current_bss == bss) {
wmm_ac_save_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 1;
+ } else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
+ os_get_reltime(&wpa_s->roam_start);
}
- } else if (rand_style > 0) {
+ }
+
+ if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
if (wpas_update_random_addr(wpa_s, rand_style) < 0)
return;
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- } else if (wpa_s->mac_addr_changed) {
+ } else if (rand_style == 0 && wpa_s->mac_addr_changed) {
if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Could not restore permanent MAC address");
@@ -1623,6 +1985,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
wpa_s->ibss_rsn = NULL;
+#else /* CONFIG_IBSS_RSN */
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "IBSS RSN not supported in the build");
+ return;
+ }
#endif /* CONFIG_IBSS_RSN */
if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
@@ -1661,10 +2030,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
wpa_s->current_bss = bss;
- wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED
- "ssid=\"%s\" id=%d",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->id);
+ wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->id);
+ wpas_notify_mesh_group_started(wpa_s, ssid);
#else /* CONFIG_MESH */
wpa_msg(wpa_s, MSG_ERROR,
"mesh mode support not included in the build");
@@ -1672,6 +2041,20 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
+ /*
+ * Set WPA state machine configuration to match the selected network now
+ * so that the information is available before wpas_start_assoc_cb()
+ * gets called. This is needed at least for RSN pre-authentication where
+ * candidate APs are added to a list based on scan result processing
+ * before completion of the first association.
+ */
+ wpa_supplicant_rsn_supp_set_config(wpa_s, ssid);
+
+#ifdef CONFIG_DPP
+ if (wpas_dpp_check_connect(wpa_s, ssid, bss) != 0)
+ return;
+#endif /* CONFIG_DPP */
+
#ifdef CONFIG_TDLS
if (bss)
wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
@@ -1694,6 +2077,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
+#ifdef CONFIG_SME
+ if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
+ /* Clear possibly set auth_alg, if any, from last attempt. */
+ wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
+ }
+#endif /* CONFIG_SME */
+
+ wpas_abort_ongoing_scan(wpa_s);
+
cwork = os_zalloc(sizeof(*cwork));
if (cwork == NULL)
return;
@@ -1715,6 +2107,31 @@ static int bss_is_ibss(struct wpa_bss *bss)
}
+static int drv_supports_vht(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ u8 channel;
+ int i;
+
+ hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ return 0;
+ for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == hw_mode) {
+ mode = &wpa_s->hw.modes[i];
+ break;
+ }
+ }
+
+ if (!mode)
+ return 0;
+
+ return mode->vht_capab != 0;
+}
+
+
void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
const struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
@@ -1727,8 +2144,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
u8 channel;
int i, chan_idx, ht40 = -1, res, obss_scan = 1;
- unsigned int j;
+ unsigned int j, k;
struct hostapd_freq_params vht_freq;
+ int chwidth, seg0, seg1;
+ u32 vht_caps = 0;
freq->freq = ssid->frequency;
@@ -1780,6 +2199,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (!mode)
return;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ freq->ht_enabled = 0;
+ return;
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
freq->ht_enabled = ht_supported(mode);
if (!freq->ht_enabled)
return;
@@ -1801,6 +2227,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
+ freq->channel = pri_chan->chan;
+
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht40) {
+ if (ssid->disable_vht)
+ return;
+ goto skip_ht40;
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
/* Check/setup HT40+/HT40- */
for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
if (ht40plus[j] == channel) {
@@ -1823,24 +2259,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
- freq->channel = pri_chan->chan;
-
- switch (ht40) {
- case -1:
+ if (ht40 == -1) {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
return;
- freq->sec_channel_offset = -1;
- break;
- case 1:
+ } else {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
return;
- freq->sec_channel_offset = 1;
- break;
- default:
- break;
}
+ freq->sec_channel_offset = ht40;
- if (freq->sec_channel_offset && obss_scan) {
+ if (obss_scan) {
struct wpa_scan_results *scan_res;
scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
@@ -1874,20 +2302,30 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
wpa_scan_results_free(scan_res);
}
+#ifdef CONFIG_HT_OVERRIDES
+skip_ht40:
+#endif /* CONFIG_HT_OVERRIDES */
wpa_printf(MSG_DEBUG,
"IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
freq->channel, freq->sec_channel_offset);
- /* Not sure if mesh is ready for VHT */
- if (ssid->mode != WPAS_MODE_IBSS)
+ if (!drv_supports_vht(wpa_s, ssid))
return;
/* For IBSS check VHT_IBSS flag */
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
return;
vht_freq = *freq;
+#ifdef CONFIG_VHT_OVERRIDES
+ if (ssid->disable_vht) {
+ freq->vht_enabled = 0;
+ return;
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
vht_freq.vht_enabled = vht_supported(mode);
if (!vht_freq.vht_enabled)
return;
@@ -1914,12 +2352,62 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
return;
}
+ chwidth = VHT_CHANWIDTH_80MHZ;
+ seg0 = vht80[j] + 6;
+ seg1 = 0;
+
+ if (ssid->max_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) {
+ /* setup center_freq2, bandwidth */
+ for (k = 0; k < ARRAY_SIZE(vht80); k++) {
+ /* Only accept 80 MHz segments separated by a gap */
+ if (j == k || abs(vht80[j] - vht80[k]) == 16)
+ continue;
+ for (i = vht80[k]; i < vht80[k] + 16; i += 4) {
+ struct hostapd_channel_data *chan;
+
+ chan = hw_get_channel_chan(mode, i, NULL);
+ if (!chan)
+ continue;
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+
+ /* Found a suitable second segment for 80+80 */
+ chwidth = VHT_CHANWIDTH_80P80MHZ;
+ vht_caps |=
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ seg1 = vht80[k] + 6;
+ }
+
+ if (chwidth == VHT_CHANWIDTH_80P80MHZ)
+ break;
+ }
+ } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) {
+ if (freq->freq == 5180) {
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ seg0 = 50;
+ } else if (freq->freq == 5520) {
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ seg0 = 114;
+ }
+ } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_USE_HT) {
+ chwidth = VHT_CHANWIDTH_USE_HT;
+ seg0 = vht80[j] + 2;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht40)
+ seg0 = 0;
+#endif /* CONFIG_HT_OVERRIDES */
+ }
+
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
freq->channel, freq->ht_enabled,
vht_freq.vht_enabled,
freq->sec_channel_offset,
- VHT_CHANWIDTH_80MHZ,
- vht80[j] + 6, 0, 0) != 0)
+ chwidth, seg0, seg1, vht_caps) != 0)
return;
*freq = vht_freq;
@@ -1929,139 +2417,177 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
}
-static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
+#ifdef CONFIG_FILS
+static size_t wpas_add_fils_hlp_req(struct wpa_supplicant *wpa_s, u8 *ie_buf,
+ size_t ie_buf_len)
{
- struct wpa_connect_work *cwork = work->ctx;
- struct wpa_bss *bss = cwork->bss;
- struct wpa_ssid *ssid = cwork->ssid;
- struct wpa_supplicant *wpa_s = work->wpa_s;
- u8 wpa_ie[200];
- size_t wpa_ie_len;
- int use_crypt, ret, i, bssid_changed;
- int algs = WPA_AUTH_ALG_OPEN;
- unsigned int cipher_pairwise, cipher_group;
- struct wpa_driver_associate_params params;
- int wep_keys_set = 0;
- int assoc_failed = 0;
- struct wpa_ssid *old_ssid;
-#ifdef CONFIG_HT_OVERRIDES
- struct ieee80211_ht_capabilities htcaps;
- struct ieee80211_ht_capabilities htcaps_mask;
-#endif /* CONFIG_HT_OVERRIDES */
-#ifdef CONFIG_VHT_OVERRIDES
- struct ieee80211_vht_capabilities vhtcaps;
- struct ieee80211_vht_capabilities vhtcaps_mask;
-#endif /* CONFIG_VHT_OVERRIDES */
-
- if (deinit) {
- if (work->started) {
- wpa_s->connect_work = NULL;
+ struct fils_hlp_req *req;
+ size_t rem_len, hdr_len, hlp_len, len, ie_len = 0;
+ const u8 *pos;
+ u8 *buf = ie_buf;
+
+ dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
+ list) {
+ rem_len = ie_buf_len - ie_len;
+ pos = wpabuf_head(req->pkt);
+ hdr_len = 1 + 2 * ETH_ALEN + 6;
+ hlp_len = wpabuf_len(req->pkt);
+
+ if (rem_len < 2 + hdr_len + hlp_len) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Cannot fit HLP - rem_len=%lu to_fill=%lu",
+ (unsigned long) rem_len,
+ (unsigned long) (2 + hdr_len + hlp_len));
+ break;
+ }
- /* cancel possible auth. timeout */
- eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
- NULL);
+ len = (hdr_len + hlp_len) > 255 ? 255 : hdr_len + hlp_len;
+ /* Element ID */
+ *buf++ = WLAN_EID_EXTENSION;
+ /* Length */
+ *buf++ = len;
+ /* Element ID Extension */
+ *buf++ = WLAN_EID_EXT_FILS_HLP_CONTAINER;
+ /* Destination MAC address */
+ os_memcpy(buf, req->dst, ETH_ALEN);
+ buf += ETH_ALEN;
+ /* Source MAC address */
+ os_memcpy(buf, wpa_s->own_addr, ETH_ALEN);
+ buf += ETH_ALEN;
+ /* LLC/SNAP Header */
+ os_memcpy(buf, "\xaa\xaa\x03\x00\x00\x00", 6);
+ buf += 6;
+ /* HLP Packet */
+ os_memcpy(buf, pos, len - hdr_len);
+ buf += len - hdr_len;
+ pos += len - hdr_len;
+
+ hlp_len -= len - hdr_len;
+ ie_len += 2 + len;
+ rem_len -= 2 + len;
+
+ while (hlp_len) {
+ len = (hlp_len > 255) ? 255 : hlp_len;
+ if (rem_len < 2 + len)
+ break;
+ *buf++ = WLAN_EID_FRAGMENT;
+ *buf++ = len;
+ os_memcpy(buf, pos, len);
+ buf += len;
+ pos += len;
+
+ hlp_len -= len;
+ ie_len += 2 + len;
+ rem_len -= 2 + len;
}
- wpas_connect_work_free(cwork);
- return;
}
- wpa_s->connect_work = work;
+ return ie_len;
+}
- if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
- wpas_network_disabled(wpa_s, ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
- wpas_connect_work_done(wpa_s);
- return;
- }
- os_memset(&params, 0, sizeof(params));
- wpa_s->reassociate = 0;
- wpa_s->eap_expected_failure = 0;
- if (bss &&
- (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
-#ifdef CONFIG_IEEE80211R
- const u8 *ie, *md = NULL;
-#endif /* CONFIG_IEEE80211R */
- wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
- " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
- wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
- bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
- os_memset(wpa_s->bssid, 0, ETH_ALEN);
- os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
- if (bssid_changed)
- wpas_notify_bssid_changed(wpa_s);
-#ifdef CONFIG_IEEE80211R
- ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
- if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
- md = ie + 2;
- wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
- if (md) {
- /* Prepare for the next transition */
- wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
- }
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_WPS
- } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
- wpa_s->conf->ap_scan == 2 &&
- (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
- /* Use ap_scan==1 style network selection to find the network
- */
- wpas_connect_work_done(wpa_s);
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- return;
-#endif /* CONFIG_WPS */
- } else {
- wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
- }
- if (!wpa_s->pno)
- wpa_supplicant_cancel_sched_scan(wpa_s);
+int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
+{
+ return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
+ (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
+}
- wpa_supplicant_cancel_scan(wpa_s);
- /* Starting new association, so clear the possibly used WPA IE from the
- * previous association. */
- wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_FILS_SK_PFS
+ return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
+#else /* CONFIG_FILS_SK_PFS */
+ return 0;
+#endif /* CONFIG_FILS_SK_PFS */
+}
-#ifdef IEEE8021X_EAPOL
- if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
- if (ssid->leap) {
- if (ssid->non_leap == 0)
- algs = WPA_AUTH_ALG_LEAP;
- else
- algs |= WPA_AUTH_ALG_LEAP;
- }
+#endif /* CONFIG_FILS */
+
+
+static u8 * wpas_populate_assoc_ies(
+ struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params,
+ enum wpa_drv_update_connect_params_mask *mask)
+{
+ u8 *wpa_ie;
+ size_t max_wpa_ie_len = 500;
+ size_t wpa_ie_len;
+ int algs = WPA_AUTH_ALG_OPEN;
+#ifdef CONFIG_MBO
+ const u8 *mbo_ie;
+#endif
+#ifdef CONFIG_SAE
+ int sae_pmksa_cached = 0;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ const u8 *realm, *username, *rrk;
+ size_t realm_len, username_len, rrk_len;
+ u16 next_seq_num;
+ struct fils_hlp_req *req;
+
+ dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
+ list) {
+ max_wpa_ie_len += 3 + 2 * ETH_ALEN + 6 + wpabuf_len(req->pkt) +
+ 2 + 2 * wpabuf_len(req->pkt) / 255;
}
-#endif /* IEEE8021X_EAPOL */
- wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
- if (ssid->auth_alg) {
- algs = ssid->auth_alg;
- wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
- "0x%x", algs);
+#endif /* CONFIG_FILS */
+
+ wpa_ie = os_malloc(max_wpa_ie_len);
+ if (!wpa_ie) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate connect IE buffer for %lu bytes",
+ (unsigned long) max_wpa_ie_len);
+ return NULL;
}
if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
+ const u8 *cache_id = NULL;
+
try_opportunistic = (ssid->proactive_key_caching < 0 ?
wpa_s->conf->okc :
ssid->proactive_key_caching) &&
(ssid->proto & WPA_PROTO_RSN);
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(ssid->key_mgmt))
+ cache_id = wpa_bss_get_fils_cache_id(bss);
+#endif /* CONFIG_FILS */
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
- ssid, try_opportunistic) == 0)
+ ssid, try_opportunistic,
+ cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
- wpa_ie_len = sizeof(wpa_ie);
+#ifdef CONFIG_SAE
+ sae_pmksa_cached = 1;
+#endif /* CONFIG_SAE */
+ }
+ wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_ie, &wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
"key management and encryption suites");
- wpas_connect_work_done(wpa_s);
- return;
+ os_free(wpa_ie);
+ return NULL;
}
+#ifdef CONFIG_HS20
+ } else if (bss && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
+ /* No PMKSA caching, but otherwise similar to RSN/WPA */
+ wpa_ie_len = max_wpa_ie_len;
+ if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
+ wpa_ie, &wpa_ie_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+ "key management and encryption suites");
+ os_free(wpa_ie);
+ return NULL;
+ }
+#endif /* CONFIG_HS20 */
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
/*
@@ -2073,20 +2599,20 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_ie_len = 0;
wpa_s->wpa_proto = 0;
} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
- wpa_ie_len = sizeof(wpa_ie);
+ wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
wpa_ie, &wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
"key management and encryption suites (no "
"scan results)");
- wpas_connect_work_done(wpa_s);
- return;
+ os_free(wpa_ie);
+ return NULL;
}
#ifdef CONFIG_WPS
} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
struct wpabuf *wps_ie;
wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
- if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
+ if (wps_ie && wpabuf_len(wps_ie) <= max_wpa_ie_len) {
wpa_ie_len = wpabuf_len(wps_ie);
os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
} else
@@ -2094,9 +2620,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpabuf_free(wps_ie);
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
- params.wps = WPS_MODE_PRIVACY;
+ params->wps = WPS_MODE_PRIVACY;
else
- params.wps = WPS_MODE_OPEN;
+ params->wps = WPS_MODE_OPEN;
wpa_s->wpa_proto = 0;
#endif /* CONFIG_WPS */
} else {
@@ -2105,13 +2631,69 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_s->wpa_proto = 0;
}
+#ifdef IEEE8021X_EAPOL
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ if (ssid->leap) {
+ if (ssid->non_leap == 0)
+ algs = WPA_AUTH_ALG_LEAP;
+ else
+ algs |= WPA_AUTH_ALG_LEAP;
+ }
+ }
+
+#ifdef CONFIG_FILS
+ /* Clear FILS association */
+ wpa_sm_set_reset_fils_completed(wpa_s->wpa, 0);
+
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
+ ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
+ eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
+ &username_len, &realm, &realm_len,
+ &next_seq_num, &rrk, &rrk_len) == 0 &&
+ (!wpa_s->last_con_fail_realm ||
+ wpa_s->last_con_fail_realm_len != realm_len ||
+ os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) {
+ algs = WPA_AUTH_ALG_FILS;
+ params->fils_erp_username = username;
+ params->fils_erp_username_len = username_len;
+ params->fils_erp_realm = realm;
+ params->fils_erp_realm_len = realm_len;
+ params->fils_erp_next_seq_num = next_seq_num;
+ params->fils_erp_rrk = rrk;
+ params->fils_erp_rrk_len = rrk_len;
+
+ if (mask)
+ *mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
+ }
+#endif /* CONFIG_FILS */
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_SAE
+ if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
+ algs = WPA_AUTH_ALG_SAE;
+#endif /* CONFIG_SAE */
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
+ if (ssid->auth_alg) {
+ algs = ssid->auth_alg;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Overriding auth_alg selection: 0x%x", algs);
+ }
+
+#ifdef CONFIG_SAE
+ if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
+ algs = WPA_AUTH_ALG_OPEN;
+ }
+#endif /* CONFIG_SAE */
+
#ifdef CONFIG_P2P
if (wpa_s->global->p2p) {
u8 *pos;
size_t len;
int res;
pos = wpa_ie + wpa_ie_len;
- len = sizeof(wpa_ie) - wpa_ie_len;
+ len = max_wpa_ie_len - wpa_ie_len;
res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
ssid->p2p_group);
if (res >= 0)
@@ -2136,25 +2718,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
#endif /* CONFIG_P2P */
-#ifdef CONFIG_HS20
- if (is_hs20_network(wpa_s, ssid, bss)) {
- struct wpabuf *hs20;
- hs20 = wpabuf_alloc(20);
- if (hs20) {
- int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
- size_t len;
-
- wpas_hs20_add_indication(hs20, pps_mo_id);
- len = sizeof(wpa_ie) - wpa_ie_len;
- if (wpabuf_len(hs20) <= len) {
- os_memcpy(wpa_ie + wpa_ie_len,
- wpabuf_head(hs20), wpabuf_len(hs20));
- wpa_ie_len += wpabuf_len(hs20);
- }
- wpabuf_free(hs20);
- }
+ if (bss) {
+ wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
+ wpa_ie + wpa_ie_len,
+ max_wpa_ie_len -
+ wpa_ie_len);
}
-#endif /* CONFIG_HS20 */
/*
* Workaround: Add Extended Capabilities element only if the AP
@@ -2164,12 +2733,18 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
* element in all cases, it is justifiable to skip it to avoid
* interoperability issues.
*/
+ if (ssid->p2p_group)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
u8 ext_capab[18];
int ext_capab_len;
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
sizeof(ext_capab));
- if (ext_capab_len > 0) {
+ if (ext_capab_len > 0 &&
+ wpa_ie_len + ext_capab_len <= max_wpa_ie_len) {
u8 *pos = wpa_ie;
if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
pos += 2 + pos[1];
@@ -2180,11 +2755,36 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
}
+#ifdef CONFIG_HS20
+ if (is_hs20_network(wpa_s, ssid, bss)) {
+ struct wpabuf *hs20;
+
+ hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
+ if (hs20) {
+ int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
+ size_t len;
+
+ wpas_hs20_add_indication(hs20, pps_mo_id,
+ get_hs20_version(bss));
+ wpas_hs20_add_roam_cons_sel(hs20, ssid);
+ len = max_wpa_ie_len - wpa_ie_len;
+ if (wpabuf_len(hs20) <= len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(hs20), wpabuf_len(hs20));
+ wpa_ie_len += wpabuf_len(hs20);
+ }
+ wpabuf_free(hs20);
+
+ hs20_configure_frame_filters(wpa_s);
+ }
+ }
+#endif /* CONFIG_HS20 */
+
if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
size_t len;
- len = sizeof(wpa_ie) - wpa_ie_len;
+ len = max_wpa_ie_len - wpa_ie_len;
if (wpabuf_len(buf) <= len) {
os_memcpy(wpa_ie + wpa_ie_len,
wpabuf_head(buf), wpabuf_len(buf));
@@ -2196,7 +2796,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
if (wpa_s->fst_ies) {
int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
- if (wpa_ie_len + fst_ies_len <= sizeof(wpa_ie)) {
+ if (wpa_ie_len + fst_ies_len <= max_wpa_ie_len) {
os_memcpy(wpa_ie + wpa_ie_len,
wpabuf_head(wpa_s->fst_ies), fst_ies_len);
wpa_ie_len += fst_ies_len;
@@ -2204,10 +2804,315 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
#endif /* CONFIG_FST */
+#ifdef CONFIG_MBO
+ mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
+ if (mbo_ie) {
+ int len;
+
+ len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
+ max_wpa_ie_len - wpa_ie_len,
+ !!mbo_attr_from_mbo_ie(mbo_ie,
+ OCE_ATTR_ID_CAPA_IND));
+ if (len >= 0)
+ wpa_ie_len += len;
+ }
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_FILS
+ if (algs == WPA_AUTH_ALG_FILS) {
+ size_t len;
+
+ len = wpas_add_fils_hlp_req(wpa_s, wpa_ie + wpa_ie_len,
+ max_wpa_ie_len - wpa_ie_len);
+ wpa_ie_len += len;
+ }
+#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_OWE
+#ifdef CONFIG_TESTING_OPTIONS
+ if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) {
+ wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (algs == WPA_AUTH_ALG_OPEN &&
+ ssid->key_mgmt == WPA_KEY_MGMT_OWE) {
+ struct wpabuf *owe_ie;
+ u16 group;
+
+ if (ssid->owe_group) {
+ group = ssid->owe_group;
+ } else if (wpa_s->assoc_status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ if (wpa_s->last_owe_group == 19)
+ group = 20;
+ else if (wpa_s->last_owe_group == 20)
+ group = 21;
+ else
+ group = OWE_DH_GROUP;
+ } else {
+ group = OWE_DH_GROUP;
+ }
+
+ wpa_s->last_owe_group = group;
+ wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
+ owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
+ if (owe_ie &&
+ wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(owe_ie), wpabuf_len(owe_ie));
+ wpa_ie_len += wpabuf_len(owe_ie);
+ }
+ wpabuf_free(owe_ie);
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
+ ssid->dpp_netaccesskey) {
+ dpp_pfs_free(wpa_s->dpp_pfs);
+ wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len);
+ if (!wpa_s->dpp_pfs) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
+ /* Try to continue without PFS */
+ goto pfs_fail;
+ }
+ if (wpabuf_len(wpa_s->dpp_pfs->ie) <=
+ max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(wpa_s->dpp_pfs->ie),
+ wpabuf_len(wpa_s->dpp_pfs->ie));
+ wpa_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
+ }
+ }
+pfs_fail:
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_IEEE80211R
+ /*
+ * Add MDIE under these conditions: the network profile allows FT,
+ * the AP supports FT, and the mobility domain ID matches.
+ */
+ if (bss && wpa_key_mgmt_ft(wpa_sm_get_key_mgmt(wpa_s->wpa))) {
+ const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+
+ if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
+ size_t len = 0;
+ const u8 *md = mdie + 2;
+ const u8 *wpa_md = wpa_sm_get_ft_md(wpa_s->wpa);
+
+ if (os_memcmp(md, wpa_md,
+ MOBILITY_DOMAIN_ID_LEN) == 0) {
+ /* Add mobility domain IE */
+ len = wpa_ft_add_mdie(
+ wpa_s->wpa, wpa_ie + wpa_ie_len,
+ max_wpa_ie_len - wpa_ie_len, mdie);
+ wpa_ie_len += len;
+ }
+#ifdef CONFIG_SME
+ if (len > 0 && wpa_s->sme.ft_used &&
+ wpa_sm_has_ptk(wpa_s->wpa)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Trying to use FT over-the-air");
+ algs |= WPA_AUTH_ALG_FT;
+ }
+#endif /* CONFIG_SME */
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ if (ssid->multi_ap_backhaul_sta) {
+ size_t multi_ap_ie_len;
+
+ multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
+ max_wpa_ie_len - wpa_ie_len,
+ MULTI_AP_BACKHAUL_STA);
+ if (multi_ap_ie_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "Multi-AP: Failed to build Multi-AP IE");
+ os_free(wpa_ie);
+ return NULL;
+ }
+ wpa_ie_len += multi_ap_ie_len;
+ }
+
+ params->wpa_ie = wpa_ie;
+ params->wpa_ie_len = wpa_ie_len;
+ params->auth_alg = algs;
+ if (mask)
+ *mask |= WPA_DRV_UPDATE_ASSOC_IES | WPA_DRV_UPDATE_AUTH_TYPE;
+
+ return wpa_ie;
+}
+
+
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_associate_params params;
+ enum wpa_drv_update_connect_params_mask mask = 0;
+ u8 *wpa_ie;
+
+ if (wpa_s->auth_alg != WPA_AUTH_ALG_OPEN)
+ return; /* nothing to do */
+
+ os_memset(&params, 0, sizeof(params));
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, &params, &mask);
+ if (!wpa_ie)
+ return;
+
+ if (params.auth_alg != WPA_AUTH_ALG_FILS) {
+ os_free(wpa_ie);
+ return;
+ }
+
+ wpa_s->auth_alg = params.auth_alg;
+ wpa_drv_update_connect_params(wpa_s, &params, mask);
+ os_free(wpa_ie);
+}
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+
+
+#ifdef CONFIG_MBO
+void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_associate_params params;
+ u8 *wpa_ie;
+
+ /*
+ * Update MBO connect params only in case of change of MBO attributes
+ * when connected, if the AP support MBO.
+ */
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid ||
+ !wpa_s->current_bss ||
+ !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
+ return;
+
+ os_memset(&params, 0, sizeof(params));
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, &params, NULL);
+ if (!wpa_ie)
+ return;
+
+ wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
+ os_free(wpa_ie);
+}
+#endif /* CONFIG_MBO */
+
+
+static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_connect_work *cwork = work->ctx;
+ struct wpa_bss *bss = cwork->bss;
+ struct wpa_ssid *ssid = cwork->ssid;
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ u8 *wpa_ie;
+ int use_crypt, ret, i, bssid_changed;
+ unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
+ struct wpa_driver_associate_params params;
+ int wep_keys_set = 0;
+ int assoc_failed = 0;
+ struct wpa_ssid *old_ssid;
+ u8 prev_bssid[ETH_ALEN];
+#ifdef CONFIG_HT_OVERRIDES
+ struct ieee80211_ht_capabilities htcaps;
+ struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ struct ieee80211_vht_capabilities vhtcaps;
+ struct ieee80211_vht_capabilities vhtcaps_mask;
+#endif /* CONFIG_VHT_OVERRIDES */
+
+ if (deinit) {
+ if (work->started) {
+ wpa_s->connect_work = NULL;
+
+ /* cancel possible auth. timeout */
+ eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
+ NULL);
+ }
+ wpas_connect_work_free(cwork);
+ return;
+ }
+
+ wpa_s->connect_work = work;
+
+ if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
+ wpas_network_disabled(wpa_s, ssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+
+ os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
+ os_memset(&params, 0, sizeof(params));
+ wpa_s->reassociate = 0;
+ wpa_s->eap_expected_failure = 0;
+ if (bss &&
+ (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
+#ifdef CONFIG_IEEE80211R
+ const u8 *ie, *md = NULL;
+#endif /* CONFIG_IEEE80211R */
+ wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
+ " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
+ bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+ os_memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+ if (bssid_changed)
+ wpas_notify_bssid_changed(wpa_s);
+#ifdef CONFIG_IEEE80211R
+ ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+ if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
+ md = ie + 2;
+ wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
+ if (md) {
+ /* Prepare for the next transition */
+ wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+ } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
+ wpa_s->conf->ap_scan == 2 &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+ /* Use ap_scan==1 style network selection to find the network
+ */
+ wpas_connect_work_done(wpa_s);
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ return;
+#endif /* CONFIG_WPS */
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ if (bss)
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+ else
+ os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+ }
+ if (!wpa_s->pno)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
+ wpa_supplicant_cancel_scan(wpa_s);
+
+ /* Starting new association, so clear the possibly used WPA IE from the
+ * previous association. */
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
+ if (!wpa_ie) {
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
cipher_pairwise = wpa_s->pairwise_cipher;
cipher_group = wpa_s->group_cipher;
+ cipher_group_mgmt = wpa_s->mgmt_group_cipher;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
@@ -2245,20 +3150,27 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
if (bss) {
params.ssid = bss->ssid;
params.ssid_len = bss->ssid_len;
- if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+ if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
MACSTR " freq=%u MHz based on scan results "
- "(bssid_set=%d)",
+ "(bssid_set=%d wps=%d)",
MAC2STR(bss->bssid), bss->freq,
- ssid->bssid_set);
+ ssid->bssid_set,
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
params.bssid = bss->bssid;
params.freq.freq = bss->freq;
}
params.bssid_hint = bss->bssid;
params.freq_hint = bss->freq;
+ params.pbss = bss_is_pbss(bss);
} else {
+ if (ssid->bssid_hint_set)
+ params.bssid_hint = ssid->bssid_hint;
+
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
+ params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
}
if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
@@ -2280,13 +3192,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.beacon_int = wpa_s->conf->beacon_int;
}
- params.wpa_ie = wpa_ie;
- params.wpa_ie_len = wpa_ie_len;
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
+ params.mgmt_group_suite = cipher_group_mgmt;
params.key_mgmt_suite = wpa_s->key_mgmt;
params.wpa_proto = wpa_s->wpa_proto;
- params.auth_alg = algs;
+ wpa_s->auth_alg = params.auth_alg;
params.mode = ssid->mode;
params.bg_scan_period = ssid->bg_scan_period;
for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -2296,7 +3207,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
params.wep_tx_keyidx = ssid->wep_tx_keyidx;
- if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
(params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
params.passphrase = ssid->passphrase;
@@ -2304,6 +3215,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.psk = ssid->psk;
}
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
+ (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
+ params.req_key_mgmt_offload = 1;
+
if (wpa_s->conf->key_mgmt_offload) {
if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
@@ -2336,14 +3254,19 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
"MFP: require MFP");
params.mgmt_frame_protection =
MGMT_FRAME_PROTECTION_REQUIRED;
+#ifdef CONFIG_OWE
+ } else if (!rsn && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !ssid->owe_only) {
+ params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_OWE */
}
}
#endif /* CONFIG_IEEE80211W */
params.p2p = ssid->p2p_group;
- if (wpa_s->parent->set_sta_uapsd)
- params.uapsd = wpa_s->parent->sta_uapsd;
+ if (wpa_s->p2pdev->set_sta_uapsd)
+ params.uapsd = wpa_s->p2pdev->sta_uapsd;
else
params.uapsd = -1;
@@ -2378,13 +3301,19 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
if (wpas_p2p_handle_frequency_conflicts(
wpa_s, params.freq.freq, ssid) < 0) {
wpas_connect_work_done(wpa_s);
+ os_free(wpa_ie);
return;
}
}
}
#endif /* CONFIG_P2P */
+ if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
+ wpa_s->current_ssid)
+ params.prev_bssid = prev_bssid;
+
ret = wpa_drv_associate(wpa_s, &params);
+ os_free(wpa_ie);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
"failed");
@@ -2451,8 +3380,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
- if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set)
+
+ if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
wpa_s->current_bss = bss;
+#ifdef CONFIG_HS20
+ hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+ }
+
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
if (old_ssid != wpa_s->current_ssid)
@@ -2497,12 +3432,12 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
- if (!is_zero_ether_addr(wpa_s->bssid))
- addr = wpa_s->bssid;
- else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
- (wpa_s->wpa_state == WPA_AUTHENTICATING ||
- wpa_s->wpa_state == WPA_ASSOCIATING))
+ if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+ wpa_s->wpa_state == WPA_ASSOCIATING))
addr = wpa_s->pending_bssid;
+ else if (!is_zero_ether_addr(wpa_s->bssid))
+ addr = wpa_s->bssid;
else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
/*
* When using driver-based BSS selection, we may not know the
@@ -2514,14 +3449,22 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
zero_addr = 1;
}
+ if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+ wpa_s->enabled_4addr_mode = 0;
+
#ifdef CONFIG_TDLS
wpa_tdls_teardown_peers(wpa_s->wpa);
#endif /* CONFIG_TDLS */
#ifdef CONFIG_MESH
if (wpa_s->ifmsh) {
- wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
- wpa_s->ifname);
+ struct mesh_conf *mconf;
+
+ mconf = wpa_s->ifmsh->mconf;
+ wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
+ wpa_s->ifname);
+ wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
+ mconf->meshid_len, reason_code);
wpa_supplicant_leave_mesh(wpa_s);
}
#endif /* CONFIG_MESH */
@@ -2546,6 +3489,7 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
return;
ssid->disabled = 0;
+ ssid->owe_transition_bss_select_count = 0;
wpas_clear_temp_disabled(wpa_s, ssid, 1);
wpas_notify_network_enabled_changed(wpa_s, ssid);
@@ -2559,6 +3503,95 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
/**
+ * wpa_supplicant_add_network - Add a new network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: The new network configuration or %NULL if operation failed
+ *
+ * This function performs the following operations:
+ * 1. Adds a new network.
+ * 2. Send network addition notification.
+ * 3. Marks the network disabled.
+ * 4. Set network default parameters.
+ */
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (!ssid)
+ return NULL;
+ wpas_notify_network_added(wpa_s, ssid);
+ ssid->disabled = 1;
+ wpa_config_set_network_defaults(ssid);
+
+ return ssid;
+}
+
+
+/**
+ * wpa_supplicant_remove_network - Remove a configured network based on id
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found, -2 if the network
+ * could not be removed
+ *
+ * This function performs the following operations:
+ * 1. Removes the network.
+ * 2. Send network removal notification.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
+{
+ struct wpa_ssid *ssid;
+ int was_disabled;
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (!ssid)
+ return -1;
+ wpas_notify_network_removed(wpa_s, ssid);
+
+ if (wpa_s->last_ssid == ssid)
+ wpa_s->last_ssid = NULL;
+
+ if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ /*
+ * Invalidate the EAP session cache if the current or
+ * previously used network is removed.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
+
+ if (ssid == wpa_s->current_ssid) {
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+
+ was_disabled = ssid->disabled;
+
+ if (wpa_config_remove_network(wpa_s->conf, id) < 0)
+ return -2;
+
+ if (!was_disabled && wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG,
+ "Stop ongoing sched_scan to remove network from filters");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
* @wpa_s: wpa_supplicant structure for a network interface
* @ssid: wpa_ssid structure for a configured network or %NULL
@@ -2622,13 +3655,19 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
wpas_notify_network_enabled_changed(
wpa_s, other_ssid);
}
- if (wpa_s->current_ssid)
+ if (wpa_s->current_ssid) {
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
} else if (ssid->disabled != 2) {
- if (ssid == wpa_s->current_ssid)
+ if (ssid == wpa_s->current_ssid) {
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
was_disabled = ssid->disabled;
@@ -2688,7 +3727,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
wpas_notify_network_enabled_changed(wpa_s, other_ssid);
}
- if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+ if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid &&
+ wpa_s->wpa_state >= WPA_AUTHENTICATING) {
/* We are already associated with the selected network */
wpa_printf(MSG_DEBUG, "Already associated with the "
"selected network - do nothing");
@@ -2713,10 +3753,14 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s->last_owe_group = 0;
+ if (ssid)
+ ssid->owe_transition_bss_select_count = 0;
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
wpa_s->scan_req = NORMAL_SCAN_REQ;
+ wpas_scan_reset_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
}
@@ -2929,6 +3973,41 @@ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
}
+#ifdef CONFIG_OWE
+static int owe_trans_ssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *entry_ssid, size_t entry_ssid_len)
+{
+ const u8 *owe, *pos, *end;
+ u8 ssid_len;
+ struct wpa_bss *bss;
+
+ /* Check network profile SSID aganst the SSID in the
+ * OWE Transition Mode element. */
+
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (!bss)
+ return 0;
+
+ owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+ if (!owe)
+ return 0;
+
+ pos = owe + 6;
+ end = owe + 2 + owe[1];
+
+ if (end - pos < ETH_ALEN + 1)
+ return 0;
+ pos += ETH_ALEN;
+ ssid_len = *pos++;
+ if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
+ return 0;
+
+ return entry_ssid_len == ssid_len &&
+ os_memcmp(pos, entry_ssid, ssid_len) == 0;
+}
+#endif /* CONFIG_OWE */
+
+
/**
* wpa_supplicant_get_ssid - Get a pointer to the current network structure
* @wpa_s: Pointer to wpa_supplicant data
@@ -2964,7 +4043,9 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
while (entry) {
if (!wpas_network_disabled(wpa_s, entry) &&
((ssid_len == entry->ssid_len &&
- os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
+ (!entry->ssid ||
+ os_memcmp(ssid, entry->ssid, ssid_len) == 0)) ||
+ wired) &&
(!entry->bssid_set ||
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
return entry;
@@ -2977,6 +4058,15 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
return entry;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_OWE
+ if (!wpas_network_disabled(wpa_s, entry) &&
+ owe_trans_ssid_match(wpa_s, bssid, entry->ssid,
+ entry->ssid_len) &&
+ (!entry->bssid_set ||
+ os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+ return entry;
+#endif /* CONFIG_OWE */
+
if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
entry->ssid_len == 0 &&
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
@@ -2994,7 +4084,7 @@ static int select_driver(struct wpa_supplicant *wpa_s, int i)
struct wpa_global *global = wpa_s->global;
if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
- global->drv_priv[i] = wpa_drivers[i]->global_init();
+ global->drv_priv[i] = wpa_drivers[i]->global_init(global);
if (global->drv_priv[i] == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize driver "
"'%s'", wpa_drivers[i]->name);
@@ -3077,15 +4167,12 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
-#ifdef CONFIG_PEERKEY
- if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
- wpa_s->current_ssid->peerkey &&
- !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
- wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
return;
}
-#endif /* CONFIG_PEERKEY */
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->wpa_state < WPA_ASSOCIATED ||
(wpa_s->last_eapol_matches_bssid &&
@@ -3136,7 +4223,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
}
if (wpa_s->eapol_received == 0 &&
- (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
+ (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) ||
!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->wpa_state != WPA_COMPLETED) &&
(wpa_s->current_ssid == NULL ||
@@ -3197,10 +4284,12 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
+ wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
+ wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
return;
wpa_drv_poll(wpa_s);
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
@@ -3226,6 +4315,11 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
wpa_supplicant_rx_eapol, wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
+
+ if (l2_packet_set_packet_filter(wpa_s->l2,
+ L2_PACKET_FILTER_PKTTYPE))
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Failed to attach pkt_type filter");
} else {
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
@@ -3361,8 +4455,12 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
wpa_s->scan_interval = 5;
wpa_s->new_connection = 1;
wpa_s->parent = parent ? parent : wpa_s;
+ wpa_s->p2pdev = wpa_s->parent;
wpa_s->sched_scanning = 0;
+ dl_list_init(&wpa_s->bss_tmp_disallowed);
+ dl_list_init(&wpa_s->fils_hlp_req);
+
return wpa_s;
}
@@ -3389,8 +4487,11 @@ static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ long v;
+
errno = 0;
- long v = strtol(tmp, &end, 16);
+ v = strtol(tmp, &end, 16);
+
if (errno == 0) {
wpa_msg(wpa_s, MSG_DEBUG,
"htcap value[%i]: %ld end: %p tmp: %p",
@@ -3430,11 +4531,11 @@ static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
{
le16 msk;
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
-
if (disabled == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
htcaps_mask->ht_capabilities_info |= msk;
if (disabled)
@@ -3451,11 +4552,11 @@ static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
struct ieee80211_ht_capabilities *htcaps_mask,
int factor)
{
- wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
-
if (factor == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
if (factor < 0 || factor > 3) {
wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
"Must be 0-3 or -1", factor);
@@ -3475,11 +4576,11 @@ static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
struct ieee80211_ht_capabilities *htcaps_mask,
int density)
{
- wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
-
if (density == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
if (density < 0 || density > 7) {
wpa_msg(wpa_s, MSG_ERROR,
"ampdu_density: %d out of range. Must be 0-7 or -1.",
@@ -3500,18 +4601,11 @@ static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
struct ieee80211_ht_capabilities *htcaps_mask,
int disabled)
{
- /* Masking these out disables HT40 */
- le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
- HT_CAP_INFO_SHORT_GI40MHZ);
-
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
-
if (disabled)
- htcaps->ht_capabilities_info &= ~msk;
- else
- htcaps->ht_capabilities_info |= msk;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
- htcaps_mask->ht_capabilities_info |= msk;
+ set_disable_ht40(htcaps, disabled);
+ set_disable_ht40(htcaps_mask, 0);
return 0;
}
@@ -3526,7 +4620,8 @@ static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
HT_CAP_INFO_SHORT_GI40MHZ);
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
+ if (disabled)
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
if (disabled)
htcaps->ht_capabilities_info &= ~msk;
@@ -3547,7 +4642,8 @@ static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
/* Masking these out disables LDPC */
le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
+ if (disabled)
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
if (disabled)
htcaps->ht_capabilities_info &= ~msk;
@@ -3560,6 +4656,58 @@ static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
}
+static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int tx_stbc)
+{
+ le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC);
+
+ if (tx_stbc == -1)
+ return 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
+
+ if (tx_stbc < 0 || tx_stbc > 1) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc);
+ return -EINVAL;
+ }
+
+ htcaps_mask->ht_capabilities_info |= msk;
+ htcaps->ht_capabilities_info &= ~msk;
+ htcaps->ht_capabilities_info |= (tx_stbc << 7) & msk;
+
+ return 0;
+}
+
+
+static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int rx_stbc)
+{
+ le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK);
+
+ if (rx_stbc == -1)
+ return 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
+
+ if (rx_stbc < 0 || rx_stbc > 3) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc);
+ return -EINVAL;
+ }
+
+ htcaps_mask->ht_capabilities_info |= msk;
+ htcaps->ht_capabilities_info &= ~msk;
+ htcaps->ht_capabilities_info |= (rx_stbc << 8) & msk;
+
+ return 0;
+}
+
+
void wpa_supplicant_apply_ht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params)
@@ -3584,6 +4732,8 @@ void wpa_supplicant_apply_ht_overrides(
wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
+ wpa_set_rx_stbc(wpa_s, htcaps, htcaps_mask, ssid->rx_stbc);
+ wpa_set_tx_stbc(wpa_s, htcaps, htcaps_mask, ssid->tx_stbc);
if (ssid->ht40_intolerant) {
le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
@@ -3614,10 +4764,20 @@ void wpa_supplicant_apply_vht_overrides(
if (!vhtcaps || !vhtcaps_mask)
return;
- vhtcaps->vht_capabilities_info = ssid->vht_capa;
- vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+ vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
+ vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_sgi) {
+ vhtcaps_mask->vht_capabilities_info |= (VHT_CAP_SHORT_GI_80 |
+ VHT_CAP_SHORT_GI_160);
+ vhtcaps->vht_capabilities_info &= ~(VHT_CAP_SHORT_GI_80 |
+ VHT_CAP_SHORT_GI_160);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "disable-sgi override specified, vht-caps: 0x%x",
+ vhtcaps->vht_capabilities_info);
+ }
+
/* if max ampdu is <= 3, we have to make the HT cap the same */
if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
int max_ampdu;
@@ -3637,15 +4797,17 @@ void wpa_supplicant_apply_vht_overrides(
#define OVERRIDE_MCS(i) \
if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
- 3 << 2 * (i - 1); \
+ host_to_le16(3 << 2 * (i - 1)); \
vhtcaps->vht_supported_mcs_set.tx_map |= \
- ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1); \
+ host_to_le16(ssid->vht_tx_mcs_nss_ ##i << \
+ 2 * (i - 1)); \
} \
if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \
vhtcaps_mask->vht_supported_mcs_set.rx_map |= \
- 3 << 2 * (i - 1); \
+ host_to_le16(3 << 2 * (i - 1)); \
vhtcaps->vht_supported_mcs_set.rx_map |= \
- ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \
+ host_to_le16(ssid->vht_rx_mcs_nss_ ##i << \
+ 2 * (i - 1)); \
}
OVERRIDE_MCS(1);
@@ -3785,10 +4947,14 @@ static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data)
{
struct wpa_supplicant *wpa_s = ctx;
- WPA_ASSERT(os_memcmp(wpa_s->bssid, da, ETH_ALEN) == 0);
+ if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) {
+ wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
+ __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
+ return -1;
+ }
return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
- wpa_s->own_addr, wpa_s->bssid,
- wpabuf_head(data), wpabuf_len(data),
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(data), wpabuf_len(data),
0);
}
@@ -3817,8 +4983,9 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
}
-const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+static const u8 * wpas_fst_get_peer_first(void *ctx,
+ struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -3830,8 +4997,9 @@ const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
}
-const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+static const u8 * wpas_fst_get_peer_next(void *ctx,
+ struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
{
return NULL;
}
@@ -3870,6 +5038,55 @@ static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
}
+enum wpa_radio_work_band wpas_freq_to_band(int freq)
+{
+ if (freq < 3000)
+ return BAND_2_4_GHZ;
+ if (freq > 50000)
+ return BAND_60_GHZ;
+ return BAND_5_GHZ;
+}
+
+
+unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs)
+{
+ int i;
+ unsigned int band = 0;
+
+ if (freqs) {
+ /* freqs are specified for the radio work */
+ for (i = 0; freqs[i]; i++)
+ band |= wpas_freq_to_band(freqs[i]);
+ } else {
+ /*
+ * freqs are not specified, implies all
+ * the supported freqs by HW
+ */
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].num_channels != 0) {
+ if (wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211B ||
+ wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211G)
+ band |= BAND_2_4_GHZ;
+ else if (wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211A)
+ band |= BAND_5_GHZ;
+ else if (wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211AD)
+ band |= BAND_60_GHZ;
+ else if (wpa_s->hw.modes[i].mode ==
+ HOSTAPD_MODE_IEEE80211ANY)
+ band = BAND_2_4_GHZ | BAND_5_GHZ |
+ BAND_60_GHZ;
+ }
+ }
+ }
+
+ return band;
+}
+
+
static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
const char *rn)
{
@@ -3922,11 +5139,126 @@ static void radio_work_free(struct wpa_radio_work *work)
}
#endif /* CONFIG_P2P */
+ if (work->started) {
+ work->wpa_s->radio->num_active_works--;
+ wpa_dbg(work->wpa_s, MSG_DEBUG,
+ "radio_work_free('%s'@%p): num_active_works --> %u",
+ work->type, work,
+ work->wpa_s->radio->num_active_works);
+ }
+
dl_list_del(&work->list);
os_free(work);
}
+static int radio_work_is_connect(struct wpa_radio_work *work)
+{
+ return os_strcmp(work->type, "sme-connect") == 0 ||
+ os_strcmp(work->type, "connect") == 0;
+}
+
+
+static int radio_work_is_scan(struct wpa_radio_work *work)
+{
+ return os_strcmp(work->type, "scan") == 0 ||
+ os_strcmp(work->type, "p2p-scan") == 0;
+}
+
+
+static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
+{
+ struct wpa_radio_work *active_work = NULL;
+ struct wpa_radio_work *tmp;
+
+ /* Get the active work to know the type and band. */
+ dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
+ if (tmp->started) {
+ active_work = tmp;
+ break;
+ }
+ }
+
+ if (!active_work) {
+ /* No active work, start one */
+ radio->num_active_works = 0;
+ dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
+ list) {
+ if (os_strcmp(tmp->type, "scan") == 0 &&
+ radio->external_scan_running &&
+ (((struct wpa_driver_scan_params *)
+ tmp->ctx)->only_new_results ||
+ tmp->wpa_s->clear_driver_scan_cache))
+ continue;
+ return tmp;
+ }
+ return NULL;
+ }
+
+ if (radio_work_is_connect(active_work)) {
+ /*
+ * If the active work is either connect or sme-connect,
+ * do not parallelize them with other radio works.
+ */
+ wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+ "Do not parallelize radio work with %s",
+ active_work->type);
+ return NULL;
+ }
+
+ dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
+ if (tmp->started)
+ continue;
+
+ /*
+ * If connect or sme-connect are enqueued, parallelize only
+ * those operations ahead of them in the queue.
+ */
+ if (radio_work_is_connect(tmp))
+ break;
+
+ /* Serialize parallel scan and p2p_scan operations on the same
+ * interface since the driver_nl80211 mechanism for tracking
+ * scan cookies does not yet have support for this. */
+ if (active_work->wpa_s == tmp->wpa_s &&
+ radio_work_is_scan(active_work) &&
+ radio_work_is_scan(tmp)) {
+ wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+ "Do not start work '%s' when another work '%s' is already scheduled",
+ tmp->type, active_work->type);
+ continue;
+ }
+ /*
+ * Check that the radio works are distinct and
+ * on different bands.
+ */
+ if (os_strcmp(active_work->type, tmp->type) != 0 &&
+ (active_work->bands != tmp->bands)) {
+ /*
+ * If a scan has to be scheduled through nl80211 scan
+ * interface and if an external scan is already running,
+ * do not schedule the scan since it is likely to get
+ * rejected by kernel.
+ */
+ if (os_strcmp(tmp->type, "scan") == 0 &&
+ radio->external_scan_running &&
+ (((struct wpa_driver_scan_params *)
+ tmp->ctx)->only_new_results ||
+ tmp->wpa_s->clear_driver_scan_cache))
+ continue;
+
+ wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+ "active_work:%s new_work:%s",
+ active_work->type, tmp->type);
+ return tmp;
+ }
+ }
+
+ /* Did not find a radio work to schedule in parallel. */
+ return NULL;
+}
+
+
static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_radio *radio = eloop_ctx;
@@ -3935,26 +5267,48 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
struct wpa_supplicant *wpa_s;
work = dl_list_first(&radio->work, struct wpa_radio_work, list);
- if (work == NULL)
+ if (work == NULL) {
+ radio->num_active_works = 0;
return;
-
- if (work->started)
- return; /* already started and still in progress */
+ }
wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
radio_list);
- if (wpa_s && wpa_s->radio->external_scan_running) {
- wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
- return;
+
+ if (!(wpa_s &&
+ wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) {
+ if (work->started)
+ return; /* already started and still in progress */
+
+ if (wpa_s && wpa_s->radio->external_scan_running) {
+ wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
+ return;
+ }
+ } else {
+ work = NULL;
+ if (radio->num_active_works < MAX_ACTIVE_WORKS) {
+ /* get the work to schedule next */
+ work = radio_work_get_next_work(radio);
+ }
+ if (!work)
+ return;
}
+ wpa_s = work->wpa_s;
os_get_reltime(&now);
os_reltime_sub(&now, &work->time, &diff);
- wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait",
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Starting radio work '%s'@%p after %ld.%06ld second wait",
work->type, work, diff.sec, diff.usec);
work->started = 1;
work->time = now;
+ radio->num_active_works++;
+
work->cb(work, 0);
+
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) &&
+ radio->num_active_works < MAX_ACTIVE_WORKS)
+ radio_work_check_next(wpa_s);
}
@@ -3995,6 +5349,22 @@ void radio_remove_works(struct wpa_supplicant *wpa_s,
}
+void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx)
+{
+ struct wpa_radio_work *work;
+ struct wpa_radio *radio = wpa_s->radio;
+
+ dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
+ if (work->ctx != ctx)
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s",
+ work->type, work, work->started ? " (started)" : "");
+ radio_work_free(work);
+ break;
+ }
+}
+
+
static void radio_remove_interface(struct wpa_supplicant *wpa_s)
{
struct wpa_radio *radio = wpa_s->radio;
@@ -4062,6 +5432,7 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
void (*cb)(struct wpa_radio_work *work, int deinit),
void *ctx)
{
+ struct wpa_radio *radio = wpa_s->radio;
struct wpa_radio_work *work;
int was_empty;
@@ -4076,6 +5447,16 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
work->cb = cb;
work->ctx = ctx;
+ if (freq)
+ work->bands = wpas_freq_to_band(freq);
+ else if (os_strcmp(type, "scan") == 0 ||
+ os_strcmp(type, "p2p-scan") == 0)
+ work->bands = wpas_get_bands(wpa_s,
+ ((struct wpa_driver_scan_params *)
+ ctx)->freqs);
+ else
+ work->bands = wpas_get_bands(wpa_s, NULL);
+
was_empty = dl_list_empty(&wpa_s->radio->work);
if (next)
dl_list_add(&wpa_s->radio->work, &work->list);
@@ -4084,6 +5465,12 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
if (was_empty) {
wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
radio_work_check_next(wpa_s);
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)
+ && radio->num_active_works < MAX_ACTIVE_WORKS) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Try to schedule a radio work (num_active_works=%u)",
+ radio->num_active_works);
+ radio_work_check_next(wpa_s);
}
return 0;
@@ -4130,7 +5517,7 @@ radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
static int wpas_init_driver(struct wpa_supplicant *wpa_s,
- struct wpa_interface *iface)
+ const struct wpa_interface *iface)
{
const char *ifname, *driver, *rn;
@@ -4178,11 +5565,47 @@ next_driver:
}
+#ifdef CONFIG_GAS_SERVER
+
+static void wpas_gas_server_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+ " result=%s",
+ freq, MAC2STR(dst),
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED"));
+ gas_server_tx_status(wpa_s->gas_server, dst, data, data_len,
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS);
+}
+
+
+static void wpas_gas_server_tx(void *ctx, int freq, const u8 *da,
+ struct wpabuf *buf, unsigned int wait_time)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ if (wait_time > wpa_s->max_remain_on_chan)
+ wait_time = wpa_s->max_remain_on_chan;
+
+ offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, broadcast,
+ wpabuf_head(buf), wpabuf_len(buf),
+ wait_time, wpas_gas_server_tx_status, 0);
+}
+
+#endif /* CONFIG_GAS_SERVER */
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
- struct wpa_interface *iface)
+ const struct wpa_interface *iface)
{
struct wpa_driver_capa capa;
int capa_res;
+ u8 dfs_domain;
wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
"'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
@@ -4212,7 +5635,13 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
return -1;
}
wpa_s->confanother = os_rel2abs_path(iface->confanother);
- wpa_config_read(wpa_s->confanother, wpa_s->conf);
+ if (wpa_s->confanother &&
+ !wpa_config_read(wpa_s->confanother, wpa_s->conf)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to read or parse configuration '%s'.",
+ wpa_s->confanother);
+ return -1;
+ }
/*
* Override ctrl_interface and driver_param if set on command
@@ -4310,7 +5739,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
&wpa_s->hw.num_modes,
- &wpa_s->hw.flags);
+ &wpa_s->hw.flags,
+ &dfs_domain);
if (wpa_s->hw.modes) {
u16 i;
@@ -4339,6 +5769,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
+ wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;
+ wpa_s->max_sched_scan_plan_interval =
+ capa.max_sched_scan_plan_interval;
+ wpa_s->max_sched_scan_plan_iterations =
+ capa.max_sched_scan_plan_iterations;
wpa_s->sched_scan_supported = capa.sched_scan_supported;
wpa_s->max_match_sets = capa.max_match_sets;
wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
@@ -4356,6 +5791,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
capa.mac_addr_rand_sched_scan_supported)
wpa_s->mac_addr_rand_supported |=
(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
+
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+ if (wpa_s->extended_capa &&
+ wpa_s->extended_capa_len >= 3 &&
+ wpa_s->extended_capa[2] & 0x40)
+ wpa_s->multi_bss_support = 1;
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
@@ -4367,8 +5808,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
*/
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
wpa_s->p2p_mgmt = iface->p2p_mgmt;
- else
- iface->p2p_mgmt = 1;
if (wpa_s->num_multichan_concurrent == 0)
wpa_s->num_multichan_concurrent = 1;
@@ -4377,10 +5816,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
return -1;
#ifdef CONFIG_TDLS
- if ((!iface->p2p_mgmt ||
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
- wpa_tdls_init(wpa_s->wpa))
+ if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
return -1;
#endif /* CONFIG_TDLS */
@@ -4415,6 +5851,19 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
if (wpas_wps_init(wpa_s))
return -1;
+#ifdef CONFIG_GAS_SERVER
+ wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);
+ if (!wpa_s->gas_server) {
+ wpa_printf(MSG_ERROR, "Failed to initialize GAS server");
+ return -1;
+ }
+#endif /* CONFIG_GAS_SERVER */
+
+#ifdef CONFIG_DPP
+ if (wpas_dpp_init(wpa_s) < 0)
+ return -1;
+#endif /* CONFIG_DPP */
+
if (wpa_supplicant_init_eapol(wpa_s) < 0)
return -1;
wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
@@ -4439,7 +5888,9 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
return -1;
}
- if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+ if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||
+ wpa_s->p2p_mgmt) &&
+ wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
return -1;
}
@@ -4447,6 +5898,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
if (wpa_bss_init(wpa_s) < 0)
return -1;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+ dl_list_init(&wpa_s->mesh_external_pmksa_cache);
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
/*
* Set Wake-on-WLAN triggers, if configured.
* Note: We don't restore/remove the triggers on shutdown (it doesn't
@@ -4458,8 +5915,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_EAP_PROXY
{
size_t len;
- wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, wpa_s->imsi,
- &len);
+ wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
+ wpa_s->imsi, &len);
if (wpa_s->mnc_len > 0) {
wpa_s->imsi[len] = '\0';
wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
@@ -4478,6 +5935,28 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpas_rrm_reset(wpa_s);
+ wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
+
+#ifdef CONFIG_HS20
+ hs20_init(wpa_s);
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+ if (wpa_s->conf->oce) {
+ if ((wpa_s->conf->oce & OCE_STA) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
+ wpa_s->enable_oce = OCE_STA;
+ if ((wpa_s->conf->oce & OCE_STA_CFON) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
+ /* TODO: Need to add STA-CFON support */
+ wpa_printf(MSG_ERROR,
+ "OCE STA-CFON feature is not yet supported");
+ }
+ }
+ wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
+#endif /* CONFIG_MBO */
+
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+
return 0;
}
@@ -4493,6 +5972,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
iface = global->ifaces;
while (iface) {
+ if (iface->p2pdev == wpa_s)
+ iface->p2pdev = iface->parent;
if (iface == wpa_s || iface->parent != wpa_s) {
iface = iface->next;
continue;
@@ -4563,6 +6044,74 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_MATCH_IFACE
+
+/**
+ * wpa_supplicant_match_iface - Match an interface description to a name
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Name of the interface to match
+ * Returns: Pointer to the created interface description or %NULL on failure
+ */
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+ const char *ifname)
+{
+ int i;
+ struct wpa_interface *iface, *miface;
+
+ for (i = 0; i < global->params.match_iface_count; i++) {
+ miface = &global->params.match_ifaces[i];
+ if (!miface->ifname ||
+ fnmatch(miface->ifname, ifname, 0) == 0) {
+ iface = os_zalloc(sizeof(*iface));
+ if (!iface)
+ return NULL;
+ *iface = *miface;
+ iface->ifname = ifname;
+ return iface;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * wpa_supplicant_match_existing - Match existing interfaces
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_supplicant_match_existing(struct wpa_global *global)
+{
+ struct if_nameindex *ifi, *ifp;
+ struct wpa_supplicant *wpa_s;
+ struct wpa_interface *iface;
+
+ ifp = if_nameindex();
+ if (!ifp) {
+ wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
+ return -1;
+ }
+
+ for (ifi = ifp; ifi->if_name; ifi++) {
+ wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
+ if (wpa_s)
+ continue;
+ iface = wpa_supplicant_match_iface(global, ifi->if_name);
+ if (iface) {
+ wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+ os_free(iface);
+ if (wpa_s)
+ wpa_s->matched = 1;
+ }
+ }
+
+ if_freenameindex(ifp);
+ return 0;
+}
+
+#endif /* CONFIG_MATCH_IFACE */
+
+
/**
* wpa_supplicant_add_iface - Add a new network interface
* @global: Pointer to global data from wpa_supplicant_init()
@@ -4667,6 +6216,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
#ifdef CONFIG_MESH
unsigned int mesh_if_created = wpa_s->mesh_if_created;
char *ifname = NULL;
+ struct wpa_supplicant *parent = wpa_s->parent;
#endif /* CONFIG_MESH */
/* Remove interface from the global list of interfaces */
@@ -4702,7 +6252,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
#ifdef CONFIG_MESH
if (mesh_if_created) {
- wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+ wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
os_free(ifname);
}
#endif /* CONFIG_MESH */
@@ -4864,6 +6414,18 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
if (params->override_ctrl_interface)
global->params.override_ctrl_interface =
os_strdup(params->override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+ global->params.match_iface_count = params->match_iface_count;
+ if (params->match_iface_count) {
+ global->params.match_ifaces =
+ os_calloc(params->match_iface_count,
+ sizeof(struct wpa_interface));
+ os_memcpy(global->params.match_ifaces,
+ params->match_ifaces,
+ params->match_iface_count *
+ sizeof(struct wpa_interface));
+ }
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
if (params->conf_p2p_dev)
global->params.conf_p2p_dev =
@@ -4939,12 +6501,18 @@ int wpa_supplicant_run(struct wpa_global *global)
struct wpa_supplicant *wpa_s;
if (global->params.daemonize &&
- wpa_supplicant_daemon(global->params.pid_file))
+ (wpa_supplicant_daemon(global->params.pid_file) ||
+ eloop_sock_requeue()))
return -1;
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_supplicant_match_existing(global))
+ return -1;
+#endif
+
if (global->params.wait_for_monitor) {
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
- if (wpa_s->ctrl_iface)
+ if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
wpa_supplicant_ctrl_iface_wait(
wpa_s->ctrl_iface);
}
@@ -5010,6 +6578,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
os_free(global->params.ctrl_interface_group);
os_free(global->params.override_driver);
os_free(global->params.override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+ os_free(global->params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
os_free(global->params.conf_p2p_dev);
#endif /* CONFIG_P2P */
@@ -5042,6 +6613,19 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
wpas_init_ext_pw(wpa_s);
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS)
+ wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
+
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_WOWLAN_TRIGGERS) {
+ struct wpa_driver_capa capa;
+ int res = wpa_drv_get_capa(wpa_s, &capa);
+
+ if (res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
+ wpa_printf(MSG_ERROR,
+ "Failed to update wowlan_triggers to '%s'",
+ wpa_s->conf->wowlan_triggers);
+ }
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -5196,11 +6780,43 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
* TODO: if more than one possible AP is available in scan results,
* could try the other ones before requesting a new scan.
*/
+
+ /* speed up the connection attempt with normal scan */
+ wpa_s->normal_scans = 0;
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
1000 * (timeout % 1000));
}
+#ifdef CONFIG_FILS
+void fils_connection_failure(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ const u8 *realm, *username, *rrk;
+ size_t realm_len, username_len, rrk_len;
+ u16 next_seq_num;
+
+ if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) ||
+ eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
+ &username, &username_len,
+ &realm, &realm_len, &next_seq_num,
+ &rrk, &rrk_len) != 0 ||
+ !realm)
+ return;
+
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "FILS: Store last connection failure realm",
+ realm, realm_len);
+ os_free(wpa_s->last_con_fail_realm);
+ wpa_s->last_con_fail_realm = os_malloc(realm_len);
+ if (wpa_s->last_con_fail_realm) {
+ wpa_s->last_con_fail_realm_len = realm_len;
+ os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len);
+ }
+}
+#endif /* CONFIG_FILS */
+
+
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
{
return wpa_s->conf->ap_scan == 2 ||
@@ -5271,6 +6887,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
case WPA_CTRL_REQ_SIM:
str_clear_free(eap->external_sim_resp);
eap->external_sim_resp = os_strdup(value);
+ eap->pending_req_sim = 0;
break;
case WPA_CTRL_REQ_PSK_PASSPHRASE:
if (wpa_config_set(ssid, "psk", value, 0) < 0)
@@ -5281,6 +6898,16 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
wpa_supplicant_req_scan(wpa_s, 0, 0);
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ if (eap->pending_ext_cert_check != PENDING_CHECK)
+ return -1;
+ if (os_strcmp(value, "good") == 0)
+ eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
+ else if (os_strcmp(value, "bad") == 0)
+ eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
+ else
+ return -1;
+ break;
default:
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
return -1;
@@ -5329,6 +6956,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
(!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
+ !(wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password) &&
!ssid->mem_only_psk)
return 1;
@@ -5350,6 +6978,19 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
return NO_MGMT_FRAME_PROTECTION;
}
+ if (ssid &&
+ (ssid->key_mgmt &
+ ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
+ WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
+ /*
+ * Do not use the default PMF value for non-RSN networks
+ * since PMF is available only with RSN and pmf=2
+ * configuration would otherwise prevent connections to
+ * all open networks.
+ */
+ return NO_MGMT_FRAME_PROTECTION;
+ }
+
return wpa_s->conf->pmf;
}
@@ -5500,6 +7141,7 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
wpa_s->extra_blacklist_count = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s->last_owe_group = 0;
if (wpa_supplicant_fast_associate(wpa_s) != 1)
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -5508,6 +7150,29 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
}
+/**
+ * wpas_request_disconnection - Request disconnection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request disconnection from the currently connected
+ * network. This will stop any ongoing scans and initiate deauthentication.
+ */
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_s->reassociate = 0;
+ wpa_s->disconnected = 1;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ radio_remove_works(wpa_s, "connect", 0);
+ radio_remove_works(wpa_s, "sme-connect", 0);
+}
+
+
void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
struct wpa_used_freq_data *freqs_data,
unsigned int len)
@@ -5605,266 +7270,206 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
}
-static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
+struct wpa_supplicant *
+wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
{
- struct rrm_data *rrm = data;
-
- if (!rrm->notify_neighbor_rep) {
- wpa_printf(MSG_ERROR,
- "RRM: Unexpected neighbor report timeout");
- return;
+ switch (frame) {
+#ifdef CONFIG_P2P
+ case VENDOR_ELEM_PROBE_REQ_P2P:
+ case VENDOR_ELEM_PROBE_RESP_P2P:
+ case VENDOR_ELEM_PROBE_RESP_P2P_GO:
+ case VENDOR_ELEM_BEACON_P2P_GO:
+ case VENDOR_ELEM_P2P_PD_REQ:
+ case VENDOR_ELEM_P2P_PD_RESP:
+ case VENDOR_ELEM_P2P_GO_NEG_REQ:
+ case VENDOR_ELEM_P2P_GO_NEG_RESP:
+ case VENDOR_ELEM_P2P_GO_NEG_CONF:
+ case VENDOR_ELEM_P2P_INV_REQ:
+ case VENDOR_ELEM_P2P_INV_RESP:
+ case VENDOR_ELEM_P2P_ASSOC_REQ:
+ case VENDOR_ELEM_P2P_ASSOC_RESP:
+ return wpa_s->p2pdev;
+#endif /* CONFIG_P2P */
+ default:
+ return wpa_s;
}
-
- wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
- rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
-
- rrm->notify_neighbor_rep = NULL;
- rrm->neighbor_rep_cb_ctx = NULL;
}
-/*
- * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
- * @wpa_s: Pointer to wpa_supplicant
- */
-void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
+void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s)
{
- wpa_s->rrm.rrm_used = 0;
+ unsigned int i;
+ char buf[30];
+
+ wpa_printf(MSG_DEBUG, "Update vendor elements");
+
+ for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
+ if (wpa_s->vendor_elem[i]) {
+ int res;
- eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
- NULL);
- if (wpa_s->rrm.notify_neighbor_rep)
- wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
- wpa_s->rrm.next_neighbor_rep_token = 1;
+ res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
+ if (!os_snprintf_error(sizeof(buf), res)) {
+ wpa_hexdump_buf(MSG_DEBUG, buf,
+ wpa_s->vendor_elem[i]);
+ }
+ }
+ }
+
+#ifdef CONFIG_P2P
+ if (wpa_s->parent == wpa_s &&
+ wpa_s->global->p2p &&
+ !wpa_s->global->p2p_disabled)
+ p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
+#endif /* CONFIG_P2P */
}
-/*
- * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
- * @wpa_s: Pointer to wpa_supplicant
- * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
- * @report_len: Length of neighbor report buffer
- */
-void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
- const u8 *report, size_t report_len)
+int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
+ const u8 *elem, size_t len)
{
- struct wpabuf *neighbor_rep;
+ u8 *ie, *end;
- wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
- if (report_len < 1)
- return;
+ ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
+ end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
- if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
- wpa_printf(MSG_DEBUG,
- "RRM: Discarding neighbor report with token %d (expected %d)",
- report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
- return;
- }
-
- eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
- NULL);
+ for (; ie + 1 < end; ie += 2 + ie[1]) {
+ if (ie + len > end)
+ break;
+ if (os_memcmp(ie, elem, len) != 0)
+ continue;
- if (!wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
- return;
+ if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
+ wpabuf_free(wpa_s->vendor_elem[frame]);
+ wpa_s->vendor_elem[frame] = NULL;
+ } else {
+ os_memmove(ie, ie + len, end - (ie + len));
+ wpa_s->vendor_elem[frame]->used -= len;
+ }
+ wpas_vendor_elem_update(wpa_s);
+ return 0;
}
- /* skipping the first byte, which is only an id (dialog token) */
- neighbor_rep = wpabuf_alloc(report_len - 1);
- if (neighbor_rep == NULL)
- return;
- wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
- wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
- report[0]);
- wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
- neighbor_rep);
- wpa_s->rrm.notify_neighbor_rep = NULL;
- wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
+ return -1;
}
-#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
-/* Workaround different, undefined for Windows, error codes used here */
-#define ENOTCONN -1
-#define EOPNOTSUPP -1
-#define ECANCELED -1
-#endif
-
-/**
- * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
- * @wpa_s: Pointer to wpa_supplicant
- * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
- * is sent in the request.
- * @cb: Callback function to be called once the requested report arrives, or
- * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
- * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
- * the requester's responsibility to free it.
- * In the latter case NULL will be sent in 'neighbor_rep'.
- * @cb_ctx: Context value to send the callback function
- * Returns: 0 in case of success, negative error code otherwise
- *
- * In case there is a previous request which has not been answered yet, the
- * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
- * Request must contain a callback function.
- */
-int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- void (*cb)(void *ctx,
- struct wpabuf *neighbor_rep),
- void *cb_ctx)
+struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+ u16 num_modes, enum hostapd_hw_mode mode)
{
- struct wpabuf *buf;
- const u8 *rrm_ie;
+ u16 i;
- if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
- wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
- return -ENOTCONN;
+ for (i = 0; i < num_modes; i++) {
+ if (modes[i].mode == mode)
+ return &modes[i];
}
- if (!wpa_s->rrm.rrm_used) {
- wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
- return -EOPNOTSUPP;
- }
+ return NULL;
+}
- rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
- WLAN_EID_RRM_ENABLED_CAPABILITIES);
- if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
- !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
- wpa_printf(MSG_DEBUG,
- "RRM: No network support for Neighbor Report.");
- return -EOPNOTSUPP;
- }
- if (!cb) {
- wpa_printf(MSG_DEBUG,
- "RRM: Neighbor Report request must provide a callback.");
- return -EINVAL;
- }
+static struct
+wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ struct wpa_bss_tmp_disallowed *bss;
- /* Refuse if there's a live request */
- if (wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_DEBUG,
- "RRM: Currently handling previous Neighbor Report.");
- return -EBUSY;
+ dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
+ struct wpa_bss_tmp_disallowed, list) {
+ if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0)
+ return bss;
}
- /* 3 = action category + action code + dialog token */
- buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0));
- if (buf == NULL) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to allocate Neighbor Report Request");
- return -ENOMEM;
- }
+ return NULL;
+}
- wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
- (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
- wpa_s->rrm.next_neighbor_rep_token);
- wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
- wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
- wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
- if (ssid) {
- wpabuf_put_u8(buf, WLAN_EID_SSID);
- wpabuf_put_u8(buf, ssid->ssid_len);
- wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
- }
-
- wpa_s->rrm.next_neighbor_rep_token++;
+static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss_tmp_disallowed *tmp;
+ unsigned int num_bssid = 0;
+ u8 *bssids;
+ int ret;
- if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
- wpa_s->own_addr, wpa_s->bssid,
- wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to send Neighbor Report Request");
- wpabuf_free(buf);
- return -ECANCELED;
- }
+ bssids = os_malloc(dl_list_len(&wpa_s->bss_tmp_disallowed) * ETH_ALEN);
+ if (!bssids)
+ return -1;
+ dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
+ struct wpa_bss_tmp_disallowed, list) {
+ os_memcpy(&bssids[num_bssid * ETH_ALEN], tmp->bssid,
+ ETH_ALEN);
+ num_bssid++;
+ }
+ ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+ os_free(bssids);
+ return ret;
+}
- wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
- wpa_s->rrm.notify_neighbor_rep = cb;
- eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
- wpas_rrm_neighbor_rep_timeout_handler,
- &wpa_s->rrm, NULL);
- wpabuf_free(buf);
- return 0;
+static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx;
+
+ /* Make sure the bss is not already freed */
+ dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
+ struct wpa_bss_tmp_disallowed, list) {
+ if (bss == tmp) {
+ dl_list_del(&tmp->list);
+ os_free(tmp);
+ wpa_set_driver_tmp_disallow_list(wpa_s);
+ break;
+ }
+ }
}
-void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
- const u8 *src,
- const u8 *frame, size_t len,
- int rssi)
+void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ unsigned int sec, int rssi_threshold)
{
- struct wpabuf *buf;
- const struct rrm_link_measurement_request *req;
- struct rrm_link_measurement_report report;
+ struct wpa_bss_tmp_disallowed *bss;
- if (wpa_s->wpa_state != WPA_COMPLETED) {
- wpa_printf(MSG_INFO,
- "RRM: Ignoring link measurement request. Not associated");
- return;
+ bss = wpas_get_disallowed_bss(wpa_s, bssid);
+ if (bss) {
+ eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
+ goto finish;
}
- if (!wpa_s->rrm.rrm_used) {
- wpa_printf(MSG_INFO,
- "RRM: Ignoring link measurement request. Not RRM network");
+ bss = os_malloc(sizeof(*bss));
+ if (!bss) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate memory for temp disallow BSS");
return;
}
- if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
- wpa_printf(MSG_INFO,
- "RRM: Measurement report failed. TX power insertion not supported");
- return;
- }
+ os_memcpy(bss->bssid, bssid, ETH_ALEN);
+ dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
+ wpa_set_driver_tmp_disallow_list(wpa_s);
- req = (const struct rrm_link_measurement_request *) frame;
- if (len < sizeof(*req)) {
- wpa_printf(MSG_INFO,
- "RRM: Link measurement report failed. Request too short");
- return;
- }
+finish:
+ bss->rssi_threshold = rssi_threshold;
+ eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
+ wpa_s, bss);
+}
- os_memset(&report, 0, sizeof(report));
- report.tpc.eid = WLAN_EID_TPC_REPORT;
- report.tpc.len = 2;
- report.rsni = 255; /* 255 indicates that RSNI is not available */
- report.dialog_token = req->dialog_token;
- /*
- * It's possible to estimate RCPI based on RSSI in dBm. This
- * calculation will not reflect the correct value for high rates,
- * but it's good enough for Action frames which are transmitted
- * with up to 24 Mbps rates.
- */
- if (!rssi)
- report.rcpi = 255; /* not available */
- else if (rssi < -110)
- report.rcpi = 0;
- else if (rssi > 0)
- report.rcpi = 220;
- else
- report.rcpi = (rssi + 110) * 2;
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+ struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
- /* action_category + action_code */
- buf = wpabuf_alloc(2 + sizeof(report));
- if (buf == NULL) {
- wpa_printf(MSG_ERROR,
- "RRM: Link measurement report failed. Buffer allocation failed");
- return;
+ dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
+ struct wpa_bss_tmp_disallowed, list) {
+ if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) {
+ disallowed = tmp;
+ break;
+ }
}
+ if (!disallowed)
+ return 0;
- wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
- wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
- wpabuf_put_data(buf, &report, sizeof(report));
- wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
- wpabuf_head(buf), wpabuf_len(buf));
+ if (disallowed->rssi_threshold != 0 &&
+ bss->level > disallowed->rssi_threshold)
+ return 0;
- if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
- wpa_s->own_addr, wpa_s->bssid,
- wpabuf_head(buf), wpabuf_len(buf), 0)) {
- wpa_printf(MSG_ERROR,
- "RRM: Link measurement report failed. Send action failed");
- }
- wpabuf_free(buf);
+ return 1;
}
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
index 68c0476..f5c2cfc 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf
@@ -87,9 +87,7 @@ eapol_version=1
# parameters (e.g., WPA IE generation); this mode can also be used with
# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
# APs (i.e., external program needs to control association). This mode must
-# also be used when using wired Ethernet drivers.
-# Note: macsec_qca driver is one type of Ethernet driver which implements
-# macsec feature.
+# also be used when using wired Ethernet drivers (including MACsec).
# 2: like 0, but associate with APs using security policy and SSID (but not
# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
# enable operation with hidden SSIDs and optimized roaming; in this mode,
@@ -106,6 +104,25 @@ eapol_version=1
# networks are found, a new IBSS or AP mode network is created.
ap_scan=1
+# Whether to force passive scan for network connection
+#
+# By default, scans will send out Probe Request frames on channels that allow
+# active scanning. This advertise the local station to the world. Normally this
+# is fine, but users may wish to do passive scanning where the radio should only
+# listen quietly for Beacon frames and not send any Probe Request frames. Actual
+# functionality may be driver dependent.
+#
+# This parameter can be used to force only passive scanning to be used
+# for network connection cases. It should be noted that this will slow
+# down scan operations and reduce likelihood of finding the AP. In
+# addition, some use cases will override this due to functional
+# requirements, e.g., for finding an AP that uses hidden SSID
+# (scan_ssid=1) or P2P device discovery.
+#
+# 0: Do normal scans (allow active scans) (default)
+# 1: Do passive scans.
+#passive_scan=0
+
# MPM residency
# By default, wpa_supplicant implements the mesh peering manager (MPM) for an
# open mesh. However, if the driver can implement the MPM, you may set this to
@@ -137,10 +154,13 @@ ap_scan=1
fast_reauth=1
# OpenSSL Engine support
-# These options can be used to load OpenSSL engines.
+# These options can be used to load OpenSSL engines in special or legacy
+# modes.
# The two engines that are supported currently are shown below:
# They are both from the opensc project (http://www.opensc.org/)
-# By default no engines are loaded.
+# By default the PKCS#11 engine is loaded if the client_cert or
+# private_key option appear to be a PKCS#11 URI, and these options
+# should not need to be used explicitly.
# make the opensc engine available
#opensc_engine_path=/usr/lib/opensc/engine_opensc.so
# make the pkcs11 engine available
@@ -151,13 +171,13 @@ fast_reauth=1
# OpenSSL cipher string
#
# This is an OpenSSL specific configuration option for configuring the default
-# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default.
+# ciphers. If not set, the value configured at build time ("DEFAULT:!EXP:!LOW"
+# by default) is used.
# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
# on cipher suite configuration. This is applicable only if wpa_supplicant is
# built to use OpenSSL.
#openssl_ciphers=DEFAULT:!EXP:!LOW
-
# Dynamic EAP methods
# If EAP methods were built dynamically as shared object files, they need to be
# loaded here before being used in the network blocks. By default, EAP methods
@@ -166,7 +186,7 @@ fast_reauth=1
#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so
# Driver interface parameters
-# This field can be used to configure arbitrary driver interace parameters. The
+# This field can be used to configure arbitrary driver interface parameters. The
# format is specific to the selected driver interface. This field is not used
# in most cases.
#driver_param="field=value"
@@ -186,9 +206,15 @@ fast_reauth=1
# Wi-Fi Protected Setup (WPS) parameters
# Universally Unique IDentifier (UUID; see RFC 4122) of the device
-# If not configured, UUID will be generated based on the local MAC address.
+# If not configured, UUID will be generated based on the mechanism selected with
+# the auto_uuid parameter.
#uuid=12345678-9abc-def0-1234-56789abcdef0
+# Automatic UUID behavior
+# 0 = generate static value based on the local MAC address (default)
+# 1 = generate a random UUID every time wpa_supplicant starts
+#auto_uuid=0
+
# Device Name
# User-friendly description of device; up to 32 octets encoded in UTF-8
#device_name=Wireless Client
@@ -244,6 +270,14 @@ fast_reauth=1
# to external program(s)
#wps_cred_processing=0
+# Whether to enable SAE (WPA3-Personal transition mode) automatically for
+# WPA2-PSK credentials received using WPS.
+# 0 = only add the explicitly listed WPA2-PSK configuration (default)
+# 1 = add both the WPA2-PSK and SAE configuration and enable PMF so that the
+# station gets configured in WPA3-Personal transition mode (supports both
+# WPA2-Personal (PSK) and WPA3-Personal (SAE) APs).
+#wps_cred_add_sae=0
+
# Vendor attribute in WPS M1, e.g., Windows 7 Vertical Pairing
# The vendor attribute contents to be added in M1 (hex string)
#wps_vendor_ext_m1=000137100100020001
@@ -272,6 +306,15 @@ fast_reauth=1
# of APs when using ap_scan=1 mode.
#bss_max_count=200
+# BSS expiration age in seconds. A BSS will be removed from the local cache
+# if it is not in use and has not been seen for this time. Default is 180.
+#bss_expiration_age=180
+
+# BSS expiration after number of scans. A BSS will be removed from the local
+# cache if it is not seen in this number of scans.
+# Default is 2.
+#bss_expiration_scan_count=2
+
# Automatic scan
# This is an optional set of parameters for automatic scanning
# within an interface in following format:
@@ -283,7 +326,9 @@ fast_reauth=1
# up to the limit of 300 seconds (3, 9, 27 ... 300)
# For periodic module, parameters would be <fixed interval>
#autoscan=periodic:30
-# So a delay of 30 seconds will be applied between each scan
+# So a delay of 30 seconds will be applied between each scan.
+# Note: If sched_scan_plans are configured and supported by the driver,
+# autoscan is ignored.
# filter_ssids - SSID-based scan result filtering
# 0 = do not filter scan results (default)
@@ -327,19 +372,26 @@ fast_reauth=1
# Protected Management Frames default
# This parameter can be used to set the default behavior for the ieee80211w
-# parameter. By default, PMF is disabled unless enabled with the global pmf=1/2
-# parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF
-# is enabled/required by default, but can be disabled with the per-network
-# ieee80211w parameter.
+# parameter for RSN networks. By default, PMF is disabled unless enabled with
+# the global pmf=1/2 parameter or with the per-network ieee80211w=1/2 parameter.
+# With pmf=1/2, PMF is enabled/required by default, but can be disabled with the
+# per-network ieee80211w parameter. This global default value does not apply
+# for non-RSN networks (key_mgmt=NONE) since PMF is available only when using
+# RSN.
#pmf=0
# Enabled SAE finite cyclic groups in preference order
# By default (if this parameter is not set), the mandatory group 19 (ECC group
-# defined over a 256-bit prime order field) is preferred, but other groups are
-# also enabled. If this parameter is set, the groups will be tried in the
-# indicated order. The group values are listed in the IANA registry:
+# defined over a 256-bit prime order field, NIST P-256) is preferred and groups
+# 20 (NIST P-384) and 21 (NIST P-521) are also enabled. If this parameter is
+# set, the groups will be tried in the indicated order.
+# The group values are listed in the IANA registry:
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
-#sae_groups=21 20 19 26 25
+# Note that groups 1, 2, 5, 22, 23, and 24 should not be used in production
+# purposes due limited security (see RFC 8247). Groups that are not as strong as
+# group 19 (ECC, NIST P-256) are unlikely to be useful for production use cases
+# since all implementations are required to support group 19.
+#sae_groups=19 20 21
# Default value for DTIM period (if not overridden in network block)
#dtim_period=2
@@ -386,11 +438,50 @@ fast_reauth=1
# 2 = like 1, but maintain OUI (with local admin bit set)
#preassoc_mac_addr=0
+# MAC address policy for GAS operations
+# 0 = use permanent MAC address
+# 1 = use random MAC address
+# 2 = like 1, but maintain OUI (with local admin bit set)
+#gas_rand_mac_addr=0
+
+# Lifetime of GAS random MAC address in seconds (default: 60)
+#gas_rand_addr_lifetime=60
+
# Interworking (IEEE 802.11u)
# Enable Interworking
# interworking=1
+# Enable P2P GO advertisement of Interworking
+# go_interworking=1
+
+# P2P GO Interworking: Access Network Type
+# 0 = Private network
+# 1 = Private network with guest access
+# 2 = Chargeable public network
+# 3 = Free public network
+# 4 = Personal device network
+# 5 = Emergency services only network
+# 14 = Test or experimental
+# 15 = Wildcard
+#go_access_network_type=0
+
+# P2P GO Interworking: Whether the network provides connectivity to the Internet
+# 0 = Unspecified
+# 1 = Network provides connectivity to the Internet
+#go_internet=1
+
+# P2P GO Interworking: Group Venue Info (optional)
+# The available values are defined in IEEE Std 802.11-2016, 9.4.1.35.
+# Example values (group,type):
+# 0,0 = Unspecified
+# 1,7 = Convention Center
+# 1,13 = Coffee Shop
+# 2,0 = Unspecified Business
+# 7,1 Private Residence
+#go_venue_group=7
+#go_venue_type=1
+
# Homogenous ESS identifier
# If this is set, scans will be used to request response only from BSSes
# belonging to the specified Homogeneous ESS. This is used only if interworking
@@ -405,6 +496,28 @@ fast_reauth=1
# matching network block
#auto_interworking=0
+# GAS Address3 field behavior
+# 0 = P2P specification (Address3 = AP BSSID); default
+# 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+# sent to not-associated AP; if associated, AP BSSID)
+#gas_address3=0
+
+# Publish fine timing measurement (FTM) responder functionality in
+# the Extended Capabilities element bit 70.
+# Controls whether FTM responder functionality will be published by AP/STA.
+# Note that actual FTM responder operation is managed outside wpa_supplicant.
+# 0 = Do not publish; default
+# 1 = Publish
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality in
+# the Extended Capabilities element bit 71.
+# Controls whether FTM initiator functionality will be published by AP/STA.
+# Note that actual FTM initiator operation is managed outside wpa_supplicant.
+# 0 = Do not publish; default
+# 1 = Publish
+#ftm_initiator=0
+
# credential block
#
# Each credential used for automatic network selection is configured as a set
@@ -439,6 +552,10 @@ fast_reauth=1
# (EAP-TLS). Full path to the file should be used since working
# directory may change when wpa_supplicant is run in the background.
#
+# Certificates from PKCS#11 tokens can be referenced by a PKCS#11 URI.
+#
+# For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
# Alternatively, a named configuration blob can be used by setting
# this to blob://blob_name.
#
@@ -449,6 +566,9 @@ fast_reauth=1
# used since working directory may change when wpa_supplicant is run
# in the background.
#
+# Keys in PKCS#11 tokens can be referenced by a PKCS#11 URI.
+# For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
# Windows certificate store can be used by leaving client_cert out and
# configuring private_key in one of the following formats:
#
@@ -487,6 +607,20 @@ fast_reauth=1
# pre-configured with the credential since the NAI Realm information
# may not be available or fetched.
#
+# required_roaming_consortium: Required Roaming Consortium OI
+# If required_roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that is required to be advertised by the AP for
+# the credential to be considered matching.
+#
+# roaming_consortiums: Roaming Consortium OI(s) memberships
+# This string field contains one or more comma delimited OIs (hexdump)
+# identifying the roaming consortiums of which the provider is a member.
+# The list is sorted from the most preferred one to the least preferred
+# one. A match between the Roaming Consortium OIs advertised by an AP and
+# the OIs in this list indicates that successful authentication is
+# possible.
+# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+#
# eap: Pre-configured EAP method
# This optional field can be used to specify which EAP method will be
# used with this credential. If not set, the EAP method is selected
@@ -553,6 +687,8 @@ fast_reauth=1
# 0 = do not use OCSP stapling (TLS certificate status extension)
# 1 = try to use OCSP stapling, but not require response
# 2 = require valid OCSP stapling response
+# 3 = require valid OCSP stapling response for all not-trusted
+# certificates in the server certificate chain
#
# sim_num: Identifier for which SIM to use in multi-SIM devices
#
@@ -585,6 +721,48 @@ fast_reauth=1
# Hotspot 2.0
# hs20=1
+# Scheduled scan plans
+#
+# A space delimited list of scan plans. Each scan plan specifies the scan
+# interval and number of iterations, delimited by a colon. The last scan plan
+# will run infinitely and thus must specify only the interval and not the number
+# of iterations.
+#
+# The driver advertises the maximum number of scan plans supported. If more scan
+# plans than supported are configured, only the first ones are set (up to the
+# maximum supported). The last scan plan that specifies only the interval is
+# always set as the last plan.
+#
+# If the scan interval or the number of iterations for a scan plan exceeds the
+# maximum supported, it will be set to the maximum supported value.
+#
+# Format:
+# sched_scan_plans=<interval:iterations> <interval:iterations> ... <interval>
+#
+# Example:
+# sched_scan_plans=10:100 20:200 30
+
+# Multi Band Operation (MBO) non-preferred channels
+# A space delimited list of non-preferred channels where each channel is a colon
+# delimited list of values.
+# Format:
+# non_pref_chan=<oper_class>:<chan>:<preference>:<reason>
+# Example:
+# non_pref_chan=81:5:10:2 81:1:0:2 81:9:0:2
+
+# MBO Cellular Data Capabilities
+# 1 = Cellular data connection available
+# 2 = Cellular data connection not available
+# 3 = Not cellular capable (default)
+#mbo_cell_capa=3
+
+# Optimized Connectivity Experience (OCE)
+# oce: Enable OCE features (bitmap)
+# Set BIT(0) to Enable OCE in non-AP STA mode (default; disabled if the driver
+# does not indicate support for OCE in STA mode)
+# Set BIT(1) to Enable OCE in STA-CFON mode
+#oce=1
+
# network block
#
# Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -646,6 +824,17 @@ fast_reauth=1
# an IBSS network with the configured SSID is already present, the frequency of
# the network will be used instead of this configured value.
#
+# pbss: Whether to use PBSS. Relevant to IEEE 802.11ad networks only.
+# 0 = do not use PBSS
+# 1 = use PBSS
+# 2 = don't care (not allowed in AP mode)
+# Used together with mode configuration. When mode is AP, it means to start a
+# PCP instead of a regular AP. When mode is infrastructure it means connect
+# to a PCP instead of AP. In this mode you can also specify 2 (don't care)
+# which means connect to either PCP or AP.
+# P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in IEEE 802.11ad network.
+# For more details, see IEEE Std 802.11ad-2012.
+#
# scan_freq: List of frequencies to scan
# Space-separated list of frequencies in MHz to scan when searching for this
# BSS. If the subset of channels used by the network is known, this option can
@@ -686,6 +875,7 @@ fast_reauth=1
# proto: list of accepted protocols
# WPA = WPA/IEEE 802.11i/D3.0
# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
+# Note that RSN is used also for WPA3.
# If not set, this defaults to: WPA RSN
#
# key_mgmt: list of accepted authenticated key management protocols
@@ -694,8 +884,27 @@ fast_reauth=1
# IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
# generated WEP keys
# NONE = WPA is not used; plaintext or static WEP could be used
+# WPA-NONE = WPA-None for IBSS (deprecated; use proto=RSN key_mgmt=WPA-PSK
+# instead)
+# FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key
+# FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication
+# FT-EAP-SHA384 = Fast BSS Transition (IEEE 802.11r) with EAP authentication
+# and using SHA384
# WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
+# SAE = Simultaneous authentication of equals; pre-shared key/password -based
+# authentication with stronger security than WPA-PSK especially when using
+# not that strong password; a.k.a. WPA3-Personal
+# FT-SAE = SAE with FT
+# WPA-EAP-SUITE-B = Suite B 128-bit level
+# WPA-EAP-SUITE-B-192 = Suite B 192-bit level
+# OSEN = Hotspot 2.0 Rel 2 online signup connection
+# FILS-SHA256 = Fast Initial Link Setup with SHA256
+# FILS-SHA384 = Fast Initial Link Setup with SHA384
+# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
+# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
+# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
+# DPP = Device Provisioning Protocol
# If not set, this defaults to: WPA-PSK WPA-EAP
#
# ieee80211w: whether management frame protection is enabled
@@ -708,6 +917,13 @@ fast_reauth=1
# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
#
+# ocv: whether operating channel validation is enabled
+# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this automatically also enables ieee80211w, if not yet enabled.
+# 0 = disabled (default)
+# 1 = enabled
+#ocv=1
+#
# auth_alg: list of allowed IEEE 802.11 authentication algorithms
# OPEN = Open System authentication (required for WPA/WPA2)
# SHARED = Shared Key authentication (requires static WEP keys)
@@ -729,6 +945,14 @@ fast_reauth=1
# WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11]
# If not set, this defaults to: CCMP TKIP WEP104 WEP40
#
+# group_mgmt: list of accepted group management ciphers for RSN (PMF)
+# AES-128-CMAC = BIP-CMAC-128
+# BIP-GMAC-128
+# BIP-GMAC-256
+# BIP-CMAC-256
+# If not set, no constraint on the cipher, i.e., accept whichever cipher the AP
+# indicates.
+#
# psk: WPA preshared key; 256-bit pre-shared key
# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
@@ -746,22 +970,71 @@ fast_reauth=1
# 1 = do not store psk/passphrase to the configuration file
#mem_only_psk=0
#
+# sae_password: SAE password
+# This parameter can be used to set a password for SAE. By default, the
+# passphrase from the psk parameter is used if this separate parameter is not
+# used, but psk follows the WPA-PSK constraints (8..63 characters) even though
+# SAE passwords do not have such constraints.
+#
+# sae_password_id: SAE password identifier
+# This parameter can be used to set an identifier for the SAE password. By
+# default, no such identifier is used. If set, the specified identifier value
+# is used by the other peer to select which password to use for authentication.
+#
# eapol_flags: IEEE 802.1X/EAPOL options (bit field)
# Dynamic WEP key required for non-WPA mode
# bit0 (1): require dynamically generated unicast WEP key
# bit1 (2): require dynamically generated broadcast WEP key
# (3 = require both keys; default)
-# Note: When using wired authentication (including macsec_qca driver),
+# Note: When using wired authentication (including MACsec drivers),
# eapol_flags must be set to 0 for the authentication to be completed
# successfully.
#
# macsec_policy: IEEE 802.1X/MACsec options
-# This determines how sessions are secured with MACsec. It is currently
-# applicable only when using the macsec_qca driver interface.
+# This determines how sessions are secured with MACsec (only for MACsec
+# drivers).
# 0: MACsec not in use (default)
# 1: MACsec enabled - Should secure, accept key server's advice to
# determine whether to use a secure session or not.
#
+# macsec_integ_only: IEEE 802.1X/MACsec transmit mode
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 0: Encrypt traffic (default)
+# 1: Integrity only
+#
+# macsec_replay_protect: IEEE 802.1X/MACsec replay protection
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 0: Replay protection disabled (default)
+# 1: Replay protection enabled
+#
+# macsec_replay_window: IEEE 802.1X/MACsec replay protection window
+# This determines a window in which replay is tolerated, to allow receipt
+# of frames that have been misordered by the network.
+# This setting applies only when MACsec replay protection active, i.e.,
+# - macsec_replay_protect is enabled
+# - the key server has decided to enable MACsec
+# 0: No replay window, strict check (default)
+# 1..2^32-1: number of packets that could be misordered
+#
+# macsec_port: IEEE 802.1X/MACsec port
+# Port component of the SCI
+# Range: 1-65534 (default: 1)
+#
+# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
+# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
+# In this mode, instances of wpa_supplicant can act as MACsec peers. The peer
+# with lower priority will become the key server and start distributing SAKs.
+# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-byte (128-bit)
+# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits)
+# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string
+# (2..64 hex-digits)
+# mka_priority (Priority of MKA Actor) is in 0..255 range with 255 being
+# default priority
+#
# mixed_cell: This option can be used to configure whether so called mixed
# cells, i.e., networks that use both plaintext and encryption in the same
# SSID, are allowed when selecting a BSS from scan results.
@@ -777,18 +1050,16 @@ fast_reauth=1
# hex without quotation, e.g., 0102030405)
# wep_tx_keyidx: Default WEP key index (TX) (0..3)
#
-# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
-# allowed. This is only used with RSN/WPA2.
-# 0 = disabled (default)
-# 1 = enabled
-#peerkey=1
-#
# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
#
+# group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
+# as the dot11RSNAConfigGroupRekeyTime parameter when operating in
+# Authenticator role in IBSS, or in AP and mesh modes.
+#
# Following fields are only used with internal EAP implementation.
# eap: space-separated list of accepted EAP methods
-# MD5 = EAP-MD5 (unsecure and does not generate keying material ->
+# MD5 = EAP-MD5 (insecure and does not generate keying material ->
# cannot be used with WPA; to be used as a Phase 2 method
# with EAP-PEAP or EAP-TTLS)
# MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used
@@ -879,23 +1150,23 @@ fast_reauth=1
# automatically converted into DH params.
# subject_match: Substring to be matched against the subject of the
# authentication server certificate. If this string is set, the server
-# sertificate is only accepted if it contains this string in the subject.
+# certificate is only accepted if it contains this string in the subject.
# The subject string is in following format:
# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
-# Note: Since this is a substring match, this cannot be used securily to
+# Note: Since this is a substring match, this cannot be used securely to
# do a suffix match against a possible domain name in the CN entry. For
# such a use case, domain_suffix_match or domain_match should be used
# instead.
# altsubject_match: Semicolon separated string of entries to be matched against
# the alternative subject name of the authentication server certificate.
-# If this string is set, the server sertificate is only accepted if it
+# If this string is set, the server certificate is only accepted if it
# contains one of the entries in an alternative subject name extension.
# altSubjectName string is in following format: TYPE:VALUE
# Example: EMAIL:server@example.com
# Example: DNS:server.example.com;DNS:server2.example.com
# Following types are supported: EMAIL, DNS, URI
# domain_suffix_match: Constraint for server domain name. If set, this FQDN is
-# used as a suffix match requirement for the AAAserver certificate in
+# used as a suffix match requirement for the AAA server certificate in
# SubjectAltName dNSName element(s). If a matching dNSName is found, this
# constraint is met. If no dNSName values are present, this constraint is
# matched against SubjectName CN using same suffix match comparison.
@@ -906,6 +1177,12 @@ fast_reauth=1
# certificate may include additional sub-level labels in addition to the
# required labels.
#
+# More than one match string can be provided by using semicolons to
+# separate the strings (e.g., example.org;example.com). When multiple
+# strings are specified, a match with any one of the values is considered
+# a sufficient match for the certificate, i.e., the conditions are ORed
+# together.
+#
# For example, domain_suffix_match=example.com would match
# test.example.com but would not match test-example.com.
# domain_match: Constraint for server domain name
@@ -918,6 +1195,12 @@ fast_reauth=1
# no subdomains or wildcard matches are allowed. Case-insensitive
# comparison is used, so "Example.com" matches "example.com", but would
# not match "test.Example.com".
+#
+# More than one match string can be provided by using semicolons to
+# separate the strings (e.g., example.org;example.com). When multiple
+# strings are specified, a match with any one of the values is considered
+# a sufficient match for the certificate, i.e., the conditions are ORed
+# together.
# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
# (string with field-value pairs, e.g., "peapver=0" or
# "peapver=1 peaplabel=1")
@@ -979,10 +1262,28 @@ fast_reauth=1
# For EAP-FAST, this must be set to 0 (or left unconfigured for the
# default value to be used automatically).
# tls_disable_tlsv1_0=1 - disable use of TLSv1.0
+# tls_disable_tlsv1_0=0 - explicitly enable use of TLSv1.0 (this allows
+# systemwide TLS policies to be overridden)
# tls_disable_tlsv1_1=1 - disable use of TLSv1.1 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_1=0 - explicitly enable use of TLSv1.1 (this allows
+# systemwide TLS policies to be overridden)
# tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_2=0 - explicitly enable use of TLSv1.2 (this allows
+# systemwide TLS policies to be overridden)
+# tls_disable_tlsv1_3=1 - disable use of TLSv1.3 (a workaround for AAA servers
+# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_3=0 - enable TLSv1.3 (experimental - disabled by default)
+# tls_ext_cert_check=0 - No external server certificate validation (default)
+# tls_ext_cert_check=1 - External server certificate validation enabled; this
+# requires an external program doing validation of server certificate
+# chain when receiving CTRL-RSP-EXT_CERT_CHECK event from the control
+# interface and report the result of the validation with
+# CTRL-RSP_EXT_CERT_CHECK.
+# tls_suiteb=0 - do not apply Suite B 192-bit constraints on TLS (default)
+# tls_suiteb=1 - apply Suite B 192-bit constraints on TLS; this is used in
+# particular when using Suite B with RSA keys of >= 3K (3072) bits
#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
@@ -1014,6 +1315,8 @@ fast_reauth=1
# 0 = do not use OCSP stapling (TLS certificate status extension)
# 1 = try to use OCSP stapling, but not require response
# 2 = require valid OCSP stapling response
+# 3 = require valid OCSP stapling response for all not-trusted
+# certificates in the server certificate chain
#
# openssl_ciphers: OpenSSL specific cipher configuration
# This can be used to override the global openssl_ciphers configuration
@@ -1047,6 +1350,13 @@ fast_reauth=1
# number of authentication servers. Strict EAP conformance mode can be
# configured by disabling workarounds with eap_workaround=0.
+# update_identifier: PPS MO ID
+# (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier)
+#
+# roaming_consortium_selection: Roaming Consortium Selection
+# The matching Roaming Consortium OI that was used to generate this
+# network profile.
+
# Station inactivity limit
#
# If a station does not send anything in ap_max_inactivity seconds, an
@@ -1070,6 +1380,16 @@ fast_reauth=1
# Beacon interval (default: 100 TU)
#beacon_int=100
+# WPS in AP mode
+# 0 = WPS enabled and configured (default)
+# 1 = WPS disabled
+#wps_disabled=0
+
+# FILS DH Group
+# 0 = PFS disabled with FILS shared key authentication (default)
+# 1-65535 = DH Group to use for FILS PFS
+#fils_dh_group=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
@@ -1114,6 +1434,20 @@ fast_reauth=1
# Treated as hint by the kernel.
# -1 = Do not make any changes.
# 0-3 = Set AMPDU density (aka factor) to specified value.
+#
+# tx_stbc: Allow overriding STBC support for TX streams
+# Value: 0-1, see IEEE Std 802.11-2016, 9.4.2.56.2.
+# -1 = Do not make any changes (default)
+# 0 = Set if not supported
+# 1 = Set if supported
+#
+# rx_stbc: Allow overriding STBC support for RX streams
+# Value: 0-3, see IEEE Std 802.11-2016, 9.4.2.56.2.
+# -1 = Do not make any changes (default)
+# 0 = Set if not supported
+# 1 = Set for support of one spatial stream
+# 2 = Set for support of one and two spatial streams
+# 3 = Set for support of one, two and three spatial streams
# disable_vht: Whether VHT should be disabled.
# 0 = VHT enabled (if AP supports it)
@@ -1129,16 +1463,23 @@ fast_reauth=1
# 2: MCS 0-9
# 3: not supported
+# multi_ap_backhaul_sta: Multi-AP backhaul STA functionality
+# 0 = normal STA (default)
+# 1 = backhaul STA
+# A backhaul STA sends the Multi-AP IE, fails to associate if the AP does not
+# support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be
+# added to a bridge to allow forwarding frames over this backhaul link.
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
-# option CONFIG_FST is set while compiling hostapd. They allow this interface
-# to be a part of FST setup.
+# option CONFIG_FST is set while compiling wpa_supplicant. They allow this
+# interface to be a part of FST setup.
#
# FST is the transfer of a session from a channel to another channel, in the
# same or different frequency bands.
#
-# For detals, see IEEE Std 802.11ad-2012.
+# For details, see IEEE Std 802.11ad-2012.
# Identifier of an FST Group the interface belongs to.
#fst_group_id=bond0
@@ -1471,22 +1812,10 @@ network={
group=CCMP TKIP
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
- client_cert="/etc/cert/user.pem"
-
- engine=1
-
- # The engine configured here must be available. Look at
- # OpenSSL engine support in the global section.
- # The key available through the engine must be the private key
- # matching the client certificate configured above.
- # use the opensc engine
- #engine_id="opensc"
- #key_id="45"
-
- # use the pkcs11 engine
- engine_id="pkcs11"
- key_id="id_45"
+ # Certificate and/or key identified by PKCS#11 URI (RFC7512)
+ client_cert="pkcs11:manufacturer=piv_II;id=%01"
+ private_key="pkcs11:manufacturer=piv_II;id=%01"
# Optional PIN configuration; this can be left out and PIN will be
# asked through the control interface
@@ -1540,15 +1869,26 @@ network={
}
-# Example MACsec configuration
-#network={
-# key_mgmt=IEEE8021X
-# eap=TTLS
-# phase2="auth=PAP"
-# anonymous_identity="anonymous@example.com"
-# identity="user@example.com"
-# password="secretr"
-# ca_cert="/etc/cert/ca.pem"
-# eapol_flags=0
-# macsec_policy=1
-#}
+# Example configuration using EAP-TTLS for authentication and key
+# generation for MACsec
+network={
+ key_mgmt=IEEE8021X
+ eap=TTLS
+ phase2="auth=PAP"
+ anonymous_identity="anonymous@example.com"
+ identity="user@example.com"
+ password="secretr"
+ ca_cert="/etc/cert/ca.pem"
+ eapol_flags=0
+ macsec_policy=1
+}
+
+# Example configuration for MACsec with preshared key
+network={
+ key_mgmt=NONE
+ eapol_flags=0
+ macsec_policy=1
+ mka_cak=0123456789ABCDEF0123456789ABCDEF
+ mka_ckn=6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435
+ mka_priority=128
+}
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
index 318768b..16e4db62 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h
@@ -9,6 +9,7 @@
#ifndef WPA_SUPPLICANT_I_H
#define WPA_SUPPLICANT_I_H
+#include "utils/bitfield.h"
#include "utils/list.h"
#include "common/defs.h"
#include "common/sae.h"
@@ -44,6 +45,7 @@ struct wpa_driver_associate_params;
struct ctrl_iface_priv;
struct ctrl_iface_global_priv;
struct wpas_dbus_priv;
+struct wpas_binder_priv;
/**
* struct wpa_interface - Parameters for wpa_supplicant_add_iface()
@@ -228,6 +230,17 @@ struct wpa_params {
char *conf_p2p_dev;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+ /**
+ * match_ifaces - Interface descriptions to match
+ */
+ struct wpa_interface *match_ifaces;
+
+ /**
+ * match_iface_count - Number of defined matching interfaces
+ */
+ int match_iface_count;
+#endif /* CONFIG_MATCH_IFACE */
};
struct p2p_srv_bonjour {
@@ -253,6 +266,7 @@ struct wpa_global {
struct wpa_params params;
struct ctrl_iface_global_priv *ctrl_iface;
struct wpas_dbus_priv *dbus;
+ struct wpas_binder_priv *binder;
void **drv_priv;
size_t drv_count;
struct os_time suspend_time;
@@ -278,10 +292,11 @@ struct wpa_global {
unsigned int p2p_24ghz_social_channels:1;
unsigned int pending_p2ps_group:1;
unsigned int pending_group_iface_for_p2ps:1;
+ unsigned int pending_p2ps_group_freq;
#ifdef CONFIG_WIFI_DISPLAY
int wifi_display;
-#define MAX_WFD_SUBELEMS 10
+#define MAX_WFD_SUBELEMS 12
struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
#endif /* CONFIG_WIFI_DISPLAY */
@@ -300,10 +315,14 @@ struct wpa_radio {
char name[16]; /* from driver_ops get_radio_name() or empty if not
* available */
unsigned int external_scan_running:1;
+ unsigned int num_active_works;
struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
struct dl_list work; /* struct wpa_radio_work::list entries */
};
+#define MAX_ACTIVE_WORKS 2
+
+
/**
* struct wpa_radio_work - Radio work item
*/
@@ -316,6 +335,7 @@ struct wpa_radio_work {
void *ctx;
unsigned int started:1;
struct os_reltime time;
+ unsigned int bands;
};
int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
@@ -325,6 +345,7 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
void radio_work_done(struct wpa_radio_work *work);
void radio_remove_works(struct wpa_supplicant *wpa_s,
const char *type, int remove_all);
+void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx);
void radio_work_check_next(struct wpa_supplicant *wpa_s);
struct wpa_radio_work *
radio_work_pending(struct wpa_supplicant *wpa_s, const char *type);
@@ -347,6 +368,9 @@ struct wpa_external_work {
unsigned int timeout;
};
+enum wpa_radio_work_band wpas_freq_to_band(int freq);
+unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs);
+
/**
* offchannel_send_action_result - Result of offchannel send Action frame
*/
@@ -371,11 +395,6 @@ struct wps_ap_info {
u8 uuid[WPS_UUID_LEN];
};
-struct wpa_ssid_value {
- u8 ssid[SSID_MAX_LEN];
- size_t ssid_len;
-};
-
#define WPA_FREQ_USED_BY_INFRA_STATION BIT(0)
#define WPA_FREQ_USED_BY_P2P_CLIENT BIT(1)
@@ -407,6 +426,12 @@ struct rrm_data {
/* next_neighbor_rep_token - Next request's dialog token */
u8 next_neighbor_rep_token;
+
+ /* token - Dialog token of the current radio measurement */
+ u8 token;
+
+ /* destination address of the current radio measurement request */
+ u8 dst_addr[ETH_ALEN];
};
enum wpa_supplicant_test_failure {
@@ -414,6 +439,44 @@ enum wpa_supplicant_test_failure {
WPAS_TEST_FAILURE_SCAN_TRIGGER,
};
+struct icon_entry {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ u8 dialog_token;
+ char *file_name;
+ u8 *image;
+ size_t image_len;
+};
+
+struct wpa_bss_tmp_disallowed {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ int rssi_threshold;
+};
+
+struct beacon_rep_data {
+ u8 token;
+ u8 last_indication;
+ struct wpa_driver_scan_params scan_params;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len;
+ u8 bssid[ETH_ALEN];
+ enum beacon_report_detail report_detail;
+ struct bitfield *eids;
+};
+
+
+struct external_pmksa_cache {
+ struct dl_list list;
+ void *pmksa_cache;
+};
+
+struct fils_hlp_req {
+ struct dl_list list;
+ u8 dst[ETH_ALEN];
+ struct wpabuf *pkt;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -427,15 +490,20 @@ struct wpa_supplicant {
struct wpa_radio *radio; /* shared radio context */
struct dl_list radio_list; /* list head: struct wpa_radio::ifaces */
struct wpa_supplicant *parent;
+ struct wpa_supplicant *p2pdev;
struct wpa_supplicant *next;
struct l2_packet_data *l2;
struct l2_packet_data *l2_br;
+ struct os_reltime roam_start;
+ struct os_reltime roam_time;
+ struct os_reltime session_start;
+ struct os_reltime session_length;
unsigned char own_addr[ETH_ALEN];
unsigned char perm_addr[ETH_ALEN];
char ifname[100];
-#ifdef CONFIG_CTRL_IFACE_DBUS
- char *dbus_path;
-#endif /* CONFIG_CTRL_IFACE_DBUS */
+#ifdef CONFIG_MATCH_IFACE
+ int matched;
+#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
char *dbus_new_path;
char *dbus_groupobj_path;
@@ -443,6 +511,9 @@ struct wpa_supplicant {
char *preq_notify_peer;
#endif /* CONFIG_AP */
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+#ifdef CONFIG_CTRL_IFACE_BINDER
+ const void *binder_object_key;
+#endif /* CONFIG_CTRL_IFACE_BINDER */
char bridge_ifname[16];
char *confname;
@@ -455,7 +526,8 @@ struct wpa_supplicant {
u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
* field contains the target BSSID. */
int reassociate; /* reassociation requested */
- int reassoc_same_bss; /* reassociating to the same bss */
+ unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
+ unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
int disconnected; /* all connections disabled; i.e., do no reassociate
* before this has been cleared */
struct wpa_ssid *current_ssid;
@@ -463,6 +535,8 @@ struct wpa_supplicant {
struct wpa_bss *current_bss;
int ap_ies_from_associnfo;
unsigned int assoc_freq;
+ u8 *last_con_fail_realm;
+ size_t last_con_fail_realm_len;
/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
int pairwise_cipher;
@@ -500,9 +574,10 @@ struct wpa_supplicant {
struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */
int sched_scan_timeout;
- int sched_scan_interval;
int first_sched_scan;
int sched_scan_timed_out;
+ struct sched_scan_plan *sched_scan_plans;
+ size_t sched_scan_plans_num;
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -533,6 +608,7 @@ struct wpa_supplicant {
struct wpa_radio_work *scan_work;
int scanning;
int sched_scanning;
+ unsigned int sched_scan_stop_req:1;
int new_connection;
int eapol_received; /* number of EAPOL packets received after the
@@ -597,6 +673,7 @@ struct wpa_supplicant {
struct os_reltime scan_min_time;
int scan_runs; /* number of scan runs since WPS was started */
int *next_scan_freqs;
+ int *select_network_scan_freqs;
int *manual_scan_freqs;
int *manual_sched_scan_freqs;
unsigned int manual_scan_passive:1;
@@ -610,9 +687,16 @@ struct wpa_supplicant {
int normal_scans; /* normal scans run before sched_scan */
int scan_for_connection; /* whether the scan request was triggered for
* finding a connection */
+ /*
+ * A unique cookie representing the vendor scan request. This cookie is
+ * returned from the driver interface. 0 indicates that there is no
+ * pending vendor scan request.
+ */
+ u64 curr_scan_cookie;
#define MAX_SCAN_ID 16
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
+ u8 next_scan_bssid[ETH_ALEN];
struct wpa_ssid_value *ssids_from_scan_req;
unsigned int num_ssids_from_scan_req;
@@ -634,6 +718,9 @@ struct wpa_supplicant {
int max_scan_ssids;
int max_sched_scan_ssids;
+ unsigned int max_sched_scan_plans;
+ unsigned int max_sched_scan_plan_interval;
+ unsigned int max_sched_scan_plan_iterations;
int sched_scan_supported;
unsigned int max_match_sets;
unsigned int max_remain_on_chan;
@@ -659,6 +746,12 @@ struct wpa_supplicant {
unsigned int mac_addr_changed:1;
unsigned int added_vif:1;
unsigned int wnmsleep_used:1;
+ unsigned int owe_transition_select:1;
+ unsigned int owe_transition_search:1;
+ unsigned int connection_set:1;
+ unsigned int connection_ht:1;
+ unsigned int connection_vht:1;
+ unsigned int connection_he:1;
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
@@ -669,13 +762,15 @@ struct wpa_supplicant {
int sta_uapsd;
int set_ap_uapsd;
int ap_uapsd;
+ int auth_alg;
+ u16 last_owe_group;
#ifdef CONFIG_SME
struct {
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int freq;
- u8 assoc_req_ie[200];
+ u8 assoc_req_ie[1500];
size_t assoc_req_ie_len;
int mfp;
int ft_used;
@@ -706,6 +801,8 @@ struct wpa_supplicant {
struct wpabuf *sae_token;
int sae_group_index;
unsigned int sae_pmksa_caching:1;
+ u16 seq_num;
+ struct external_auth ext_auth;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -723,7 +820,12 @@ struct wpa_supplicant {
int mesh_if_idx;
unsigned int mesh_if_created:1;
unsigned int mesh_ht_enabled:1;
- int mesh_auth_block_duration; /* sec */
+ unsigned int mesh_vht_enabled:1;
+ struct wpa_driver_mesh_join_params *mesh_params;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ /* struct external_pmksa_cache::list */
+ struct dl_list mesh_external_pmksa_cache;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
#endif /* CONFIG_MESH */
unsigned int off_channel_freq;
@@ -743,6 +845,7 @@ struct wpa_supplicant {
result);
unsigned int roc_waiting_drv_freq;
int action_tx_wait_time;
+ int action_tx_wait_time_used;
int p2p_mgmt;
@@ -810,11 +913,13 @@ struct wpa_supplicant {
unsigned int p2p_auto_join:1;
unsigned int p2p_auto_pd:1;
+ unsigned int p2p_go_do_acs:1;
unsigned int p2p_persistent_group:1;
unsigned int p2p_fallback_to_go_neg:1;
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
unsigned int p2p_go_vht:1;
+ unsigned int p2p_go_he:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
unsigned int group_formation_reported:1;
@@ -825,6 +930,7 @@ struct wpa_supplicant {
unsigned int p2p_disable_ip_addr_req:1;
unsigned int p2ps_method_config_any:1;
unsigned int p2p_cli_probe:1;
+ enum hostapd_hw_mode p2p_go_acs_band;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
@@ -845,6 +951,10 @@ struct wpa_supplicant {
int *p2p_group_common_freqs;
unsigned int p2p_group_common_freqs_num;
u8 p2ps_join_addr[ETH_ALEN];
+
+ unsigned int p2p_go_max_oper_chwidth;
+ unsigned int p2p_go_vht_center_freq2;
+ int p2p_lo_started;
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;
@@ -873,6 +983,7 @@ struct wpa_supplicant {
int best_overall_freq;
struct gas_query *gas;
+ struct gas_server *gas_server;
#ifdef CONFIG_INTERWORKING
unsigned int fetch_anqp_in_progress:1;
@@ -886,6 +997,7 @@ struct wpa_supplicant {
unsigned int fetch_osu_icon_in_progress:1;
struct wpa_bss *interworking_gas_bss;
unsigned int osu_icon_id;
+ struct dl_list icon_head; /* struct icon_entry */
struct osu_provider *osu_prov;
size_t osu_prov_count;
struct os_reltime osu_icon_fetch_start;
@@ -915,6 +1027,13 @@ struct wpa_supplicant {
/* WLAN_REASON_* reason codes. Negative if locally generated. */
int disconnect_reason;
+ /* WLAN_STATUS_* status codes from last received Authentication frame
+ * from the AP. */
+ u16 auth_status_code;
+
+ /* WLAN_STATUS_* status codes from (Re)Association Response frame. */
+ u16 assoc_status_code;
+
struct ext_password_data *ext_pw;
struct wpabuf *last_gas_resp, *prev_gas_resp;
@@ -927,6 +1046,7 @@ struct wpa_supplicant {
unsigned int wmm_ac_supported:1;
unsigned int ext_work_in_progress:1;
unsigned int own_disconnect_req:1;
+ unsigned int ignore_post_flush_scan_res:1;
#define MAC_ADDR_RAND_SCAN BIT(0)
#define MAC_ADDR_RAND_SCHED_SCAN BIT(1)
@@ -952,6 +1072,15 @@ struct wpa_supplicant {
struct neighbor_report *wnm_neighbor_report_elements;
struct os_reltime wnm_cand_valid_until;
u8 wnm_cand_from_bss[ETH_ALEN];
+ enum bss_trans_mgmt_status_code bss_tm_status;
+ struct wpabuf *coloc_intf_elems;
+ u8 coloc_intf_dialog_token;
+ u8 coloc_intf_auto_report;
+ u8 coloc_intf_timeout;
+#ifdef CONFIG_MBO
+ unsigned int wnm_mbo_trans_reason_present:1;
+ u8 wnm_mbo_transition_reason;
+#endif /* CONFIG_MBO */
#endif /* CONFIG_WNM */
#ifdef CONFIG_TESTING_GET_GTK
@@ -970,6 +1099,19 @@ struct wpa_supplicant {
struct l2_packet_data *l2_test;
unsigned int extra_roc_dur;
enum wpa_supplicant_test_failure test_failure;
+ char *get_pref_freq_list_override;
+ unsigned int reject_btm_req_reason;
+ unsigned int p2p_go_csa_on_inv:1;
+ unsigned int ignore_auth_resp:1;
+ unsigned int ignore_assoc_disallow:1;
+ unsigned int testing_resend_assoc:1;
+ struct wpabuf *sae_commit_override;
+ enum wpa_alg last_tk_alg;
+ u8 last_tk_addr[ETH_ALEN];
+ int last_tk_key_idx;
+ u8 last_tk[WPA_TK_MAX_LEN];
+ size_t last_tk_len;
+ struct wpabuf *last_assoc_req_wpa_ie;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -980,12 +1122,135 @@ struct wpa_supplicant {
u8 last_tspecs_count;
struct rrm_data rrm;
+ struct beacon_rep_data beacon_rep_data;
#ifdef CONFIG_FST
struct fst_iface *fst;
const struct wpabuf *fst_ies;
struct wpabuf *received_mb_ies;
#endif /* CONFIG_FST */
+
+#ifdef CONFIG_MBO
+ /* Multiband operation non-preferred channel */
+ struct wpa_mbo_non_pref_channel {
+ enum mbo_non_pref_chan_reason reason;
+ u8 oper_class;
+ u8 chan;
+ u8 preference;
+ } *non_pref_chan;
+ size_t non_pref_chan_num;
+ u8 mbo_wnm_token;
+ /**
+ * enable_oce - Enable OCE if it is enabled by user and device also
+ * supports OCE.
+ * User can enable OCE with wpa_config's 'oce' parameter as follows -
+ * - Set BIT(0) to enable OCE in non-AP STA mode.
+ * - Set BIT(1) to enable OCE in STA-CFON mode.
+ */
+ u8 enable_oce;
+#endif /* CONFIG_MBO */
+
+ /*
+ * This should be under CONFIG_MBO, but it is left out to allow using
+ * the bss_temp_disallowed list for other purposes as well.
+ */
+ struct dl_list bss_tmp_disallowed;
+
+ /*
+ * Content of a measurement report element with type 8 (LCI),
+ * own location.
+ */
+ struct wpabuf *lci;
+ struct os_reltime lci_time;
+
+ struct os_reltime beacon_rep_scan;
+
+ /* FILS HLP requests (struct fils_hlp_req) */
+ struct dl_list fils_hlp_req;
+
+ struct sched_scan_relative_params {
+ /**
+ * relative_rssi_set - Enable relatively preferred BSS reporting
+ *
+ * 0 = Disable reporting relatively preferred BSSs
+ * 1 = Enable reporting relatively preferred BSSs
+ */
+ int relative_rssi_set;
+
+ /**
+ * relative_rssi - Relative RSSI for reporting better BSSs
+ *
+ * Amount of RSSI by which a BSS should be better than the
+ * current connected BSS so that the new BSS can be reported
+ * to user space. This applies to sched_scan operations.
+ */
+ int relative_rssi;
+
+ /**
+ * relative_adjust_band - Band in which RSSI is to be adjusted
+ */
+ enum set_band relative_adjust_band;
+
+ /**
+ * relative_adjust_rssi - RSSI adjustment
+ *
+ * An amount of relative_adjust_rssi should be added to the
+ * BSSs that belong to the relative_adjust_band while comparing
+ * with other bands for BSS reporting.
+ */
+ int relative_adjust_rssi;
+ } srp;
+
+ /* RIC elements for FT protocol */
+ struct wpabuf *ric_ies;
+
+ int last_auth_timeout_sec;
+
+#ifdef CONFIG_DPP
+ struct dpp_global *dpp;
+ struct dpp_authentication *dpp_auth;
+ struct wpa_radio_work *dpp_listen_work;
+ unsigned int dpp_pending_listen_freq;
+ unsigned int dpp_listen_freq;
+ u8 dpp_allowed_roles;
+ int dpp_qr_mutual;
+ int dpp_netrole_ap;
+ int dpp_auth_ok_on_ack;
+ int dpp_in_response_listen;
+ int dpp_gas_client;
+ int dpp_gas_dialog_token;
+ u8 dpp_intro_bssid[ETH_ALEN];
+ void *dpp_intro_network;
+ struct dpp_pkex *dpp_pkex;
+ struct dpp_bootstrap_info *dpp_pkex_bi;
+ char *dpp_pkex_code;
+ char *dpp_pkex_identifier;
+ char *dpp_pkex_auth_cmd;
+ char *dpp_configurator_params;
+ struct os_reltime dpp_last_init;
+ struct os_reltime dpp_init_iter_start;
+ unsigned int dpp_init_max_tries;
+ unsigned int dpp_init_retry_time;
+ unsigned int dpp_resp_wait_time;
+ unsigned int dpp_resp_max_tries;
+ unsigned int dpp_resp_retry_time;
+#ifdef CONFIG_DPP2
+ struct dpp_pfs *dpp_pfs;
+#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_TESTING_OPTIONS
+ char *dpp_config_obj_override;
+ char *dpp_discovery_override;
+ char *dpp_groups_override;
+ unsigned int dpp_ignore_netaccesskey_mismatch:1;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_FILS
+ unsigned int disable_fils:1;
+#endif /* CONFIG_FILS */
+ unsigned int ieee80211ac:1;
+ unsigned int enabled_4addr_mode:1;
+ unsigned int multi_bss_support:1;
};
@@ -1018,6 +1283,7 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s);
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec);
+void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff);
void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
enum wpa_states state);
@@ -1027,6 +1293,8 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code);
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1051,6 +1319,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s);
void wpa_show_license(void);
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+ const char *ifname);
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
struct wpa_interface *iface,
struct wpa_supplicant *parent);
@@ -1071,6 +1341,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void fils_connection_failure(struct wpa_supplicant *wpa_s);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason);
@@ -1080,6 +1351,7 @@ int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
size_t ssid_len);
void wpas_request_connection(struct wpa_supplicant *wpa_s);
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s);
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
@@ -1089,14 +1361,59 @@ void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
const u8 *report, size_t report_len);
int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
+ const struct wpa_ssid_value *ssid,
+ int lci, int civic,
void (*cb)(void *ctx,
struct wpabuf *neighbor_rep),
void *cb_ctx);
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *dst,
+ const u8 *frame, size_t len);
void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
const u8 *src,
const u8 *frame, size_t len,
int rssi);
+void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s);
+int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res,
+ struct scan_info *info);
+void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
+
+
+/* MBO functions */
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
+ int add_oce_capa);
+const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
+const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
+ enum mbo_attr_id attr);
+int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
+ const char *non_pref_chan);
+void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
+void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
+ size_t len);
+size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
+ size_t len,
+ enum mbo_transition_reject_reason reason);
+void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa);
+struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, u32 mbo_subtypes);
+void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, const u8 *sa,
+ const u8 *data, size_t slen);
+void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s);
+
+/* op_classes.c */
+enum chan_allowed {
+ NOT_ALLOWED, NO_IR, ALLOWED
+};
+
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
+ u8 bw);
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ int freq, u8 *pos, size_t len);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -1128,6 +1445,9 @@ void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid **selected_ssid);
+int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
+ struct channel_list_changed *info);
/* eap_register.c */
int eap_register_methods(void);
@@ -1159,6 +1479,12 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx);
+void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s);
+struct wpa_supplicant * wpas_vendor_elem(struct wpa_supplicant *wpa_s,
+ enum wpa_vendor_elem_frame frame);
+int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
+ const u8 *elem, size_t len);
+
#ifdef CONFIG_FST
struct fst_wpa_obj;
@@ -1168,4 +1494,28 @@ void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_FST */
+int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd);
+
+struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+ u16 num_modes, enum hostapd_hw_mode mode);
+
+void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ unsigned int sec, int rssi_threshold);
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss);
+void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s);
+
+struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
+ int i, struct wpa_bss *bss,
+ struct wpa_ssid *group,
+ int only_first_ssid, int debug_print);
+
+int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type if_type,
+ unsigned int *num,
+ unsigned int *freq_list);
+
+int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
+int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf b/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf
index f3f2a64..f55227f 100644
--- a/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf
+++ b/contrib/wpa/wpa_supplicant/wpa_supplicant_template.conf
@@ -4,3 +4,4 @@ eapol_version=1
ap_scan=1
fast_reauth=1
pmf=1
+p2p_add_cli_chan=1
diff --git a/contrib/wpa/wpa_supplicant/wpas_glue.c b/contrib/wpa/wpa_supplicant/wpas_glue.c
index 29c22ba..449e04a 100644
--- a/contrib/wpa/wpa_supplicant/wpas_glue.c
+++ b/contrib/wpa/wpa_supplicant/wpas_glue.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "eapol_supp/eapol_supp_sm.h"
+#include "eap_peer/eap.h"
#include "rsn_supp/wpa.h"
#include "eloop.h"
#include "config.h"
@@ -145,6 +146,8 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
* extra copy here */
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP ||
wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
/* Current SSID is not using IEEE 802.1X/EAP, so drop possible
* EAPOL frames (mainly, EAPOL-Start) from EAPOL state
@@ -293,7 +296,7 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
}
if (result != EAPOL_SUPP_RESULT_SUCCESS ||
- !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return;
if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
@@ -499,6 +502,16 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
wpa_s->last_gtk_len = key_len;
}
#endif /* CONFIG_TESTING_GET_GTK */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (addr && !is_broadcast_ether_addr(addr)) {
+ wpa_s->last_tk_alg = alg;
+ os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
+ wpa_s->last_tk_key_idx = key_idx;
+ if (key)
+ os_memcpy(wpa_s->last_tk, key, key_len);
+ wpa_s->last_tk_len = key_len;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
key, key_len);
}
@@ -513,17 +526,74 @@ static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
}
-static int wpa_supplicant_add_pmkid(void *wpa_s,
- const u8 *bssid, const u8 *pmkid)
+static struct wpa_ssid * wpas_get_network_ctx(struct wpa_supplicant *wpa_s,
+ void *network_ctx)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (network_ctx == ssid)
+ return ssid;
+ }
+
+ return NULL;
+}
+
+
+static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
+ const u8 *bssid, const u8 *pmkid,
+ const u8 *fils_cache_id,
+ const u8 *pmk, size_t pmk_len)
{
- return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
+ struct wpa_supplicant *wpa_s = _wpa_s;
+ struct wpa_ssid *ssid;
+ struct wpa_pmkid_params params;
+
+ os_memset(&params, 0, sizeof(params));
+ ssid = wpas_get_network_ctx(wpa_s, network_ctx);
+ if (ssid)
+ wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d",
+ MAC2STR(bssid), ssid->id);
+ if (ssid && fils_cache_id) {
+ params.ssid = ssid->ssid;
+ params.ssid_len = ssid->ssid_len;
+ params.fils_cache_id = fils_cache_id;
+ } else {
+ params.bssid = bssid;
+ }
+
+ params.pmkid = pmkid;
+ params.pmk = pmk;
+ params.pmk_len = pmk_len;
+
+ return wpa_drv_add_pmkid(wpa_s, &params);
}
-static int wpa_supplicant_remove_pmkid(void *wpa_s,
- const u8 *bssid, const u8 *pmkid)
+static int wpa_supplicant_remove_pmkid(void *_wpa_s, void *network_ctx,
+ const u8 *bssid, const u8 *pmkid,
+ const u8 *fils_cache_id)
{
- return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
+ struct wpa_supplicant *wpa_s = _wpa_s;
+ struct wpa_ssid *ssid;
+ struct wpa_pmkid_params params;
+
+ os_memset(&params, 0, sizeof(params));
+ ssid = wpas_get_network_ctx(wpa_s, network_ctx);
+ if (ssid)
+ wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_REMOVED MACSTR " %d",
+ MAC2STR(bssid), ssid->id);
+ if (ssid && fils_cache_id) {
+ params.ssid = ssid->ssid;
+ params.ssid_len = ssid->ssid_len;
+ params.fils_cache_id = fils_cache_id;
+ } else {
+ params.bssid = bssid;
+ }
+
+ params.pmkid = pmkid;
+
+ return wpa_drv_remove_pmkid(wpa_s, &params);
}
@@ -739,6 +809,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
return WPA_CTRL_REQ_SIM;
else if (os_strcmp(field, "PSK_PASSPHRASE") == 0)
return WPA_CTRL_REQ_PSK_PASSPHRASE;
+ else if (os_strcmp(field, "EXT_CERT_CHECK") == 0)
+ return WPA_CTRL_REQ_EXT_CERT_CHECK;
return WPA_CTRL_REQ_UNKNOWN;
}
@@ -782,6 +854,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
*txt = "PSK or passphrase";
ret = "PSK_PASSPHRASE";
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ *txt = "External server certificate validation";
+ ret = "EXT_CERT_CHECK";
+ break;
default:
break;
}
@@ -837,6 +913,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
if (ssid == NULL)
return;
+ if (field == WPA_CTRL_REQ_EXT_CERT_CHECK)
+ ssid->eap.pending_ext_cert_check = PENDING_CHECK;
wpas_notify_network_request(wpa_s, ssid, field, default_txt);
field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
@@ -857,12 +935,13 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
#ifdef CONFIG_EAP_PROXY
+
static void wpa_supplicant_eap_proxy_cb(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
size_t len;
- wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
+ wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
wpa_s->imsi, &len);
if (wpa_s->mnc_len > 0) {
wpa_s->imsi[len] = '\0';
@@ -872,6 +951,52 @@ static void wpa_supplicant_eap_proxy_cb(void *ctx)
wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
}
}
+
+
+static void wpa_sm_sim_state_error_handler(struct wpa_supplicant *wpa_s)
+{
+ int i;
+ struct wpa_ssid *ssid;
+ const struct eap_method_type *eap_methods;
+
+ if (!wpa_s->conf)
+ return;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ eap_methods = ssid->eap.eap_methods;
+ if (!eap_methods)
+ continue;
+
+ for (i = 0; eap_methods[i].method != EAP_TYPE_NONE; i++) {
+ if (eap_methods[i].vendor == EAP_VENDOR_IETF &&
+ (eap_methods[i].method == EAP_TYPE_SIM ||
+ eap_methods[i].method == EAP_TYPE_AKA ||
+ eap_methods[i].method == EAP_TYPE_AKA_PRIME)) {
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+ break;
+ }
+ }
+ }
+}
+
+
+static void
+wpa_supplicant_eap_proxy_notify_sim_status(void *ctx,
+ enum eap_proxy_sim_state sim_state)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpa_printf(MSG_DEBUG, "eap_proxy: SIM card status %u", sim_state);
+ switch (sim_state) {
+ case SIM_STATE_ERROR:
+ wpa_sm_sim_state_error_handler(wpa_s);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "eap_proxy: SIM card status unknown");
+ break;
+ }
+}
+
#endif /* CONFIG_EAP_PROXY */
@@ -913,6 +1038,14 @@ static void wpa_supplicant_status_cb(void *ctx, const char *status,
}
+static void wpa_supplicant_eap_error_cb(void *ctx, int error_code)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpas_notify_eap_error(wpa_s, error_code);
+}
+
+
static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -982,12 +1115,15 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
#ifdef CONFIG_EAP_PROXY
ctx->eap_proxy_cb = wpa_supplicant_eap_proxy_cb;
+ ctx->eap_proxy_notify_sim_status =
+ wpa_supplicant_eap_proxy_notify_sim_status;
#endif /* CONFIG_EAP_PROXY */
ctx->port_cb = wpa_supplicant_port_cb;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
ctx->status_cb = wpa_supplicant_status_cb;
+ ctx->eap_error_cb = wpa_supplicant_eap_error_cb;
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
@@ -1004,6 +1140,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
#ifndef CONFIG_NO_WPA
+
static void wpa_supplicant_set_rekey_offload(void *ctx,
const u8 *kek, size_t kek_len,
const u8 *kck, size_t kck_len,
@@ -1013,7 +1150,6 @@ static void wpa_supplicant_set_rekey_offload(void *ctx,
wpa_drv_set_rekey_info(wpa_s, kek, kek_len, kck, kck_len, replay_ctr);
}
-#endif /* CONFIG_NO_WPA */
static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
@@ -1030,6 +1166,35 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
}
+static void wpa_supplicant_fils_hlp_rx(void *ctx, const u8 *dst, const u8 *src,
+ const u8 *pkt, size_t pkt_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ char *hex;
+ size_t hexlen;
+
+ hexlen = pkt_len * 2 + 1;
+ hex = os_malloc(hexlen);
+ if (!hex)
+ return;
+ wpa_snprintf_hex(hex, hexlen, pkt, pkt_len);
+ wpa_msg(wpa_s, MSG_INFO, FILS_HLP_RX "dst=" MACSTR " src=" MACSTR
+ " frame=%s", MAC2STR(dst), MAC2STR(src), hex);
+ os_free(hex);
+}
+
+
+static int wpa_supplicant_channel_info(void *_wpa_s,
+ struct wpa_channel_info *ci)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+
+ return wpa_drv_channel_info(wpa_s, ci);
+}
+
+#endif /* CONFIG_NO_WPA */
+
+
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
@@ -1076,6 +1241,8 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_TDLS */
ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
+ ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx;
+ ctx->channel_info = wpa_supplicant_channel_info;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
@@ -1097,7 +1264,6 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
if (ssid) {
os_memset(&conf, 0, sizeof(conf));
conf.network_ctx = ssid;
- conf.peerkey_enabled = ssid->peerkey;
conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
#ifdef IEEE8021X_EAPOL
conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
@@ -1124,6 +1290,12 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
}
}
#endif /* CONFIG_P2P */
+ conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation;
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(wpa_s->key_mgmt))
+ conf.fils_cache_id =
+ wpa_bss_get_fils_cache_id(wpa_s->current_bss);
+#endif /* CONFIG_FILS */
}
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
}
diff --git a/contrib/wpa/wpa_supplicant/wpas_kay.c b/contrib/wpa/wpa_supplicant/wpas_kay.c
index 354decf..41477d5 100644
--- a/contrib/wpa/wpa_supplicant/wpas_kay.c
+++ b/contrib/wpa/wpa_supplicant/wpas_kay.c
@@ -5,7 +5,7 @@
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
-#include <openssl/ssl.h>
+
#include "utils/includes.h"
#include "utils/common.h"
@@ -38,22 +38,33 @@ static int wpas_macsec_deinit(void *priv)
}
+static int wpas_macsec_get_capability(void *priv, enum macsec_cap *cap)
+{
+ return wpa_drv_macsec_get_capability(priv, cap);
+}
+
+
static int wpas_enable_protect_frames(void *wpa_s, Boolean enabled)
{
return wpa_drv_enable_protect_frames(wpa_s, enabled);
}
+static int wpas_enable_encrypt(void *wpa_s, Boolean enabled)
+{
+ return wpa_drv_enable_encrypt(wpa_s, enabled);
+}
+
+
static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
{
return wpa_drv_set_replay_protect(wpa_s, enabled, window);
}
-static int wpas_set_current_cipher_suite(void *wpa_s, const u8 *cs,
- size_t cs_len)
+static int wpas_set_current_cipher_suite(void *wpa_s, u64 cs)
{
- return wpa_drv_set_current_cipher_suite(wpa_s, cs, cs_len);
+ return wpa_drv_set_current_cipher_suite(wpa_s, cs);
}
@@ -63,30 +74,27 @@ static int wpas_enable_controlled_port(void *wpa_s, Boolean enabled)
}
-static int wpas_get_receive_lowest_pn(void *wpa_s, u32 channel,
- u8 an, u32 *lowest_pn)
+static int wpas_get_receive_lowest_pn(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_get_receive_lowest_pn(wpa_s, channel, an, lowest_pn);
+ return wpa_drv_get_receive_lowest_pn(wpa_s, sa);
}
-static int wpas_get_transmit_next_pn(void *wpa_s, u32 channel,
- u8 an, u32 *next_pn)
+static int wpas_get_transmit_next_pn(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_get_transmit_next_pn(wpa_s, channel, an, next_pn);
+ return wpa_drv_get_transmit_next_pn(wpa_s, sa);
}
-static int wpas_set_transmit_next_pn(void *wpa_s, u32 channel,
- u8 an, u32 next_pn)
+static int wpas_set_transmit_next_pn(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_set_transmit_next_pn(wpa_s, channel, an, next_pn);
+ return wpa_drv_set_transmit_next_pn(wpa_s, sa);
}
-static int wpas_get_available_receive_sc(void *wpa_s, u32 *channel)
+static int wpas_set_receive_lowest_pn(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_get_available_receive_sc(wpa_s, channel);
+ return wpa_drv_set_receive_lowest_pn(wpa_s, sa);
}
@@ -104,81 +112,79 @@ static unsigned int conf_offset_val(enum confidentiality_offset co)
}
-static int wpas_create_receive_sc(void *wpa_s, u32 channel,
- struct ieee802_1x_mka_sci *sci,
+static int wpas_create_receive_sc(void *wpa_s, struct receive_sc *sc,
enum validate_frames vf,
enum confidentiality_offset co)
{
- return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr, sci->port,
- conf_offset_val(co), vf);
+ return wpa_drv_create_receive_sc(wpa_s, sc, conf_offset_val(co), vf);
}
-static int wpas_delete_receive_sc(void *wpa_s, u32 channel)
+static int wpas_delete_receive_sc(void *wpa_s, struct receive_sc *sc)
{
- return wpa_drv_delete_receive_sc(wpa_s, channel);
+ return wpa_drv_delete_receive_sc(wpa_s, sc);
}
-static int wpas_create_receive_sa(void *wpa_s, u32 channel, u8 an,
- u32 lowest_pn, const u8 *sak)
+static int wpas_create_receive_sa(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_create_receive_sa(wpa_s, channel, an, lowest_pn, sak);
+ return wpa_drv_create_receive_sa(wpa_s, sa);
}
-static int wpas_enable_receive_sa(void *wpa_s, u32 channel, u8 an)
+static int wpas_delete_receive_sa(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_enable_receive_sa(wpa_s, channel, an);
+ return wpa_drv_delete_receive_sa(wpa_s, sa);
}
-static int wpas_disable_receive_sa(void *wpa_s, u32 channel, u8 an)
+static int wpas_enable_receive_sa(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_disable_receive_sa(wpa_s, channel, an);
+ return wpa_drv_enable_receive_sa(wpa_s, sa);
}
-static int wpas_get_available_transmit_sc(void *wpa_s, u32 *channel)
+static int wpas_disable_receive_sa(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_get_available_transmit_sc(wpa_s, channel);
+ return wpa_drv_disable_receive_sa(wpa_s, sa);
}
static int
-wpas_create_transmit_sc(void *wpa_s, u32 channel,
- const struct ieee802_1x_mka_sci *sci,
+wpas_create_transmit_sc(void *wpa_s, struct transmit_sc *sc,
enum confidentiality_offset co)
{
- return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr, sci->port,
- conf_offset_val(co));
+ return wpa_drv_create_transmit_sc(wpa_s, sc, conf_offset_val(co));
}
-static int wpas_delete_transmit_sc(void *wpa_s, u32 channel)
+static int wpas_delete_transmit_sc(void *wpa_s, struct transmit_sc *sc)
{
- return wpa_drv_delete_transmit_sc(wpa_s, channel);
+ return wpa_drv_delete_transmit_sc(wpa_s, sc);
}
-static int wpas_create_transmit_sa(void *wpa_s, u32 channel, u8 an,
- u32 next_pn, Boolean confidentiality,
- const u8 *sak)
+static int wpas_create_transmit_sa(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_create_transmit_sa(wpa_s, channel, an, next_pn,
- confidentiality, sak);
+ return wpa_drv_create_transmit_sa(wpa_s, sa);
}
-static int wpas_enable_transmit_sa(void *wpa_s, u32 channel, u8 an)
+static int wpas_delete_transmit_sa(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_enable_transmit_sa(wpa_s, channel, an);
+ return wpa_drv_delete_transmit_sa(wpa_s, sa);
}
-static int wpas_disable_transmit_sa(void *wpa_s, u32 channel, u8 an)
+static int wpas_enable_transmit_sa(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_disable_transmit_sa(wpa_s, channel, an);
+ return wpa_drv_enable_transmit_sa(wpa_s, sa);
+}
+
+
+static int wpas_disable_transmit_sa(void *wpa_s, struct transmit_sa *sa)
+{
+ return wpa_drv_disable_transmit_sa(wpa_s, sa);
}
@@ -193,7 +199,14 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
if (!ssid || ssid->macsec_policy == 0)
return 0;
- policy = ssid->macsec_policy == 1 ? SHOULD_SECURE : DO_NOT_SECURE;
+ if (ssid->macsec_policy == 1) {
+ if (ssid->macsec_integ_only == 1)
+ policy = SHOULD_SECURE;
+ else
+ policy = SHOULD_ENCRYPT;
+ } else {
+ policy = DO_NOT_SECURE;
+ }
kay_ctx = os_zalloc(sizeof(*kay_ctx));
if (!kay_ctx)
@@ -203,32 +216,36 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
kay_ctx->macsec_init = wpas_macsec_init;
kay_ctx->macsec_deinit = wpas_macsec_deinit;
+ kay_ctx->macsec_get_capability = wpas_macsec_get_capability;
kay_ctx->enable_protect_frames = wpas_enable_protect_frames;
+ kay_ctx->enable_encrypt = wpas_enable_encrypt;
kay_ctx->set_replay_protect = wpas_set_replay_protect;
kay_ctx->set_current_cipher_suite = wpas_set_current_cipher_suite;
kay_ctx->enable_controlled_port = wpas_enable_controlled_port;
kay_ctx->get_receive_lowest_pn = wpas_get_receive_lowest_pn;
kay_ctx->get_transmit_next_pn = wpas_get_transmit_next_pn;
kay_ctx->set_transmit_next_pn = wpas_set_transmit_next_pn;
- kay_ctx->get_available_receive_sc = wpas_get_available_receive_sc;
+ kay_ctx->set_receive_lowest_pn = wpas_set_receive_lowest_pn;
kay_ctx->create_receive_sc = wpas_create_receive_sc;
kay_ctx->delete_receive_sc = wpas_delete_receive_sc;
kay_ctx->create_receive_sa = wpas_create_receive_sa;
+ kay_ctx->delete_receive_sa = wpas_delete_receive_sa;
kay_ctx->enable_receive_sa = wpas_enable_receive_sa;
kay_ctx->disable_receive_sa = wpas_disable_receive_sa;
- kay_ctx->get_available_transmit_sc = wpas_get_available_transmit_sc;
kay_ctx->create_transmit_sc = wpas_create_transmit_sc;
kay_ctx->delete_transmit_sc = wpas_delete_transmit_sc;
kay_ctx->create_transmit_sa = wpas_create_transmit_sa;
+ kay_ctx->delete_transmit_sa = wpas_delete_transmit_sa;
kay_ctx->enable_transmit_sa = wpas_enable_transmit_sa;
kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa;
- res = ieee802_1x_kay_init(kay_ctx, policy, wpa_s->ifname,
+ res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_replay_protect,
+ ssid->macsec_replay_window, ssid->macsec_port,
+ ssid->mka_priority, wpa_s->ifname,
wpa_s->own_addr);
- if (res == NULL) {
- os_free(kay_ctx);
+ /* ieee802_1x_kay_init() frees kay_ctx on failure */
+ if (res == NULL)
return -1;
- }
wpa_s->kay = res;
@@ -259,7 +276,7 @@ static int ieee802_1x_auth_get_session_id(struct wpa_supplicant *wpa_s,
return -1;
}
- need_len = 1 + 2 * SSL3_RANDOM_SIZE;
+ need_len = 1 + 2 * 32 /* random size */;
if (need_len > id_len) {
wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
return -1;
@@ -340,8 +357,8 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
/* Derive CAK from MSK */
cak->len = DEFAULT_KEY_LEN;
- if (ieee802_1x_cak_128bits_aes_cmac(msk->key, wpa_s->own_addr,
- peer_addr, cak->key)) {
+ if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, wpa_s->own_addr,
+ peer_addr, cak->key, cak->len)) {
wpa_printf(MSG_ERROR,
"IEEE 802.1X: Deriving CAK failed");
goto fail;
@@ -350,9 +367,8 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
/* Derive CKN from MSK */
ckn->len = DEFAULT_CKN_LEN;
- if (ieee802_1x_ckn_128bits_aes_cmac(msk->key, wpa_s->own_addr,
- peer_addr, sid, sid_len,
- ckn->name)) {
+ if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, wpa_s->own_addr,
+ peer_addr, sid, sid_len, ckn->name)) {
wpa_printf(MSG_ERROR,
"IEEE 802.1X: Deriving CKN failed");
goto fail;
@@ -376,3 +392,49 @@ fail:
return res;
}
+
+
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct mka_key *cak;
+ struct mka_key_name *ckn;
+ void *res = NULL;
+
+ if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
+ goto end;
+
+ ckn = os_zalloc(sizeof(*ckn));
+ if (!ckn)
+ goto end;
+
+ cak = os_zalloc(sizeof(*cak));
+ if (!cak)
+ goto free_ckn;
+
+ if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0 || !wpa_s->kay)
+ goto free_cak;
+
+ if (wpa_s->kay->policy == DO_NOT_SECURE)
+ goto dealloc;
+
+ cak->len = ssid->mka_cak_len;
+ os_memcpy(cak->key, ssid->mka_cak, cak->len);
+
+ ckn->len = ssid->mka_ckn_len;
+ os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
+
+ res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);
+ if (res)
+ goto free_cak;
+
+dealloc:
+ /* Failed to create MKA */
+ ieee802_1x_dealloc_kay_sm(wpa_s);
+free_cak:
+ os_free(cak);
+free_ckn:
+ os_free(ckn);
+end:
+ return res;
+}
diff --git a/contrib/wpa/wpa_supplicant/wpas_kay.h b/contrib/wpa/wpa_supplicant/wpas_kay.h
index b7236d0..81f8e0c 100644
--- a/contrib/wpa/wpa_supplicant/wpas_kay.h
+++ b/contrib/wpa/wpa_supplicant/wpas_kay.h
@@ -17,6 +17,9 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
const u8 *peer_addr);
void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s);
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+
#else /* CONFIG_MACSEC */
static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s,
@@ -36,6 +39,13 @@ static inline void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s)
{
}
+static inline void *
+ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ return 0;
+}
+
#endif /* CONFIG_MACSEC */
#endif /* WPAS_KAY_H */
diff --git a/contrib/wpa/wpa_supplicant/wpas_module_tests.c b/contrib/wpa/wpa_supplicant/wpas_module_tests.c
index 6af1678..4e37591 100644
--- a/contrib/wpa/wpa_supplicant/wpas_module_tests.c
+++ b/contrib/wpa/wpa_supplicant/wpas_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "wpa_supplicant_i.h"
#include "blacklist.h"
@@ -79,30 +80,18 @@ int wpas_module_tests(void)
ret = -1;
#ifdef CONFIG_WPS
- {
- int wps_module_tests(void);
- if (wps_module_tests() < 0)
- ret = -1;
- }
+ if (wps_module_tests() < 0)
+ ret = -1;
#endif /* CONFIG_WPS */
- {
- int utils_module_tests(void);
- if (utils_module_tests() < 0)
- ret = -1;
- }
-
- {
- int common_module_tests(void);
- if (common_module_tests() < 0)
- ret = -1;
- }
-
- {
- int crypto_module_tests(void);
- if (crypto_module_tests() < 0)
- ret = -1;
- }
+ if (utils_module_tests() < 0)
+ ret = -1;
+
+ if (common_module_tests() < 0)
+ ret = -1;
+
+ if (crypto_module_tests() < 0)
+ ret = -1;
return ret;
}
diff --git a/contrib/wpa/wpa_supplicant/wps_supplicant.c b/contrib/wpa/wpa_supplicant/wps_supplicant.c
index 60f761c..0579274 100644
--- a/contrib/wpa/wpa_supplicant/wps_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/wps_supplicant.c
@@ -203,6 +203,9 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
if (ssid->ssid == NULL)
return;
bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
+ if (!bss)
+ bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+ ssid->ssid, ssid->ssid_len);
if (bss == NULL) {
wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
"table - use credential as-is");
@@ -490,6 +493,16 @@ static int wpa_supplicant_wps_cred(void *ctx,
ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
ssid->group_cipher |= WPA_CIPHER_GCMP;
}
+ if (wpa_s->drv_capa_known &&
+ (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256)) {
+ ssid->pairwise_cipher |= WPA_CIPHER_GCMP_256;
+ ssid->group_cipher |= WPA_CIPHER_GCMP_256;
+ }
+ if (wpa_s->drv_capa_known &&
+ (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256)) {
+ ssid->pairwise_cipher |= WPA_CIPHER_CCMP_256;
+ ssid->group_cipher |= WPA_CIPHER_CCMP_256;
+ }
break;
}
@@ -517,11 +530,18 @@ static int wpa_supplicant_wps_cred(void *ctx,
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+ if (wpa_s->conf->wps_cred_add_sae &&
+ cred->key_len != 2 * PMK_LEN) {
+ ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
+#ifdef CONFIG_IEEE80211W
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+#endif /* CONFIG_IEEE80211W */
+ }
ssid->proto = WPA_PROTO_RSN;
break;
}
- if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
if (cred->key_len == 2 * PMK_LEN) {
if (hexstr2bin((const char *) cred->key, ssid->psk,
PMK_LEN)) {
@@ -583,8 +603,8 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
m2d->dev_password_id, m2d->config_error);
wpas_notify_wps_event_m2d(wpa_s, m2d);
#ifdef CONFIG_P2P
- if (wpa_s->parent && wpa_s->parent != wpa_s) {
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) {
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D
"dev_password_id=%d config_error=%d",
m2d->dev_password_id, m2d->config_error);
}
@@ -617,8 +637,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error, fail->error_indication,
wps_ei_str(fail->error_indication));
- if (wpa_s->parent && wpa_s->parent != wpa_s)
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error,
fail->error_indication,
@@ -627,8 +647,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d",
fail->msg, fail->config_error);
- if (wpa_s->parent && wpa_s->parent != wpa_s)
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d",
fail->msg, fail->config_error);
}
@@ -683,6 +703,13 @@ static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
}
+int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+{
+ return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb,
+ wpa_s, NULL);
+}
+
+
static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
{
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
@@ -1020,10 +1047,9 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
continue;
os_free(ssid->ssid);
- ssid->ssid = os_malloc(bss->ssid_len);
+ ssid->ssid = os_memdup(bss->ssid, bss->ssid_len);
if (ssid->ssid == NULL)
break;
- os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
ssid->ssid_len = bss->ssid_len;
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
"scan results",
@@ -1118,9 +1144,10 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
- int p2p_group)
+ int p2p_group, int multi_ap_backhaul_sta)
{
struct wpa_ssid *ssid;
+ char phase1[32];
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -1135,6 +1162,13 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
return -1;
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ /*
+ * When starting a regular WPS process (not P2P group formation)
+ * the registrar/final station can be either AP or PCP
+ * so use a "don't care" value for the pbss flag.
+ */
+ if (!p2p_group)
+ ssid->pbss = 2;
#ifdef CONFIG_P2P
if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
@@ -1142,15 +1176,24 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
ssid->ssid_len = wpa_s->go_params->ssid_len;
os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
ssid->ssid_len);
+ if (wpa_s->go_params->freq > 56160) {
+ /* P2P in 60 GHz uses PBSS */
+ ssid->pbss = 1;
+ }
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
}
#endif /* CONFIG_P2P */
- if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
+ os_snprintf(phase1, sizeof(phase1), "pbc=1%s",
+ multi_ap_backhaul_sta ? " multi_ap=1" : "");
+ if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0)
return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
+ if (multi_ap_backhaul_sta)
+ ssid->multi_ap_backhaul_sta = 1;
+ wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
@@ -1186,6 +1229,13 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
}
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ /*
+ * When starting a regular WPS process (not P2P group formation)
+ * the registrar/final station can be either AP or PCP
+ * so use a "don't care" value for the pbss flag.
+ */
+ if (!p2p_group)
+ ssid->pbss = 2;
if (ssid_val) {
ssid->ssid = os_malloc(ssid_len);
if (ssid->ssid) {
@@ -1209,6 +1259,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
ssid->ssid_len = wpa_s->go_params->ssid_len;
os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
ssid->ssid_len);
+ if (wpa_s->go_params->freq > 56160) {
+ /* P2P in 60 GHz uses PBSS */
+ ssid->pbss = 1;
+ }
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1221,7 +1275,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s,
os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
dev_pw_id, hash);
} else {
- rpin = wps_generate_pin();
+ if (wps_generate_pin(&rpin) < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN");
+ return -1;
+ }
os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
rpin, dev_pw_id, hash);
}
@@ -1449,6 +1506,9 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
wpa_s->global->ifaces->wps->uuid,
WPS_UUID_LEN);
src = "from the first interface";
+ } else if (wpa_s->conf->auto_uuid == 1) {
+ uuid_random(wps->uuid);
+ src = "based on random data";
} else {
uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
src = "based on MAC address";
diff --git a/contrib/wpa/wpa_supplicant/wps_supplicant.h b/contrib/wpa/wpa_supplicant/wps_supplicant.h
index 3c25ca8..0fbc851 100644
--- a/contrib/wpa/wpa_supplicant/wps_supplicant.h
+++ b/contrib/wpa/wpa_supplicant/wps_supplicant.h
@@ -30,7 +30,7 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid);
int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
- int p2p_group);
+ int p2p_group, int multi_ap_backhaul_sta);
int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin, int p2p_group, u16 dev_pw_id);
void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s);
@@ -85,6 +85,7 @@ int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s);
#else /* CONFIG_WPS */
@@ -147,6 +148,12 @@ static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
{
}
+static inline int
+wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
#endif /* CONFIG_WPS */
#endif /* WPS_SUPPLICANT_H */
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
index c35cea9..8e281d9 100644
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -487,6 +487,7 @@ fast_syscall_common:
testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%rax)
jne 3f
call handle_ibrs_exit
+ callq *mds_handler
/* Restore preserved registers. */
MEXITCOUNT
movq TF_RDI(%rsp),%rdi /* bonus; preserve arg 1 */
@@ -1121,6 +1122,7 @@ ld_regs:
jz 2f /* keep running with kernel GS.base */
cli
call handle_ibrs_exit_rs
+ callq *mds_handler
cmpb $0,pti
je 1f
pushq %rdx
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
index 28f584f..fd45d22 100644
--- a/sys/amd64/amd64/genassym.c
+++ b/sys/amd64/amd64/genassym.c
@@ -230,6 +230,9 @@ ASSYM(PC_SAVED_UCR3, offsetof(struct pcpu, pc_saved_ucr3));
ASSYM(PC_PTI_STACK, offsetof(struct pcpu, pc_pti_stack));
ASSYM(PC_PTI_STACK_SZ, PC_PTI_STACK_SZ);
ASSYM(PC_IBPB_SET, offsetof(struct pcpu, pc_ibpb_set));
+ASSYM(PC_MDS_TMP, offsetof(struct pcpu, pc_mds_tmp));
+ASSYM(PC_MDS_BUF, offsetof(struct pcpu, pc_mds_buf));
+ASSYM(PC_MDS_BUF64, offsetof(struct pcpu, pc_mds_buf64));
ASSYM(LA_EOI, LAPIC_EOI * LAPIC_MEM_MUL);
ASSYM(LA_ISR, LAPIC_ISR0 * LAPIC_MEM_MUL);
diff --git a/sys/amd64/amd64/initcpu.c b/sys/amd64/amd64/initcpu.c
index abe9d63..9df6477 100644
--- a/sys/amd64/amd64/initcpu.c
+++ b/sys/amd64/amd64/initcpu.c
@@ -223,6 +223,7 @@ initializecpu(void)
}
hw_ibrs_recalculate();
hw_ssb_recalculate(false);
+ hw_mds_recalculate();
switch (cpu_vendor_id) {
case CPU_VENDOR_AMD:
init_amd();
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index cf7ccb2..c0e8f3f 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1851,6 +1851,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
TUNABLE_INT_FETCH("hw.ibrs_disable", &hw_ibrs_disable);
TUNABLE_INT_FETCH("hw.spec_store_bypass_disable", &hw_ssb_disable);
+ TUNABLE_INT_FETCH("hw.mds_disable", &hw_mds_disable);
/* Location of kernel stack for locore */
return ((u_int64_t)thread0.td_pcb);
diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S
index b092ef0..d045168 100644
--- a/sys/amd64/amd64/support.S
+++ b/sys/amd64/amd64/support.S
@@ -1,8 +1,13 @@
/*-
+ * Copyright (c) 2018-2019 The FreeBSD Foundation
* Copyright (c) 2003 Peter Wemm.
* Copyright (c) 1993 The Regents of the University of California.
* All rights reserved.
*
+ * Portions of this software were developed by
+ * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from
+ * the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -892,3 +897,246 @@ ENTRY(handle_ibrs_exit_rs)
END(handle_ibrs_exit_rs)
.noaltmacro
+
+ENTRY(mds_handler_void)
+ retq
+END(mds_handler_void)
+
+ENTRY(mds_handler_verw)
+ subq $8, %rsp
+ movw %ds, (%rsp)
+ verw (%rsp)
+ addq $8, %rsp
+ retq
+END(mds_handler_verw)
+
+ENTRY(mds_handler_ivb)
+ pushq %rax
+ pushq %rdx
+ pushq %rcx
+
+ movq %cr0, %rax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movq PCPU(MDS_BUF), %rdx
+ movdqa %xmm0, PCPU(MDS_TMP)
+ pxor %xmm0, %xmm0
+
+ lfence
+ orpd (%rdx), %xmm0
+ orpd (%rdx), %xmm0
+ mfence
+ movl $40, %ecx
+ addq $16, %rdx
+2: movntdq %xmm0, (%rdx)
+ addq $16, %rdx
+ decl %ecx
+ jnz 2b
+ mfence
+
+ movdqa PCPU(MDS_TMP),%xmm0
+ testb $CR0_TS, %al
+ je 3f
+ movq %rax, %cr0
+3: popq %rcx
+ popq %rdx
+ popq %rax
+ retq
+END(mds_handler_ivb)
+
+ENTRY(mds_handler_bdw)
+ pushq %rax
+ pushq %rbx
+ pushq %rcx
+ pushq %rdi
+ pushq %rsi
+
+ movq %cr0, %rax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movq PCPU(MDS_BUF), %rbx
+ movdqa %xmm0, PCPU(MDS_TMP)
+ pxor %xmm0, %xmm0
+
+ movq %rbx, %rdi
+ movq %rbx, %rsi
+ movl $40, %ecx
+2: movntdq %xmm0, (%rbx)
+ addq $16, %rbx
+ decl %ecx
+ jnz 2b
+ mfence
+ movl $1536, %ecx
+ rep; movsb
+ lfence
+
+ movdqa PCPU(MDS_TMP),%xmm0
+ testb $CR0_TS, %al
+ je 3f
+ movq %rax, %cr0
+3: popq %rsi
+ popq %rdi
+ popq %rcx
+ popq %rbx
+ popq %rax
+ retq
+END(mds_handler_bdw)
+
+ENTRY(mds_handler_skl_sse)
+ pushq %rax
+ pushq %rdx
+ pushq %rcx
+ pushq %rdi
+
+ movq %cr0, %rax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movq PCPU(MDS_BUF), %rdi
+ movq PCPU(MDS_BUF64), %rdx
+ movdqa %xmm0, PCPU(MDS_TMP)
+ pxor %xmm0, %xmm0
+
+ lfence
+ orpd (%rdx), %xmm0
+ orpd (%rdx), %xmm0
+ xorl %eax, %eax
+2: clflushopt 5376(%rdi, %rax, 8)
+ addl $8, %eax
+ cmpl $8 * 12, %eax
+ jb 2b
+ sfence
+ movl $6144, %ecx
+ xorl %eax, %eax
+ rep; stosb
+ mfence
+
+ movdqa PCPU(MDS_TMP), %xmm0
+ testb $CR0_TS, %al
+ je 3f
+ movq %rax, %cr0
+3: popq %rdi
+ popq %rcx
+ popq %rdx
+ popq %rax
+ retq
+END(mds_handler_skl_sse)
+
+ENTRY(mds_handler_skl_avx)
+ pushq %rax
+ pushq %rdx
+ pushq %rcx
+ pushq %rdi
+
+ movq %cr0, %rax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movq PCPU(MDS_BUF), %rdi
+ movq PCPU(MDS_BUF64), %rdx
+ vmovdqa %ymm0, PCPU(MDS_TMP)
+ vpxor %ymm0, %ymm0, %ymm0
+
+ lfence
+ vorpd (%rdx), %ymm0, %ymm0
+ vorpd (%rdx), %ymm0, %ymm0
+ xorl %eax, %eax
+2: clflushopt 5376(%rdi, %rax, 8)
+ addl $8, %eax
+ cmpl $8 * 12, %eax
+ jb 2b
+ sfence
+ movl $6144, %ecx
+ xorl %eax, %eax
+ rep; stosb
+ mfence
+
+ vmovdqa PCPU(MDS_TMP), %ymm0
+ testb $CR0_TS, %al
+ je 3f
+ movq %rax, %cr0
+3: popq %rdi
+ popq %rcx
+ popq %rdx
+ popq %rax
+ retq
+END(mds_handler_skl_avx)
+
+ENTRY(mds_handler_skl_avx512)
+ pushq %rax
+ pushq %rdx
+ pushq %rcx
+ pushq %rdi
+
+ movq %cr0, %rax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movq PCPU(MDS_BUF), %rdi
+ movq PCPU(MDS_BUF64), %rdx
+/* vmovdqa64 %zmm0, PCPU(MDS_TMP) */
+ .byte 0x65, 0x62, 0xf1, 0xfd, 0x48, 0x7f, 0x04, 0x25
+ .long PC_MDS_TMP
+/* vpxor %zmm0, %zmm0, %zmm0 */
+ .byte 0x62, 0xf1, 0xfd, 0x48, 0xef, 0xc0
+
+ lfence
+/* vorpd (%rdx), %zmm0, %zmm0 */
+ .byte 0x62, 0xf1, 0xfd, 0x48, 0x56, 0x02
+/* vorpd (%rdx), %zmm0, %zmm0 */
+ .byte 0x62, 0xf1, 0xfd, 0x48, 0x56, 0x02
+ xorl %eax, %eax
+2: clflushopt 5376(%rdi, %rax, 8)
+ addl $8, %eax
+ cmpl $8 * 12, %eax
+ jb 2b
+ sfence
+ movl $6144, %ecx
+ xorl %eax, %eax
+ rep; stosb
+ mfence
+
+/* vmovdqa64 PCPU(MDS_TMP), %zmm0 */
+ .byte 0x65, 0x62, 0xf1, 0xfd, 0x48, 0x6f, 0x04, 0x25
+ .long PC_MDS_TMP
+ testb $CR0_TS, %al
+ je 3f
+ movq %rax, %cr0
+3: popq %rdi
+ popq %rcx
+ popq %rdx
+ popq %rax
+ retq
+END(mds_handler_skl_avx512)
+
+ENTRY(mds_handler_silvermont)
+ pushq %rax
+ pushq %rdx
+ pushq %rcx
+
+ movq %cr0, %rax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movq PCPU(MDS_BUF), %rdx
+ movdqa %xmm0, PCPU(MDS_TMP)
+ pxor %xmm0, %xmm0
+
+ movl $16, %ecx
+2: movntdq %xmm0, (%rdx)
+ addq $16, %rdx
+ decl %ecx
+ jnz 2b
+ mfence
+
+ movdqa PCPU(MDS_TMP),%xmm0
+ testb $CR0_TS, %al
+ je 3f
+ movq %rax, %cr0
+3: popq %rcx
+ popq %rdx
+ popq %rax
+ retq
+END(mds_handler_silvermont)
diff --git a/sys/amd64/include/pcpu.h b/sys/amd64/include/pcpu.h
index e40c521..c7fa379 100644
--- a/sys/amd64/include/pcpu.h
+++ b/sys/amd64/include/pcpu.h
@@ -73,7 +73,11 @@
uint32_t pc_pcid_gen; \
uint32_t pc_smp_tlb_done; /* TLB op acknowledgement */ \
uint32_t pc_ibpb_set; \
- char __pad[96] /* be divisor of PAGE_SIZE \
+ void *pc_mds_buf; \
+ void *pc_mds_buf64; \
+ uint32_t pc_pad[20]; \
+ uint8_t pc_mds_tmp[64]; \
+ char __pad[960] /* be divisor of PAGE_SIZE \
after cache alignment */
#define PC_DBREG_CMD_NONE 0
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index 5da6827..f22259f 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -44,7 +44,7 @@
TYPE="FreeBSD"
REVISION="11.2"
-BRANCH="RELEASE-p9"
+BRANCH="RELEASE-p10"
if [ -n "${BRANCH_OVERRIDE}" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
diff --git a/sys/dev/cpuctl/cpuctl.c b/sys/dev/cpuctl/cpuctl.c
index 76163ca..bafd861 100644
--- a/sys/dev/cpuctl/cpuctl.c
+++ b/sys/dev/cpuctl/cpuctl.c
@@ -530,6 +530,7 @@ cpuctl_do_eval_cpu_features(int cpu, struct thread *td)
hw_ibrs_recalculate();
restore_cpu(oldcpu, is_bound, td);
hw_ssb_recalculate(true);
+ hw_mds_recalculate();
printcpuinfo();
return (0);
}
diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s
index 53b846a..dddb9d8 100644
--- a/sys/i386/i386/exception.s
+++ b/sys/i386/i386/exception.s
@@ -406,6 +406,7 @@ doreti_ast:
*/
doreti_exit:
MEXITCOUNT
+ call *mds_handler
.globl doreti_popl_fs
doreti_popl_fs:
diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c
index c4c61ed..9445767 100644
--- a/sys/i386/i386/genassym.c
+++ b/sys/i386/i386/genassym.c
@@ -217,6 +217,9 @@ ASSYM(PC_CURRENTLDT, offsetof(struct pcpu, pc_currentldt));
ASSYM(PC_CPUID, offsetof(struct pcpu, pc_cpuid));
ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap));
ASSYM(PC_PRIVATE_TSS, offsetof(struct pcpu, pc_private_tss));
+ASSYM(PC_MDS_TMP, offsetof(struct pcpu, pc_mds_tmp));
+ASSYM(PC_MDS_BUF, offsetof(struct pcpu, pc_mds_buf));
+ASSYM(PC_MDS_BUF64, offsetof(struct pcpu, pc_mds_buf64));
#ifdef DEV_APIC
ASSYM(LA_EOI, LAPIC_EOI * LAPIC_MEM_MUL);
diff --git a/sys/i386/i386/initcpu.c b/sys/i386/i386/initcpu.c
index ce86133..9637dc4 100644
--- a/sys/i386/i386/initcpu.c
+++ b/sys/i386/i386/initcpu.c
@@ -768,6 +768,7 @@ initializecpu(void)
elf32_nxstack = 1;
}
#endif
+ hw_mds_recalculate();
}
void
diff --git a/sys/i386/i386/support.s b/sys/i386/i386/support.s
index 3535c7a..1125143 100644
--- a/sys/i386/i386/support.s
+++ b/sys/i386/i386/support.s
@@ -826,3 +826,194 @@ END(handle_ibrs_entry)
ENTRY(handle_ibrs_exit)
ret
END(handle_ibrs_exit)
+
+ENTRY(mds_handler_void)
+ ret
+END(mds_handler_void)
+
+ENTRY(mds_handler_verw)
+ subl $4, %esp
+ movw %ds, (%esp)
+ verw (%esp)
+ addl $4, %esp
+ ret
+END(mds_handler_verw)
+
+ENTRY(mds_handler_ivb)
+ movl %cr0, %eax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movl PCPU(MDS_BUF), %edx
+ movdqa %xmm0, PCPU(MDS_TMP)
+ pxor %xmm0, %xmm0
+
+ lfence
+ orpd (%edx), %xmm0
+ orpd (%edx), %xmm0
+ mfence
+ movl $40, %ecx
+ addl $16, %edx
+2: movntdq %xmm0, (%edx)
+ addl $16, %edx
+ decl %ecx
+ jnz 2b
+ mfence
+
+ movdqa PCPU(MDS_TMP),%xmm0
+ testb $CR0_TS, %al
+ je 3f
+ movl %eax, %cr0
+3: ret
+END(mds_handler_ivb)
+
+ENTRY(mds_handler_bdw)
+ movl %cr0, %eax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movl PCPU(MDS_BUF), %ebx
+ movdqa %xmm0, PCPU(MDS_TMP)
+ pxor %xmm0, %xmm0
+
+ movl %ebx, %edi
+ movl %ebx, %esi
+ movl $40, %ecx
+2: movntdq %xmm0, (%ebx)
+ addl $16, %ebx
+ decl %ecx
+ jnz 2b
+ mfence
+ movl $1536, %ecx
+ rep; movsb
+ lfence
+
+ movdqa PCPU(MDS_TMP),%xmm0
+ testb $CR0_TS, %al
+ je 3f
+ movl %eax, %cr0
+3: ret
+END(mds_handler_bdw)
+
+ENTRY(mds_handler_skl_sse)
+ movl %cr0, %eax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movl PCPU(MDS_BUF), %edi
+ movl PCPU(MDS_BUF64), %edx
+ movdqa %xmm0, PCPU(MDS_TMP)
+ pxor %xmm0, %xmm0
+
+ lfence
+ orpd (%edx), %xmm0
+ orpd (%edx), %xmm0
+ xorl %eax, %eax
+2: clflushopt 5376(%edi, %eax, 8)
+ addl $8, %eax
+ cmpl $8 * 12, %eax
+ jb 2b
+ sfence
+ movl $6144, %ecx
+ xorl %eax, %eax
+ rep; stosb
+ mfence
+
+ movdqa PCPU(MDS_TMP), %xmm0
+ testb $CR0_TS, %al
+ je 3f
+ movl %eax, %cr0
+3: ret
+END(mds_handler_skl_sse)
+
+ENTRY(mds_handler_skl_avx)
+ movl %cr0, %eax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movl PCPU(MDS_BUF), %edi
+ movl PCPU(MDS_BUF64), %edx
+ vmovdqa %ymm0, PCPU(MDS_TMP)
+ vpxor %ymm0, %ymm0, %ymm0
+
+ lfence
+ vorpd (%edx), %ymm0, %ymm0
+ vorpd (%edx), %ymm0, %ymm0
+ xorl %eax, %eax
+2: clflushopt 5376(%edi, %eax, 8)
+ addl $8, %eax
+ cmpl $8 * 12, %eax
+ jb 2b
+ sfence
+ movl $6144, %ecx
+ xorl %eax, %eax
+ rep; stosb
+ mfence
+
+ vmovdqa PCPU(MDS_TMP), %ymm0
+ testb $CR0_TS, %al
+ je 3f
+ movl %eax, %cr0
+3: ret
+END(mds_handler_skl_avx)
+
+ENTRY(mds_handler_skl_avx512)
+ movl %cr0, %eax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movl PCPU(MDS_BUF), %edi
+ movl PCPU(MDS_BUF64), %edx
+/* vmovdqa64 %zmm0, PCPU(MDS_TMP) */
+ .byte 0x64, 0x62, 0xf1, 0xfd, 0x48, 0x7f, 0x05
+ .long PC_MDS_TMP
+/* vpxor %zmm0, %zmm0, %zmm0 */
+ .byte 0x62, 0xf1, 0xfd, 0x48, 0xef, 0xc0
+
+ lfence
+/* vorpd (%edx), %zmm0, %zmm0 */
+ .byte 0x62, 0xf1, 0xfd, 0x48, 0x56, 0x02
+/* vorpd (%edx), %zmm0, %zmm0 */
+ .byte 0x62, 0xf1, 0xfd, 0x48, 0x56, 0x02
+ xorl %eax, %eax
+2: clflushopt 5376(%edi, %eax, 8)
+ addl $8, %eax
+ cmpl $8 * 12, %eax
+ jb 2b
+ sfence
+ movl $6144, %ecx
+ xorl %eax, %eax
+ rep; stosb
+ mfence
+
+/* vmovdqa64 PCPU(MDS_TMP), %zmm0 */
+ .byte 0x64, 0x62, 0xf1, 0xfd, 0x48, 0x6f, 0x05
+ .long PC_MDS_TMP
+ testb $CR0_TS, %al
+ je 3f
+ movl %eax, %cr0
+3: ret
+END(mds_handler_skl_avx512)
+
+ENTRY(mds_handler_silvermont)
+ movl %cr0, %eax
+ testb $CR0_TS, %al
+ je 1f
+ clts
+1: movl PCPU(MDS_BUF), %edx
+ movdqa %xmm0, PCPU(MDS_TMP)
+ pxor %xmm0, %xmm0
+
+ movl $16, %ecx
+2: movntdq %xmm0, (%edx)
+ addl $16, %edx
+ decl %ecx
+ jnz 2b
+ mfence
+
+ movdqa PCPU(MDS_TMP),%xmm0
+ testb $CR0_TS, %al
+ je 3f
+ movl %eax, %cr0
+3: ret
+END(mds_handler_silvermont)
diff --git a/sys/i386/include/pcpu.h b/sys/i386/include/pcpu.h
index a74cf9f..df809f7 100644
--- a/sys/i386/include/pcpu.h
+++ b/sys/i386/include/pcpu.h
@@ -69,7 +69,11 @@
vm_offset_t pc_qmap_addr; /* KVA for temporary mappings */\
uint32_t pc_smp_tlb_done; /* TLB op acknowledgement */ \
uint32_t pc_ibpb_set; \
- char __pad[185]
+ void *pc_mds_buf; \
+ void *pc_mds_buf64; \
+ uint32_t pc_pad[12]; \
+ uint8_t pc_mds_tmp[64]; \
+ char __pad[153]
#ifdef _KERNEL
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 36c7d54..3733fa9 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -4703,7 +4703,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
{
struct pf_addr *saddr = pd->src, *daddr = pd->dst;
u_int16_t icmpid = 0, *icmpsum;
- u_int8_t icmptype;
+ u_int8_t icmptype, icmpcode;
int state_icmp = 0;
struct pf_state_key_cmp key;
@@ -4712,6 +4712,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
#ifdef INET
case IPPROTO_ICMP:
icmptype = pd->hdr.icmp->icmp_type;
+ icmpcode = pd->hdr.icmp->icmp_code;
icmpid = pd->hdr.icmp->icmp_id;
icmpsum = &pd->hdr.icmp->icmp_cksum;
@@ -4726,6 +4727,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
#ifdef INET6
case IPPROTO_ICMPV6:
icmptype = pd->hdr.icmp6->icmp6_type;
+ icmpcode = pd->hdr.icmp6->icmp6_code;
icmpid = pd->hdr.icmp6->icmp6_id;
icmpsum = &pd->hdr.icmp6->icmp6_cksum;
@@ -4924,6 +4926,23 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
#endif /* INET6 */
}
+ if (PF_ANEQ(pd->dst, pd2.src, pd->af)) {
+ if (V_pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pf: BAD ICMP %d:%d outer dst: ",
+ icmptype, icmpcode);
+ pf_print_host(pd->src, 0, pd->af);
+ printf(" -> ");
+ pf_print_host(pd->dst, 0, pd->af);
+ printf(" inner src: ");
+ pf_print_host(pd2.src, 0, pd2.af);
+ printf(" -> ");
+ pf_print_host(pd2.dst, 0, pd2.af);
+ printf("\n");
+ }
+ REASON_SET(reason, PFRES_BADSTATE);
+ return (PF_DROP);
+ }
+
switch (pd2.proto) {
case IPPROTO_TCP: {
struct tcphdr th;
@@ -4980,7 +4999,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
!SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)))) {
if (V_pf_status.debug >= PF_DEBUG_MISC) {
printf("pf: BAD ICMP %d:%d ",
- icmptype, pd->hdr.icmp->icmp_code);
+ icmptype, icmpcode);
pf_print_host(pd->src, 0, pd->af);
printf(" -> ");
pf_print_host(pd->dst, 0, pd->af);
@@ -4993,7 +5012,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
} else {
if (V_pf_status.debug >= PF_DEBUG_MISC) {
printf("pf: OK ICMP %d:%d ",
- icmptype, pd->hdr.icmp->icmp_code);
+ icmptype, icmpcode);
pf_print_host(pd->src, 0, pd->af);
printf(" -> ");
pf_print_host(pd->dst, 0, pd->af);
diff --git a/sys/x86/include/specialreg.h b/sys/x86/include/specialreg.h
index bdd87ef..e17068f 100644
--- a/sys/x86/include/specialreg.h
+++ b/sys/x86/include/specialreg.h
@@ -385,6 +385,7 @@
/*
* CPUID instruction 7 Structured Extended Features, leaf 0 edx info
*/
+#define CPUID_STDEXT3_MD_CLEAR 0x00000400
#define CPUID_STDEXT3_IBPB 0x04000000
#define CPUID_STDEXT3_STIBP 0x08000000
#define CPUID_STDEXT3_L1D_FLUSH 0x10000000
@@ -395,6 +396,7 @@
#define IA32_ARCH_CAP_RDCL_NO 0x00000001
#define IA32_ARCH_CAP_IBRS_ALL 0x00000002
#define IA32_ARCH_CAP_SSBD_NO 0x00000004
+#define IA32_ARCH_CAP_MDS_NO 0x00000020
/*
* CPUID manufacturers identifiers
diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
index 8dd28f3..c17fe5c 100644
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -83,6 +83,7 @@ extern int use_xsave;
extern uint64_t xsave_mask;
extern int pti;
extern int hw_ibrs_active;
+extern int hw_mds_disable;
extern int hw_ssb_active;
struct pcb;
@@ -134,6 +135,7 @@ int isa_nmi(int cd);
void handle_ibrs_entry(void);
void handle_ibrs_exit(void);
void hw_ibrs_recalculate(void);
+void hw_mds_recalculate(void);
void hw_ssb_recalculate(bool all_cpus);
void nmi_call_kdb(u_int cpu, u_int type, struct trapframe *frame);
void nmi_call_kdb_smp(u_int type, struct trapframe *frame);
diff --git a/sys/x86/x86/cpu_machdep.c b/sys/x86/x86/cpu_machdep.c
index 47d1d67..0604054 100644
--- a/sys/x86/x86/cpu_machdep.c
+++ b/sys/x86/x86/cpu_machdep.c
@@ -938,3 +938,198 @@ SYSCTL_PROC(_hw, OID_AUTO, spec_store_bypass_disable, CTLTYPE_INT |
hw_ssb_disable_handler, "I",
"Speculative Store Bypass Disable (0 - off, 1 - on, 2 - auto");
+int hw_mds_disable;
+
+/*
+ * Handler for Microarchitectural Data Sampling issues. Really not a
+ * pointer to C function: on amd64 the code must not change any CPU
+ * architectural state except possibly %rflags. Also, it is always
+ * called with interrupts disabled.
+ */
+void (*mds_handler)(void);
+void mds_handler_void(void);
+void mds_handler_verw(void);
+void mds_handler_ivb(void);
+void mds_handler_bdw(void);
+void mds_handler_skl_sse(void);
+void mds_handler_skl_avx(void);
+void mds_handler_skl_avx512(void);
+void mds_handler_silvermont(void);
+
+static int
+sysctl_hw_mds_disable_state_handler(SYSCTL_HANDLER_ARGS)
+{
+ const char *state;
+
+ if (mds_handler == mds_handler_void)
+ state = "inactive";
+ else if (mds_handler == mds_handler_verw)
+ state = "VERW";
+ else if (mds_handler == mds_handler_ivb)
+ state = "software IvyBridge";
+ else if (mds_handler == mds_handler_bdw)
+ state = "software Broadwell";
+ else if (mds_handler == mds_handler_skl_sse)
+ state = "software Skylake SSE";
+ else if (mds_handler == mds_handler_skl_avx)
+ state = "software Skylake AVX";
+ else if (mds_handler == mds_handler_skl_avx512)
+ state = "software Skylake AVX512";
+ else if (mds_handler == mds_handler_silvermont)
+ state = "software Silvermont";
+ else
+ state = "unknown";
+ return (SYSCTL_OUT(req, state, strlen(state)));
+}
+
+SYSCTL_PROC(_hw, OID_AUTO, mds_disable_state,
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
+ sysctl_hw_mds_disable_state_handler, "A",
+ "Microarchitectural Data Sampling Mitigation state");
+
+_Static_assert(__offsetof(struct pcpu, pc_mds_tmp) % 64 == 0, "MDS AVX512");
+
+void
+hw_mds_recalculate(void)
+{
+ struct pcpu *pc;
+ vm_offset_t b64;
+ u_long xcr0;
+ int i;
+
+ /*
+ * Allow user to force VERW variant even if MD_CLEAR is not
+ * reported. For instance, hypervisor might unknowingly
+ * filter the cap out.
+ * For the similar reasons, and for testing, allow to enable
+ * mitigation even for RDCL_NO or MDS_NO caps.
+ */
+ if (cpu_vendor_id != CPU_VENDOR_INTEL || hw_mds_disable == 0 ||
+ ((cpu_ia32_arch_caps & (IA32_ARCH_CAP_RDCL_NO |
+ IA32_ARCH_CAP_MDS_NO)) != 0 && hw_mds_disable == 3)) {
+ mds_handler = mds_handler_void;
+ } else if (((cpu_stdext_feature3 & CPUID_STDEXT3_MD_CLEAR) != 0 &&
+ hw_mds_disable == 3) || hw_mds_disable == 1) {
+ mds_handler = mds_handler_verw;
+ } else if (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ (CPUID_TO_MODEL(cpu_id) == 0x2e || CPUID_TO_MODEL(cpu_id) == 0x1e ||
+ CPUID_TO_MODEL(cpu_id) == 0x1f || CPUID_TO_MODEL(cpu_id) == 0x1a ||
+ CPUID_TO_MODEL(cpu_id) == 0x2f || CPUID_TO_MODEL(cpu_id) == 0x25 ||
+ CPUID_TO_MODEL(cpu_id) == 0x2c || CPUID_TO_MODEL(cpu_id) == 0x2d ||
+ CPUID_TO_MODEL(cpu_id) == 0x2a || CPUID_TO_MODEL(cpu_id) == 0x3e ||
+ CPUID_TO_MODEL(cpu_id) == 0x3a) &&
+ (hw_mds_disable == 2 || hw_mds_disable == 3)) {
+ /*
+ * Nehalem, SandyBridge, IvyBridge
+ */
+ CPU_FOREACH(i) {
+ pc = pcpu_find(i);
+ if (pc->pc_mds_buf == NULL) {
+ pc->pc_mds_buf = malloc(672, M_TEMP,
+ M_WAITOK);
+ bzero(pc->pc_mds_buf, 16);
+ }
+ }
+ mds_handler = mds_handler_ivb;
+ } else if (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ (CPUID_TO_MODEL(cpu_id) == 0x3f || CPUID_TO_MODEL(cpu_id) == 0x3c ||
+ CPUID_TO_MODEL(cpu_id) == 0x45 || CPUID_TO_MODEL(cpu_id) == 0x46 ||
+ CPUID_TO_MODEL(cpu_id) == 0x56 || CPUID_TO_MODEL(cpu_id) == 0x4f ||
+ CPUID_TO_MODEL(cpu_id) == 0x47 || CPUID_TO_MODEL(cpu_id) == 0x3d) &&
+ (hw_mds_disable == 2 || hw_mds_disable == 3)) {
+ /*
+ * Haswell, Broadwell
+ */
+ CPU_FOREACH(i) {
+ pc = pcpu_find(i);
+ if (pc->pc_mds_buf == NULL) {
+ pc->pc_mds_buf = malloc(1536, M_TEMP,
+ M_WAITOK);
+ bzero(pc->pc_mds_buf, 16);
+ }
+ }
+ mds_handler = mds_handler_bdw;
+ } else if (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ ((CPUID_TO_MODEL(cpu_id) == 0x55 && (cpu_id &
+ CPUID_STEPPING) <= 5) ||
+ CPUID_TO_MODEL(cpu_id) == 0x4e || CPUID_TO_MODEL(cpu_id) == 0x5e ||
+ (CPUID_TO_MODEL(cpu_id) == 0x8e && (cpu_id &
+ CPUID_STEPPING) <= 0xb) ||
+ (CPUID_TO_MODEL(cpu_id) == 0x9e && (cpu_id &
+ CPUID_STEPPING) <= 0xc)) &&
+ (hw_mds_disable == 2 || hw_mds_disable == 3)) {
+ /*
+ * Skylake, KabyLake, CoffeeLake, WhiskeyLake,
+ * CascadeLake
+ */
+ CPU_FOREACH(i) {
+ pc = pcpu_find(i);
+ if (pc->pc_mds_buf == NULL) {
+ pc->pc_mds_buf = malloc(6 * 1024,
+ M_TEMP, M_WAITOK);
+ b64 = (vm_offset_t)malloc(64 + 63,
+ M_TEMP, M_WAITOK);
+ pc->pc_mds_buf64 = (void *)roundup2(b64, 64);
+ bzero(pc->pc_mds_buf64, 64);
+ }
+ }
+ xcr0 = rxcr(0);
+ if ((xcr0 & XFEATURE_ENABLED_ZMM_HI256) != 0 &&
+ (cpu_stdext_feature2 & CPUID_STDEXT_AVX512DQ) != 0)
+ mds_handler = mds_handler_skl_avx512;
+ else if ((xcr0 & XFEATURE_ENABLED_AVX) != 0 &&
+ (cpu_feature2 & CPUID2_AVX) != 0)
+ mds_handler = mds_handler_skl_avx;
+ else
+ mds_handler = mds_handler_skl_sse;
+ } else if (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ ((CPUID_TO_MODEL(cpu_id) == 0x37 ||
+ CPUID_TO_MODEL(cpu_id) == 0x4a ||
+ CPUID_TO_MODEL(cpu_id) == 0x4c ||
+ CPUID_TO_MODEL(cpu_id) == 0x4d ||
+ CPUID_TO_MODEL(cpu_id) == 0x5a ||
+ CPUID_TO_MODEL(cpu_id) == 0x5d ||
+ CPUID_TO_MODEL(cpu_id) == 0x6e ||
+ CPUID_TO_MODEL(cpu_id) == 0x65 ||
+ CPUID_TO_MODEL(cpu_id) == 0x75 ||
+ CPUID_TO_MODEL(cpu_id) == 0x1c ||
+ CPUID_TO_MODEL(cpu_id) == 0x26 ||
+ CPUID_TO_MODEL(cpu_id) == 0x27 ||
+ CPUID_TO_MODEL(cpu_id) == 0x35 ||
+ CPUID_TO_MODEL(cpu_id) == 0x36 ||
+ CPUID_TO_MODEL(cpu_id) == 0x7a))) {
+ /* Silvermont, Airmont */
+ CPU_FOREACH(i) {
+ pc = pcpu_find(i);
+ if (pc->pc_mds_buf == NULL)
+ pc->pc_mds_buf = malloc(256, M_TEMP, M_WAITOK);
+ }
+ mds_handler = mds_handler_silvermont;
+ } else {
+ hw_mds_disable = 0;
+ mds_handler = mds_handler_void;
+ }
+}
+
+static int
+sysctl_mds_disable_handler(SYSCTL_HANDLER_ARGS)
+{
+ int error, val;
+
+ val = hw_mds_disable;
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (val < 0 || val > 3)
+ return (EINVAL);
+ hw_mds_disable = val;
+ hw_mds_recalculate();
+ return (0);
+}
+
+SYSCTL_PROC(_hw, OID_AUTO, mds_disable, CTLTYPE_INT |
+ CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_MPSAFE, NULL, 0,
+ sysctl_mds_disable_handler, "I",
+ "Microarchitectural Data Sampling Mitigation "
+ "(0 - off, 1 - on VERW, 2 - on SW, 3 - on AUTO");
+
diff --git a/usr.bin/xinstall/tests/install_test.sh b/usr.bin/xinstall/tests/install_test.sh
index 4332f9b..92044f3 100755
--- a/usr.bin/xinstall/tests/install_test.sh
+++ b/usr.bin/xinstall/tests/install_test.sh
@@ -377,6 +377,29 @@ mkdir_simple_body() {
atf_check install -d dir1/dir2/dir3
}
+atf_test_case symbolic_link_relative_absolute_common
+symbolic_link_relative_absolute_common_head() {
+ atf_set "descr" "Verify -l rs with absolute paths having common components"
+}
+symbolic_link_relative_absolute_common_body() {
+ filename=foo.so
+ src_path=lib
+ src_path_prefixed=$PWD/$src_path
+ dest_path=$PWD/libexec/
+ src_file=$src_path_prefixed/$filename
+ dest_file=$dest_path/$filename
+
+ atf_check mkdir $src_path_prefixed $dest_path
+ atf_check touch $src_file
+ atf_check install -l sr $src_file $dest_path
+
+ dest_path_relative=$(readlink $dest_file)
+ src_path_relative="../lib/$filename"
+ if [ "$src_path_relative" != "$dest_path_relative" ]; then
+ atf_fail "unexpected symlink contents ('$src_path_relative' != '$dest_path_relative')"
+ fi
+}
+
atf_init_test_cases() {
atf_add_test_case copy_to_nonexistent
atf_add_test_case copy_to_nonexistent_safe
@@ -415,5 +438,6 @@ atf_init_test_cases() {
atf_add_test_case symbolic_link_relative_absolute_source_and_dest1
atf_add_test_case symbolic_link_relative_absolute_source_and_dest1_double_slash
atf_add_test_case symbolic_link_relative_absolute_source_and_dest2
+ atf_add_test_case symbolic_link_relative_absolute_common
atf_add_test_case mkdir_simple
}
diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c
index 16eba77..6688591 100644
--- a/usr.bin/xinstall/xinstall.c
+++ b/usr.bin/xinstall/xinstall.c
@@ -667,7 +667,7 @@ makelink(const char *from_name, const char *to_name,
}
if (dolink & LN_RELATIVE) {
- char *to_name_copy, *cp, *d, *s;
+ char *to_name_copy, *cp, *d, *ld, *ls, *s;
if (*from_name != '/') {
/* this is already a relative link */
@@ -703,8 +703,19 @@ makelink(const char *from_name, const char *to_name,
free(to_name_copy);
/* Trim common path components. */
- for (s = src, d = dst; *s == *d; s++, d++)
+ ls = ld = NULL;
+ for (s = src, d = dst; *s == *d; ls = s, ld = d, s++, d++)
continue;
+ /*
+ * If we didn't end after a directory separator, then we've
+ * falsely matched the last component. For example, if one
+ * invoked install -lrs /lib/foo.so /libexec/ then the source
+ * would terminate just after the separator while the
+ * destination would terminate in the middle of 'libexec',
+ * leading to a full directory getting falsely eaten.
+ */
+ if ((ls != NULL && *ls != '/') || (ld != NULL && *ld != '/'))
+ s--, d--;
while (*s != '/')
s--, d--;
diff --git a/usr.sbin/ntp/config.h b/usr.sbin/ntp/config.h
index 9bc0564..da6896a 100644
--- a/usr.sbin/ntp/config.h
+++ b/usr.sbin/ntp/config.h
@@ -313,6 +313,9 @@
/* Provide the explicit 127.0.0.0/8 martian filter? */
#define ENABLE_BUG3020_FIX 1
+/* Enable CMAC support? */
+#define ENABLE_CMAC 1
+
/* nls support in libopts */
/* #undef ENABLE_NLS */
@@ -374,6 +377,14 @@
/* Define to 1 if you have the `daemon' function. */
#define HAVE_DAEMON 1
+/* Define to 1 if you have the declaration of `siglongjmp', and to 0 if you
+ don't. */
+#define HAVE_DECL_SIGLONGJMP 1
+
+/* Define to 1 if you have the declaration of `sigsetjmp', and to 0 if you
+ don't. */
+#define HAVE_DECL_SIGSETJMP 1
+
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
don't. */
#define HAVE_DECL_STRERROR_R 1
@@ -655,6 +666,12 @@
/* if you have NT Threads */
/* #undef HAVE_NT_THREADS */
+/* Define to 1 if you have the <openssl/cmac.h> header file. */
+#define HAVE_OPENSSL_CMAC_H 1
+
+/* Define to 1 if you have the <openssl/hmac.h> header file. */
+#define HAVE_OPENSSL_HMAC_H 1
+
/* Define to 1 if the system has the type `pid_t'. */
#define HAVE_PID_T 1
@@ -959,6 +976,9 @@
/* Define to 1 if you have the <sys/lock.h> header file. */
#define HAVE_SYS_LOCK_H 1
+/* Define to 1 if you have the <sys/mac.h> header file. */
+#define HAVE_SYS_MAC_H 1
+
/* Define to 1 if you have the <sys/mman.h> header file. */
#define HAVE_SYS_MMAN_H 1
@@ -1445,7 +1465,7 @@
#define PACKAGE_NAME "ntp"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "ntp 4.2.8p11"
+#define PACKAGE_STRING "ntp 4.2.8p12"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "ntp"
@@ -1454,7 +1474,7 @@
#define PACKAGE_URL "http://www.ntp.org./"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "4.2.8p11"
+#define PACKAGE_VERSION "4.2.8p12"
/* data dir */
#define PERLLIBDIR "/usr/share/ntp/lib"
@@ -1635,10 +1655,10 @@ typedef unsigned int uintptr_t;
/* #undef USE_UDP_SIGPOLL */
/* Version number of package */
-#define VERSION "4.2.8p11"
+#define VERSION "4.2.8p12"
/* vsnprintf expands "%m" to strerror(errno) */
-/* #undef VSNPRINTF_PERCENT_M */
+#define VSNPRINTF_PERCENT_M 1
/* configure --enable-ipv6 */
#define WANT_IPV6 1
@@ -1812,5 +1832,5 @@ typedef union mpinfou {
/*
* FreeBSD specific: Explicitly specify date/time for reproducible build.
*/
-#define MKREPRO_DATE "Feb 28 2018"
-#define MKREPRO_TIME "06:33:03"
+#define MKREPRO_DATE "Aug 19 2018"
+#define MKREPRO_TIME "01:24:29"
diff --git a/usr.sbin/ntp/doc/ntp-keygen.8 b/usr.sbin/ntp/doc/ntp-keygen.8
index e4b7eaf..f17666d 100644
--- a/usr.sbin/ntp/doc/ntp-keygen.8
+++ b/usr.sbin/ntp/doc/ntp-keygen.8
@@ -1,11 +1,11 @@
-.Dd February 27 2018
+.Dd August 14 2018
.Dt NTP_KEYGEN 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:16:00 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed August 14, 2018 at 08:30:38 AM by AutoGen 5.18.5
.\" From the definitions ntp-keygen-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -945,7 +945,7 @@ Following the header the keys are entered one per line in the format
.D1 Ar keyno Ar type Ar key
where
.Ar keyno
-is a positive integer in the range 1\-65534;
+is a positive integer in the range 1\-65535;
.Ar type
is the key type for the message digest algorithm, which in the absence of the
OpenSSL library must be
diff --git a/usr.sbin/ntp/doc/ntp.conf.5 b/usr.sbin/ntp/doc/ntp.conf.5
index 14632ce..efbc983 100644
--- a/usr.sbin/ntp/doc/ntp.conf.5
+++ b/usr.sbin/ntp/doc/ntp.conf.5
@@ -1,11 +1,11 @@
-.Dd February 27 2018
+.Dd August 14 2018
.Dt NTP_CONF 5 File Formats
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:42 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed August 14, 2018 at 08:29:15 AM by AutoGen 5.18.5
.\" From the definitions ntp.conf.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -327,7 +327,7 @@ option.
All packets sent to and received from the server or peer are to
include authentication fields encrypted using the specified
.Ar key
-identifier with values from 1 to 65534, inclusive.
+identifier with values from 1 to 65535, inclusive.
The
default is to include no encryption field.
.It Cm minpoll Ar minpoll
@@ -585,7 +585,7 @@ and reports at the NTP project page linked from
.Li http://www.ntp.org/ .
.Ss Symmetric\-Key Cryptography
The original RFC\-1305 specification allows any one of possibly
-65,534 keys, each distinguished by a 32\-bit key identifier, to
+65,535 keys, each distinguished by a 32\-bit key identifier, to
authenticate an association.
The servers and clients involved must
agree on the key and key identifier to
@@ -879,7 +879,7 @@ The
.Ar key
argument is
the key identifier for a trusted key, where the value can be in the
-range 1 to 65,534, inclusive.
+range 1 to 65,535, inclusive.
.It Xo Ic crypto
.Op Cm cert Ar file
.Op Cm leap Ar file
@@ -983,7 +983,7 @@ The
.Ar key
argument is a key identifier
for the trusted key, where the value can be in the range 1 to
-65,534, inclusive.
+65,535, inclusive.
.It Ic revoke Ar logsec
Specifies the interval between re\-randomization of certain
cryptographic values used by the Autokey scheme, as a power of 2 in
@@ -1010,7 +1010,7 @@ servers.
The
.Ar key
arguments are 32\-bit unsigned
-integers with values from 1 to 65,534.
+integers with values from 1 to 65,535.
.El
.Ss Error Codes
The following error codes are reported via the NTP control
diff --git a/usr.sbin/ntp/doc/ntp.keys.5 b/usr.sbin/ntp/doc/ntp.keys.5
index aeb7338..5c3785a 100644
--- a/usr.sbin/ntp/doc/ntp.keys.5
+++ b/usr.sbin/ntp/doc/ntp.keys.5
@@ -1,11 +1,11 @@
-.Dd February 27 2018
+.Dd August 14 2018
.Dt NTP_KEYS 5 File Formats
.Os SunOS 5.10
.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:46 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed August 14, 2018 at 08:29:18 AM by AutoGen 5.18.5
.\" From the definitions ntp.keys.def
.\" and the template file agmdoc-file.tpl
.Sh NAME
@@ -39,7 +39,7 @@ statement in the configuration file.
While key number 0 is fixed by the NTP standard
(as 56 zero bits)
and may not be changed,
-one or more keys numbered between 1 and 65534
+one or more keys numbered between 1 and 65535
may be arbitrarily set in the keys file.
.Pp
The key file uses the same comment conventions
@@ -50,7 +50,7 @@ Key entries use a fixed format of the form
.Pp
where
.Ar keyno
-is a positive integer (between 1 and 65534),
+is a positive integer (between 1 and 65535),
.Ar type
is the message digest algorithm,
.Ar key
diff --git a/usr.sbin/ntp/doc/ntpd.8 b/usr.sbin/ntp/doc/ntpd.8
index 7fb6529..07cb6d5 100644
--- a/usr.sbin/ntp/doc/ntpd.8
+++ b/usr.sbin/ntp/doc/ntpd.8
@@ -1,11 +1,11 @@
-.Dd February 27 2018
+.Dd August 14 2018
.Dt NTPD 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpd-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:14:47 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed August 14, 2018 at 08:29:20 AM by AutoGen 5.18.5
.\" From the definitions ntpd-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/usr.sbin/ntp/doc/ntpdc.8 b/usr.sbin/ntp/doc/ntpdc.8
index c1b9c3e..c0ffef1 100644
--- a/usr.sbin/ntp/doc/ntpdc.8
+++ b/usr.sbin/ntp/doc/ntpdc.8
@@ -1,11 +1,11 @@
-.Dd February 27 2018
+.Dd August 14 2018
.Dt NTPDC 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpdc-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:09 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed August 14, 2018 at 08:29:43 AM by AutoGen 5.18.5
.\" From the definitions ntpdc-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/usr.sbin/ntp/doc/ntpq.8 b/usr.sbin/ntp/doc/ntpq.8
index f1b77d3..04f1d70 100644
--- a/usr.sbin/ntp/doc/ntpq.8
+++ b/usr.sbin/ntp/doc/ntpq.8
@@ -1,11 +1,11 @@
-.Dd February 27 2018
+.Dd August 14 2018
.Dt NTPQ 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpq-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:15:28 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed August 14, 2018 at 08:30:05 AM by AutoGen 5.18.5
.\" From the definitions ntpq-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/usr.sbin/ntp/doc/sntp.8 b/usr.sbin/ntp/doc/sntp.8
index 813bcdd..2cf625f 100644
--- a/usr.sbin/ntp/doc/sntp.8
+++ b/usr.sbin/ntp/doc/sntp.8
@@ -1,11 +1,11 @@
-.Dd February 27 2018
+.Dd August 14 2018
.Dt SNTP 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (sntp-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 27, 2018 at 05:13:14 PM by AutoGen 5.18.5
+.\" It has been AutoGen-ed August 14, 2018 at 08:27:40 AM by AutoGen 5.18.5
.\" From the definitions sntp-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/usr.sbin/ntp/libntp/Makefile b/usr.sbin/ntp/libntp/Makefile
index bd3b8b5..3480571 100644
--- a/usr.sbin/ntp/libntp/Makefile
+++ b/usr.sbin/ntp/libntp/Makefile
@@ -29,7 +29,7 @@ NTP_SRCS= systime.c a_md5encrypt.c adjtime.c atoint.c \
socktoa.c socktohost.c ssl_init.c statestr.c \
strdup.c strl_obsd.c syssignal.c timetoa.c \
timevalops.c uglydate.c vint64ops.c work_fork.c \
- work_thread.c ymd2yd.c
+ work_thread.c xsbprintf.c ymd2yd.c
ISC_PTHREADS_SRCS= condition.c \
thread.c \
diff --git a/usr.sbin/ntp/scripts/mkver b/usr.sbin/ntp/scripts/mkver
index 40e22f6..4e81652 100755
--- a/usr.sbin/ntp/scripts/mkver
+++ b/usr.sbin/ntp/scripts/mkver
@@ -6,7 +6,7 @@ PROG=${1-UNKNOWN}
ConfStr="$PROG"
-ConfStr="$ConfStr 4.2.8p11"
+ConfStr="$ConfStr 4.2.8p12"
case "$CSET" in
'') ;;
diff --git a/usr.sbin/wpa/Makefile.crypto b/usr.sbin/wpa/Makefile.crypto
index 5c03f7d..8f7965d 100644
--- a/usr.sbin/wpa/Makefile.crypto
+++ b/usr.sbin/wpa/Makefile.crypto
@@ -1,7 +1,8 @@
# $FreeBSD$
.if ${MK_OPENSSL} != "no" && !defined(RELEASE_CRUNCH)
-SRCS+= crypto_openssl.c random.c sha1-prf.c sha256-prf.c sha256-tlsprf.c
+SRCS+= crypto_openssl.c random.c sha1-prf.c sha256-prf.c sha256-tlsprf.c \
+ sha512.c
LIBADD+= ssl crypto
CFLAGS+= -DCONFIG_SHA256
.else
@@ -21,6 +22,7 @@ CONFIG_INTERNAL_DH=y
NEED_AES_ENC=true
NEED_AES_CBC=true
.endif
+NEED_AES_OMAC1=true
.if defined(TLS_FUNCS)
NEED_TLS_PRF=y
@@ -49,7 +51,7 @@ NEED_MD4=y
NEED_RC4=y
.else
CFLAGS+=-DEAP_TLS_OPENSSL
-SRCS+= tls_openssl.c
+SRCS+= tls_openssl.c tls_openssl_ocsp.c
.endif
.endif
diff --git a/usr.sbin/wpa/Makefile.inc b/usr.sbin/wpa/Makefile.inc
index 2029fd6..c2e216c 100644
--- a/usr.sbin/wpa/Makefile.inc
+++ b/usr.sbin/wpa/Makefile.inc
@@ -7,13 +7,10 @@ WPA_SUPPLICANT_DISTDIR?=${WPA_DISTDIR}/wpa_supplicant
HOSTAPD_DISTDIR?= ${WPA_DISTDIR}/hostapd
.PATH.c:${.CURDIR:H} \
- ${WPA_DISTDIR}/src/ap \
${WPA_DISTDIR}/src/common \
${WPA_DISTDIR}/src/crypto \
${WPA_DISTDIR}/src/eapol_auth \
${WPA_DISTDIR}/src/eap_common \
- ${WPA_DISTDIR}/src/eap_peer \
- ${WPA_DISTDIR}/src/eap_server \
${WPA_DISTDIR}/src/eapol_supp \
${WPA_DISTDIR}/src/l2_packet \
${WPA_DISTDIR}/src/radius \
@@ -34,5 +31,7 @@ CFLAGS+=-I${WPA_DISTDIR}/src/wps
CFLAGS+= -DCONFIG_CTRL_IFACE
CFLAGS+= -DCONFIG_CTRL_IFACE_UNIX
+CFLAGS+= -DNEED_AP_MLME
+CFLAGS+= -DTLS_DEFAULT_CIPHERS=\"DEFAULT:!EXP:!LOW\"
.include <bsd.own.mk>
diff --git a/usr.sbin/wpa/hostapd/Makefile b/usr.sbin/wpa/hostapd/Makefile
index b2feb94..eace6cb 100644
--- a/usr.sbin/wpa/hostapd/Makefile
+++ b/usr.sbin/wpa/hostapd/Makefile
@@ -4,27 +4,90 @@
.include "../Makefile.inc"
.PATH.c:${HOSTAPD_DISTDIR} \
- ${WPA_DISTDIR}/src/drivers
+ ${WPA_DISTDIR}/src/ap \
+ ${WPA_DISTDIR}/src/eap_server \
+ ${WPA_DISTDIR}/src/eap_peer \
+ ${WPA_DISTDIR}/src/drivers \
+ ${WPA_DISTDIR}/wpa_supplicant
PROG= hostapd
-SRCS= accounting.c aes-omac1.c ap_config.c ap_drv_ops.c ap_mlme.c authsrv.c \
- base64.c beacon.c bss_load.c chap.c common.c config_file.c \
+SRCS= accounting.c \
+ ap_config.c \
+ ap_drv_ops.c \
+ ap_list.c \
+ ap_mlme.c \
+ authsrv.c \
+ base64.c \
+ beacon.c \
+ bss_load.c \
+ chap.c \
+ common.c \
+ config_file.c \
ctrl_iface.c \
- ctrl_iface_ap.c driver_common.c l2_packet_freebsd.c driver_bsd.c \
- drivers.c drv_callbacks.c eap_common.c eap_peap_common.c \
- eap_register.c eap_server.c eap_server_methods.c eap_user_db.c \
- eapol_auth_dump.c eapol_auth_sm.c eloop.c gas.c gas_serv.c hostapd.c \
- hs20.c http_client.c http_server.c httpread.c \
- hw_features_common.c ieee802_11_auth.c \
- ieee802_11_common.c ieee802_11_shared.c ieee802_1x.c ip_addr.c \
- main.c ms_funcs.c os_unix.c peerkey_auth.c pmksa_cache_auth.c \
- preauth_auth.c radius.c radius_client.c radius_das.c sta_info.c \
- tkip_countermeasures.c upnp_xml.c utils.c uuid.c vlan_init.c \
- wpa_auth.c wpa_auth_glue.c wpa_auth_ie.c wpa_common.c wpa_debug.c \
- wpabuf.c wps.c wps_attr_build.c wps_attr_parse.c wps_attr_process.c \
- wps_common.c wps_dev_attr.c wps_enrollee.c wps_hostapd.c \
- wps_registrar.c wps_upnp.c wps_upnp_ap.c wps_upnp_event.c \
- wps_upnp_ssdp.c wps_upnp_web.c
+ ctrl_iface_ap.c \
+ ctrl_iface_common.c \
+ dfs.c \
+ driver_bsd.c \
+ driver_common.c \
+ drivers.c \
+ drv_callbacks.c \
+ eloop.c \
+ gas.c \
+ gas_serv.c \
+ http_client.c \
+ http_server.c \
+ httpread.c \
+ hostapd.c \
+ hs20.c \
+ hw_features.c \
+ hw_features_common.c \
+ ieee802_11.c \
+ ieee802_11_auth.c \
+ ieee802_11_common.c \
+ ieee802_11_shared.c \
+ ieee802_1x.c \
+ ip_addr.c \
+ l2_packet_freebsd.c \
+ main.c \
+ ms_funcs.c \
+ neighbor_db.c \
+ os_unix.c \
+ pmksa_cache_auth.c \
+ preauth_auth.c \
+ radius.c \
+ radius_client.c \
+ radius_das.c \
+ rrm.c \
+ sta_info.c \
+ tkip_countermeasures.c \
+ upnp_xml.c \
+ utils.c \
+ uuid.c \
+ vlan.c \
+ vlan_ifconfig.c \
+ vlan_init.c \
+ wmm.c \
+ wpa_auth.c \
+ wpa_auth_glue.c \
+ wpa_auth_ie.c \
+ wpa_common.c \
+ wpa_ctrl.c \
+ wpa_debug.c \
+ wpabuf.c \
+ wps.c \
+ wps_attr_build.c \
+ wps_attr_process.c \
+ wps_attr_parse.c \
+ wps_common.c \
+ wps_dev_attr.c \
+ wps_enrollee.c \
+ wps_hostapd.c \
+ wps_registrar.c \
+ wps_upnp.c \
+ wps_upnp_ap.c \
+ wps_upnp_event.c \
+ wps_upnp_ssdp.c \
+ wps_upnp_web.c
MAN= hostapd.8 hostapd.conf.5
@@ -34,7 +97,9 @@ FILESDIR= ${SHAREDIR}/examples/hostapd
FILES= hostapd.conf hostapd.eap_user hostapd.wpa_psk
.endif
-CFLAGS+=-DCONFIG_DRIVER_BSD \
+CFLAGS+=-I${.CURDIR:H}/wpa_supplicant \
+ -I${WPA_DISTDIR}/src/eap_peer \
+ -DCONFIG_DRIVER_BSD \
-DCONFIG_DRIVER_RADIUS_ACL \
-DCONFIG_HS20 \
-DCONFIG_INTERWORKING \
@@ -69,15 +134,23 @@ CFLAGS+=-DDPKCS12_FUNCS \
-DEAP_TLS_FUNCS
SRCS+= eap_server_gtc.c \
+ eap_common.c \
+ eap_peap_common.c \
+ eap_register.c \
+ eap_server.c \
eap_server_identity.c \
eap_server_md5.c \
+ eap_server_methods.c \
eap_server_mschapv2.c \
eap_server_peap.c \
eap_server_tls.c \
eap_server_tls_common.c \
eap_server_ttls.c \
eap_server_wsc.c \
- eap_wsc_common.c
+ eap_user_db.c \
+ eap_wsc_common.c \
+ eapol_auth_dump.c \
+ eapol_auth_sm.c
TLS_FUNCS=y
.if !empty(CFLAGS:M*-DCONFIG_WPS)
diff --git a/usr.sbin/wpa/hostapd_cli/Makefile b/usr.sbin/wpa/hostapd_cli/Makefile
index a9c4393..ad65233 100644
--- a/usr.sbin/wpa/hostapd_cli/Makefile
+++ b/usr.sbin/wpa/hostapd_cli/Makefile
@@ -5,7 +5,8 @@
.PATH.c:${HOSTAPD_DISTDIR}
PROG= hostapd_cli
-SRCS= common.c edit.c eloop.c hostapd_cli.c os_unix.c wpa_ctrl.c wpa_debug.c
+SRCS= cli.c common.c edit.c eloop.c hostapd_cli.c os_unix.c \
+ wpa_ctrl.c wpa_debug.c
CFLAGS+= -DCONFIG_CTRL_IFACE
CFLAGS+= -DCONFIG_CTRL_IFACE_UNIX
diff --git a/usr.sbin/wpa/wpa_cli/Makefile b/usr.sbin/wpa/wpa_cli/Makefile
index 585499d..f6db85e 100644
--- a/usr.sbin/wpa/wpa_cli/Makefile
+++ b/usr.sbin/wpa/wpa_cli/Makefile
@@ -1,20 +1,41 @@
# $FreeBSD$
+.include <src.opts.mk>
+
.include "../Makefile.inc"
-.PATH.c:${WPA_SUPPLICANT_DISTDIR}
+.PATH.c:${WPA_SUPPLICANT_DISTDIR} \
+ ${WPA_DISTDIR}/wpa_supplicant \
+ ${WPA_DISTDIR}/src/eap_peer \
+ ${WPA_DISTDIR}/src/drivers
PROG= wpa_cli
-SRCS= common.c edit.c eloop.c os_unix.c wpa_cli.c wpa_ctrl.c wpa_debug.c
+SRCS= base64.c bitfield.c blacklist.c bss.c cli.c common.c config.c \
+ config_file.c \
+ ctrl_iface.c ctrl_iface_common.c ctrl_iface_unix.c \
+ drivers.c driver_common.c \
+ eap_register.c \
+ edit.c eloop.c events.c hw_features_common.c \
+ ieee802_11_common.c l2_packet_freebsd.c notify.c \
+ op_classes.c \
+ os_unix.c rrm.c scan.c wmm_ac.c \
+ wpa.c wpa_cli.c \
+ wpa_ctrl.c wpa_common.c \
+ wpa_debug.c wpa_ie.c wpa_supplicant.c wpabuf.c wpas_glue.c
MAN= wpa_cli.8
CFLAGS+= -DCONFIG_CTRL_IFACE
CFLAGS+= -DCONFIG_CTRL_IFACE_UNIX
+CFLAGS+= -DCONFIG_TLS=openssl
# enable use of d_type to identify unix domain sockets
CFLAGS+= -D_DIRENT_HAVE_D_TYPE
CFLAGS+= -DCONFIG_WPA_CLI_EDIT=y
-LIBADD+= util
+LIBADD+= pcap util
+
+TLS_FUNCS=y
+
+.include "../Makefile.crypto"
.include <bsd.prog.mk>
diff --git a/usr.sbin/wpa/wpa_supplicant/Makefile b/usr.sbin/wpa/wpa_supplicant/Makefile
index a8ccb16..673e45b 100644
--- a/usr.sbin/wpa/wpa_supplicant/Makefile
+++ b/usr.sbin/wpa/wpa_supplicant/Makefile
@@ -5,25 +5,30 @@
.include "../Makefile.inc"
.PATH.c:${WPA_SUPPLICANT_DISTDIR} \
+ ${WPA_DISTDIR}/src/eap_peer \
${WPA_DISTDIR}/src/drivers
PROG= wpa_supplicant
-SRCS= ap_drv_ops.c base64.c blacklist.c bss.c common.c config.c \
- config_file.c ctrl_iface.c ctrl_iface_unix.c driver_bsd.c \
- driver_common.c driver_ndis.c driver_wired.c drivers.c \
- eap_register.c eloop.c events.c gas.c gas_query.c hs20.c \
- hs20_supplicant.c http_client.c http_server.c httpread.c \
- hw_features_common.c \
- ieee802_11_common.c ieee802_11_shared.c \
- interworking.c l2_packet_freebsd.c main.c \
- notify.c offchannel.c os_unix.c peerkey.c pmksa_cache.c \
- preauth.c scan.c upnp_xml.c uuid.c wmm_ac.c \
- wpa.c wpa_common.c wpa_debug.c \
- wpa_ft.c wpa_ie.c wpa_supplicant.c wpabuf.c wpas_glue.c wps.c \
- wps_attr_build.c wps_attr_parse.c wps_attr_process.c \
+
+SRCS= base64.c bitfield.c blacklist.c bss.c cli.c common.c \
+ config.c config_file.c \
+ ctrl_iface.c ctrl_iface_common.c ctrl_iface_unix.c \
+ dh_groups.c driver_bsd.c driver_common.c \
+ driver_ndis.c driver_wired.c driver_wired_common.c drivers.c \
+ eap_register.c eap_wsc.c eap_wsc_common.c eloop.c \
+ events.c gas.c gas_query.c hs20_supplicant.c \
+ http_client.c http_server.c \
+ httpread.c hw_features_common.c \
+ ieee802_11_common.c interworking.c l2_packet_freebsd.c main.c \
+ notify.c offchannel.c op_classes.c os_unix.c pmksa_cache.c preauth.c \
+ rrm.c scan.c upnp_xml.c uuid.c \
+ wmm_ac.c wpa.c wpa_common.c wpa_ctrl.c \
+ wpa_debug.c wpa_ft.c wpa_ie.c wpa_supplicant.c wpabuf.c wpas_glue.c \
+ wps.c wps_attr_build.c wps_attr_parse.c wps_attr_process.c \
wps_common.c wps_dev_attr.c wps_enrollee.c wps_registrar.c \
wps_supplicant.c wps_upnp.c wps_upnp_ap.c wps_upnp_event.c \
- wps_upnp_ssdp.c wps_upnp_web.c Packet32.c
+ wps_upnp_ssdp.c wps_upnp_web.c \
+ Packet32.c
MAN= wpa_supplicant.8 wpa_supplicant.conf.5
OpenPOWER on IntegriCloud